Hook Configuration
Hook configuration decides which hooks run, when they run, and what happens when one fails.
A matcher picks the events. An if filter narrows them to some tool calls.
The timeout and onFailure fields set limits.
For example, "matcher": "Bash" with "if": "Bash(git push *)" runs a hook only for git push commands.
Turn hooks off with disableAllHooks or allowManagedHooksOnly, or remove the entry.
Example
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"if": "Edit(*.ts)",
"command": "bunx prettier --write \"$CLAUDE_PROJECT_DIR\"",
"timeout": 60,
"statusMessage": "Formatting"
}
]
}
]
}
}
The hook runs after an edit or write, but only for .ts files.
It can run for up to 60 seconds.
Matcher Rules
The matcher key is a string on a matcher group. It picks which occurrences of the event run the group.
| Matcher form | Status | What it does | Notes |
|---|---|---|---|
"*", "", or no matcher | Documented | Matches everything. | The group runs on every occurrence. |
Letters, digits, _, -, space, ,, | only | Documented | An exact string or a list. | Edit|Write and Edit, Write both match either name. mcp__ alone matches no tool. |
| Any other character | Documented | A JavaScript regular expression, not anchored. | Tested with Reg. Use ^ and $ to match a whole name. |
File and Stop | Documented | A narrower exact set. | Only letters, digits, _, and | count as exact. A hyphen, space, or comma makes it a regex. |
| A matcher on an event with no matcher | Documented | Silently ignored. | No error. |
Matcher Targets
What the matcher is tested against depends on the event.
| Target | Status | Values | Events |
|---|---|---|---|
| Tool name | Documented | Bash, Edit|Write, mcp__.. Plugin MCP tools are mcp__. | Pre, Post, Post, Permission, Permission |
| Start source | Documented | startup, resume, clear, compact, fork. fork needs 2.1.214. | Session |
| CLI flag | Documented | init, maintenance | Setup |
| End reason | Documented | clear, resume, logout, prompt_, other | Session |
| Notification type | Documented | See Events. | Notification |
| Agent type | Documented | general-, Explore, Plan, or a custom name. A plugin name such as my- contains a colon, so it is a regex. Write ^my-. | Subagent, Subagent |
| Trigger | Documented | manual, auto | Pre, Post |
| Target model | Documented | The canonical name of to_, without [1m]. If no canonical name is known, every hook runs. | Pre, Post |
| Config source | Documented | user_, project_, local_, policy_, skills | Config |
| Add source | Documented | slash_, register_ | Directory |
| File names | Documented | Literal names split on |. Claude Code filters by base name. The matcher also builds the watch list. | File |
| Error type | Differs | rate_, overloaded, authentication_, oauth_, account_, billing_, invalid_, model_, server_, max_, cloud_, unknown. | Stop |
| Load reason | Documented | session_, nested_, path_, include, compact | Instructions |
| Command name | Documented | Skill or command names. | User |
| MCP server name | Documented | Names of configured servers. | Elicitation, Elicitation |
| No matcher | Documented | Always fires. | User, Post, Stop, Teammate, Task, Task, Worktree, Worktree, Message, Cwd |
The if Filter
if is a handler field. It holds one permission rule, such as Bash(git *) or Edit(*.ts).
| Item | Status | What it does | Notes |
|---|---|---|---|
if | Documented | Runs the handler only when the rule matches the tool call. | Only the five tool events read it. On any other event the hook never runs. You cannot use && or a list. |
| Bash patterns | Documented | Checked on each subcommand. | A leading VAR=value is removed. Claude Code also checks $() and backticks. If it cannot parse the command, the hook runs. |
| File patterns | Documented | For example Edit(src/. | Matches only src in the working directory. Use **/ for any depth. This changed in 2.1.214. |
Timeouts
timeout is a number of seconds.
A hook that times out is canceled and its output is dropped.
| Item | Status | What it does | Notes |
|---|---|---|---|
Default timeout | Documented | 600 seconds for command, http, mcp_. 30 for prompt. 60 for agent. | The program was not searched for each default. They come from the docs. |
| Lower defaults | Documented | 30 seconds on User, Pre, Post. 10 seconds on Message. | For command, http, mcp_. |
Session budget | Documented | 1.5 seconds shared by all hooks. | Raised to the largest per-hook timeout in settings, up to 60 seconds. Plugin timeouts do not raise it. |
Pre timeout | Documented | A hook that times out blocks the switch. | |
Pre timeout | Documented | A command, http, or mcp_ hook that times out does not block. | Use on to block. An SDK callback that times out does block. |
async | Undocumented | A first reply of {"async": moves a command hook to the background and sets its time limit. | Default 15000 ms. Only the Agent SDK pages name it. See Agent SDK Hooks. |
Failure Handling
A failure means the hook could not start, timed out, exited with a code other than 0 or 2, printed invalid JSON, or got a non-2xx HTTP status.
| Item | Status | What it does | Notes |
|---|---|---|---|
on | Documented | The default. The action goes on after a failure. | command and http handlers. |
on | Documented | A failure counts as exit 2. | The error text says blocking because on. |
on has no effect | Undocumented | On async hooks and on Stop, Subagent, Task, Teammate. | The field text in the program says so. The Hooks Reference does not. |
| Windows without Git Bash | Documented | A shell-form Pre or Permission hook that fails can block. | Set shell:, or use exec form with on. |
Background process keeps stdout open | Documented | After an allow, this blocks the call with refusing to honor the suspect capture. | Redirect the output of background child processes. |
CLAUDE_ | Undocumented | Your own hooks in user files must succeed. Their grant and rewrite fields are dropped. | Program messages: blocking because it is one of the user's own hooks. Affects Pre, Permission, Pre, User, User. |
Environment Variables for Hooks
| Variable | Status | What it does | Notes |
|---|---|---|---|
CLAUDE_ | Documented | The project root where the session started. | Stays fixed in a worktree. cwd in the input follows Claude. Also set for stdio MCP servers and plugin LSP. |
CLAUDE_, CLAUDE_ | Documented | The plugin install folder and data folder. | Replaced in command and args. Also exported. |
CLAUDE_ | Documented | A plugin user option. | Use it in shell form. ${user_ works only in exec form. |
CLAUDE_ | Documented | A file of export lines that later Bash commands load. | Append with >>. Set for Session, Setup, Cwd, File. Not set for PowerShell hooks. |
CLAUDE_ | Documented | The effort level of the turn. | Also visible in Bash. |
CLAUDE_ | Documented | "true" in remote web environments. | Unset in the local CLI. |
CLAUDE_ | Documented | The Remote Control session ID. | Set from 2.1.199 while connected. |
| Inherited environment | Documented | The parent environment minus OTEL_. | CLAUDE_ strips more. HIPAA sessions drop Anthropic credentials. |
CLAUDE_ | Documented | Does not exist. | Use Post and to_. |
CLAUDE_ | Documented | The Session budget. | See Environment Variables. |
CLAUDE_ | Documented | The most Stop continuations in a row. | Default 8. |
CLAUDE_ | Documented | Turns off the permission_ notification in SDK hosts. | |
CLAUDE_ | Documented | Stops @ insertion. | |
CLAUDE_ | Documented | The Git Bash path on Windows. | |
MCP_ | Documented | How long an MCP hook waits for a server that is still connecting. | |
CLAUDE_ | Undocumented | Runs function hooks on the main thread, not in a worker. | The program picks same- or worker. For mods. |
CLAUDE_ | Undocumented | Turns off hook forwarding in SDK and remote sessions. See Plugins and MCP. | |
DISABLE_ | Undocumented | Skips the brief-mode check at the end of a turn. See Features and Toggles. | |
CLAUDE_ | Undocumented | Sets how long a resume waits for Session hooks. See Sessions and Storage. |
Settings Keys and Trust
| Item | Status | What it does | Notes |
|---|---|---|---|
hooks | Documented | The event map. | Merges across levels. |
disable | Differs | Turns hooks off. | Managed hooks stay unless you set it in managed settings. Also works with --. |
allow | Documented | Only managed hooks and hooks of managed-enabled plugins run. | Also narrows status, file, and subagent. Managed settings only. |
allowed | Documented | A URL allowlist for http hooks. | * is a wildcard. An empty array blocks all. Arrays merge across levels. |
http | Documented | A name allowlist for header values. | Intersected with each hook's allowed. Arrays merge. |
| Workspace trust | Documented | Settings hooks wait for the trust dialog. | - and SDK sessions treat the folder as trusted. Hooks of project subagents need the dialog. |
/ menu | Documented | A read-only browser of your hooks. | Shows where each one comes from. |
| Debug output | Documented | claude -- writes hook activity. | CLAUDE_ adds matcher lines. |
Related Pages
- Hooks: the overview.
- Handlers: the fields of each handler type.
- Input and Output: exit codes and JSON fields.
- Environment Variables: the full variable list.
- Settings Files and Scopes: the settings keys.
Source: Hooks Reference and the settings schema (claude-code-settings.json).