Hook Handlers
A handler is the part of a hook that does the work.
It can run a command, call a URL, call an MCP tool, ask a model, or start a subagent.
The type key picks which one.
For example, {"type": "command", "command": "./check.sh"} runs a script.
To disable a handler, remove the entry or use disableAllHooks.
Example
An HTTP hook that posts every Stop event to a local service.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "http",
"url": "http://localhost:8080/claude-stop",
"headers": { "Authorization": "Bearer $HOOK_TOKEN" },
"allowedEnvVars": ["HOOK_TOKEN"],
"timeout": 5
}
]
}
]
}
}
Claude Code fills only names in allowedEnvVars into headers. Other references become empty strings.
Handler Types
| Type | Status | What it does | Events it works on |
|---|---|---|---|
command | Documented: An official docs page names this item. | Runs a shell command or an executable. Input on stdin. Result by exit code, stdout, and stderr. | All 33 events. |
http | Documented: An official docs page names this item. | Sends the input as JSON in a POST to a URL. The result is the response body, and needs a 2xx status. | 31 events. Not Session and not Setup. |
mcp_ | Documented: An official docs page names this item. | Calls a tool on a configured MCP server. Claude Code reads the text result like stdout. A result with is is a non-blocking error. | 33 events. Claude Code skips it on Setup, and on Session when Claude Code starts. |
prompt | Documented: An official docs page names this item. | One model call that returns ok. | 12 events, plus Permission. |
agent | Documented: An official docs page names this item. Experimental: The program or the official docs call this experimental or beta. | A subagent that checks a condition. Up to 50 turns. Experimental, and the docs say it may change. | 12 events. Not Permission. |
callback | Undocumented: Only the program shows this item. It can change without notice. | A function that an SDK host or a mod registers. | Events that run device hooks. It is not a config key. |
script | Differs: The official docs and the program disagree. The row says how. Rejected in 2.1.305. Do not use. | Some text names this type. | 2. rejects it with Unknown hook type "script". A script entry under Pre also disables the whole settings file it sits in. |
The 12 events of prompt and agent are PermissionDenied, PostToolBatch, PostToolUse, PostToolUseFailure, PreToolUse, Stop, SubagentStop, TaskCompleted, TaskCreated, TeammateIdle, UserPromptExpansion, and UserPromptSubmit.
SessionStart and Setup accept command and mcp_tool only.
A script hook never runs in 2.1.305. Worse, one script entry under PreToolUse turns off every hook in that settings file.
Source: a probe of the program (see Probes).
Common Fields
| Field | Status | What it does | Notes |
|---|---|---|---|
type | Documented: An official docs page names this item. | Picks the handler kind. | One of command, http, mcp_, prompt, agent. |
if | Documented: An official docs page names this item. | One permission rule that filters the handler. | Only tool events read it. See Configuration. |
timeout | Documented: An official docs page names this item. | Seconds before Claude Code cancels the hook. | A positive number. Defaults are on Configuration. |
status | Documented: An official docs page names this item. | Spinner text while the hook runs. | A string. |
once | Documented: An official docs page names this item. | Removes the hook after its first successful run. | A failure, exit 2, or timeout keeps it. Claude Code honors it only in skill frontmatter. |
Command Fields
| Field | Status | What it does | Notes |
|---|---|---|---|
command | Documented: An official docs page names this item. | The command string, or the program to run when you set args. | Shell form uses sh -, Git Bash, or PowerShell. |
args | Documented: An official docs page names this item. | An argument list for exec form. | No shell runs. Claude Code replaces placeholders in command and in each element. |
shell | Documented: An official docs page names this item. | bash or powershell. | Claude Code ignores it when you set args. |
async | Documented: An official docs page names this item. | Runs in the background. | Claude Code does not enforce timeout. The hook cannot block. Output arrives on the next turn. |
async | Documented: An official docs page names this item. | A background run that wakes the model on exit 2. | stderr (or stdout if stderr is empty) becomes a system reminder. timeout still applies. Implies async. |
on | Documented: An official docs page names this item. | continue or block. | Needs 2.1.295. See Configuration. Also works on http. |
rewake | Undocumented: Only the program shows this item. It can change without notice. | A custom prefix for the system reminder of async. | An internal field. |
rewake | Undocumented: Only the program shows this item. It can change without notice. | A one-line summary that Claude Code shows to you for async. | An internal field. Default text is Stop hook feedback. |
cloud | Undocumented: Only the program shows this item. It can change without notice. | device or skip for cloud sessions that this machine drives. | An internal field. An unknown value reads as skip. Also works on http. |
HTTP Fields
| Field | Status | What it does | Notes |
|---|---|---|---|
url | Documented: An official docs page names this item. | The POST target. | Must pass allowed when that setting exists. |
headers | Documented: An official docs page names this item. | Extra request headers. | Claude Code replaces $VAR and ${VAR} only for names in allowed. |
allowed | Documented: An official docs page names this item. | Names that Claude Code may replace in headers. | Other references become empty strings. http narrows the list. |
on | Documented: An official docs page names this item. | continue or block. | A non-2xx status or a connection error counts as a failure. |
MCP Tool Fields
| Field | Status | What it does | Notes |
|---|---|---|---|
server | Documented: An official docs page names this item. | The name of a configured MCP server. | Plugin servers use plugin:. |
tool | Documented: An official docs page names this item. | The tool to call. | A string. |
input | Documented: An official docs page names this item. | The tool arguments. | String values accept ${path} from the hook input, such as ${tool_. |
On events that can block, Claude Code waits for a server that is still connecting.
The wait lasts at most MCP_TIMEOUT and the hook timeout.
On observer events, it does not wait.
Prompt and Agent Fields
| Field | Status | What it does | Notes |
|---|---|---|---|
prompt | Documented: An official docs page names this item. | The text to evaluate. | Claude Code replaces $ARGUMENTS with the input JSON. Without it, Claude Code appends the JSON. |
model | Differs: The official docs and the program disagree. The row says how. Docs: the default is the background model for both types. Program: the agent default is Haiku. | The model for the check. | Applies to prompt and agent. |
continue | Documented: An official docs page names this item. | Feeds an ok: reason to Claude. Then it continues. | prompt only. Default false. Agent hooks always act as if true. |
ok (model reply) | Documented: An official docs page names this item. | true allows. false blocks. | The effect of false per event is in the Response schema section of the Hooks Reference. |
reason (model reply) | Documented: An official docs page names this item. | Why the model blocked. | Required when ok is false. |
impossible (model reply) | Documented: An official docs page names this item. | The condition can never be met. | On Stop and Subagent the turn ends. Agents ignore it. prompt only. |
Prompt and Agent Concurrency
Since 2.1.312, the program limits how many prompt and agent hooks run at the same time.
The limits do not cover command, http, or mcp_tool hooks.
| Limit | Status | What it does | Notes |
|---|---|---|---|
| 24 at a time | Documented: An official docs page names this item. | At most 24 prompt and agent hooks run at once. | The program counts them per session host, not per agent. A hook over the limit waits for a free place. |
| 12 overdue | Documented: An official docs page names this item. | At most 12 more run when they waited longer than the timeout of their event. | These hooks use a second count of 12. It is separate from the first. |
| 12 per event | Undocumented: Only the program shows this item. It can change without notice. | When one event starts several of these hooks, at most 12 start together. | The program also uses this number to size the time budget of the event. |
Source: the program (chunk-r5cyd28m.js, the model hooks and overdue model hooks counts).
We did not trace that a subagent shares the session host of its parent.
Related Pages
- Hooks: the overview.
- Configuration: matchers,
if, timeouts, and failure handling. - Input and Output: what each handler can answer.
Source: Hooks Reference and the program (handler schemas for command, prompt, mcp_tool, http, and agent).
Cloud sessions forward only your own hooks of kind command and http from user settings, settings.local.json, or --settings. They never forward prompt, agent, or mcp_tool hooks, or plugin or managed hooks. A device client registers up to 128 hooks with a lease of 60 to 3600 seconds (600 by default). The cloud worker calls back with hook_callback. We read these rules in the program. We did not run them, because a cloud session needs a login (needs a cloud session, not run).