Claude Code Hooks: Exhaustive Reference
This document provides a comprehensive reference for the Claude Code hooks system, including all hook event types, JSON schemas, edge cases, known bugs, and undocumented behaviors.
Overview
Claude Code Hooks: Exhaustive Reference
This document provides a comprehensive reference for the Claude Code hooks system, including all hook event types, JSON schemas, edge cases, known bugs, and undocumented behaviors.
Last Updated: January 2026 Claude Code Version Coverage: v1.0.38 through v2.1.1
Table of Contents
- Hook Event Types
- Tool Names and Input Schemas
- Configuration Format
- Hook Input JSON Schema
- Hook Output JSON Schema
- Permission Decision Types
- Exit Code Behavior
- Error Handling
- Async and Parallel Execution
- Version History and Changelog
- Known Bugs and Issues
- Edge Cases and Gotchas
- Undocumented Behavior
Hook Event Types
Claude Code provides 11 hook events covering the complete session lifecycle:
| Event | Trigger | Matcher Support | Primary Use Cases |
|---|---|---|---|
| PreToolUse | Before tool execution | Yes | Validation, modification, approval/denial |
| PostToolUse | After successful tool completion | Yes | Logging, formatting, analysis |
| PostToolUseFailure | After tool execution fails | Yes | Error handling, retry logic |
| PermissionRequest | Before permission dialog shown | Yes | Auto-approve/deny permission requests |
| UserPromptSubmit | When user submits a prompt | No | Context injection, prompt validation |
| Notification | When Claude sends notifications | Partial | Logging, custom reactions |
| Stop | Main agent finishes responding | No | Completeness validation, force continuation |
| SubagentStop | Subagent finishes | No | Task validation, output quality checks |
| SubagentStart | Subagent spawns (v2.0.64+) | No | Agent lifecycle tracking |
| PreCompact | Before context compaction | No | Transcript backup, context preservation |
| SessionStart | Session begins or resumes | No | Environment setup, context loading |
| SessionEnd | Session terminates | No | Cleanup, state saving, logging |
Event Details
PreToolUse
- When: After Claude creates tool parameters, before execution
- Can: Block, allow, modify tool inputs, request user confirmation
- Introduced: v2.0.38
- Input modification: v2.0.10+
PostToolUse
- When: Immediately after a tool completes successfully
- Can: Provide feedback to Claude, log results, trigger follow-up actions
- Note:
tool_resultfield available in input
PostToolUseFailure
- When: After a tool execution fails
- Can: Handle errors, suggest retries
- Documentation: Sparse; mentioned in Agent SDK but not main hooks docs
PermissionRequest
- When: Before permission dialog is shown to user
- Can: Auto-approve or deny on behalf of user
- Introduced: v2.0.45
- Warning: Race condition bug exists (see Known Bugs)
UserPromptSubmit
- When: User submits a prompt, before Claude processes it
- Can: Block prompts, inject context via
additionalContext - Note: stdout is added to context (unlike other hooks)
Notification
- When: Claude Code sends a notification
- Matchers:
permission_promptand other notification types - Payload includes:
message,notification_type
Stop / SubagentStop
- When: Agent/subagent finishes responding
- Can: Force continuation, validate completeness
- Split: v2.0.42 separated Stop and SubagentStop
SubagentStart
- When: Subagent spawns via Task tool
- Introduced: v2.0.64 (November 19, 2025)
- Payload:
agent_id,parent_agent_id,subagent_type,description
PreCompact
- When: Before context compaction/summarization
- Use: Last chance to preserve critical information
- Introduced: v2.0.30
SessionStart / SessionEnd
- When: Session lifecycle boundaries
- SessionStart special: Can persist variables via
$CLAUDE_ENV_FILE - SessionEnd: Supports
systemMessage(v2.1.0+)
Tool Names and Input Schemas
Claude Code has 16+ built-in tools. Hook matchers must use exact tool names (case-sensitive).
Complete Tool List
File Operations
| Tool | Description | Key Input Parameters |
|---|---|---|
| Read | Read files (images, PDFs, notebooks) | file_path, offset?, limit? |
| Write | Create/overwrite files | file_path, content |
| Edit | Single find-and-replace | file_path, old_string, new_string, replace_all? |
| MultiEdit | Multiple sequential edits | file_path, edits[] (array of edit operations) |
| NotebookEdit | Edit Jupyter cells | notebook_path, new_source, cell_id?, cell_type?, edit_mode? |
| LS | List directory contents | path, ignore? |
| Glob | File pattern matching | pattern, path? |
| Grep | Content search (ripgrep) | pattern, path?, output_mode?, glob?, type?, -A?, -B?, -C?, -i?, -n?, multiline?, head_limit? |
Execution
| Tool | Description | Key Input Parameters |
|---|---|---|
| Bash | Shell commands | command, description?, timeout?, run_in_background? |
| BashOutput | Get background shell output | bash_id, filter? |
| KillShell | Terminate background shell | shell_id |
Web
| Tool | Description | Key Input Parameters |
|---|---|---|
| WebFetch | Fetch and analyze URLs | url, prompt |
| WebSearch | Web search | query, allowed_domains?, blocked_domains? |
Task Management
| Tool | Description | Key Input Parameters |
|---|---|---|
| Task | Launch subagents | subagent_type, prompt, description |
| TodoWrite | Manage task lists | todos[] (with content, status, activeForm) |
| ExitPlanMode | Exit planning mode | plan |
| Skill | Execute user-defined skills | skill, args? |
| SlashCommand | Execute slash commands | command |
IDE Integration
| Tool | Description | Key Input Parameters |
|---|---|---|
| getDiagnostics | VS Code diagnostics | uri? |
| executeCode | Jupyter kernel execution | code |
MCP Tool Naming Convention
MCP (Model Context Protocol) tools follow this pattern:
mcp__<server_name>__<tool_name>
Examples:
mcp__github__create_issuemcp__memory__retrieve_memorymcp__filesystem__read_file
Matcher patterns for MCP tools:
"matcher": "mcp__memory__.*" // All tools from memory server
"matcher": "mcp__.*" // All MCP tools
"matcher": "mcp__github__create_issue" // Specific tool
Configuration Format
Configuration Locations (Precedence Order)
.claude/settings.local.json(local, not committed).claude/settings.json(project-level, shared)~/.claude/settings.json(user-level)
Settings File Format
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "/path/to/script.sh",
"timeout": 60
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Verify all tasks are complete: $ARGUMENTS",
"timeout": 30
}
]
}
]
}
}
Plugin Format (hooks/hooks.json)
{
"description": "Brief explanation (optional)",
"hooks": {
"PreToolUse": [...],
"Stop": [...]
}
}
Hook Types
| Type | Description | Default Timeout |
|---|---|---|
command | Bash command execution | 60 seconds |
prompt | LLM-based evaluation (Haiku) | 30 seconds |
Matcher Syntax
| Pattern | Matches |
|---|---|
"Write" | Exact match (case-sensitive) |
| `"Write\ | Edit"` |
"*" or "" | All tools |
"Bash(npm test*)" | Argument patterns with wildcards |
"mcp__memory__.*" | Regex patterns |
Important: Matchers are case-sensitive. "bash" will NOT match "Bash".
Configuration Options
| Field | Type | Default | Description |
|---|---|---|---|
matcher | string | "*" | Tool name pattern |
hooks | array | required | Array of hook definitions |
type | string | required | "command" or "prompt" |
command | string | - | Shell command (for type: command) |
prompt | string | - | LLM prompt (for type: prompt) |
timeout | number | 60/30 | Seconds before timeout |
once | boolean | false | Run only once per session |
Component-Scoped Hooks (v2.1.0+)
Hooks can be defined in Skills, subagents, and slash commands via frontmatter:
---
hooks:
PreToolUse:
- matcher: "Write"
hooks:
- type: command
command: "./validate.sh"
---
These hooks are scoped to the component's lifecycle and auto-cleanup when finished.
Hook Input JSON Schema
All hooks receive JSON via stdin with these common fields:
Common Fields (All Hooks)
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
"cwd": "/Users/lily/project",
"permission_mode": "default",
"hook_event_name": "PreToolUse"
}
| Field | Type | Description |
|---|---|---|
session_id | string | Unique session identifier |
transcript_path | string | Path to conversation JSONL transcript |
cwd | string | Current working directory |
permission_mode | string | "default", "plan", "acceptEdits", "dontAsk", "bypassPermissions" |
hook_event_name | string | The hook event type |
Tool-Related Hooks (PreToolUse, PostToolUse, PermissionRequest)
Additional fields:
{
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_use_id": "toolu_abc123"
}
PostToolUse Additional Fields
{
"tool_result": "Success: file written"
}
UserPromptSubmit
{
"user_prompt": "The user's submitted text"
}
Stop / SubagentStop
{
"reason": "Task completed"
}
SubagentStart (v2.0.64+)
{
"agent_id": "agent_xyz",
"parent_agent_id": "agent_abc",
"subagent_type": "general-purpose",
"description": "Research task"
}
SessionStart Additional
{
"agent_type": "custom-agent"
}
Notification
{
"message": "Claude needs your permission to use Bash",
"notification_type": "permission_prompt"
}
Environment Variables Available
| Variable | Description | Availability |
|---|---|---|
CLAUDE_PROJECT_DIR | Project root path | All hooks |
CLAUDE_PLUGIN_ROOT | Plugin directory | Plugin hooks |
CLAUDE_CODE_REMOTE | Set if remote context | All hooks |
CLAUDE_ENV_FILE | For persisting variables | SessionStart only |
CLAUDE_CODE_ENTRYPOINT | Entry point (e.g., "cli") | All hooks |
Hook Output JSON Schema
Hooks communicate via stdout with optional JSON structure.
Universal Output Fields
{
"continue": true,
"stopReason": "Optional message when continue=false",
"suppressOutput": false,
"systemMessage": "Message shown to USER (not Claude)"
}
| Field | Type | Default | Description |
|---|