Hooks: events, exit codes and decisions
The enforcement layer. Exit codes are near-guaranteed exam content.
6 min read · Lesson 6 of 11 in this domain
Hooks are the enforcement layer. A hook is a shell command Claude Code runs at a fixed point in the lifecycle — before a tool call, after one, when a session starts — and because the harness runs it rather than the model choosing to, it happens every time. The exit code is how the hook talks back, and the semantics are worth memorising precisely because they are unusual: 2 is the special one. Zero means success and your stdout may be parsed for structured decisions; two means block, and your stderr is fed to Claude so it can react; anything else is a non-blocking complaint that gets logged while execution continues.
- Hooks run as shell commands at fixed lifecycle events, regardless of what Claude decides. That is what makes them enforcement rather than guidance.
- PreToolUse runs before a tool call and can block it. PostToolUse runs after success and cannot — the tool already ran.
- Other commonly tested events:
UserPromptSubmit,SessionStart,SessionEnd,Stop,SubagentStop,PreCompact/PostCompact,Notification,InstructionsLoaded. - Beyond exit codes, hooks can return JSON. PreToolUse supports
permissionDecisionofallow/deny/ask/defer, plusupdatedInputto rewrite the tool arguments before execution. - Universal JSON fields include
continue,stopReason,suppressOutputandsystemMessage.
| Exit code | Meaning | Behaviour |
|---|---|---|
| 0 | Success | stdout parsed for JSON output fields |
| 2 | Blocking error | stderr fed to Claude; stdout and JSON ignored |
| Other | Non-blocking error | stderr shown in transcript; execution continues |
Blocking a dangerous command. You register a PreToolUse hook on Bash. It inspects the command, sees rm -rf /, writes "refusing: destructive path" to stderr and exits 2. The tool call never runs, and Claude receives your stderr as feedback so it can choose a different approach. Had the script exited 1 instead, the message would have appeared in the transcript and the command would have run anyway — the difference between a guardrail and a log line is one digit.
Assuming any non-zero exit blocks. Only 2 blocks; everything else is advisory.
A hook exits with code 2. What happens?
Exit 0 is success, 2 blocks, anything else is non-blocking.
Which event can block a dangerous command before it runs?
PostToolUse fires after the tool already ran, so it cannot block.
Practise this domain with 20%%-weighted questions in the study app.
Open in study appSource: Claude Code Docs — Hooks · Independent study aid, not affiliated with or endorsed by Anthropic.