Skip to main content

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​

.claude/settings.json
{
"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 formStatusWhat it doesNotes
"*", "", or no matcherDocumentedMatches everything.The group runs on every occurrence.
Letters, digits, _, -, space, ,, | onlyDocumentedAn exact string or a list.Edit|Write and Edit, Write both match either name. mcp__memory alone matches no tool.
Any other characterDocumentedA JavaScript regular expression, not anchored.Tested with RegExp.prototype.test. Use ^ and $ to match a whole name.
FileChanged and StopFailureDocumentedA 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 matcherDocumentedSilently ignored.No error.

Matcher Targets​

What the matcher is tested against depends on the event.

TargetStatusValuesEvents
Tool nameDocumentedBash, Edit|Write, mcp__.*. Plugin MCP tools are mcp__plugin_<plugin>_<server>__<tool>.PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied
Start sourceDocumentedstartup, resume, clear, compact, fork. fork needs 2.1.214.SessionStart
CLI flagDocumentedinit, maintenanceSetup
End reasonDocumentedclear, resume, logout, prompt_input_exit, otherSessionEnd
Notification typeDocumentedSee Events.Notification
Agent typeDocumentedgeneral-purpose, Explore, Plan, or a custom name. A plugin name such as my-plugin:reviewer contains a colon, so it is a regex. Write ^my-plugin:reviewer$.SubagentStart, SubagentStop
TriggerDocumentedmanual, autoPreCompact, PostCompact
Target modelDocumentedThe canonical name of to_model, without [1m]. If no canonical name is known, every hook runs.PreModelSwitch, PostModelSwitch
Config sourceDocumenteduser_settings, project_settings, local_settings, policy_settings, skillsConfigChange
Add sourceDocumentedslash_command, register_repo_rootDirectoryAdded
File namesDocumentedLiteral names split on |. Claude Code filters by base name. The matcher also builds the watch list.FileChanged
Error typeDiffersrate_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, unknown.StopFailure
Load reasonDocumentedsession_start, nested_traversal, path_glob_match, include, compactInstructionsLoaded
Command nameDocumentedSkill or command names.UserPromptExpansion
MCP server nameDocumentedNames of configured servers.Elicitation, ElicitationResult
No matcherDocumentedAlways fires.UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplay, CwdChanged

The if Filter​

if is a handler field. It holds one permission rule, such as Bash(git *) or Edit(*.ts).

ItemStatusWhat it doesNotes
ifDocumentedRuns 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 patternsDocumentedChecked 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 patternsDocumentedFor example Edit(src/**).Matches only src in the working directory. Use **/src/** 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.

ItemStatusWhat it doesNotes
Default timeoutDocumented600 seconds for command, http, mcp_tool. 30 for prompt. 60 for agent.The program was not searched for each default. They come from the docs.
Lower defaultsDocumented30 seconds on UserPromptSubmit, PreModelSwitch, PostModelSwitch. 10 seconds on MessageDisplay.For command, http, mcp_tool.
SessionEnd budgetDocumented1.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.
PreModelSwitch timeoutDocumentedA hook that times out blocks the switch.
PreToolUse timeoutDocumentedA command, http, or mcp_tool hook that times out does not block.Use onFailure: "block" to block. An SDK callback that times out does block.
asyncTimeoutUndocumentedA first reply of {"async":true,"asyncTimeout":ms} 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.

ItemStatusWhat it doesNotes
onFailure: "continue"DocumentedThe default. The action goes on after a failure.command and http handlers.
onFailure: "block"DocumentedA failure counts as exit 2.The error text says blocking because onFailure is "block".
onFailure has no effectUndocumentedOn async hooks and on Stop, SubagentStop, TaskCompleted, TeammateIdle.The field text in the program says so. The Hooks Reference does not.
Windows without Git BashDocumentedA shell-form PreToolUse or PermissionRequest hook that fails can block.Set shell: "powershell", or use exec form with onFailure.
Background process keeps stdout openDocumentedAfter an allow, this blocks the call with refusing to honor the suspect capture.Redirect the output of background child processes.
CLAUDE_CODE_RESTRICT_PERSONAL_CONFIGUndocumentedYour 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 PreToolUse, PermissionRequest, PreModelSwitch, UserPromptSubmit, UserPromptExpansion.

Environment Variables for Hooks​

VariableStatusWhat it doesNotes
CLAUDE_PROJECT_DIRDocumentedThe 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_PLUGIN_ROOT, CLAUDE_PLUGIN_DATADocumentedThe plugin install folder and data folder.Replaced in command and args. Also exported.
CLAUDE_PLUGIN_OPTION_<KEY>DocumentedA plugin userConfig option.Use it in shell form. ${user_config.*} works only in exec form.
CLAUDE_ENV_FILEDocumentedA file of export lines that later Bash commands load.Append with >>. Set for SessionStart, Setup, CwdChanged, FileChanged. Not set for PowerShell hooks.
CLAUDE_EFFORTDocumentedThe effort level of the turn.Also visible in Bash.
CLAUDE_CODE_REMOTEDocumented"true" in remote web environments.Unset in the local CLI.
CLAUDE_CODE_BRIDGE_SESSION_IDDocumentedThe Remote Control session ID.Set from 2.1.199 while connected.
Inherited environmentDocumentedThe parent environment minus OTEL_*.CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 strips more. HIPAA sessions drop Anthropic credentials.
CLAUDE_MODELDocumentedDoes not exist.Use PostModelSwitch and to_model.
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MSDocumentedThe SessionEnd budget.See Environment Variables.
CLAUDE_CODE_STOP_HOOK_BLOCK_CAPDocumentedThe most Stop continuations in a row.Default 8.
CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKSDocumentedTurns off the permission_prompt notification in SDK hosts.
CLAUDE_CODE_DISABLE_FILE_MENTIONSDocumentedStops @ insertion.
CLAUDE_CODE_GIT_BASH_PATHDocumentedThe Git Bash path on Windows.
MCP_TIMEOUTDocumentedHow long an MCP hook waits for a server that is still connecting.
CLAUDE_CODE_HOOKS_SAME_THREADUndocumentedRuns function hooks on the main thread, not in a worker.The program picks same-thread or worker. For mods.
CLAUDE_CODE_DISABLE_HOOK_FORWARDINGUndocumentedTurns off hook forwarding in SDK and remote sessions. See Plugins and MCP.
DISABLE_BRIEF_MODE_STOP_HOOKUndocumentedSkips the brief-mode check at the end of a turn. See Features and Toggles.
CLAUDE_CODE_RESUME_SESSIONSTART_HOOKS_WAIT_MSUndocumentedSets how long a resume waits for SessionStart hooks. See Sessions and Storage.

Settings Keys and Trust​

ItemStatusWhat it doesNotes
hooksDocumentedThe event map.Merges across levels.
disableAllHooksDiffersTurns hooks off.Managed hooks stay unless you set it in managed settings. Also works with --settings.
allowManagedHooksOnlyDocumentedOnly managed hooks and hooks of managed-enabled plugins run.Also narrows statusLine, fileSuggestion, and subagentStatusLine. Managed settings only.
allowedHttpHookUrlsDocumentedA URL allowlist for http hooks.* is a wildcard. An empty array blocks all. Arrays merge across levels.
httpHookAllowedEnvVarsDocumentedA name allowlist for header values.Intersected with each hook's allowedEnvVars. Arrays merge.
Workspace trustDocumentedSettings hooks wait for the trust dialog.-p and SDK sessions treat the folder as trusted. Hooks of project subagents need the dialog.
/hooks menuDocumentedA read-only browser of your hooks.Shows where each one comes from.
Debug outputDocumentedclaude --debug-file <path> writes hook activity.CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose adds matcher lines.

Source: Hooks Reference and the settings schema (claude-code-settings.json).