Back to cards
Reference Card

Hook Events

Code that runs when the harness fires. Zero context cost — the deterministic edge.

Context Ladder · rung 4 — Hook
Phase · before tool

PreToolUse

Gatekeeper. Reject before the tool runs.

Use for
  • Block dangerous commands
  • Require auth on risky tools
  • Lock paths off-limits
Exit 2

Prevents the tool call.

Canonical — protect-files.sh blocks edits to flagged paths.

Phase · after tool

PostToolUse

Verifier. Inspect what just happened, surface back to Claude.

Use for
  • Lint edits
  • Run formatter / type-check
  • Emit metrics, audit log
Exit 2

Stderr is surfaced to Claude as an actionable error.

Canonical — lint-on-edit.sh runs ruff after every *.py edit.

Phase · end of turn

Stop

Final-state check. The agent says "I'm done" — you check first.

Use for
  • Run the test suite
  • End-of-turn invariants (no TODOs, clean tree)
  • Commit-state validation
Exit 2

Prevents the turn from completing — agent must keep working.

Canonical — tests-on-stop.sh blocks "done" claims if tests fail.

Phase · before /compact

PreCompact

Compaction guard. Catch the surprise auto-compact moment.

Use for
  • Block auto-compaction
  • Enable user to run /context to audit first
  • Treat compaction as a signal for refactoring workflow, not a default
Exit 2

Blocks the compaction. Manual /compact still proceeds.

Canonical — precompact-checkpoint on matcher "auto".

Four common cases, not the full set — Claude Code emits ~28 events across the agent lifecycle (session, turn, agentic loop, file, compaction, worktree, notification). Browse all registered hooks with /hooks · full event list →

Exit codes

Claude Code's interpretation

Exit What Claude Code does
0 Success. Action proceeds. stdout goes to Claude Code's debug log — not surfaced to Claude.
2 Block. PreToolUse / PreCompact / Stop → action prevented. PostToolUse → stderr is surfaced to Claude as an actionable error in-turn.
1 Non-blocking error. Action still proceeds — Claude Code treats this as a soft failure. Use 2 if you actually want to block.
Hook types beyond command: prompt (Claude evaluates a rule) · agent (forks a subagent) · http (calls a webhook). Same registration shape, different runner.

Where to register — settings precedence

Four files. Lower wins — local overrides project overrides user; managed overrides everything.

File Scope Checked in
~/.claude/settings.json You · every project
./.claude/settings.json Team · everyone on this repo
./.claude/settings.local.json You · this repo only — (gitignored)
managed-settings.json Org · IT-controlled (rare for solo dev) — (OS policy)