AI Automation

Claude Code Hooks: auto-format, block dangerous commands, enforce tests — no reminders needed

TL;DR

A hook is a shell command (or HTTP, prompt…) that runs on events like PreToolUse, PostToolUse, Stop. Exit code 2 in PreToolUse blocks the tool call and feeds the reason to Claude; in Stop it forces Claude to keep going. Configure in .claude/settings.json, inspect with /hooks.

Example 1: format after every edit

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{ "type": "command", "command": "npx prettier --write \"$(jq -r .tool_input.file_path)\"" }]
    }]
  }
}

Example 2: block rm -rf

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{ "type": "command", "if": "Bash(rm *)",
                   "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh" }]
    }]
  }
}

# block-rm.sh
echo "Deleting files with rm is not allowed. Ask the user." >&2
exit 2

Exit codes that matter

EventExit 2 means
PreToolUseBlock the tool; stderr becomes Claude's reason
PostToolUseNo block (tool already ran); stderr goes to Claude
StopClaude can't stop — e.g. while tests are red
  • Exit 1 does not block — use exit 2 for hard rules.
  • Hooks in .claude/settings.json are committed so the whole team shares them.
  • Disable all temporarily: "disableAllHooks": true.