Lesson 18 / 25
Pre-Action Hooks
Run your own policy check before each tool call and block with a clear reason.
Code that runs before every action
A hook is a command your agent tool runs automatically at a defined moment. A pre-tool hook receives the planned action (tool name and arguments), can inspect it using the logic from this course (parsed allowlist, path guard, protected paths) and block it, with a message the model reads and adapts to. Because the harness runs the hook, it works even if the model forgets or is tricked. Hook inputs and exit-code conventions differ by tool and version, so follow your tool's documentation.
Rules that run every time
Hooks and budgets turn guardrail ideas into code that executes on every action.
A blocking hook sketch
This follows the Claude Code convention (JSON on stdin, exit code 2 blocks and shows stderr to the model). The allowed function is the parsed allowlist from the permissions section; other tools use different formats.
#!/usr/bin/env python3
# .claude/hooks/check_bash.py
import json, sys
event = json.load(sys.stdin)
cmd = event.get("tool_input", {}).get("command", "")
if not allowed(cmd): # parsed allowlist from earlier
print(f"Blocked: '{cmd}' is not on the approved command list. "
"Use a listed command or ask the user.", file=sys.stderr)
sys.exit(2)
sys.exit(0)Keep hooks fast and boring
A slow or flaky hook slows every action and tempts people to disable it. Keep it small, deterministic and well tested, and fail closed (block) if the hook itself crashes.
Quick check: When should a hook fail?
- Closed: block the action if the hook crashes
- Open: allow the action if the hook crashes
- Randomly
- Never
Answer
Closed: block the action if the hook crashes — Failing closed prevents a broken check from silently letting risky actions through.