33The table below summarizes when each event fires. The [Hook events](#hook-events) section documents the full input schema and decision control options for each one.33The table below summarizes when each event fires. The [Hook events](#hook-events) section documents the full input schema and decision control options for each one.
34 34
35| Event | When it fires |35| Event | When it fires |
36| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |36| :- | :- |
37| `SessionStart` | When a session begins or resumes |37| `SessionStart` | When a session begins or resumes |
38| `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts |38| `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts |
39| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |39| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |
251Where you define a hook determines its scope:251Where you define a hook determines its scope:
252 252
253| Location | Scope | Shareable |253| Location | Scope | Shareable |
254| :------------------------------------------------ | :--------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------- |254| :- | :- | :- |
255| `~/.claude/settings.json` | All your projects | No, local to your machine |255| `~/.claude/settings.json` | All your projects | No, local to your machine |
256| `.claude/settings.json` | Single project | Yes, can be committed to the repo |256| `.claude/settings.json` | Single project | Yes, can be committed to the repo |
257| `.claude/settings.local.json` | Single project | No, gitignored when Claude Code saves a setting to it |257| `.claude/settings.local.json` | Single project | No, gitignored when Claude Code saves a setting to it |
287The `matcher` field filters when hooks fire. How a matcher is evaluated depends on the characters it contains:287The `matcher` field filters when hooks fire. How a matcher is evaluated depends on the characters it contains:
288 288
289| Matcher value | Evaluated as | Example |289| Matcher value | Evaluated as | Example |
290| :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- |290| :- | :- | :- |
291| `"*"`, `""`, or omitted | Match all | fires on every occurrence of the event |291| `"*"`, `""`, or omitted | Match all | fires on every occurrence of the event |
292| Only letters, digits, `_`, `-`, spaces, `,`, and `\|` | Exact string, or list of exact strings separated by `\|` or `,` with optional surrounding whitespace | `Bash` matches only the Bash tool; `Edit\|Write` and `Edit, Write` each match either tool exactly; `code-reviewer` matches only that agent type |292| Only letters, digits, `_`, `-`, spaces, `,`, and `\|` | Exact string, or list of exact strings separated by `\|` or `,` with optional surrounding whitespace | `Bash` matches only the Bash tool; `Edit\|Write` and `Edit, Write` each match either tool exactly; `code-reviewer` matches only that agent type |
293| Contains any other character | JavaScript regular expression, unanchored | `^Notebook` matches any tool whose name starts with `Notebook`; `mcp__memory__.*` matches every tool from the `memory` server |293| Contains any other character | JavaScript regular expression, unanchored | `^Notebook` matches any tool whose name starts with `Notebook`; `mcp__memory__.*` matches every tool from the `memory` server |
303Each event type matches on a different field:303Each event type matches on a different field:
304 304
305| Event | What the matcher filters | Example matcher values |305| Event | What the matcher filters | Example matcher values |
306| :------------------------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |306| :- | :- | :- |
307| `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `PermissionDenied` | tool name | `Bash`, `Edit\|Write`, `mcp__.*` |307| `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, `PermissionDenied` | tool name | `Bash`, `Edit\|Write`, `mcp__.*` |
308| `SessionStart` | how the session started | `startup`, `resume`, `clear`, `compact`, `fork` |308| `SessionStart` | how the session started | `startup`, `resume`, `clear`, `compact`, `fork` |
309| `Setup` | which CLI flag triggered setup | `init`, `maintenance` |309| `Setup` | which CLI flag triggered setup | `init`, `maintenance` |
422These fields apply to all hook types:422These fields apply to all hook types:
423 423
424| Field | Required | Description |424| Field | Required | Description |
425| :-------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |425| :- | :- | :- |
426| `type` | yes | `"command"`, `"http"`, `"mcp_tool"`, `"prompt"`, or `"agent"` |426| `type` | yes | `"command"`, `"http"`, `"mcp_tool"`, `"prompt"`, or `"agent"` |
427| `if` | no | Permission rule syntax to filter when this hook runs, such as `"Bash(git *)"` or `"Edit(*.ts)"`. The hook command only runs if the tool call matches the pattern. See the [Bash matching table](#bash-if-matching) below for how Bash patterns evaluate against subcommands, `$()`, and backticks. Only evaluated on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, and `PermissionDenied`. On other events, a hook with `if` set never runs. Uses the same syntax as [permission rules](/docs/en/permissions) |427| `if` | no | Permission rule syntax to filter when this hook runs, such as `"Bash(git *)"` or `"Edit(*.ts)"`. The hook command only runs if the tool call matches the pattern. See the [Bash matching table](#bash-if-matching) below for how Bash patterns evaluate against subcommands, `$()`, and backticks. Only evaluated on tool events: `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, and `PermissionDenied`. On other events, a hook with `if` set never runs. Uses the same syntax as [permission rules](/docs/en/permissions) |
428| `timeout` | no | Seconds before canceling. Claude Code doesn't enforce it on a command hook you run with [`async: true`](#run-hooks-in-the-background). Defaults: 600 for `command`, `http`, and `mcp_tool`; 30 for `prompt`; 60 for `agent`. Claude Code lowers the `command`, `http`, and `mcp_tool` default to 30 on [`UserPromptSubmit`](#userpromptsubmit), [`PreModelSwitch`](#premodelswitch), and [`PostModelSwitch`](#postmodelswitch), and to 10 on [`MessageDisplay`](#messagedisplay). [`SessionEnd`](#sessionend) hooks share a 1.5-second budget; if your settings set a longer per-hook `timeout`, Claude Code raises the budget to match, up to 60 seconds |428| `timeout` | no | Seconds before canceling. Claude Code doesn't enforce it on a command hook you run with [`async: true`](#run-hooks-in-the-background). Defaults: 600 for `command`, `http`, and `mcp_tool`; 30 for `prompt`; 60 for `agent`. Claude Code lowers the `command`, `http`, and `mcp_tool` default to 30 on [`UserPromptSubmit`](#userpromptsubmit), [`PreModelSwitch`](#premodelswitch), and [`PostModelSwitch`](#postmodelswitch), and to 10 on [`MessageDisplay`](#messagedisplay). [`SessionEnd`](#sessionend) hooks share a 1.5-second budget; if your settings set a longer per-hook `timeout`, Claude Code raises the budget to match, up to 60 seconds |
436<span id="bash-if-matching" />For Bash patterns, whether your hook command runs depends on the shape of the pattern and the Bash command Claude is invoking. Leading `VAR=value` assignments are stripped before matching.436<span id="bash-if-matching" />For Bash patterns, whether your hook command runs depends on the shape of the pattern and the Bash command Claude is invoking. Leading `VAR=value` assignments are stripped before matching.
437 437
438| `if` pattern | Bash command | Hook runs? | Why |438| `if` pattern | Bash command | Hook runs? | Why |
439| :----------------- | :-------------------------- | :--------- | :------------------------------------------------------------------------------------------------------------------------ |439| :- | :- | :- | :- |
440| `Bash(git *)` | `FOO=bar git push` | yes | leading assignments are stripped; `git push` matches |440| `Bash(git *)` | `FOO=bar git push` | yes | leading assignments are stripped; `git push` matches |
441| `Bash(git *)` | `npm test && git push` | yes | each subcommand is checked; `git push` matches |441| `Bash(git *)` | `npm test && git push` | yes | each subcommand is checked; `git push` matches |
442| `Bash(rm *)` | `echo $(rm -rf /)` | yes | commands inside `$()` and backticks are checked; `rm -rf /` matches |442| `Bash(rm *)` | `echo $(rm -rf /)` | yes | commands inside `$()` and backticks are checked; `rm -rf /` matches |
452In addition to the [common fields](#common-fields), command hooks accept these fields:452In addition to the [common fields](#common-fields), command hooks accept these fields:
453 453
454| Field | Required | Description |454| Field | Required | Description |
455| :------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |455| :- | :- | :- |
456| `command` | yes | Shell command to execute. With `args`, the executable to spawn directly. See [Exec form and shell form](#exec-form-and-shell-form) |456| `command` | yes | Shell command to execute. With `args`, the executable to spawn directly. See [Exec form and shell form](#exec-form-and-shell-form) |
457| `args` | no | Argument list. When present, `command` is resolved as an executable and spawned directly with `args` as the argument vector, with no shell involved. See [Exec form and shell form](#exec-form-and-shell-form) |457| `args` | no | Argument list. When present, `command` is resolved as an executable and spawned directly with `args` as the argument vector, with no shell involved. See [Exec form and shell form](#exec-form-and-shell-form) |
458| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |458| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |
459| `asyncRewake` | no | If `true`, runs in the background and wakes Claude on exit code 2. The hook's stderr, or stdout if stderr is empty, is shown to Claude as a system reminder so it can react to a long-running background failure |459| `asyncRewake` | no | If `true`, runs in the background and wakes Claude on exit code 2. The hook's stderr, or stdout if stderr is empty, is shown to Claude as a [system reminder](/docs/en/glossary#system-reminder) so it can react to a long-running background failure |
460| `shell` | no | Shell to use for this hook. Accepts `"bash"` or `"powershell"`. Defaults to `"bash"`, or to `"powershell"` on Windows when Git Bash isn't installed. Setting `"powershell"` runs the command via PowerShell on Windows. Does not require `CLAUDE_CODE_USE_POWERSHELL_TOOL` since hooks spawn PowerShell directly. Ignored when `args` is set |460| `shell` | no | Shell to use for this hook. Accepts `"bash"` or `"powershell"`. Defaults to `"bash"`, or to `"powershell"` on Windows when Git Bash isn't installed. Setting `"powershell"` runs the command via PowerShell on Windows. Does not require `CLAUDE_CODE_USE_POWERSHELL_TOOL` since hooks spawn PowerShell directly. Ignored when `args` is set |
461 461
462<a id="exec-form-and-shell-form" />462<a id="exec-form-and-shell-form" />
507In addition to the [common fields](#common-fields), HTTP hooks accept these fields:507In addition to the [common fields](#common-fields), HTTP hooks accept these fields:
508 508
509| Field | Required | Description |509| Field | Required | Description |
510| :--------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |510| :- | :- | :- |
511| `url` | yes | URL to send the POST request to |511| `url` | yes | URL to send the POST request to |
512| `headers` | no | Additional HTTP headers as key-value pairs. Values support environment variable interpolation using `$VAR_NAME` or `${VAR_NAME}` syntax. Only variables listed in `allowedEnvVars` are resolved |512| `headers` | no | Additional HTTP headers as key-value pairs. Values support environment variable interpolation using `$VAR_NAME` or `${VAR_NAME}` syntax. Only variables listed in `allowedEnvVars` are resolved |
513| `allowedEnvVars` | no | List of environment variable names that may be interpolated into header values. References to unlisted variables are replaced with empty strings. Required for any env var interpolation to work |513| `allowedEnvVars` | no | List of environment variable names that may be interpolated into header values. References to unlisted variables are replaced with empty strings. Required for any env var interpolation to work |
546In addition to the [common fields](#common-fields), MCP tool hooks accept these fields:546In addition to the [common fields](#common-fields), MCP tool hooks accept these fields:
547 547
548| Field | Required | Description |548| Field | Required | Description |
549| :------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |549| :- | :- | :- |
550| `server` | yes | Name of a configured MCP server. For a [plugin-bundled server](/docs/en/mcp#plugin-provided-mcp-servers), this is the scoped name `plugin:<plugin-name>:<server-name>`, such as `plugin:my-plugin:db`, not the bare server key |550| `server` | yes | Name of a configured MCP server. For a [plugin-bundled server](/docs/en/mcp#plugin-provided-mcp-servers), this is the scoped name `plugin:<plugin-name>:<server-name>`, such as `plugin:my-plugin:db`, not the bare server key |
551| `tool` | yes | Name of the tool to call on that server |551| `tool` | yes | Name of the tool to call on that server |
552| `input` | no | Arguments passed to the tool. String values support `${path}` substitution from the hook's [JSON input](#hook-input-and-output), such as `"${tool_input.file_path}"` |552| `input` | no | Arguments passed to the tool. String values support `${path}` substitution from the hook's [JSON input](#hook-input-and-output), such as `"${tool_input.file_path}"` |
592In addition to the [common fields](#common-fields), prompt and agent hooks accept these fields:592In addition to the [common fields](#common-fields), prompt and agent hooks accept these fields:
593 593
594| Field | Required | Description |594| Field | Required | Description |
595| :------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |595| :- | :- | :- |
596| `prompt` | yes | Prompt text to send to the model. Use `$ARGUMENTS` as a placeholder for the hook input JSON. Escape with a backslash to include literal text: `\$1.00` renders as `$1.00` |596| `prompt` | yes | Prompt text to send to the model. Use `$ARGUMENTS` as a placeholder for the hook input JSON. Escape with a backslash to include literal text: `\$1.00` renders as `$1.00` |
597| `model` | no | Model to use for evaluation. Defaults to a fast model |597| `model` | no | Model to use for evaluation. Defaults to a fast model |
598 598
732Hook events receive these fields as JSON, in addition to event-specific fields documented in each [hook event](#hook-events) section. For command hooks, this JSON arrives via stdin. For HTTP hooks, it arrives as the POST request body.732Hook events receive these fields as JSON, in addition to event-specific fields documented in each [hook event](#hook-events) section. For command hooks, this JSON arrives via stdin. For HTTP hooks, it arrives as the POST request body.
733 733
734| Field | Description |734| Field | Description |
735| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |735| :- | :- |
736| `session_id` | Current session identifier |736| `session_id` | Current session identifier |
737| `prompt_id` | UUID identifying the user prompt currently being processed. Matches the [`prompt.id` attribute on OpenTelemetry events](/docs/en/monitoring-usage#event-correlation-attributes), so you can correlate hook output with telemetry for a single prompt. Absent until the first user input. Requires Claude Code v2.1.196 or later |737| `prompt_id` | UUID identifying the user prompt currently being processed. Matches the [`prompt.id` attribute on OpenTelemetry events](/docs/en/monitoring-usage#event-correlation-attributes), so you can correlate hook output with telemetry for a single prompt. Absent until the first user input. Requires Claude Code v2.1.196 or later |
738| `transcript_path` | Path to conversation JSON. The transcript file is written asynchronously and may lag the in-memory conversation, so it may not yet include the current turn's most recent messages when a hook fires. Hooks that need the final assistant text of the current turn should use `last_assistant_message` on [Stop](#stop) and [SubagentStop](#subagentstop) instead of reading the transcript |738| `transcript_path` | Path to conversation JSON. The transcript file is written asynchronously and may lag the in-memory conversation, so it may not yet include the current turn's most recent messages when a hook fires. Hooks that need the final assistant text of the current turn should use `last_assistant_message` on [Stop](#stop) and [SubagentStop](#subagentstop) instead of reading the transcript |
745When running with `--agent` or inside a subagent, two additional fields are included:745When running with `--agent` or inside a subagent, two additional fields are included:
746 746
747| Field | Description |747| Field | Description |
748| :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |748| :- | :- |
749| `agent_id` | Unique identifier for the subagent. Present only when the hook fires inside a subagent call. Use this to distinguish subagent hook calls from main-thread calls. |749| `agent_id` | Unique identifier for the subagent. Present only when the hook fires inside a subagent call. Use this to distinguish subagent hook calls from main-thread calls. |
750| `agent_type` | Agent name (for example, `"Explore"` or `"security-reviewer"`). Present when the session uses `--agent` or the hook fires inside a subagent. For subagents, the subagent's type takes precedence over the session's `--agent` value. See [SubagentStart](#subagentstart) for the values custom and plugin subagents report and how to write a matcher against a plugin-scoped name. |750| `agent_type` | Agent name (for example, `"Explore"` or `"security-reviewer"`). Present when the session uses `--agent` or the hook fires inside a subagent. For subagents, the subagent's type takes precedence over the session's `--agent` value. See [SubagentStart](#subagentstart) for the values custom and plugin subagents report and how to write a matcher against a plugin-scoped name. |
751 751
860Exit code 2 is the way a hook signals "stop, don't do this." The effect depends on the event, because some events represent actions that can be blocked (like a tool call that hasn't happened yet) and others represent things that already happened or can't be prevented.860Exit code 2 is the way a hook signals "stop, don't do this." The effect depends on the event, because some events represent actions that can be blocked (like a tool call that hasn't happened yet) and others represent things that already happened or can't be prevented.
861 861
862| Hook event | Can block? | What happens on exit 2 |862| Hook event | Can block? | What happens on exit 2 |
863| :-------------------- | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |863| :- | :- | :- |
864| `PreToolUse` | Yes | Blocks the tool call |864| `PreToolUse` | Yes | Blocks the tool call |
865| `PermissionRequest` | No | Exit code 2 isn't honored for this event and the permission flow proceeds unchanged. Deny through the [`decision` object](#permissionrequest-decision-control) instead |865| `PermissionRequest` | No | Exit code 2 isn't honored for this event and the permission flow proceeds unchanged. Deny through the [`decision` object](#permissionrequest-decision-control) instead |
866| `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt |866| `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt |
933* **`hookSpecificOutput`** is a nested object for events that need richer control. It requires a `hookEventName` field set to the event name.933* **`hookSpecificOutput`** is a nested object for events that need richer control. It requires a `hookEventName` field set to the event name.
934 934
935| Field | Default | Description |935| Field | Default | Description |
936| :----------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |936| :- | :- | :- |
937| `continue` | `true` | If `false`, Claude stops processing entirely after the hook runs. Takes precedence over any event-specific decision fields |937| `continue` | `true` | If `false`, Claude stops processing entirely after the hook runs. Takes precedence over any event-specific decision fields |
938| `stopReason` | none | Message shown to the user when `continue` is `false`. It stays in the conversation, so Claude sees it if the conversation continues |938| `stopReason` | none | Message shown to the user when `continue` is `false`. It stays in the conversation, so Claude sees it if the conversation continues |
939| `suppressOutput` | `false` | Has no effect: Claude Code accepts the field but doesn't act on it. A successful hook's stdout is never shown in the transcript and is recorded in the debug log |939| `suppressOutput` | `false` | Has no effect: Claude Code accepts the field but doesn't act on it. A successful hook's stdout is never shown in the transcript and is recorded in the debug log |
983 983
984#### Add context for Claude984#### Add context for Claude
985 985
986The `additionalContext` field passes a string from your hook into Claude's context window. Claude Code wraps the string in a system reminder and inserts it into the conversation at the point where the hook fired. Claude reads the reminder on the next model request, but it doesn't appear as a chat message in the interface.986The `additionalContext` field passes a string from your hook into Claude's context window. Claude Code wraps the string in a [system reminder](/docs/en/glossary#system-reminder) and inserts it into the conversation at the point where the hook fired. Claude reads the reminder on the next model request, but it doesn't appear as a chat message in the interface.
987 987
988Return `additionalContext` inside `hookSpecificOutput` alongside the event name:988Return `additionalContext` inside `hookSpecificOutput` alongside the event name:
989 989
1025Not every event supports blocking or controlling behavior through JSON. The events that do each use a different set of fields to express that decision. Use this table as a quick reference before writing a hook:1025Not every event supports blocking or controlling behavior through JSON. The events that do each use a different set of fields to express that decision. Use this table as a quick reference before writing a hook:
1026 1026
1027| Events | Decision pattern | Key fields |1027| Events | Decision pattern | Key fields |
1028| :---------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1028| :- | :- | :- |
1029| UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, PreCompact | Top-level `decision` | `decision: "block"`, `reason`. Stop and SubagentStop also accept `hookSpecificOutput.additionalContext` for [non-error feedback that continues the conversation](#stop-decision-control) |1029| UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, PreCompact | Top-level `decision` | `decision: "block"`, `reason`. Stop and SubagentStop also accept `hookSpecificOutput.additionalContext` for [non-error feedback that continues the conversation](#stop-decision-control) |
1030| TeammateIdle, TaskCompleted | Exit code or `continue: false` | Exit code 2 blocks the action with stderr feedback. JSON `{"continue": false, "stopReason": "..."}` also stops the teammate entirely, matching `Stop` hook behavior; [TaskCompleted ignores it when the `TaskUpdate` tool triggered the event](#taskcompleted-decision-control) |1030| TeammateIdle, TaskCompleted | Exit code or `continue: false` | Exit code 2 blocks the action with stderr feedback. JSON `{"continue": false, "stopReason": "..."}` also stops the teammate entirely, matching `Stop` hook behavior; [TaskCompleted ignores it when the `TaskUpdate` tool triggered the event](#taskcompleted-decision-control) |
1031| TaskCreated | Exit code or top-level `decision` | Exit code 2 or `decision: "block"` [cancels the task](#taskcreated-decision-control) and returns the message to Claude. `continue: false` is ignored |1031| TaskCreated | Exit code or top-level `decision` | Exit code 2 or `decision: "block"` [cancels the task](#taskcreated-decision-control) and returns the message to Claude. `continue: false` is ignored |
1112The matcher value corresponds to how the session was initiated:1112The matcher value corresponds to how the session was initiated:
1113 1113
1114| Matcher | When it fires |1114| Matcher | When it fires |
1115| :-------- | :------------------------------------------------------------------------------------------------------------------------------------- |1115| :- | :- |
1116| `startup` | New session |1116| `startup` | New session |
1117| `resume` | `--resume`, `--continue`, or `/resume` |1117| `resume` | `--resume`, `--continue`, or `/resume` |
1118| `clear` | `/clear` |1118| `clear` | `/clear` |
1134In addition to the [common input fields](#common-input-fields), SessionStart hooks receive `source` and optionally `model`, `agent_type`, and `session_title`:1134In addition to the [common input fields](#common-input-fields), SessionStart hooks receive `source` and optionally `model`, `agent_type`, and `session_title`:
1135 1135
1136| Field | Description |1136| Field | Description |
1137| :-------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1137| :- | :- |
1138| `source` | How the session started: `"startup"` for new sessions, `"resume"` for resumed sessions, `"clear"` after `/clear`, `"compact"` after compaction, or `"fork"` for a new session forked from an existing one |1138| `source` | How the session started: `"startup"` for new sessions, `"resume"` for resumed sessions, `"clear"` after `/clear`, `"compact"` after compaction, or `"fork"` for a new session forked from an existing one |
1139| `model` | The active model identifier. It can be omitted, for example after `/clear` or when a session is restored through conversation recovery, so check for the field before reading it |1139| `model` | The active model identifier. It can be omitted, for example after `/clear` or when a session is restored through conversation recovery, so check for the field before reading it |
1140| `agent_type` | The agent name, present when you start Claude Code with `claude --agent <name>` |1140| `agent_type` | The agent name, present when you start Claude Code with `claude --agent <name>` |
1143When `source` is `"resume"` or `"fork"` and the transcript contains at least one response from Claude, SessionStart hooks also receive the four fields below. Your hook can use them to report what resuming a stale conversation costs before the first request, for example in a [`systemMessage`](#json-output). These fields require Claude Code v2.1.251 or later.1143When `source` is `"resume"` or `"fork"` and the transcript contains at least one response from Claude, SessionStart hooks also receive the four fields below. Your hook can use them to report what resuming a stale conversation costs before the first request, for example in a [`systemMessage`](#json-output). These fields require Claude Code v2.1.251 or later.
1144 1144
1145| Field | Description |1145| Field | Description |
1146| :---------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1146| :- | :- |
1147| `seconds_since_last_response` | Wall-clock seconds since the last response in the resumed transcript |1147| `seconds_since_last_response` | Wall-clock seconds since the last response in the resumed transcript |
1148| `context_tokens` | Tokens the first request of the resumed session re-sends as its prompt |1148| `context_tokens` | Tokens the first request of the resumed session re-sends as its prompt |
1149| `prompt_cache_likely_expired` | `true` when the last response is older than the session's [prompt cache lifetime](/docs/en/prompt-caching#cache-lifetime) or a later compaction replaced the cached conversation |1149| `prompt_cache_likely_expired` | `true` when the last response is older than the session's [prompt cache lifetime](/docs/en/prompt-caching#cache-lifetime) or a later compaction replaced the cached conversation |
1171Claude Code adds stdout it [treats as plain text](#exit-code-0) to Claude's context. In addition to the [JSON output fields](#json-output) available to all hooks, you can return these event-specific fields:1171Claude Code adds stdout it [treats as plain text](#exit-code-0) to Claude's context. In addition to the [JSON output fields](#json-output) available to all hooks, you can return these event-specific fields:
1172 1172
1173| Field | Description |1173| Field | Description |
1174| :------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1174| :- | :- |
1175| `additionalContext` | String added to Claude's context at the start of the conversation, before the first prompt. See [Add context for Claude](#add-context-for-claude) for how the text is delivered and what to put in it |1175| `additionalContext` | String added to Claude's context at the start of the conversation, before the first prompt. See [Add context for Claude](#add-context-for-claude) for how the text is delivered and what to put in it |
1176| `initialUserMessage` | String used as the first user message of the session. Applies in [non-interactive mode](/docs/en/headless) with the `-p` flag, where it becomes the first turn even if no prompt is provided. If a prompt is provided, it follows as the next turn. Unlike `additionalContext`, which attaches to an existing turn, this creates the turn |1176| `initialUserMessage` | String used as the first user message of the session. Applies in [non-interactive mode](/docs/en/headless) with the `-p` flag, where it becomes the first turn even if no prompt is provided. If a prompt is provided, it follows as the next turn. Unlike `additionalContext`, which attaches to an existing turn, this creates the turn |
1177| `sessionTitle` | Sets the session title, with the same effect as `/rename`. Use to name sessions automatically from the launch folder, git branch, or worktree name. Applies when `source` is `"startup"`, `"resume"`, or `"fork"`; ignored on `"clear"` and `"compact"` |1177| `sessionTitle` | Sets the session title, with the same effect as `/rename`. Use to name sessions automatically from the launch folder, git branch, or worktree name. Applies when `source` is `"startup"`, `"resume"`, or `"fork"`; ignored on `"clear"` and `"compact"` |
1251The matcher value corresponds to the CLI flag that triggered the hook:1251The matcher value corresponds to the CLI flag that triggered the hook:
1252 1252
1253| Matcher | When it fires |1253| Matcher | When it fires |
1254| :------------ | :----------------------------------------- |1254| :- | :- |
1255| `init` | `claude --init-only` or `claude -p --init` |1255| `init` | `claude --init-only` or `claude -p --init` |
1256| `maintenance` | `claude -p --maintenance` |1256| `maintenance` | `claude -p --maintenance` |
1257 1257
1296In addition to the [common input fields](#common-input-fields), InstructionsLoaded hooks receive these fields:1296In addition to the [common input fields](#common-input-fields), InstructionsLoaded hooks receive these fields:
1297 1297
1298| Field | Description |1298| Field | Description |
1299| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1299| :- | :- |
1300| `file_path` | Absolute path to the instruction file that was loaded |1300| `file_path` | Absolute path to the instruction file that was loaded |
1301| `memory_type` | Scope of the file: `"User"`, `"Project"`, `"Local"`, or `"Managed"` |1301| `memory_type` | Scope of the file: `"User"`, `"Project"`, `"Local"`, or `"Managed"` |
1302| `load_reason` | Why the file was loaded: `"session_start"`, `"nested_traversal"`, `"path_glob_match"`, `"include"`, or `"compact"`. The `"compact"` value fires when instruction files are re-loaded after a compaction event |1302| `load_reason` | Why the file was loaded: `"session_start"`, `"nested_traversal"`, `"path_glob_match"`, `"include"`, or `"compact"`. The `"compact"` value fires when instruction files are re-loaded after a compaction event |
1361To block a prompt, return a JSON object with `decision` set to `"block"`:1361To block a prompt, return a JSON object with `decision` set to `"block"`:
1362 1362
1363| Field | Description |1363| Field | Description |
1364| :----------------------- | :--------------------------------------------------------------------------------------------------------------------- |1364| :- | :- |
1365| `decision` | `"block"` prevents the prompt from being processed and erases it from context. Omit to allow the prompt to proceed |1365| `decision` | `"block"` prevents the prompt from being processed and erases it from context. Omit to allow the prompt to proceed |
1366| `reason` | Shown to the user when `decision` is `"block"`. Not added to context |1366| `reason` | Shown to the user when `decision` is `"block"`. Not added to context |
1367| `additionalContext` | String added to Claude's context alongside the submitted prompt. See [Add context for Claude](#add-context-for-claude) |1367| `additionalContext` | String added to Claude's context alongside the submitted prompt. See [Add context for Claude](#add-context-for-claude) |
1414`UserPromptExpansion` hooks can block the expansion or add context. All [JSON output fields](#json-output) are available.1414`UserPromptExpansion` hooks can block the expansion or add context. All [JSON output fields](#json-output) are available.
1415 1415
1416| Field | Description |1416| Field | Description |
1417| :------------------ | :-------------------------------------------------------------------------------------------------------------------- |1417| :- | :- |
1418| `decision` | `"block"` prevents the command from expanding. Omit to allow it to proceed |1418| `decision` | `"block"` prevents the command from expanding. Omit to allow it to proceed |
1419| `reason` | Shown to the user when `decision` is `"block"` |1419| `reason` | Shown to the user when `decision` is `"block"` |
1420| `additionalContext` | String added to Claude's context alongside the expanded prompt. See [Add context for Claude](#add-context-for-claude) |1420| `additionalContext` | String added to Claude's context alongside the expanded prompt. See [Add context for Claude](#add-context-for-claude) |
1455In addition to the [common input fields](#common-input-fields), MessageDisplay hooks receive identifiers for the turn and message, the position of this call within the message, and the new text in `delta`. Batch boundaries depend on how the text streams, so use `index` and `final` to track progress through a message rather than expecting lines to be grouped a particular way.1455In addition to the [common input fields](#common-input-fields), MessageDisplay hooks receive identifiers for the turn and message, the position of this call within the message, and the new text in `delta`. Batch boundaries depend on how the text streams, so use `index` and `final` to track progress through a message rather than expecting lines to be grouped a particular way.
1456 1456
1457| Field | Description |1457| Field | Description |
1458| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1458| :- | :- |
1459| `turn_id` | UUID of the current turn |1459| `turn_id` | UUID of the current turn |
1460| `message_id` | UUID of the assistant message being displayed. Stable across every batch of the same message. This is not the API `msg_…` id, so it can't be correlated with transcript message ids |1460| `message_id` | UUID of the assistant message being displayed. Stable across every batch of the same message. This is not the API `msg_…` id, so it can't be correlated with transcript message ids |
1461| `index` | Zero-based index of this batch within the message |1461| `index` | Zero-based index of this batch within the message |
1481In addition to the [JSON output fields](#json-output) available to all hooks, MessageDisplay hooks can return `displayContent` to replace the delta on screen:1481In addition to the [JSON output fields](#json-output) available to all hooks, MessageDisplay hooks can return `displayContent` to replace the delta on screen:
1482 1482
1483| Field | Description |1483| Field | Description |
1484| :--------------- | :-------------------------------------------------------------------- |1484| :- | :- |
1485| `displayContent` | Text displayed in place of the delta. Omit it to display the original |1485| `displayContent` | Text displayed in place of the delta. Omit it to display the original |
1486 1486
1487MessageDisplay hooks have no decision control. They can't block the message or change what is stored in the transcript or sent to Claude. Claude Code acts on `displayContent` from their JSON output and discards `systemMessage` and `continue`.1487MessageDisplay hooks have no decision control. They can't block the message or change what is stored in the transcript or sent to Claude. Claude Code acts on `displayContent` from their JSON output and discards `systemMessage` and `continue`.
1616Executes shell commands.1616Executes shell commands.
1617 1617
1618| Field | Type | Example | Description |1618| Field | Type | Example | Description |
1619| :------------------ | :------ | :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |1619| :- | :- | :- | :- |
1620| `command` | string | `"npm test"` | The shell command to execute |1620| `command` | string | `"npm test"` | The shell command to execute |
1621| `description` | string | `"Run test suite"` | Optional description of what the command does |1621| `description` | string | `"Run test suite"` | Optional description of what the command does |
1622| `timeout` | number | `120000` | Optional timeout in milliseconds. Values above the [maximum](/docs/en/tools-reference#bash-tool-behavior) are reduced to the maximum rather than rejected |1622| `timeout` | number | `120000` | Optional timeout in milliseconds. Values above the [maximum](/docs/en/tools-reference#bash-tool-behavior) are reduced to the maximum rather than rejected |
1633`changedFiles` and `files` list what the command changed; the remaining fields say how complete and how reliable that list is.1633`changedFiles` and `files` list what the command changed; the remaining fields say how complete and how reliable that list is.
1634 1634
1635| Field | Type | Example | Description |1635| Field | Type | Example | Description |
1636| :------------- | :------ | :------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------- |1636| :- | :- | :- | :- |
1637| `changedFiles` | array | `["/path/to/src/app.ts"]` | Absolute paths of the files the command changed, at most 200. Present whenever `files` holds a diff or `moreFiles` is above zero |1637| `changedFiles` | array | `["/path/to/src/app.ts"]` | Absolute paths of the files the command changed, at most 200. Present whenever `files` holds a diff or `moreFiles` is above zero |
1638| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | Diffs of up to 5 changed files, for display. `created` or `deleted` is `true` for a file the command added or removed |1638| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | Diffs of up to 5 changed files, for display. `created` or `deleted` is `true` for a file the command added or removed |
1639| `moreFiles` | number | `2` | Count of changed files with no diff in `files` |1639| `moreFiles` | number | `2` | Count of changed files with no diff in `files` |
1650The fields match the Bash tool, with the command string in `command`:1650The fields match the Bash tool, with the command string in `command`:
1651 1651
1652| Field | Type | Example | Description |1652| Field | Type | Example | Description |
1653| :------------------ | :------ | :------------------------- | :-------------------------------------------- |1653| :- | :- | :- | :- |
1654| `command` | string | `"Get-ChildItem -Recurse"` | The PowerShell command to execute |1654| `command` | string | `"Get-ChildItem -Recurse"` | The PowerShell command to execute |
1655| `description` | string | `"List files recursively"` | Optional description of what the command does |1655| `description` | string | `"List files recursively"` | Optional description of what the command does |
1656| `timeout` | number | `120000` | Optional timeout in milliseconds |1656| `timeout` | number | `120000` | Optional timeout in milliseconds |
1667Creates or overwrites a file.1667Creates or overwrites a file.
1668 1668
1669| Field | Type | Example | Description |1669| Field | Type | Example | Description |
1670| :---------- | :----- | :-------------------- | :--------------------------------- |1670| :- | :- | :- | :- |
1671| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to write |1671| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to write |
1672| `content` | string | `"file content"` | Content to write to the file |1672| `content` | string | `"file content"` | Content to write to the file |
1673 1673
1676Replaces a string in an existing file.1676Replaces a string in an existing file.
1677 1677
1678| Field | Type | Example | Description |1678| Field | Type | Example | Description |
1679| :------------ | :------ | :-------------------- | :--------------------------------- |1679| :- | :- | :- | :- |
1680| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to edit |1680| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to edit |
1681| `old_string` | string | `"original text"` | Text to find and replace |1681| `old_string` | string | `"original text"` | Text to find and replace |
1682| `new_string` | string | `"replacement text"` | Replacement text |1682| `new_string` | string | `"replacement text"` | Replacement text |
1687Reads file contents.1687Reads file contents.
1688 1688
1689| Field | Type | Example | Description |1689| Field | Type | Example | Description |
1690| :---------- | :----- | :-------------------- | :----------------------------------------- |1690| :- | :- | :- | :- |
1691| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to read |1691| `file_path` | string | `"/path/to/file.txt"` | Absolute path to the file to read |
1692| `offset` | number | `10` | Optional line number to start reading from |1692| `offset` | number | `10` | Optional line number to start reading from |
1693| `limit` | number | `50` | Optional number of lines to read |1693| `limit` | number | `50` | Optional number of lines to read |
1697Finds files matching a glob pattern.1697Finds files matching a glob pattern.
1698 1698
1699| Field | Type | Example | Description |1699| Field | Type | Example | Description |
1700| :-------- | :----- | :--------------- | :--------------------------------------------------------------------- |1700| :- | :- | :- | :- |
1701| `pattern` | string | `"**/*.ts"` | Glob pattern to match files against |1701| `pattern` | string | `"**/*.ts"` | Glob pattern to match files against |
1702| `path` | string | `"/path/to/dir"` | Optional directory to search in. Defaults to current working directory |1702| `path` | string | `"/path/to/dir"` | Optional directory to search in. Defaults to current working directory |
1703 1703
1706Searches file contents with regular expressions.1706Searches file contents with regular expressions.
1707 1707
1708| Field | Type | Example | Description |1708| Field | Type | Example | Description |
1709| :------------ | :------ | :--------------- | :------------------------------------------------------------------------------------ |1709| :- | :- | :- | :- |
1710| `pattern` | string | `"TODO.*fix"` | Regular expression pattern to search for |1710| `pattern` | string | `"TODO.*fix"` | Regular expression pattern to search for |
1711| `path` | string | `"/path/to/dir"` | Optional file or directory to search in |1711| `path` | string | `"/path/to/dir"` | Optional file or directory to search in |
1712| `glob` | string | `"*.ts"` | Optional glob pattern to filter files |1712| `glob` | string | `"*.ts"` | Optional glob pattern to filter files |
1719Fetches and processes web content.1719Fetches and processes web content.
1720 1720
1721| Field | Type | Example | Description |1721| Field | Type | Example | Description |
1722| :------- | :----- | :---------------------------- | :----------------------------------- |1722| :- | :- | :- | :- |
1723| `url` | string | `"https://example.com/api"` | URL to fetch content from |1723| `url` | string | `"https://example.com/api"` | URL to fetch content from |
1724| `prompt` | string | `"Extract the API endpoints"` | Prompt to run on the fetched content |1724| `prompt` | string | `"Extract the API endpoints"` | Prompt to run on the fetched content |
1725 1725
1728Searches the web.1728Searches the web.
1729 1729
1730| Field | Type | Example | Description |1730| Field | Type | Example | Description |
1731| :---------------- | :----- | :----------------------------- | :------------------------------------------------ |1731| :- | :- | :- | :- |
1732| `query` | string | `"react hooks best practices"` | Search query |1732| `query` | string | `"react hooks best practices"` | Search query |
1733| `allowed_domains` | array | `["docs.example.com"]` | Optional: only include results from these domains |1733| `allowed_domains` | array | `["docs.example.com"]` | Optional: only include results from these domains |
1734| `blocked_domains` | array | `["spam.example.com"]` | Optional: exclude results from these domains |1734| `blocked_domains` | array | `["spam.example.com"]` | Optional: exclude results from these domains |
1738Spawns a [subagent](/docs/en/sub-agents).1738Spawns a [subagent](/docs/en/sub-agents).
1739 1739
1740| Field | Type | Example | Description |1740| Field | Type | Example | Description |
1741| :-------------- | :----- | :------------------------- | :------------------------------------------- |1741| :- | :- | :- | :- |
1742| `prompt` | string | `"Find all API endpoints"` | The task for the agent to perform |1742| `prompt` | string | `"Find all API endpoints"` | The task for the agent to perform |
1743| `description` | string | `"Find API endpoints"` | Short description of the task |1743| `description` | string | `"Find API endpoints"` | Short description of the task |
1744| `subagent_type` | string | `"Explore"` | Type of specialized agent to use |1744| `subagent_type` | string | `"Explore"` | Type of specialized agent to use |
1747When a foreground Agent call completes, your [PostToolUse hook](#posttooluse) receives the subagent's result and run telemetry in `tool_response`. Read these fields to inspect the run; for token and cost rollups across subagents, use the [token and cost counters](/docs/en/monitoring-usage#token-counter) filtered to `query_source` `"subagent"`, since `totalTokens` and `usage` cover the final request only:1747When a foreground Agent call completes, your [PostToolUse hook](#posttooluse) receives the subagent's result and run telemetry in `tool_response`. Read these fields to inspect the run; for token and cost rollups across subagents, use the [token and cost counters](/docs/en/monitoring-usage#token-counter) filtered to `query_source` `"subagent"`, since `totalTokens` and `usage` cover the final request only:
1748 1748
1749| Field | Type | Example | Description |1749| Field | Type | Example | Description |
1750| :------------------ | :----- | :---------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1750| :- | :- | :- | :- |
1751| `status` | string | `"completed"` | `"completed"` for foreground subagents, `"async_launched"` for background subagents. As of v2.1.198, subagents run in the background by default, so an omitted `run_in_background` also produces `"async_launched"` |1751| `status` | string | `"completed"` | `"completed"` for foreground subagents, `"async_launched"` for background subagents. As of v2.1.198, subagents run in the background by default, so an omitted `run_in_background` also produces `"async_launched"` |
1752| `agentId` | string | `"a4d2c8f1e0b3a297"` | Identifier for the subagent run |1752| `agentId` | string | `"a4d2c8f1e0b3a297"` | Identifier for the subagent run |
1753| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | The subagent's final text blocks, or, for a subagent whose report goes through `SubagentHandback`, a short note about that hand-back in their place |1753| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | The subagent's final text blocks, or, for a subagent whose report goes through `SubagentHandback`, a short note about that hand-back in their place |
1771Asks the user one to four multiple-choice questions.1771Asks the user one to four multiple-choice questions.
1772 1772
1773| Field | Type | Example | Description |1773| Field | Type | Example | Description |
1774| :---------- | :----- | :----------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1774| :- | :- | :- | :- |
1775| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | Questions to present, each with a `question` string, short `header`, `options` array, and optional `multiSelect` flag |1775| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | Questions to present, each with a `question` string, short `header`, `options` array, and optional `multiSelect` flag |
1776| `answers` | object | `{"Which framework?": "React"}` | Optional. Maps question text to the selected option label. Multi-select answers join labels with commas. Claude doesn't set this field; supply it via `updatedInput` to answer programmatically |1776| `answers` | object | `{"Which framework?": "React"}` | Optional. Maps question text to the selected option label. Multi-select answers join labels with commas. Claude doesn't set this field; supply it via `updatedInput` to answer programmatically |
1777 1777
1780Presents a plan and asks the user to approve it before Claude leaves [plan mode](/docs/en/permission-modes#analyze-before-you-edit-with-plan-mode). Claude writes the plan to a file on disk before calling the tool, so the literal `tool_input` from the model is typically empty. Claude Code injects the plan content and file path before passing the input to hooks.1780Presents a plan and asks the user to approve it before Claude leaves [plan mode](/docs/en/permission-modes#analyze-before-you-edit-with-plan-mode). Claude writes the plan to a file on disk before calling the tool, so the literal `tool_input` from the model is typically empty. Claude Code injects the plan content and file path before passing the input to hooks.
1781 1781
1782| Field | Type | Example | Description |1782| Field | Type | Example | Description |
1783| :--------------- | :----- | :------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------- |1783| :- | :- | :- | :- |
1784| `plan` | string | `"## Refactor auth\n1. Extract..."` | Plan content in Markdown. Injected from the plan file on disk |1784| `plan` | string | `"## Refactor auth\n1. Extract..."` | Plan content in Markdown. Injected from the plan file on disk |
1785| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | Path to the plan file. Injected |1785| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | Path to the plan file. Injected |
1786| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | Deprecated. Claude Code accepts the field but ignores it. Before v2.1.205, it carried prompt-based permissions Claude requested to implement the plan |1786| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | Deprecated. Claude Code accepts the field but ignores it. Before v2.1.205, it carried prompt-based permissions Claude requested to implement the plan |
1792`PreToolUse` hooks can control whether a tool call proceeds. Unlike other hooks that use a top-level `decision` field, PreToolUse returns its decision inside a `hookSpecificOutput` object. This gives it richer control: four outcomes (allow, deny, ask, or defer) plus the ability to modify tool input before execution.1792`PreToolUse` hooks can control whether a tool call proceeds. Unlike other hooks that use a top-level `decision` field, PreToolUse returns its decision inside a `hookSpecificOutput` object. This gives it richer control: four outcomes (allow, deny, ask, or defer) plus the ability to modify tool input before execution.
1793 1793
1794| Field | Description |1794| Field | Description |
1795| :------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1795| :- | :- |
1796| `permissionDecision` | `"allow"` skips the permission prompt, except for the [actions no mode auto-approves](/docs/en/permission-modes#actions-no-mode-auto-approves) and for `AskUserQuestion` and `ExitPlanMode`, which need [`updatedInput` paired with it](#allow-with-updatedinput). `"deny"` prevents the tool call. `"ask"` prompts the user to confirm. `"defer"` exits gracefully so the tool can be resumed later. [Deny and ask rules](/docs/en/permissions#manage-permissions) are still evaluated regardless of what the hook returns |1796| `permissionDecision` | `"allow"` skips the permission prompt, except for the [actions no mode auto-approves](/docs/en/permission-modes#actions-no-mode-auto-approves) and for `AskUserQuestion` and `ExitPlanMode`, which need [`updatedInput` paired with it](#allow-with-updatedinput). `"deny"` prevents the tool call. `"ask"` prompts the user to confirm. `"defer"` exits gracefully so the tool can be resumed later. [Deny and ask rules](/docs/en/permissions#manage-permissions) are still evaluated regardless of what the hook returns |
1797| `permissionDecisionReason` | For `"allow"` and `"ask"`, shown to the user but not Claude. For `"deny"`, shown to Claude. For `"defer"`, ignored |1797| `permissionDecisionReason` | For `"allow"` and `"ask"`, shown to the user but not Claude. For `"deny"`, shown to Claude. For `"defer"`, ignored |
1798| `updatedInput` | Modifies the tool's input parameters before execution. Replaces the entire input object, so include unchanged fields alongside modified ones. Claude Code evaluates permission rules and a Bash command's [auto-background eligibility](/docs/en/tools-reference#background-commands) against the input your hook returns, not the input Claude sent. Combine with `"allow"` to auto-approve, or `"ask"` to show the modified input to the user. For `"defer"`, ignored |1798| `updatedInput` | Modifies the tool's input parameters before execution. Replaces the entire input object, so include unchanged fields alongside modified ones. Claude Code evaluates permission rules and a Bash command's [auto-background eligibility](/docs/en/tools-reference#background-commands) against the input your hook returns, not the input Claude sent. Combine with `"allow"` to auto-approve, or `"ask"` to show the modified input to the user. For `"defer"`, ignored |
1917`PermissionRequest` hooks can allow or deny permission requests. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return a `decision` object with these event-specific fields:1917`PermissionRequest` hooks can allow or deny permission requests. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return a `decision` object with these event-specific fields:
1918 1918
1919| Field | Description |1919| Field | Description |
1920| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |1920| :- | :- |
1921| `behavior` | `"allow"` grants the permission, `"deny"` denies it. [Deny and ask rules](/docs/en/permissions#manage-permissions) are still evaluated, so a hook returning `"allow"` doesn't override a matching deny rule |1921| `behavior` | `"allow"` grants the permission, `"deny"` denies it. [Deny and ask rules](/docs/en/permissions#manage-permissions) are still evaluated, so a hook returning `"allow"` doesn't override a matching deny rule |
1922| `updatedInput` | For `"allow"` only: modifies the tool's input parameters before execution. Replaces the entire input object, so include unchanged fields alongside modified ones. The modified input is re-evaluated against deny and ask rules |1922| `updatedInput` | For `"allow"` only: modifies the tool's input parameters before execution. Replaces the entire input object, so include unchanged fields alongside modified ones. The modified input is re-evaluated against deny and ask rules |
1923| `updatedPermissions` | For `"allow"` only: array of [permission update entries](#permission-update-entries) to apply, such as adding an allow rule or changing the session permission mode |1923| `updatedPermissions` | For `"allow"` only: array of [permission update entries](#permission-update-entries) to apply, such as adding an allow rule or changing the session permission mode |
1945The `updatedPermissions` output field and the [`permission_suggestions` input field](#permissionrequest-input) both use the same array of entry objects. Each entry has a `type` that determines its other fields, and a `destination` that controls where the change is written.1945The `updatedPermissions` output field and the [`permission_suggestions` input field](#permissionrequest-input) both use the same array of entry objects. Each entry has a `type` that determines its other fields, and a `destination` that controls where the change is written.
1946 1946
1947| `type` | Fields | Effect |1947| `type` | Fields | Effect |
1948| :------------------ | :--------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1948| :- | :- | :- |
1949| `addRules` | `rules`, `behavior`, `destination` | Adds permission rules. `rules` is an array of `{toolName, ruleContent?}` objects. Omit `ruleContent` to match the whole tool. `behavior` is `"allow"`, `"deny"`, or `"ask"` |1949| `addRules` | `rules`, `behavior`, `destination` | Adds permission rules. `rules` is an array of `{toolName, ruleContent?}` objects. Omit `ruleContent` to match the whole tool. `behavior` is `"allow"`, `"deny"`, or `"ask"` |
1950| `replaceRules` | `rules`, `behavior`, `destination` | Replaces all rules of the given `behavior` at the `destination` with the provided `rules` |1950| `replaceRules` | `rules`, `behavior`, `destination` | Replaces all rules of the given `behavior` at the `destination` with the provided `rules` |
1951| `removeRules` | `rules`, `behavior`, `destination` | Removes matching rules of the given `behavior` |1951| `removeRules` | `rules`, `behavior`, `destination` | Removes matching rules of the given `behavior` |
1962The `destination` field on every entry determines whether the change stays in memory or persists to a settings file.1962The `destination` field on every entry determines whether the change stays in memory or persists to a settings file.
1963 1963
1964| `destination` | Writes to |1964| `destination` | Writes to |
1965| :---------------- | :---------------------------------------------- |1965| :- | :- |
1966| `session` | in-memory only, discarded when the session ends |1966| `session` | in-memory only, discarded when the session ends |
1967| `localSettings` | `.claude/settings.local.json` |1967| `localSettings` | `.claude/settings.local.json` |
1968| `projectSettings` | `.claude/settings.json` |1968| `projectSettings` | `.claude/settings.json` |
2007```2007```
2008 2008
2009| Field | Description |2009| Field | Description |
2010| :------------ | :------------------------------------------------------------------------------------------------------------ |2010| :- | :- |
2011| `duration_ms` | Optional. Tool execution time in milliseconds. Excludes time spent in permission prompts and PreToolUse hooks |2011| `duration_ms` | Optional. Tool execution time in milliseconds. Excludes time spent in permission prompts and PreToolUse hooks |
2012 2012
2013#### PostToolUse decision control2013#### PostToolUse decision control
2015`PostToolUse` hooks can provide feedback to Claude after tool execution. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:2015`PostToolUse` hooks can provide feedback to Claude after tool execution. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:
2016 2016
2017| Field | Description |2017| Field | Description |
2018| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2018| :- | :- |
2019| `decision` | `"block"` adds the `reason` next to the tool result. Claude still sees the original output; to replace it, use `updatedToolOutput` |2019| `decision` | `"block"` adds the `reason` next to the tool result. Claude still sees the original output; to replace it, use `updatedToolOutput` |
2020| `reason` | Explanation shown to Claude when `decision` is `"block"` |2020| `reason` | Explanation shown to Claude when `decision` is `"block"` |
2021| `additionalContext` | String added to Claude's context alongside the tool result. See [Add context for Claude](#add-context-for-claude) |2021| `additionalContext` | String added to Claude's context alongside the tool result. See [Add context for Claude](#add-context-for-claude) |
2111```2111```
2112 2112
2113| Field | Description |2113| Field | Description |
2114| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2114| :- | :- |
2115| `error` | String describing what went wrong. The format depends on the tool that failed |2115| `error` | String describing what went wrong. The format depends on the tool that failed |
2116| `is_interrupt` | Optional boolean. True when the failure reached Claude Code as an abort rather than as an error the tool reported. Cancelling a running tool does not fire this hook; the tool result carries the interruption message instead |2116| `is_interrupt` | Optional boolean. True when the failure reached Claude Code as an abort rather than as an error the tool reported. Cancelling a running tool does not fire this hook; the tool result carries the interruption message instead |
2117| `duration_ms` | Optional. Tool execution time in milliseconds. Excludes time spent in permission prompts and PreToolUse hooks |2117| `duration_ms` | Optional. Tool execution time in milliseconds. Excludes time spent in permission prompts and PreToolUse hooks |
2127`PostToolUseFailure` hooks can provide context to Claude after a tool failure. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:2127`PostToolUseFailure` hooks can provide context to Claude after a tool failure. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:
2128 2128
2129| Field | Description |2129| Field | Description |
2130| :------------------ | :---------------------------------------------------------------------------------------------------------- |2130| :- | :- |
2131| `additionalContext` | String added to Claude's context alongside the error. See [Add context for Claude](#add-context-for-claude) |2131| `additionalContext` | String added to Claude's context alongside the error. See [Add context for Claude](#add-context-for-claude) |
2132 2132
2133```json theme={null}2133```json theme={null}
2182`PostToolBatch` hooks can inject context for Claude. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:2182`PostToolBatch` hooks can inject context for Claude. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:
2183 2183
2184| Field | Description |2184| Field | Description |
2185| :------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2185| :- | :- |
2186| `additionalContext` | Context string injected once before the next model call. See [Add context for Claude](#add-context-for-claude) for delivery details, what to put in it, and how resumed sessions handle past values |2186| `additionalContext` | Context string injected once before the next model call. See [Add context for Claude](#add-context-for-claude) for delivery details, what to put in it, and how resumed sessions handle past values |
2187 2187
2188```json theme={null}2188```json theme={null}
2224```2224```
2225 2225
2226| Field | Description |2226| Field | Description |
2227| :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2227| :- | :- |
2228| `reason` | The denial reason. For a classifier verdict, in most sessions it names the matched rule in square brackets, such as `[Data Exfiltration]`; see [Review denials](/docs/en/auto-mode-config#review-denials) for the other forms. For a [no-verdict denial](#permissiondenied-decision-control), it starts with `Auto mode could not evaluate this action and is blocking it for safety`. For a denial because the classifier model was unavailable, it is the fixed text `Classifier unavailable` |2228| `reason` | The denial reason. For a classifier verdict, in most sessions it names the matched rule in square brackets, such as `[Data Exfiltration]`; see [Review denials](/docs/en/auto-mode-config#review-denials) for the other forms. For a [no-verdict denial](#permissiondenied-decision-control), it starts with `Auto mode could not evaluate this action and is blocking it for safety`. For a denial because the classifier model was unavailable, it is the fixed text `Classifier unavailable` |
2229 2229
2230#### PermissionDenied decision control2230#### PermissionDenied decision control
2251You receive these hook events even with desktop notifications turned off: the `preferredNotifChannel` setting, including `notifications_disabled`, changes only how you're alerted, not whether your hook runs.2251You receive these hook events even with desktop notifications turned off: the `preferredNotifChannel` setting, including `notifications_disabled`, changes only how you're alerted, not whether your hook runs.
2252 2252
2253| Matcher | When it fires |2253| Matcher | When it fires |
2254| :--------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2254| :- | :- |
2255| `permission_prompt` | Claude needs you to approve a tool use or a sandboxed command's [network request](/docs/en/sandboxing#network-isolation), and the prompt has waited about six seconds |2255| `permission_prompt` | Claude needs you to approve a tool use or a sandboxed command's [network request](/docs/en/sandboxing#network-isolation), and the prompt has waited about six seconds |
2256| `idle_prompt` | Claude finished responding about 60 seconds ago and you haven't typed since |2256| `idle_prompt` | Claude finished responding about 60 seconds ago and you haven't typed since |
2257| `auth_success` | Authentication completes |2257| `auth_success` | Authentication completes |
2362SubagentStart hooks can't block subagent creation, but they can inject context into the subagent. In addition to the [JSON output fields](#json-output) available to all hooks, you can return:2362SubagentStart hooks can't block subagent creation, but they can inject context into the subagent. In addition to the [JSON output fields](#json-output) available to all hooks, you can return:
2363 2363
2364| Field | Description |2364| Field | Description |
2365| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------ |2365| :- | :- |
2366| `additionalContext` | String added to the subagent's context at the start of its conversation, before its first prompt. See [Add context for Claude](#add-context-for-claude) |2366| `additionalContext` | String added to the subagent's context at the start of its conversation, before its first prompt. See [Add context for Claude](#add-context-for-claude) |
2367 2367
2368```json theme={null}2368```json theme={null}
2436```2436```
2437 2437
2438| Field | Description |2438| Field | Description |
2439| :----------------- | :------------------------------------------------------------------------- |2439| :- | :- |
2440| `task_id` | Identifier of the task being created |2440| `task_id` | Identifier of the task being created |
2441| `task_subject` | Title of the task |2441| `task_subject` | Title of the task |
2442| `task_description` | Detailed description of the task. May be absent |2442| `task_description` | Detailed description of the task. May be absent |
2491```2491```
2492 2492
2493| Field | Description |2493| Field | Description |
2494| :----------------- | :------------------------------------------------------------------------- |2494| :- | :- |
2495| `task_id` | Identifier of the task being completed |2495| `task_id` | Identifier of the task being completed |
2496| `task_subject` | Title of the task |2496| `task_subject` | Title of the task |
2497| `task_description` | Detailed description of the task. May be absent |2497| `task_description` | Detailed description of the task. May be absent |
2542Each entry in `background_tasks` describes one in-flight task and uses these fields:2542Each entry in `background_tasks` describes one in-flight task and uses these fields:
2543 2543
2544| Field | Description |2544| Field | Description |
2545| :------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2545| :- | :- |
2546| `id` | Task identifier |2546| `id` | Task identifier |
2547| `type` | Friendly task-type label such as `shell`, `subagent`, `monitor`, `workflow`, `teammate`, `cloud session`, or `MCP task`. Each label identifies which Claude Code feature created the task. Falls back to the raw discriminant for unrecognized types |2547| `type` | Friendly task-type label such as `shell`, `subagent`, `monitor`, `workflow`, `teammate`, `cloud session`, or `MCP task`. Each label identifies which Claude Code feature created the task. Falls back to the raw discriminant for unrecognized types |
2548| `status` | Current task status |2548| `status` | Current task status |
2556Each entry in `session_crons` describes one session-scoped scheduled wakeup, sourced from `CronCreate`, `ScheduleWakeup`, and `/loop`:2556Each entry in `session_crons` describes one session-scoped scheduled wakeup, sourced from `CronCreate`, `ScheduleWakeup`, and `/loop`:
2557 2557
2558| Field | Description |2558| Field | Description |
2559| :---------- | :------------------------------------------------------------------------------------------------------------------- |2559| :- | :- |
2560| `id` | Cron task identifier |2560| `id` | Cron task identifier |
2561| `schedule` | Cron expression, for example `0 9 * * 1-5` |2561| `schedule` | Cron expression, for example `0 9 * * 1-5` |
2562| `recurring` | `false` for one-shot wakeups whose schedule encodes a single fire time, `true` for tasks that re-fire on every match |2562| `recurring` | `false` for one-shot wakeups whose schedule encodes a single fire time, `true` for tasks that re-fire on every match |
2598`Stop` and `SubagentStop` hooks can control whether Claude continues. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:2598`Stop` and `SubagentStop` hooks can control whether Claude continues. In addition to the [JSON output fields](#json-output) available to all hooks, your hook script can return these event-specific fields:
2599 2599
2600| Field | Description |2600| Field | Description |
2601| :------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2601| :- | :- |
2602| `decision` | `"block"` prevents Claude from stopping. Omit to allow Claude to stop |2602| `decision` | `"block"` prevents Claude from stopping. Omit to allow Claude to stop |
2603| `reason` | Required when `decision` is `"block"`. Tells Claude why it should continue |2603| `reason` | Required when `decision` is `"block"`. Tells Claude why it should continue |
2604| `hookSpecificOutput.additionalContext` | Non-error feedback for Claude. The conversation continues so Claude can act on it, but unlike `decision: "block"` it is shown in the transcript as hook feedback rather than a hook error |2604| `hookSpecificOutput.additionalContext` | Non-error feedback for Claude. The conversation continues so Claude can act on it, but unlike `decision: "block"` it is shown in the transcript as hook feedback rather than a hook error |
2632In addition to the [common input fields](#common-input-fields), StopFailure hooks receive `error`, optional `error_details`, and optional `last_assistant_message`. The `error` field identifies the error type and is used for matcher filtering.2632In addition to the [common input fields](#common-input-fields), StopFailure hooks receive `error`, optional `error_details`, and optional `last_assistant_message`. The `error` field identifies the error type and is used for matcher filtering.
2633 2633
2634| Field | Description |2634| Field | Description |
2635| :----------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2635| :- | :- |
2636| `error` | Error type: `rate_limit`, `overloaded`, `authentication_failed`, `oauth_org_not_allowed`, `account_on_hold`, `billing_error`, `invalid_request`, `model_not_found`, `server_error`, `max_output_tokens`, `cloud_credential_error`, or `unknown` |2636| `error` | Error type: `rate_limit`, `overloaded`, `authentication_failed`, `oauth_org_not_allowed`, `account_on_hold`, `billing_error`, `invalid_request`, `model_not_found`, `server_error`, `max_output_tokens`, `cloud_credential_error`, or `unknown` |
2637| `error_details` | Additional details about the error, when available |2637| `error_details` | Additional details about the error, when available |
2638| `last_assistant_message` | The rendered error text shown in the conversation. Unlike `Stop` and `SubagentStop`, where this field holds Claude's conversational output, for `StopFailure` it contains the API error string itself, such as `"API Error: Rate limit reached"` |2638| `last_assistant_message` | The rendered error text shown in the conversation. Unlike `Stop` and `SubagentStop`, where this field holds Claude's conversational output, for `StopFailure` it contains the API error string itself, such as `"API Error: Rate limit reached"` |
2674```2674```
2675 2675
2676| Field | Description |2676| Field | Description |
2677| :-------------- | :------------------------------------------------------------------------- |2677| :- | :- |
2678| `teammate_name` | Name of the teammate that is about to go idle |2678| `teammate_name` | Name of the teammate that is about to go idle |
2679| `team_name` | Deprecated. Session-derived team name; will be removed in a future release |2679| `team_name` | Deprecated. Session-derived team name; will be removed in a future release |
2680 2680
2707The matcher filters on the configuration source:2707The matcher filters on the configuration source:
2708 2708
2709| Matcher | When it fires |2709| Matcher | When it fires |
2710| :----------------- | :----------------------------------------------------------------- |2710| :- | :- |
2711| `user_settings` | `~/.claude/settings.json` changes |2711| `user_settings` | `~/.claude/settings.json` changes |
2712| `project_settings` | `.claude/settings.json` changes |2712| `project_settings` | `.claude/settings.json` changes |
2713| `local_settings` | `.claude/settings.local.json` changes |2713| `local_settings` | `.claude/settings.local.json` changes |
2754ConfigChange hooks can block configuration changes from taking effect. Use exit code 2 or a JSON `decision` to prevent the change. When blocked, the new settings are not applied to the running session.2754ConfigChange hooks can block configuration changes from taking effect. Use exit code 2 or a JSON `decision` to prevent the change. When blocked, the new settings are not applied to the running session.
2755 2755
2756| Field | Description |2756| Field | Description |
2757| :--------- | :--------------------------------------------------------------------------------------- |2757| :- | :- |
2758| `decision` | `"block"` prevents the configuration change from being applied. Omit to allow the change |2758| `decision` | `"block"` prevents the configuration change from being applied. Omit to allow the change |
2759| `reason` | Accepted but never shown |2759| `reason` | Accepted but never shown |
2760 2760
2797In addition to the [JSON output fields](#json-output) available to all hooks, CwdChanged hooks can return `watchPaths` to dynamically set which file paths [FileChanged](#filechanged) watches:2797In addition to the [JSON output fields](#json-output) available to all hooks, CwdChanged hooks can return `watchPaths` to dynamically set which file paths [FileChanged](#filechanged) watches:
2798 2798
2799| Field | Description |2799| Field | Description |
2800| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2800| :- | :- |
2801| `watchPaths` | Array of absolute paths. Replaces the current dynamic watch list. Paths from your `matcher` configuration are always watched. Returning an empty array clears the dynamic list, which is typical when entering a new directory |2801| `watchPaths` | Array of absolute paths. Replaces the current dynamic watch list. Paths from your `matcher` configuration are always watched. Returning an empty array clears the dynamic list, which is typical when entering a new directory |
2802 2802
2803CwdChanged hooks have no decision control. They can't block the directory change.2803CwdChanged hooks have no decision control. They can't block the directory change.
2821The matcher filters on how the directory was added:2821The matcher filters on how the directory was added:
2822 2822
2823| Matcher | When it fires |2823| Matcher | When it fires |
2824| :------------------- | :--------------------------------------------------------------------------- |2824| :- | :- |
2825| `slash_command` | You add a directory with `/add-dir` |2825| `slash_command` | You add a directory with `/add-dir` |
2826| `register_repo_root` | An SDK client adds a directory with the `register_repo_root` control request |2826| `register_repo_root` | An SDK client adds a directory with the `register_repo_root` control request |
2827 2827
2830In addition to the [common input fields](#common-input-fields), DirectoryAdded hooks receive `directory` and `source`.2830In addition to the [common input fields](#common-input-fields), DirectoryAdded hooks receive `directory` and `source`.
2831 2831
2832| Field | Description |2832| Field | Description |
2833| :---------- | :------------------------------------------------------------------------------------------------------------------ |2833| :- | :- |
2834| `directory` | Absolute path of the directory that was added |2834| `directory` | Absolute path of the directory that was added |
2835| `source` | How the directory was added, `"slash_command"` for `/add-dir` or `"register_repo_root"` for the SDK control request |2835| `source` | How the directory was added, `"slash_command"` for `/add-dir` or `"register_repo_root"` for the SDK control request |
2836 2836
2900In addition to the [common input fields](#common-input-fields), FileChanged hooks receive `file_path` and `event`.2900In addition to the [common input fields](#common-input-fields), FileChanged hooks receive `file_path` and `event`.
2901 2901
2902| Field | Description |2902| Field | Description |
2903| :---------- | :---------------------------------------------------------------------------------------------------------- |2903| :- | :- |
2904| `file_path` | Absolute path to the file that changed |2904| `file_path` | Absolute path to the file that changed |
2905| `event` | What happened: `"change"` for a modified file, `"add"` for a created file, or `"unlink"` for a deleted file |2905| `event` | What happened: `"change"` for a modified file, `"add"` for a created file, or `"unlink"` for a deleted file |
2906 2906
2920In addition to the [JSON output fields](#json-output) available to all hooks, FileChanged hooks can return `watchPaths` to dynamically update which file paths are watched:2920In addition to the [JSON output fields](#json-output) available to all hooks, FileChanged hooks can return `watchPaths` to dynamically update which file paths are watched:
2921 2921
2922| Field | Description |2922| Field | Description |
2923| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2923| :- | :- |
2924| `watchPaths` | Array of absolute paths. Replaces the current dynamic watch list. Paths from your `matcher` configuration are always watched. Use this when your hook script discovers additional files to watch based on the changed file |2924| `watchPaths` | Array of absolute paths. Replaces the current dynamic watch list. Paths from your `matcher` configuration are always watched. Use this when your hook script discovers additional files to watch based on the changed file |
2925 2925
2926FileChanged hooks have no decision control. They can't block the file change from occurring.2926FileChanged hooks have no decision control. They can't block the file change from occurring.
3044The matcher value indicates whether compaction was triggered manually or automatically:3044The matcher value indicates whether compaction was triggered manually or automatically:
3045 3045
3046| Matcher | When it fires |3046| Matcher | When it fires |
3047| :------- | :----------------------------------------------------------------------------------------------------------------- |3047| :- | :- |
3048| `manual` | `/compact` |3048| `manual` | `/compact` |
3049| `auto` | Auto-compact when the conversation reaches the [auto-compact window](/docs/en/model-config#set-the-auto-compact-window) |3049| `auto` | Auto-compact when the conversation reaches the [auto-compact window](/docs/en/model-config#set-the-auto-compact-window) |
3050 3050
3076The same matcher values apply as for `PreCompact`:3076The same matcher values apply as for `PreCompact`:
3077 3077
3078| Matcher | When it fires |3078| Matcher | When it fires |
3079| :------- | :----------------------------------------------------------------------------------------------------------------------- |3079| :- | :- |
3080| `manual` | After `/compact` |3080| `manual` | After `/compact` |
3081| `auto` | After auto-compact when the conversation reaches the [auto-compact window](/docs/en/model-config#set-the-auto-compact-window) |3081| `auto` | After auto-compact when the conversation reaches the [auto-compact window](/docs/en/model-config#set-the-auto-compact-window) |
3082 3082
3188In addition to the [common input fields](#common-input-fields), PreModelSwitch hooks receive the fields in this table. The last five describe what re-sending the conversation to the new model costs, so a hook can show that figure before the switch happens.3188In addition to the [common input fields](#common-input-fields), PreModelSwitch hooks receive the fields in this table. The last five describe what re-sending the conversation to the new model costs, so a hook can show that figure before the switch happens.
3189 3189
3190| Field | Type | Description |3190| Field | Type | Description |
3191| :-------------------------- | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |3191| :- | :- | :- |
3192| `from_model` | string | Model ID the switch changes from |3192| `from_model` | string | Model ID the switch changes from |
3193| `to_model` | string | Model ID the switch changes to. The matcher compares against this model's canonical name |3193| `to_model` | string | Model ID the switch changes to. The matcher compares against this model's canonical name |
3194| `requested_model` | string or `null` | The model the request named: an alias such as `opus`, a full model ID, or `null` when the request was for the default model |3194| `requested_model` | string or `null` | The model the request named: an alias such as `opus`, a full model ID, or `null` when the request was for the default model |
3226For finer control, return `permissionDecision` and `permissionDecisionReason` in a `hookSpecificOutput` object, as on [PreToolUse](#pretooluse-decision-control). `PreModelSwitch` accepts `"allow"`, `"deny"`, and `"ask"`. It doesn't accept `"defer"`, `updatedInput`, or `additionalContext`. The table below describes both fields:3226For finer control, return `permissionDecision` and `permissionDecisionReason` in a `hookSpecificOutput` object, as on [PreToolUse](#pretooluse-decision-control). `PreModelSwitch` accepts `"allow"`, `"deny"`, and `"ask"`. It doesn't accept `"defer"`, `updatedInput`, or `additionalContext`. The table below describes both fields:
3227 3227
3228| Field | Description |3228| Field | Description |
3229| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |3229| :- | :- |
3230| `permissionDecision` | `"allow"` proceeds and skips the [confirmation Claude Code shows while the prompt cache is warm](/docs/en/prompt-caching#switching-models). `"deny"` cancels the switch. `"ask"` prompts the user to confirm it |3230| `permissionDecision` | `"allow"` proceeds and skips the [confirmation Claude Code shows while the prompt cache is warm](/docs/en/prompt-caching#switching-models). `"deny"` cancels the switch. `"ask"` prompts the user to confirm it |
3231| `permissionDecisionReason` | For `"deny"`, shown to the user as the reason the switch was blocked, or returned as the error for a `set_model` request. For `"ask"`, shown in the confirmation prompt. Ignored for `"allow"` |3231| `permissionDecisionReason` | For `"deny"`, shown to the user as the reason the switch was blocked, or returned as the error for a `set_model` request. For `"ask"`, shown in the confirmation prompt. Ignored for `"allow"` |
3232 3232
3300Claude Code takes your hook's [plain-text stdout](#exit-code-0) on exit 0, or `additionalContext` from JSON output, and delivers it to Claude with the next request after the switch. In addition to the [JSON output fields](#json-output) available to all hooks, you can return:3300Claude Code takes your hook's [plain-text stdout](#exit-code-0) on exit 0, or `additionalContext` from JSON output, and delivers it to Claude with the next request after the switch. In addition to the [JSON output fields](#json-output) available to all hooks, you can return:
3301 3301
3302| Field | Description |3302| Field | Description |
3303| :------------------ | :------------------------------------------------------------------------------------------------------------ |3303| :- | :- |
3304| `additionalContext` | String added to Claude's context with the next request. See [Add context for Claude](#add-context-for-claude) |3304| `additionalContext` | String added to Claude's context with the next request. See [Add context for Claude](#add-context-for-claude) |
3305 3305
3306If the hook hasn't finished within five seconds after you send the next prompt, Claude Code sends that request without the output and attaches it to the following request instead. If the model changes several times before the next request, Claude Code delivers only the output for the last switch's target model.3306If the hook hasn't finished within five seconds after you send the next prompt, Claude Code sends that request without the output and attaches it to the following request instead. If the model changes several times before the next request, Claude Code delivers only the output for the last switch's target model.
3313The `reason` field in the hook input indicates why the session ended:3313The `reason` field in the hook input indicates why the session ended:
3314 3314
3315| Reason | Description |3315| Reason | Description |
3316| :---------------------------- | :---------------------------------------------------------------------------------------- |3316| :- | :- |
3317| `clear` | Session cleared with `/clear` command |3317| `clear` | Session cleared with `/clear` command |
3318| `resume` | Session switched via interactive `/resume` |3318| `resume` | Session switched via interactive `/resume` |
3319| `logout` | User logged out |3319| `logout` | User logged out |
3412```3412```
3413 3413
3414| Field | Values | Description |3414| Field | Values | Description |
3415| :-------- | :---------------------------- | :--------------------------------------------------------------- |3415| :- | :- | :- |
3416| `action` | `accept`, `decline`, `cancel` | Whether to accept, decline, or cancel the request |3416| `action` | `accept`, `decline`, `cancel` | Whether to accept, decline, or cancel the request |
3417| `content` | object | Form field values to submit. Only used when `action` is `accept` |3417| `content` | object | Form field values to submit. Only used when `action` is `accept` |
3418 3418
3459```3459```
3460 3460
3461| Field | Values | Description |3461| Field | Values | Description |
3462| :-------- | :---------------------------- | :--------------------------------------------------------------------- |3462| :- | :- | :- |
3463| `action` | `accept`, `decline`, `cancel` | Overrides the user's action |3463| `action` | `accept`, `decline`, `cancel` | Overrides the user's action |
3464| `content` | object | Overrides form field values. Only meaningful when `action` is `accept` |3464| `content` | object | Overrides form field values. Only meaningful when `action` is `accept` |
3465 3465
3543```3543```
3544 3544
3545| Field | Required | Description |3545| Field | Required | Description |
3546| :---------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |3546| :- | :- | :- |
3547| `type` | yes | Must be `"prompt"` |3547| `type` | yes | Must be `"prompt"` |
3548| `prompt` | yes | The prompt text to send to the LLM. Use `$ARGUMENTS` as a placeholder for the hook input JSON. If `$ARGUMENTS` is not present, input JSON is appended to the prompt |3548| `prompt` | yes | The prompt text to send to the LLM. Use `$ARGUMENTS` as a placeholder for the hook input JSON. If `$ARGUMENTS` is not present, input JSON is appended to the prompt |
3549| `model` | no | Model to use for evaluation. Defaults to a fast model |3549| `model` | no | Model to use for evaluation. Defaults to a fast model |
3563```3563```
3564 3564
3565| Field | Description |3565| Field | Description |
3566| :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |3566| :- | :- |
3567| `ok` | `true` to allow. For `false`, see the per-event behavior below |3567| `ok` | `true` to allow. For `false`, see the per-event behavior below |
3568| `reason` | Required when `ok` is `false` |3568| `reason` | Required when `ok` is `false` |
3569| `impossible` | Optional. The model returns it with `ok: false` when it judges the condition can never be satisfied. On `Stop` and `SubagentStop`, Claude Code then lets the turn end instead of feeding the reason back. Agent hooks and other events ignore it |3569| `impossible` | Optional. The model returns it with `ok: false` when it judges the condition can never be satisfied. On `Stop` and `SubagentStop`, Claude Code then lets the turn end instead of feeding the reason back. Agent hooks and other events ignore it |