Lesson 4 of 5 in Claude Code Configuration & Workflows
2.4 · Hooks — lifecycle & exit codes
Hooks are the deterministic gates in Claude Code. Where CLAUDE.md is suggestion, hooks are code — and code is enforcement. This lesson covers the lifecycle events, the exit-code contract that controls what happens, and the patterns hooks solve better than prompts.
Lifecycle events
Hooks fire on events like PreToolUse (before a tool runs), PostToolUse (after), Stop (session ends), Notification (something's asked of the user). Each hook is an external command whose exit code determines what happens next.
The exit code contract
Exit 0: allow, no message. Exit 2: block the action and surface stderr back to Claude as feedback so it can adjust. Other non-zero: an error occurred but action proceeds. Stdout goes to the user; stderr on exit 2 goes to Claude.
PreToolUse hook for a file write: if path starts with /secrets: echo 'blocked: protected path' >&2; exit 2 else: exit 0
Hooks are deterministic, prompts are not
Anything you need to enforce absolutely — never touch this path, always run this formatter, log every tool call — belongs in a hook. Prompts are suggestions; hooks are code and code is enforcement.
Common hook patterns
Audit logging on PreToolUse. Blocking writes to protected paths. Auto-running formatters and linters on PostToolUse for edits. Auto-running tests after code changes. Blocking access to files matching secret patterns.
PostToolUse hook after edit → run prettier + eslint --fix on the changed file
Takeaways
- Exit 0 allows; exit 2 blocks and feeds stderr to Claude
- Stdout → user; stderr on exit 2 → Claude
- Hooks are deterministic gates; use them for absolute rules
- Common uses: audit logs, safety nets, auto-lint, test runs
Exam traps
Practice scenario
A mutating tool 'issue_refund' occasionally times out. The agent retries and sometimes the refund gets issued twice. What's the correct fix?