Blocks Claude from editing .env files, secrets folders and lock files — before the edit happens.
WHEN TO USE IT
When some files must never be changed by an assistant, however sensible the reason sounds at the time.
Formats change. If a field stops working, check it against Anthropic's documentation.
Read it before you install it. A hook runs with your user account's permissions, on its own, every time it is triggered. That is what makes it useful, and why a stranger's should never be installed unread — this one included.
PreToolUse runs before the tool and can stop it. The matcher is a plain list, so Edit|Write means exactly those two tools.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
Exit 2 is the only code that blocks; the message on stderr is what Claude is told. Needs jq, and refuses every edit without it rather than allowing them all. Before relying on it, log stdin once (cat > /tmp/hook.json) to confirm the path field for your version.
#!/usr/bin/env bash
# Blocks edits to protected paths. Reads the hook event from stdin.
# Fail CLOSED: without jq the path reads as empty and every edit
# would be allowed, silently. Exit 2 says so instead.
command -v jq >/dev/null || { echo "protect-files: install jq" >&2; exit 2; }
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
*.env|*.env.*|*/secrets/*|*.pem|*.key|*package-lock.json|*yarn.lock)
echo "Blocked: $file is protected. Ask the user to change it by hand." >&2
exit 2
;;
esac
exit 0
The script must be executable, or the hook fails with a non-blocking error and the edit goes through.
mkdir -p .claude/hooks
mv protect-files.sh .claude/hooks/
chmod +x .claude/hooks/protect-files.sh
# merge the "hooks" block into .claude/settings.json, then check it
# inside Claude Code with: /hooks
MORE HOOKS
The authority
Anthropic's documentation for Hooks
This template is a starting point. Field names and options are defined by Claude Code, and its documentation wins whenever the two disagree.
https://code.claude.com/docs/en/hooks