- Tools
- Claude Code, jq
- Price
- Included (jq is free)
- Time
- 15 min
- Level
- Terminal, intermediate
A CLAUDE.md file gives the AI instructions, and Claude usually follows them. Usually. For an invoice you have already sent, “usually” is not enough: an issued invoice must not change. Hooks solve this. Anthropic describes them as “deterministic” control: a given action always happens, instead of relying on the model to remember it.
How it works
A hook lives in a settings file, settings.json. It ties a moment (an “event”) to a command. The most useful moments:
PreToolUse: just before an action by Claude (editing a file, running a command). This hook can block it.PostToolUse: just after a successful action, for example to reformat a file.Notification: when Claude is waiting for your answer or permission.SessionStart: when a session starts.
The matcher field says which actions the hook applies to: Edit|Write targets file edits. To block, the command must exit with code 2. Careful: exit code 1 does not block, it only produces a warning.
To start: get notified when the AI is waiting
A first, risk-free hook from the docs: a macOS notification whenever Claude needs you. Add it to ~/.claude/settings.json (create the file if it does not exist):
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}If nothing shows up, open System Settings, Notifications, and allow “Script Editor”, the app these notifications go through.
Block edits to your invoices
- Check that jq is installedjq reads the data Claude Code passes to the hook. If the first command does not answer, install it with Homebrew.
jq --version brew install jq - Create the check scriptIn your business folder, save this file as
.claude/hooks/protect-files.sh. Adapt the list of protected patterns:#!/bin/bash # Blocks Claude Code from editing certain files INPUT=$(cat) FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') PROTECTED=("invoices/" ".env" ".git/") for pattern in "${PROTECTED[@]}"; do if [[ "$FILE" == *"$pattern"* ]]; then echo "Blocked: $FILE is protected ($pattern). Ask the user first." >&2 exit 2 fi done exit 0 - Make it executableWithout this step, Claude Code cannot run it.
chmod +x .claude/hooks/protect-files.sh - Test it by handSend the script a fake edit request. It should print the “Blocked” message, then the code 2.
echo '{"tool_name":"Edit","tool_input":{"file_path":"invoices/INV-2026-001.md"}}' | .claude/hooks/protect-files.sh echo $? - Register the hookAdd this block to
.claude/settings.jsonat the root of the same folder. If it already has ahookskey, addPreToolUsenext to the other events instead of replacing everything.{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" } ] } ] } } - Check it in Claude CodeType
/hooks: your hook appears underPreToolUse. Then ask Claude to add a line to an invoice: the edit is refused before it happens, and Claude receives your message so it can adjust its approach.
Where to put a hook
~/.claude/settings.json: all your folders, on this computer only..claude/settings.json: one folder, shareable with your team..claude/settings.local.json: one folder, just for you.
A blocking PreToolUse hook applies in every permission mode, even when you let Claude act without asking. That is what makes it a real guardrail.
Limits
- This hook watches the file-editing tools. A terminal command run by Claude (
rm,mv) goes through the Bash tool and is not covered: you would need a second hook onBash, or adenypermission rule. - If the hook does not fire: check
/hooks, thechmod +x, and that the JSON is valid (no trailing comma, no comments). - Nothing extra to pay: a “command” hook runs on your computer, without calling the model.
Security. A hook runs commands with your full user permissions: it can read, change or delete any of your files. Read and test every hook before adding it, and be wary of hooks sitting in the .claude/ folder of a project you got from elsewhere. Claude Code waits until you trust the folder before running them in an interactive session: do not grant that trust blindly.
Sources
- Claude Code docs: Automate actions with hooks
- Claude Code docs: Hooks reference (Security considerations)
- jq, a JSON processor
Want AI agents that work on your quotes and invoices with guardrails like these from day one? That is what I build as AI agents.