4 4
5# Hooks reference5# Hooks reference
6 6
7> Reference for Claude Code hook events, configuration schema, JSON input/output formats, exit codes, async hooks, prompt hooks, and MCP tool hooks.7> Reference for Claude Code hook events, configuration schema, JSON input/output formats, exit codes, async hooks, HTTP hooks, prompt hooks, and MCP tool hooks.
8 8
9<Tip>9<Tip>
10 For a quickstart guide with examples, see [Automate workflows with hooks](/en/hooks-guide).10 For a quickstart guide with examples, see [Automate workflows with hooks](/en/hooks-guide).
11</Tip>11</Tip>
12 12
13Hooks are user-defined shell commands or LLM prompts that execute automatically at specific points in Claude Code's lifecycle. Use this reference to look up event schemas, configuration options, JSON input/output formats, and advanced features like async hooks and MCP tool hooks. If you're setting up hooks for the first time, start with the [guide](/en/hooks-guide) instead.13Hooks are user-defined shell commands, HTTP endpoints, or LLM prompts that execute automatically at specific points in Claude Code's lifecycle. Use this reference to look up event schemas, configuration options, JSON input/output formats, and advanced features like async hooks, HTTP hooks, and MCP tool hooks. If you're setting up hooks for the first time, start with the [guide](/en/hooks-guide) instead.
14 14
15## Hook lifecycle15## Hook lifecycle
16 16
17Hooks fire at specific points during a Claude Code session. When an event fires and a matcher matches, Claude Code passes JSON context about the event to your hook handler. For command hooks, this arrives on stdin. Your handler can then inspect the input, take action, and optionally return a decision. Some events fire once per session, while others fire repeatedly inside the agentic loop:17Hooks fire at specific points during a Claude Code session. When an event fires and a matcher matches, Claude Code passes JSON context about the event to your hook handler. For command hooks, input arrives on stdin. For HTTP hooks, it arrives as the POST request body. Your handler can then inspect the input, take action, and optionally return a decision. Some events fire once per session, while others fire repeatedly inside the agentic loop:
18 18
19<div style={{maxWidth: "500px", margin: "0 auto"}}>19<div style={{maxWidth: "500px", margin: "0 auto"}}>
20 <Frame>20 <Frame>
139See [How a hook resolves](#how-a-hook-resolves) above for a complete walkthrough with an annotated example.139See [How a hook resolves](#how-a-hook-resolves) above for a complete walkthrough with an annotated example.
140 140
141<Note>141<Note>
142 This page uses specific terms for each level: **hook event** for the lifecycle point, **matcher group** for the filter, and **hook handler** for the shell command, prompt, or agent that runs. "Hook" on its own refers to the general feature.142 This page uses specific terms for each level: **hook event** for the lifecycle point, **matcher group** for the filter, and **hook handler** for the shell command, HTTP endpoint, prompt, or agent that runs. "Hook" on its own refers to the general feature.
143</Note>143</Note>
144 144
145### Hook locations145### Hook locations
243 243
244### Hook handler fields244### Hook handler fields
245 245
246Each object in the inner `hooks` array is a hook handler: the shell command, LLM prompt, or agent that runs when the matcher matches. There are three types:246Each object in the inner `hooks` array is a hook handler: the shell command, HTTP endpoint, LLM prompt, or agent that runs when the matcher matches. There are four types:
247 247
248* **[Command hooks](#command-hook-fields)** (`type: "command"`): run a shell command. Your script receives the event's [JSON input](#hook-input-and-output) on stdin and communicates results back through exit codes and stdout.248* **[Command hooks](#command-hook-fields)** (`type: "command"`): run a shell command. Your script receives the event's [JSON input](#hook-input-and-output) on stdin and communicates results back through exit codes and stdout.
249* **[HTTP hooks](#http-hook-fields)** (`type: "http"`): send the event's JSON input as an HTTP POST request to a URL. The endpoint communicates results back through the response body using the same [JSON output format](#json-output) as command hooks.
249* **[Prompt hooks](#prompt-and-agent-hook-fields)** (`type: "prompt"`): send a prompt to a Claude model for single-turn evaluation. The model returns a yes/no decision as JSON. See [Prompt-based hooks](#prompt-based-hooks).250* **[Prompt hooks](#prompt-and-agent-hook-fields)** (`type: "prompt"`): send a prompt to a Claude model for single-turn evaluation. The model returns a yes/no decision as JSON. See [Prompt-based hooks](#prompt-based-hooks).
250* **[Agent hooks](#prompt-and-agent-hook-fields)** (`type: "agent"`): spawn a subagent that can use tools like Read, Grep, and Glob to verify conditions before returning a decision. See [Agent-based hooks](#agent-based-hooks).251* **[Agent hooks](#prompt-and-agent-hook-fields)** (`type: "agent"`): spawn a subagent that can use tools like Read, Grep, and Glob to verify conditions before returning a decision. See [Agent-based hooks](#agent-based-hooks).
251 252
255 256
256| Field | Required | Description |257| Field | Required | Description |
257| :-------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |258| :-------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
258| `type` | yes | `"command"`, `"prompt"`, or `"agent"` |259| `type` | yes | `"command"`, `"http"`, `"prompt"`, or `"agent"` |
259| `timeout` | no | Seconds before canceling. Defaults: 600 for command, 30 for prompt, 60 for agent |260| `timeout` | no | Seconds before canceling. Defaults: 600 for command, 30 for prompt, 60 for agent |
260| `statusMessage` | no | Custom spinner message displayed while the hook runs |261| `statusMessage` | no | Custom spinner message displayed while the hook runs |
261| `once` | no | If `true`, runs only once per session then is removed. Skills only, not agents. See [Hooks in skills and agents](#hooks-in-skills-and-agents) |262| `once` | no | If `true`, runs only once per session then is removed. Skills only, not agents. See [Hooks in skills and agents](#hooks-in-skills-and-agents) |
269| `command` | yes | Shell command to execute |270| `command` | yes | Shell command to execute |
270| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |271| `async` | no | If `true`, runs in the background without blocking. See [Run hooks in the background](#run-hooks-in-the-background) |
271 272
273#### HTTP hook fields
274
275In addition to the [common fields](#common-fields), HTTP hooks accept these fields:
276
277| Field | Required | Description |
278| :--------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
279| `url` | yes | URL to send the POST request to |
280| `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 |
281| `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 |
282
283Claude Code sends the hook's [JSON input](#hook-input-and-output) as the POST request body with `Content-Type: application/json`. The response body uses the same [JSON output format](#json-output) as command hooks.
284
285Error handling differs from command hooks: non-2xx responses, connection failures, and timeouts all produce non-blocking errors that allow execution to continue. To block a tool call or deny a permission, return a 2xx response with a JSON body containing `decision: "block"` or a `hookSpecificOutput` with `permissionDecision: "deny"`.
286
287This example sends `PreToolUse` events to a local validation service, authenticating with a token from the `MY_TOKEN` environment variable:
288
289```json theme={null}
290{
291 "hooks": {
292 "PreToolUse": [
293 {
294 "matcher": "Bash",
295 "hooks": [
296 {
297 "type": "http",
298 "url": "http://localhost:8080/hooks/pre-tool-use",
299 "timeout": 30,
300 "headers": {
301 "Authorization": "Bearer $MY_TOKEN"
302 },
303 "allowedEnvVars": ["MY_TOKEN"]
304 }
305 ]
306 }
307 ]
308 }
309}
310```
311
312<Note>
313 HTTP hooks must be configured by editing settings JSON directly. The `/hooks` interactive menu only supports adding command hooks.
314</Note>
315
272#### Prompt and agent hook fields316#### Prompt and agent hook fields
273 317
274In addition to the [common fields](#common-fields), prompt and agent hooks accept these fields:318In addition to the [common fields](#common-fields), prompt and agent hooks accept these fields:
278| `prompt` | yes | Prompt text to send to the model. Use `$ARGUMENTS` as a placeholder for the hook input JSON |322| `prompt` | yes | Prompt text to send to the model. Use `$ARGUMENTS` as a placeholder for the hook input JSON |
279| `model` | no | Model to use for evaluation. Defaults to a fast model |323| `model` | no | Model to use for evaluation. Defaults to a fast model |
280 324
281All matching hooks run in parallel, and identical handlers are deduplicated automatically. Handlers run in the current directory with Claude Code's environment. The `$CLAUDE_CODE_REMOTE` environment variable is set to `"true"` in remote web environments and not set in the local CLI.325All matching hooks run in parallel, and identical handlers are deduplicated automatically. Command hooks are deduplicated by command string, and HTTP hooks are deduplicated by URL. Handlers run in the current directory with Claude Code's environment. The `$CLAUDE_CODE_REMOTE` environment variable is set to `"true"` in remote web environments and not set in the local CLI.
282 326
283### Reference scripts by path327### Reference scripts by path
284 328
387 431
388## Hook input and output432## Hook input and output
389 433
390Hooks receive JSON data via stdin and communicate results through exit codes, stdout, and stderr. This section covers fields and behavior common to all events. Each event's section under [Hook events](#hook-events) includes its specific input schema and decision control options.434Command hooks receive JSON data via stdin and communicate results through exit codes, stdout, and stderr. HTTP hooks receive the same JSON as the POST request body and communicate results through the HTTP response body. This section covers fields and behavior common to all events. Each event's section under [Hook events](#hook-events) includes its specific input schema and decision control options.
391 435
392### Common input fields436### Common input fields
393 437
394All hook events receive these fields via stdin as JSON, in addition to event-specific fields documented in each [hook event](#hook-events) section:438All hook 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.
395 439
396| Field | Description |440| Field | Description |
397| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |441| :---------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
468| `WorktreeCreate` | Yes | Any non-zero exit code causes worktree creation to fail |512| `WorktreeCreate` | Yes | Any non-zero exit code causes worktree creation to fail |
469| `WorktreeRemove` | No | Failures are logged in debug mode only |513| `WorktreeRemove` | No | Failures are logged in debug mode only |
470 514
515### HTTP response handling
516
517HTTP hooks use HTTP status codes and response bodies instead of exit codes and stdout:
518
519* **2xx with an empty body**: success, equivalent to exit code 0 with no output
520* **2xx with a plain text body**: success, the text is added as context
521* **2xx with a JSON body**: success, parsed using the same [JSON output](#json-output) schema as command hooks
522* **Non-2xx status**: non-blocking error, execution continues
523* **Connection failure or timeout**: non-blocking error, execution continues
524
525Unlike command hooks, HTTP hooks cannot signal a blocking error through status codes alone. To block a tool call or deny a permission, return a 2xx response with a JSON body containing the appropriate decision fields.
526
471### JSON output527### JSON output
472 528
473Exit codes let you allow or block, but JSON output gives you finer-grained control. Instead of exiting with code 2 to block, exit 0 and print a JSON object to stdout. Claude Code reads specific fields from that JSON to control behavior, including [decision control](#decision-control) for blocking, allowing, or escalating to the user.529Exit codes let you allow or block, but JSON output gives you finer-grained control. Instead of exiting with code 2 to block, exit 0 and print a JSON object to stdout. Claude Code reads specific fields from that JSON to control behavior, including [decision control](#decision-control) for blocking, allowing, or escalating to the user.
1711 1767
1712### Disclaimer1768### Disclaimer
1713 1769
1714Hooks run with your system user's full permissions.1770Command hooks run with your system user's full permissions.
1715 1771
1716<Warning>1772<Warning>
1717 Hooks execute shell commands with your full user permissions. They can modify, delete, or access any files your user account can access. Review and test all hook commands before adding them to your configuration.1773 Command hooks execute shell commands with your full user permissions. They can modify, delete, or access any files your user account can access. Review and test all hook commands before adding them to your configuration.
1718</Warning>1774</Warning>
1719 1775
1720### Security best practices1776### Security best practices