Lesson 15 / 25
A Guardrail Hook
Block dangerous commands before they run and format files after edits.
Check, then allow or block
A pre-tool hook sees the tool call before it executes and can reject it, with a message the model reads and adapts to. A post-tool hook can run formatters or tests after an edit. Together they enforce rules without extra prompting.
Block force pushes
This script reads the hook JSON, and exits with code 2 to block the call and show the reason. The exact JSON fields and exit-code behaviour are defined by your agent's hook documentation, so check them for your version.
#!/usr/bin/env bash
# .claude/hooks/block-force-push.sh
cmd=$(jq -r '.tool_input.command // ""')
if echo "$cmd" | grep -Eq 'git push.*(--force|-f)'; then
echo "Blocked: force pushes are not allowed. Use a normal push." >&2
exit 2
fiBlock with a reason
A bare "denied" leaves the model guessing. A message that says what to do instead lets it fix the plan on the next turn.
Quick check: Why should a blocking hook print a reason?
- Reasons are required by Linux
- So the model can adjust its plan
- To slow the agent down
- Hooks cannot block otherwise
Answer
So the model can adjust its plan — The message is fed back to the model, which can then choose a safe alternative.