Hook events
Each hook is registered under one of the following events:| Event | When it fires |
|---|---|
PreToolUse | Before a tool is invoked |
PostToolUse | After a tool returns successfully |
PostToolUseFailure | After a tool returns an error |
Notification | When Claude Code sends a desktop notification |
UserPromptSubmit | When the user submits a message |
SessionStart | At the start of a new session |
SessionEnd | When the session ends |
Stop | When the agent finishes its response |
StopFailure | When the agent stops due to an error |
SubagentStart | When a sub-agent is spawned |
SubagentStop | When a sub-agent finishes |
PreCompact | Before context compaction |
PostCompact | After context compaction |
PermissionRequest | When a permission check is triggered |
PermissionDenied | When a permission is denied |
Setup | On init or maintenance trigger |
ConfigChange | When settings change on disk |
InstructionsLoaded | When a CLAUDE.md file is loaded |
CwdChanged | When the working directory changes |
FileChanged | When a watched file changes |
Configuration
Hooks are defined in your settings JSON file (e.g.~/.claude/settings.json for user-level hooks, or .claude/settings.json for project-level hooks) under the hooks key. The value is a map from event name to an array of matcher configurations.
matcher(optional) — a string pattern matched against the tool name (e.g."Bash","Write")hooks— an array of hook definitions to run when the matcher matches
The if condition
Every hook supports an if field that uses permission rule syntax to filter when the hook runs. The condition is evaluated against the hook input’s tool_name and tool_input fields.
"Bash(git *)"— any Bash call starting withgit"Read(*.ts)"— any Read call on a.tsfile"Write"— any Write call, regardless of path
Hook types
command — shell command
command — shell command
Runs a shell command. The hook input is passed as JSON via stdin.
Exit code behaviour:
| Field | Type | Description |
|---|---|---|
command | string | Shell command to execute |
if | string | Permission rule filter (optional) |
shell | "bash" | "powershell" | Shell interpreter. Defaults to bash (uses $SHELL) |
timeout | number | Timeout in seconds for this command |
statusMessage | string | Custom spinner message while the hook runs |
once | boolean | If true, the hook is removed after its first execution |
async | boolean | If true, runs in the background without blocking the agent |
asyncRewake | boolean | Runs in the background; wakes the model if exit code is 2 (implies async) |
0— success, continue normally2(withasyncRewake: true) — the model is woken and given the hook’s stdout as a new message- Any other non-zero — the hook is treated as an error
prompt — LLM evaluation
prompt — LLM evaluation
Sends a prompt to an LLM. Use
$ARGUMENTS in the prompt string to inject the hook input JSON.| Field | Type | Description |
|---|---|---|
prompt | string | Prompt to evaluate. Use $ARGUMENTS for hook input JSON |
if | string | Permission rule filter (optional) |
model | string | Model to use (e.g. "claude-sonnet-4-6"). Defaults to the small fast model |
timeout | number | Timeout in seconds |
statusMessage | string | Custom spinner message |
once | boolean | If true, removed after first execution |
agent — sub-agent verifier
agent — sub-agent verifier
Spawns a sub-agent to verify or act on the hook event. The agent receives a prompt describing what to check, with
$ARGUMENTS replaced by the hook input JSON.| Field | Type | Description |
|---|---|---|
prompt | string | Verification prompt. Use $ARGUMENTS for hook input JSON |
if | string | Permission rule filter (optional) |
model | string | Model for the agent (e.g. "claude-sonnet-4-6"). Defaults to Haiku |
timeout | number | Timeout in seconds (default 60) |
statusMessage | string | Custom spinner message |
once | boolean | If true, removed after first execution |
http — HTTP webhook
http — HTTP webhook
POSTs the hook input JSON to a URL. Useful for integrating with external systems or webhooks.
| Field | Type | Description |
|---|---|---|
url | string | URL to POST the hook input JSON to |
if | string | Permission rule filter (optional) |
timeout | number | Timeout in seconds |
headers | Record<string, string> | Additional HTTP headers. Values can reference env vars using $VAR_NAME |
allowedEnvVars | string[] | Env var names allowed to be interpolated in header values |
statusMessage | string | Custom spinner message |
once | boolean | If true, removed after first execution |
Background execution
By default hooks run synchronously and block the agent until they complete. Useasync to run a hook in the background:
asyncRewake:
2, Claude Code treats the stdout as a new user message and resumes the model. Any other exit code is treated as normal background completion.
Full example
The following settings configuration uses all four hook types across multiple events:Hook scripts receive the full hook input as JSON on stdin. For
PreToolUse and PostToolUse events this includes tool_name, tool_input, session_id, transcript_path, and cwd.