Claude Code Hooks: Complete Guide to All 12 Lifecycle Events
Master Claude Code hooks with exit codes, JSON output, and production patterns. Stop clicking approve and fully automate your workflow.
Agentic Orchestration Kit for Claude Code.
Problem: You're deep in flow state, building a feature. Claude needs to write a file. Click approve. Run a command. Click approve. Format code. Click approve. Twenty interruptions later, you've forgotten what you were building.
Quick Win: Add this to .claude/settings.json and never approve a Prettier format again:
Every file Claude writes now auto-formats. Zero clicks. Zero context switches.
The 12 Hook Lifecycle Events
Hooks intercept Claude Code events and execute shell commands or LLM prompts. Here's the complete list:
| Hook | When It Fires | Can Block? | Best Use |
|---|---|---|---|
| SessionStart | Session begins or resumes | NO | Load context, set env vars |
| UserPromptSubmit | You hit enter | YES | Context injection, validation |
| PreToolUse | Before tool runs | YES | Security blocking, auto-approve (extends permission system) |
| PermissionRequest | Permission dialog appears | YES | Auto-approve/deny |
| PostToolUse | After tool succeeds | NO* | Auto-format, lint, log |
| PostToolUseFailure | After tool fails | NO | Error handling |
| SubagentStart | Spawning subagent | NO | Subagent initialization |
| SubagentStop | Subagent finishes | YES | Subagent validation |
| Stop | Claude finishes responding | YES | Task enforcement |
| PreCompact | Before compaction | NO | Transcript backup |
| Setup | With --init/--maintenance | NO | One-time setup |
| SessionEnd | Session terminates | NO | Cleanup, logging |
| Notification | Claude sends notification | NO | Desktop alerts, TTS |
*PostToolUse can prompt Claude with feedback but cannot undo the tool execution.
Exit Codes: The Control Mechanism
Every hook communicates via exit codes:
| Exit Code | What Happens |
|---|---|
| 0 | Success - hook ran, stdout processed for JSON |
| 2 | Block - operation stopped, stderr sent to Claude |
| Other | Error - stderr shown to user, execution continues |
Exit code 2 is your power tool. A PreToolUse hook that exits 2 stops the tool. A Stop hook that exits 2 forces Claude to keep working.
Hook Types: Command, HTTP, Prompt, and Agent
Claude Code supports four hook handler types. Pick the one that fits your use case:
Command hooks run shell scripts:
HTTP hooks POST to an endpoint and receive JSON back: New - Feb 2026
HTTP hooks send the event's JSON input as the POST body (Content-Type: application/json). The response uses the same JSON output format as command hooks. Key differences from command hooks:
- Non-blocking errors: Non-2xx responses, connection failures, and timeouts produce non-blocking errors (execution continues). To actually block a tool call, return a 2xx response with
decision: "block"in the JSON body. - Header env vars: Use
$VAR_NAMEor${VAR_NAME}in header values. Only variables listed inallowedEnvVarsget resolved; unlisted ones become empty strings. - Deduplication: HTTP hooks are deduplicated by URL (command hooks by command string).
- Config only: Must be added by editing settings JSON directly. The
/hooksinteractive menu only supports command hooks.
Prompt hooks use LLM evaluation (great for Stop/SubagentStop):
The LLM responds with {"ok": true} or {"ok": false, "reason": "..."}.
Agent hooks spawn a subagent with tool access (Read, Grep, Glob) for deeper verification:
Agent hooks can explore the codebase before making a decision, making them more thorough than prompt hooks but slower (default timeout: 60s vs 30s for prompts).
Async Hooks (Non-Blocking) New - Jan 2026
Add async: true to run hooks in the background without blocking Claude's execution. Released by Anthropic in January 2026:
Best for:
- Logging and analytics
- Backup creation (PreCompact)
- Notifications
- Any side-effect that shouldn't slow things down
Not suitable for:
- Security blocking (PreToolUse with exit code 2)
- Auto-approve decisions (PermissionRequest)
- Any hook where Claude needs the result
HTTP Hooks: Post to Endpoints New - Feb 2026
HTTP hooks let you send hook events to a web server instead of running a local script. This opens up use cases that were previously awkward or impossible with command hooks:
- Remote validation services that enforce team-wide policies
- Centralized logging to a shared audit system
- Webhook integrations with Slack, PagerDuty, or custom dashboards
- Microservice architectures where hook logic runs alongside your API
Basic HTTP Hook
Route all Bash commands through a validation endpoint:
Your server receives the exact same JSON that command hooks get via stdin, but as the POST request body. Return the same JSON output format in the response body.
HTTP Response Handling
HTTP hooks interpret responses differently from command hooks. There are no exit codes, only HTTP status codes and response bodies:
| Response | Behavior |
|---|---|
| 2xx + empty body | Success, equivalent to exit code 0 with no output |
| 2xx + plain text body | Success, the text is added as context to Claude |
| 2xx + JSON body | Success, parsed using the same JSON output schema as command hooks |
| Non-2xx status | Non-blocking error, execution continues |
| Connection failure / timeout | Non-blocking error, execution continues |
The critical difference: HTTP hooks cannot block via status codes alone. A 4xx or 5xx just logs an error and keeps going. To actually block a tool call or deny a permission, you must return a 2xx response with the appropriate decision fields in the JSON body:
Secure Header Authentication
The headers field supports environment variable interpolation, but only for variables explicitly listed in allowedEnvVars. This prevents accidental secret leakage:
Any $VAR reference not in allowedEnvVars resolves to an empty string. No warnings, no errors. Just empty. So double-check your allowlist.
JSON Output: Advanced Control
Beyond exit codes, hooks can return structured JSON for precise control.
PreToolUse Decisions
"allow": Bypasses permission system"deny": Blocks tool, tells Claude why"ask": Prompts user for confirmationupdatedInput: Modify tool parameters before execution
PermissionRequest Decisions
Stop/SubagentStop Enforcement
Hook 1: Auto-Format on Save
Run formatters after every file write:
Multiple hooks run in parallel. Format AND lint before Claude's response appears.
Hook 2: Session Context Injection
Load context when sessions start:
Persist Environment Variables
SessionStart and Setup hooks can set environment variables for the session:
Hook 3: Security Blocking
Block dangerous operations with PreToolUse:
Hook 4: Auto-Approve Safe Commands
Use PermissionRequest to auto-approve without prompts:
Hook 5: Transcript Backup
Save transcripts before compaction with PreCompact. Use async: true since backups don't need to block Claude:
Use matchers manual or auto to distinguish between /compact and auto-compact.
Hook 6: Task Completion Enforcement
Use Stop hooks to ensure work is complete:
See the Stop Hook guide for command-based patterns.
Hook 7: Skill Activation
The Skill Activation Hook intercepts prompts and appends skill recommendations. It matches keywords in your input against a rules file and injects the right skill context before Claude starts working -- so Claude loads database optimization rules for a Postgres query without you asking. The Code Kit's SkillActivationHook implements this pattern against 21 skill categories:
Hook 8: Threshold-Based Backups via StatusLine
StatusLine is the only mechanism that receives live context metrics. Use it to trigger backups at thresholds:
Critical: The remaining_percentage field includes a fixed 33K-token autocompact buffer. To get actual "free until autocompact":
The backup system uses two trigger systems simultaneously. The token-based system is the primary trigger, with percentage thresholds as a safety net:
Unlike PreCompact (which triggers on compaction), StatusLine-based backups capture state proactively. The token-based system ensures early backups on large context windows (1M) where percentage thresholds would fire too late.
Architecture: Three-File Structure
The backup system uses a clean separation of concerns:
| File | Trigger | Responsibility |
|---|---|---|
backup-core.mjs | Called by others | Parse transcript, format markdown, save file, update state |
statusline-monitor.mjs | StatusLine (continuous) | Monitor tokens/context %, detect triggers, display status |
conv-backup.mjs | PreCompact hook | Handle pre-compaction event |
This architecture means backup logic lives in one place. Changes to formatting, file naming, or state management only need to be made in backup-core.mjs.
Backup File Naming
Backups use numbered filenames with timestamps for history:
StatusLine Display
When a backup exists for the current session, the statusline shows the backup path:
This tells you exactly which file to load after compaction.
State Tracking
Both StatusLine and PreCompact hooks update a shared state file at ~/.claude/claudefast-statusline-state.json:
Recommended workflow: When compaction occurs, run /clear to start a fresh session, then load the backup file shown in the statusline. This avoids confusion from having both compaction summary and injected context.
Hook 9: Setup Hooks for Installation and Maintenance
Setup hooks run before your session starts, triggered by special CLI flags:
Configure them with matchers in settings.json:
The power move: Pass a prompt after the flag:
The hook runs first (deterministic), then the /install command executes (agentic). This combines predictable script execution with intelligent agent oversight.
See the complete Setup Hooks Guide for the full pattern including interactive onboarding and justfile integration.
Configuration Locations
| Location | Scope | Priority |
|---|---|---|
| Managed policy | Enterprise | Highest |
.claude/settings.json | Project (shared) | High |
.claude/settings.local.json | Project (personal) | Medium |
~/.claude/settings.json | All projects | Lowest |
Disabling and Restricting Hooks
Disable All Hooks
If hooks are causing issues or you want a clean baseline, set disableAllHooks to true in your settings:
This turns off all hooks across every scope (user, project, and local settings). Useful for debugging or when a hook causes unexpected behavior.
Managed Hook Restrictions
For organizations that need centralized control, administrators can set allowManagedHooksOnly to true in managed settings:
When enabled, only hooks defined in the managed settings file and SDK hooks are allowed. User-level, project-level, and plugin hooks are all blocked. This prevents developers from adding hooks that could bypass organizational security policies.
This pairs well with allowManagedPermissionRulesOnly, which applies the same restriction to permission rules. Together, these settings give administrators full control over both the permission system and its hook-based extensions.
Matcher Syntax
| Pattern | Matches |
|---|---|
"" or omitted | All tools |
"Bash" | Only Bash (exact, case-sensitive) |
"Write|Edit" | Write OR Edit (regex) |
"mcp__memory__.*" | All memory MCP tools |
Critical: No spaces around |. Matchers are case-sensitive.
Event-Specific Matchers
SessionStart: startup, resume, clear, compact
PreCompact: manual, auto
Setup: init, maintenance
Notification: permission_prompt, idle_prompt, auth_success
Environment Variables
| Variable | Description |
|---|---|
CLAUDE_PROJECT_DIR | Project root (all hooks) |
CLAUDE_ENV_FILE | Persist env vars (SessionStart, Setup) |
CLAUDE_CODE_REMOTE | "true" if web, empty if CLI |
Debugging
Hook not triggering?
- Check matcher syntax (case-sensitive, no spaces)
- Verify settings file location
- Test:
echo '{"session_id":"test"}' | python your-hook.py
Command failing?
- Add logging:
command 2>&1 | tee ~/.claude/hook-debug.log - Run with debug:
claude --debug - Hooks breaking on other operating systems? See cross-platform hook patterns
Infinite loops with Stop?
- Always check
stop_hook_activeflag first
Start With One Hook
Pick your biggest friction point:
- Constant formatting? PostToolUse formatter
- Approving safe commands? PermissionRequest auto-approve
- Missing context? SessionStart injection
- Losing progress? PreCompact backup
- Incomplete tasks? Stop enforcement
One hook. One friction point eliminated. Then iterate. If you want a head start, the Code Kit ships with 5 pre-configured hooks covering skill activation, auto-formatting, context recovery, permission automation, and code validation -- each following the patterns in this guide.
Next Steps
- Configure Setup Hooks for automated onboarding and maintenance
- Configure the Stop Hook to enforce task completion
- Install the Permission Hook for intelligent auto-approval
- Set up Skill Activation for automatic skill loading
- Configure Context Recovery to survive compaction
- Explore Session Lifecycle Hooks for setup and cleanup
- Master permission rules and modes for static permission control alongside hooks
- Learn configuration basics for complete Claude Code setup
Last updated on