This lesson is being recorded
Every video of this course is being uploaded to my YouTube channel. Subscribe so you do not miss it.
Module 10 · Lesson 10.3 · 12 min
Hooks: Automatic Triggers and Guardrails
Add hooks that run automatically before and after the agent's actions, to log changes and block anything your policy forbids.
Use ← → to move. The marker highlights text and the pencil draws on the slide; navigation locks while you annotate. Undo removes the last mark, Esc exits.
1Know where hooks live
Hooks are configured in a settings file: .claude/settings.json in your project (shared with your team) or ~/.claude/settings.json for your own machine. Each hook has an event name, a matcher for which tools it applies to, and the command to run. The /hooks command inside Claude Code shows what is configured.
/hooks2Add an audit log of every file change
This PostToolUse hook records every file the agent edits or writes into logs/agent-edits.log. It needs the small jq tool (included with recent macOS versions, or install it with Homebrew). You now have a record of what changed, even for runs that happened overnight.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -c '{tool: .tool_name, file: .tool_input.file_path}' >> \"$CLAUDE_PROJECT_DIR\"/logs/agent-edits.log"
}
]
}
]
}
}3Block risky commands before they run
A PreToolUse hook on Bash receives the command as JSON. If your script exits with code 2, the command is blocked and the message you print is shown to Claude. The recipes file has a ready script that blocks deletions, pushes to your live site and outgoing POST requests.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-risky.sh"
}
]
}
]
}
}4Ask Claude to help, then test it yourself
You can ask Claude to write or adapt a hook, but always test it by deliberately trying the blocked action. A guardrail you have never seen fire is a guardrail you are only hoping works.
Add a PreToolUse hook to .claude/settings.json that runs .claude/hooks/block-risky.sh for every Bash command. Create the script so it blocks any command containing rm -rf, git push or curl with POST or DELETE, prints a clear reason, and exits with code 2. Make the script executable. Then tell me exactly how to test that it works.5Combine hooks with permission rules
Hooks and permission rules work together. Use deny rules in settings for simple, absolute bans (for example reading .env files) and hooks for checks that need logic, like looking inside a command. Module 11 goes deeper into both.
Instructions in CLAUDE.md are like telling a new employee the rules. They will usually follow them. Usually is not good enough for sending money, deleting files or pushing to your live website. Hooks are different: they are small commands that Claude Code itself runs at fixed moments, whatever the model decides.
A PreToolUse hook runs before an action and can block it. A PostToolUse hook runs after an action, perfect for keeping an audit log. There are also hooks for when a session starts, when Claude stops, and when it sends a notification. You do not need to be a developer to use them: you copy a tested example and change one line.
Key points
- Instructions guide the agent; hooks enforce the rules.
- PreToolUse can block, PostToolUse can record.
- Exit code 2 blocks the action and tells Claude why.
- Test every guardrail by trying to break it.
Avoid
- Relying on CLAUDE.md alone for rules that must never be broken.
- Writing a hook and never testing that it actually blocks.
- Putting a personal hook in the shared project settings, or the reverse.
- Making hooks so strict that normal work is blocked and people disable them.
A London agency lets Claude Code update client landing pages in a staging folder. The owner's fear was an agent pushing unreviewed changes to a live client site. A PreToolUse hook now blocks any git push and any upload command, with the message: publishing needs a human. A PostToolUse hook logs every edited file. In the first month the hook fired six times, each time on a perfectly reasonable request that simply needed a person to sign off.