This page provides reference documentation for implementing hooks in Claude Code.
~/.claude/settings.json
- User settings.claude/settings.json
- Project settings.claude/settings.local.json
- Local project settings (not committed)PreToolUse
and PostToolUse
)
Write
matches only the Write toolEdit|Write
or Notebook.*
*
to match all tools. You can also use empty string (""
) or leave
matcher
blank.type
: Currently only "command"
is supportedcommand
: The bash command to execute (can use $CLAUDE_PROJECT_DIR
environment variable)timeout
: (Optional) How long a command should run, in seconds, before
canceling that specific command.UserPromptSubmit
, Notification
, Stop
, and SubagentStop
that don’t use matchers, you can omit the matcher field:
CLAUDE_PROJECT_DIR
(only available when
Claude Code spawns the hook command) to reference scripts stored in your project,
ensuring they work regardless of Claude’s current directory:
Task
- Subagent tasks (see subagents documentation)Bash
- Shell commandsGlob
- File pattern matchingGrep
- Content searchRead
- File readingEdit
, MultiEdit
- File editingWrite
- File writingWebFetch
, WebSearch
- Web operationsmanual
- Invoked from /compact
auto
- Invoked from auto-compact (due to full context window)startup
- Invoked from startupresume
- Invoked from --resume
, --continue
, or /resume
clear
- Invoked from /clear
tool_input
depends on the tool.
tool_input
and tool_response
depends on the tool.
stop_hook_active
is true when Claude Code is already continuing as a result of
a stop hook. Check this value or process the transcript to prevent Claude Code
from running indefinitely.
manual
, custom_instructions
comes from what the user passes into
/compact
. For auto
, custom_instructions
is empty.
stdout
is shown to the user in transcript mode
(CTRL-R), except for UserPromptSubmit
and SessionStart
, where stdout is
added to the context.stderr
is fed back to Claude to process
automatically. See per-hook-event behavior below.stderr
is shown to the user and
execution continues.UserPromptSubmit
hook where stdout is injected as context.Hook Event | Behavior |
---|---|
PreToolUse | Blocks the tool call, shows stderr to Claude |
PostToolUse | Shows stderr to Claude (tool already ran) |
Notification | N/A, shows stderr to user only |
UserPromptSubmit | Blocks prompt processing, erases prompt, shows stderr to user only |
Stop | Blocks stoppage, shows stderr to Claude |
SubagentStop | Blocks stoppage, shows stderr to Claude subagent |
PreCompact | N/A, shows stderr to user only |
SessionStart | N/A, shows stderr to user only |
stdout
for more sophisticated control:
continue
is false, Claude stops processing after the hooks run.
PreToolUse
, this is different from "permissionDecision": "deny"
, which
only blocks a specific tool call and provides automatic feedback to Claude.PostToolUse
, this is different from "decision": "block"
, which
provides automated feedback to Claude.UserPromptSubmit
, this prevents the prompt from being processed.Stop
and SubagentStop
, this takes precedence over any
"decision": "block"
output."continue" = false
takes precedence over any
"decision": "block"
output.stopReason
accompanies continue
with a reason shown to the user, not shown
to Claude.
PreToolUse
Decision ControlPreToolUse
hooks can control whether a tool call proceeds.
"allow"
bypasses the permission system. permissionDecisionReason
is shown
to the user but not to Claude. (Deprecated "approve"
value + reason
has
the same behavior.)"deny"
prevents the tool call from executing. permissionDecisionReason
is
shown to Claude. ("block"
value + reason
has the same behavior.)"ask"
asks the user to confirm the tool call in the UI.
permissionDecisionReason
is shown to the user but not to Claude.PostToolUse
Decision ControlPostToolUse
hooks can control whether a tool call proceeds.
"block"
automatically prompts Claude with reason
.undefined
does nothing. reason
is ignored.UserPromptSubmit
Decision ControlUserPromptSubmit
hooks can control whether a user prompt is processed.
"block"
prevents the prompt from being processed. The submitted prompt is
erased from context. "reason"
is shown to the user but not added to context.undefined
allows the prompt to proceed normally. "reason"
is ignored."hookSpecificOutput.additionalContext"
adds the string to the context if not
blocked.Stop
/SubagentStop
Decision ControlStop
and SubagentStop
hooks can control whether Claude must continue.
"block"
prevents Claude from stopping. You must populate reason
for Claude
to know how to proceed.undefined
allows Claude to stop. reason
is ignored.SessionStart
Decision ControlSessionStart
hooks allow you to load in context at the start of a session.
"hookSpecificOutput.additionalContext"
adds the string to the context.UserPromptSubmit
hooks, you can inject context using either method:UserPromptSubmit
)mcp__<server>__<tool>
, for example:
mcp__memory__create_entities
- Memory server’s create entities toolmcp__filesystem__read_file
- Filesystem server’s read file toolmcp__github__search_repositories
- GitHub server’s search tool"$VAR"
not $VAR
..
in file paths$CLAUDE_PROJECT_DIR
for the project path).env
, .git/
, keys, etc./hooks
menu for changes to applyCLAUDE_PROJECT_DIR
environment variable is available and contains the
absolute path to the project root directory--debug
)/hooks
to see if your hook is registeredclaude --debug
to see hook execution details\"
inside JSON stringsclaude --debug
to see detailed hook
executionclaude --debug
to see hook execution details: