Hooks System
Automate and enforce Claude Code lifecycle rules with the current nested hooks schema.
What You’ll Learn
Hooks run deterministic automation at defined points in the Claude Code lifecycle. They can audit activity, add context, format files, or block an action before it happens.
The current settings schema is nested:
hooks
└── event name
└── matcher group
└── hooks
└── handler
Do not use the old flat event-to-command shape.
Configure a Hook
Put hooks in user, project, or local settings according to the scope you need. This project hook checks Bash commands before they run:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-command.sh",
"timeout": 30
}
]
}
]
}
}
The outer key selects an event. A matcher group filters that event, and its nested hooks array contains one or more handlers. Handler types currently include command, http, mcp_tool, prompt, and experimental agent hooks.
Use /hooks to inspect the effective configuration and its source. The menu is read-only; edit the relevant settings file to change behavior.
Major Lifecycle Events
There are more than four events. Choose the event that matches the exact point at which a decision is still useful.
| Phase | Main events | Typical use |
|---|---|---|
| Session | SessionStart, SessionEnd | Load context, initialize or archive |
| User turn | UserPromptSubmit, Stop, StopFailure | Validate input, enforce completion, record failures |
| Tool call | PreToolUse, PermissionRequest, PostToolUse, PostToolUseFailure | Block, approve, audit, or react to tools |
| Workers and teams | SubagentStart, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted | Observe workers and enforce quality gates |
| Context and configuration | PreCompact, PostCompact, ConfigChange, InstructionsLoaded | Protect context transitions and configuration |
| Worktrees | WorktreeCreate, WorktreeRemove | Customize isolation setup and cleanup |
The reference contains additional events and their exact matchers. Treat that list as versioned documentation, not an enum copied permanently into your own article or library.
Command Hook Input
Command hooks receive JSON on stdin. Common fields include session_id, cwd, and hook_event_name; each event adds its own fields. For example, PreToolUse includes tool_name, tool_input, and tool_use_id.
#!/usr/bin/env bash
set -euo pipefail
payload=$(< /dev/stdin)
command=$(jq -r '.tool_input.command // ""' <<< "$payload")
if [[ "$command" == rm\ * ]]; then
echo "Blocked by project policy" >&2
exit 2
fi
exit 0
Keep hook scripts small, deterministic, and fast. Validate missing fields because payloads differ by event.
Output and Blocking Rules
For command hooks:
- exit
0: success; Claude Code may parse JSON written to stdout; - exit
2: blocking error for events that can still be blocked; feedback comes from stderr; - another non-zero code: non-blocking error for most events;
WorktreeCreateis the notable exception: any non-zero exit aborts creation.
The event determines what “block” means. PreToolUse can stop a tool before execution. PostToolUse cannot undo a tool that already ran. Stop can keep the agent working, while SessionEnd cannot prevent an already-ending session.
For structured PreToolUse control, return JSON on exit 0:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
Decision fields are event-specific. Copy them from the event’s official reference instead of generalizing one event’s schema to every hook.
Safety Rules
- Quote variables and parse JSON with a real parser.
- Use absolute paths or
${CLAUDE_PROJECT_DIR}for project scripts. - Never print secrets or the full environment into hook output.
- Prefer
PreToolUsefor prevention; post events are for observation and follow-up. - Remember that all matching hooks may run in parallel. Do not have multiple hooks race to rewrite the same input.
- Test scripts with representative stdin JSON, then verify registration with
/hooks.
Hooks can tighten policy even in permissive modes, but an allow response cannot override a stronger deny rule. Design hooks as an enforcement layer, not a permissions bypass.
Official Sources
Next Session
Next, manage session continuity through supported commands and IDs instead of parsing private transcript structures.