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
fi

Block 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.