Configuration
Hooks are configured in any Claude Code settings file. The top-levelhooks key maps event names to an array of matcher objects.
Settings file locations
Higher-priority settings files take precedence. All hooks across all files run; they are not overridden.
Matcher configuration
string
A string pattern that filters when these hooks run. The field matched depends on the event:
PreToolUse/PostToolUse/PostToolUseFailure/PermissionRequest/PermissionDenied— matched againsttool_nameNotification— matched againstnotification_typeSessionStart— matched againstsource(startup,resume,clear,compact)Setup— matched againsttrigger(init,maintenance)SubagentStart/SubagentStop— matched againstagent_typePreCompact/PostCompact— matched againsttrigger(manual,auto)StopFailure— matched againsterrorConfigChange— matched againstsourceInstructionsLoaded— matched againstload_reasonElicitation/ElicitationResult— matched againstmcp_server_nameFileChanged— matched against filenames (e.g.,".envrc|.env")
matcher to run the hook for all instances of the event.HookCommand[]
required
One or more hook definitions to execute when the matcher fires.
Hook types
command — shell command
CLAUDE_ENV_FILE environment variable is set for CwdChanged and FileChanged hooks — write export KEY=value lines there to inject environment variables into subsequent Bash tool calls.
string
required
Shell command to execute.
number
Timeout in seconds. Defaults to the global hook timeout (60 s).
'bash' | 'powershell'
Shell interpreter.
bash uses your $SHELL (bash/zsh/sh). Defaults to bash.boolean
When
true, the hook runs in the background without blocking Claude. Output is ignored.boolean
When
true, the hook runs in the background but wakes the model if it exits with code 2. Implies async: true.boolean
When
true, the hook runs once and is removed from the configuration after execution.string
Permission rule syntax (e.g.,
"Bash(git *)") evaluated against the hook input. The hook is skipped if the condition does not match. Avoids spawning processes for non-matching tool calls.string
Custom message shown in the spinner while the hook runs.
prompt — LLM evaluation
$ARGUMENTS placeholder is replaced with the hook input JSON. The model’s response is treated as the hook output.
string
required
Prompt sent to the model. Use
$ARGUMENTS to embed the hook input.string
Model to use. Defaults to the small fast model.
agent — agentic verifier
PostToolUse hooks where you want the verifier to read files or run commands.
string
required
Verification prompt. Use
$ARGUMENTS to embed the hook input.http — HTTP endpoint
$VAR_NAME syntax, but only variables listed in allowedEnvVars are interpolated.
string
required
URL to POST the hook input JSON to.
Record<string, string>
Additional request headers.
string[]
Environment variable names that may be interpolated in header values.
Base hook input
Every hook receives a JSON object on stdin with these fields present for all event types.string
required
The event that fired (e.g.,
"PreToolUse").string
required
Current session identifier.
string
required
Absolute path to the JSONL transcript file for this session.
string
required
Current working directory at the time the hook fired.
string
Active permission mode (
"default", "acceptEdits", "bypassPermissions", "plan", "dontAsk").string
Subagent identifier. Present only when the hook fires from within a subagent. Use this field to distinguish subagent calls from main-thread calls.
string
Agent type name (e.g.,
"general-purpose", "code-reviewer"). Present when the hook fires from a subagent, or on the main thread of a session started with --agent.Sync hook output (JSON on stdout)
For blocking hooks, write a JSON object to stdout before exiting. The schema is the same for all events, with event-specific fields nested underhookSpecificOutput.
boolean
When
false, Claude stops the current turn immediately.boolean
When
true, the hook’s stdout is not shown in transcript mode.'approve' | 'block'
Explicit approve/block decision. Takes effect only when the CLI reads it.
string
Message injected into Claude’s context as a system turn.
string
Human-readable reason for the decision. Shown to the user when a hook blocks an action.
object
Event-specific output. See each event section below for the allowed fields.
Hook events
PreToolUse
Fires immediately before a tool executes. You can inspect the tool input, approve or block the call, or modify the input before it reaches the tool.
When it fires: Before every tool invocation.
Input fields:
string
Name of the tool about to run (e.g.,
"Bash", "Write", "mcp__myserver__my_tool").unknown
The raw tool input object as Claude submitted it.
string
Unique ID for this tool invocation.
hookSpecificOutput fields:
literal: 'PreToolUse'
required
Must be
"PreToolUse".'allow' | 'deny' | 'ask'
Override the permission decision for this tool call.
"allow" approves the call; "deny" blocks it; "ask" forces the permission dialog.string
Reason string shown to the user when the decision is
"deny" or "ask".Record<string, unknown>
Replacement tool input. When provided, the tool receives this object instead of Claude’s original input.
string
Text injected into Claude’s context for this turn.
PostToolUse
Fires after a tool completes successfully. You can observe the tool output or inject context for Claude to act on.
When it fires: After every successful tool execution.
Input fields:
string
Tool that ran.
unknown
Input that was passed to the tool.
unknown
The tool’s output.
string
Unique ID for this invocation.
hookSpecificOutput fields:
string
Context injected into Claude’s conversation after the tool result.
unknown
Replacement for the MCP tool’s output. Only effective for MCP tool calls.
PostToolUseFailure
Fires when a tool call ends in an error or is interrupted.
When it fires: When a tool throws or is aborted.
Input fields:
string
Tool that failed.
unknown
Input that was passed to the tool.
string
Unique ID for this invocation.
string
Error message from the tool.
boolean
Whether the failure was caused by an interrupt signal.
PostToolUse. Hook output and exit codes are logged but do not affect the failed tool result.
PermissionRequest
Fires when a permission dialog would be shown to the user. Hooks can programmatically approve or deny without showing any UI.
When it fires: When Claude requests permission for a tool call and the default behavior is to prompt.
Input fields:
string
Tool requesting permission.
unknown
Input the tool would receive if approved.
PermissionUpdate[]
Suggested permission rules (allow/deny) that the UI would offer.
hookSpecificOutput fields:
literal: 'PermissionRequest'
required
Must be
"PermissionRequest".object
The approval or denial decision.
PermissionDenied
Fires when a tool call is denied (by rules, mode, or classifier). You can instruct Claude to retry the action.
When it fires: After every permission denial.
Input fields:
string
Denied tool.
unknown
Input that was denied.
string
Unique ID for this invocation.
string
Human-readable denial reason.
hookSpecificOutput fields:
boolean
When
true, Claude is told it may retry the denied action.Stop
Fires just before Claude concludes its response for the current turn.
When it fires: When the model is about to stop and return control to the user.
Input fields:
boolean
Whether a Stop hook is currently running (prevents infinite loops if your Stop hook itself would trigger a Stop).
string
Text content of the last assistant message before stopping. Saves you from parsing the transcript file.
StopFailure
Fires instead of Stop when the turn ends due to an API error.
When it fires: When a rate limit, authentication failure, or other API error ends the turn.
Input fields:
'authentication_failed' | 'billing_error' | 'rate_limit' | 'invalid_request' | 'server_error' | 'unknown' | 'max_output_tokens'
The error category.
string
Detailed error message.
string
Last assistant message text, if any was produced before the error.
SubagentStart
Fires when Claude spawns a subagent via the Agent tool.
When it fires: When an Agent tool call begins.
Input fields:
string
Unique ID for this subagent instance.
string
Agent type name (e.g.,
"general-purpose").hookSpecificOutput fields:
string
Context injected into the subagent’s conversation at the start.
SubagentStop
Fires just before a subagent concludes its response. Mirrors Stop but for subagents.
When it fires: When a subagent is about to return its result to the parent.
Input fields:
string
Subagent instance ID.
string
Agent type name.
string
Path to the subagent’s JSONL transcript.
boolean
Whether a SubagentStop hook is already running.
string
Last message from the subagent.
SessionStart
Fires when a session begins. Use this to inject initial context or set up the environment.
When it fires: On session startup, resume, clear (/clear), or after compaction.
Input fields:
'startup' | 'resume' | 'clear' | 'compact'
What triggered the session start.
string
Active model for the session.
hookSpecificOutput fields:
string
Context injected into Claude’s system prompt for this session.
string
Auto-submitted as the first user message of the session.
string[]
Absolute file paths to register with the
FileChanged watcher.SessionEnd
Fires when a session is about to end.
When it fires: On clear, logout, prompt-input exit, or other termination reasons.
Input fields:
'clear' | 'resume' | 'logout' | 'prompt_input_exit' | 'other' | 'bypass_permissions_disabled'
The reason the session is ending.
Setup
Fires during repository initialization and maintenance checks.
When it fires: On init (first time Claude Code runs in a directory) or maintenance (periodic checks).
Input fields:
'init' | 'maintenance'
What triggered the setup hook.
hookSpecificOutput fields:
string
Context provided to Claude for the setup phase.
PreCompact
Fires before context compaction begins.
When it fires: Before the compaction summary is generated, whether triggered manually (/compact) or automatically.
Input fields:
'manual' | 'auto'
Whether compaction was requested by the user or triggered automatically.
string | null
Any custom compaction instructions already configured.
PostCompact
Fires after compaction completes.
When it fires: After the compaction summary has been generated and applied.
Input fields:
'manual' | 'auto'
How compaction was triggered.
string
The summary produced by compaction.
UserPromptSubmit
Fires when the user submits a prompt, before Claude processes it.
When it fires: Each time you press Enter with a message in the terminal.
Input fields:
string
The raw prompt text the user submitted.
hookSpecificOutput fields:
string
Context appended to Claude’s view of the user message.
Notification
Fires when Claude Code sends a notification (e.g., permission prompts, idle alerts).
When it fires: When a notification event is raised internally.
Input fields:
string
Notification message text.
string
Notification title.
'permission_prompt' | 'idle_prompt' | 'auth_success' | 'elicitation_dialog' | 'elicitation_complete' | 'elicitation_response'
The type of notification.
Elicitation
Fires when an MCP server requests user input. Hooks can auto-respond without showing the dialog.
When it fires: When an MCP server sends an elicitation request (a structured input form or URL).
Input fields:
string
Name of the MCP server requesting input.
string
The prompt message from the server.
'form' | 'url'
Input mode.
string
Request identifier.
Record<string, unknown>
JSON schema describing the expected input structure.
hookSpecificOutput fields:
'accept' | 'decline' | 'cancel'
The programmatic response to the elicitation.
Record<string, unknown>
Form data to submit when
action is "accept".ElicitationResult
Fires after a user responds to an MCP elicitation. Hooks can observe or override the response.
When it fires: After the user (or an Elicitation hook) responds to the elicitation.
Input fields:
string
Name of the MCP server.
string
Request identifier.
'accept' | 'decline' | 'cancel'
How the user responded.
Record<string, unknown>
Submitted form data, if accepted.
hookSpecificOutput fields:
'accept' | 'decline' | 'cancel'
Override the user’s action before it is sent to the server.
Record<string, unknown>
Override the submitted content.
ConfigChange
Fires when a settings file changes during a session.
When it fires: When user_settings, project_settings, local_settings, policy_settings, or skills files are modified on disk.
Input fields:
'user_settings' | 'project_settings' | 'local_settings' | 'policy_settings' | 'skills'
Which settings source changed.
string
Absolute path to the changed file.
InstructionsLoaded
Fires when a CLAUDE.md or instruction rule file is loaded. This event is observability-only.
When it fires: When any instruction file is loaded into context.
Input fields:
string
Path to the loaded file.
'User' | 'Project' | 'Local' | 'Managed'
The memory scope of the file.
'session_start' | 'nested_traversal' | 'path_glob_match' | 'include' | 'compact'
Why the file was loaded.
string[]
The
paths: frontmatter patterns that matched (if load_reason is path_glob_match).string
The file Claude accessed that caused this load (for
path_glob_match).string
The file that
@included this one (for include).WorktreeCreate
Fires when Claude Code needs to create an isolated worktree. The hook is responsible for actually creating the worktree and reporting its path.
When it fires: When worktree isolation is requested for a task.
Input fields:
string
Suggested slug for the worktree directory.
WorktreeRemove
Fires when Claude Code needs to remove a previously created worktree.
When it fires: When a worktree task completes and the worktree should be cleaned up.
Input fields:
string
Absolute path of the worktree to remove.
CwdChanged
Fires after the working directory changes.
When it fires: When Claude changes directories during a session.
Input fields:
string
Previous working directory.
string
New working directory.
hookSpecificOutput fields:
string[]
Absolute paths to add to the
FileChanged watcher. Return this to start watching files in the new directory.CLAUDE_ENV_FILE environment variable is set — write export KEY=value lines to apply environment variables to subsequent Bash tool commands.
FileChanged
Fires when a watched file is modified, added, or removed.
When it fires: When a file registered via SessionStart.watchPaths or CwdChanged.watchPaths changes on disk.
Input fields:
string
Absolute path of the changed file.
'change' | 'add' | 'unlink'
The type of filesystem event.
hookSpecificOutput fields:
string[]
Update the watch list with these absolute paths.
CLAUDE_ENV_FILE environment variable is set for this hook as well.
Async hooks
For hooks that need to run in the background without delaying Claude, output an async acknowledgment on stdout instead of the normal sync output:literal: true
required
Signals that this hook is running asynchronously.
number
How long (in seconds) the async hook is allowed to run before it is cancelled.