| name | hook-capabilities |
| description | Claude Code Hook system reference for capabilities, possibilities, and limitations. Use when you want to know what hooks can do. |
| allowed-tools | Read |
Claude Code Hook Capabilities
Reference for what hooks can do in Claude Code.
Why Hooks Matter: The Only Guarantee
Hook = 100% execution guarantee (event-based)
Skill/Agent/MCP = ~20-80% (Claude's judgment)
Key insight: Hooks are the ONLY mechanism that executes without Claude's decision.
See orchestration-patterns.md for forcing skill/agent activation.
5 Hook Roles
| Role |
Description |
Examples |
| Gate |
Block/allow tool execution |
Prevent dangerous commands, workflow precondition checks |
| Side Effect |
Auto-actions after tool execution |
Formatters, linters, auto-commit |
| State Manager |
Workflow state management |
State file creation/deletion, phase tracking |
| External Integrator |
External system integration |
MCP calls, HTTP API, WebSocket, Slack |
| Context Injector |
Session context injection |
Load project settings, activate services |
Event Types and Characteristics
| Event |
Block |
Special Features |
Verification |
| SessionStart |
No |
source (compact/new) |
Verified |
| UserPromptSubmit |
Yes |
stdout auto-injects into Claude context |
Verified |
| PreToolUse |
Yes |
updatedInput modifies input, tool_use_id |
Verified |
| PermissionRequest |
Yes |
allow/deny/ask + input modification |
Unverified |
| PostToolUse |
No |
tool_response (access results) |
Verified |
| Stop |
Yes |
stop_hook_active (loop prevention) |
Verified |
| SubagentStop |
Yes |
parent-child correlation via tool_use_id |
Unverified |
| Notification |
No |
includes notification_type |
Verified |
| PreCompact |
No |
trigger (auto/manual) |
Verified |
| SessionEnd |
No |
On session end |
Unverified |
22 Universal Approaches
Control Patterns
| Approach |
Description |
Event |
| Iteration Control |
Track iteration count + max limit |
Stop |
| Force Continuation |
Use exit 2 to continue Claude work |
Stop |
| Promise Detection |
Detect Claude response patterns, conditional exit |
Stop |
| Infinite Loop Prevention |
Prevent recursion via parent_tool_use_id |
UserPromptSubmit |
| Threshold Branching |
Branch based on error/warning count |
Stop |
Input Manipulation
| Approach |
Description |
Event |
| Input Modification |
Modify tool input via updatedInput |
PreToolUse, PermissionRequest |
| Path Normalization |
Auto-convert relative to absolute paths |
PreToolUse |
| Environment Injection |
Auto-inject environment variables |
PreToolUse |
| Dry-run Enforcement |
Auto-add --dry-run to dangerous commands |
PreToolUse |
Context Management
| Approach |
Description |
Event |
| Context Injection |
stdout auto-injects into Claude context |
UserPromptSubmit |
| Progressive Loading |
Load context/skills on demand |
UserPromptSubmit |
| Skill Auto-Activation |
Keywords trigger skill suggestions |
UserPromptSubmit |
| Transcript Parsing |
Read and analyze previous responses |
Stop |
| Transcript Backup |
Backup session transcript |
PreCompact |
State Management
| Approach |
Description |
Event |
| Session Cache |
Accumulate per-session state + aggregate results |
PostToolUse |
| Session Lifecycle |
Initialize/cleanup state via SessionStart/End |
SessionStart/End |
| Checkpoint Commit |
Checkpoint on every change, then squash |
PostToolUse, Stop |
| Session Branching |
Auto-isolate Git branches per session |
Pre/PostToolUse |
External Integration
| Approach |
Description |
Event |
| Notification Forwarding |
Forward notifications to Slack/Discord/external |
Notification |
| Desktop/Audio Alert |
osascript, notify-send, TTS |
Notification |
| Subagent Correlation |
Track parent-child via tool_use_id |
SubagentStop |
Security & Compliance
| Approach |
Description |
Event |
| Auto-Approval |
Auto-approve specific tools/commands |
PermissionRequest |
| Secret Scanning |
Detect and block API keys/secrets |
PreToolUse |
| Compliance Audit |
Compliance logging + violation detection |
PostToolUse |
Implementation Techniques
| Approach |
Description |
Event |
| TypeScript Delegation |
Delegate complex logic to .ts |
Any |
| Hook Chaining |
Execute multiple hooks sequentially |
Any |
| Background Execution |
Async via run_in_background |
Any |
| Argument Pattern Matching |
Match arguments like Bash(npm test*) |
PreToolUse |
| MCP Tool Matching |
Match MCP like mcp__memory__.* |
PreToolUse |
| Prompt-Type Hook |
LLM evaluation via type: "prompt" |
Any |
Capabilities vs Limitations
| Possible |
Not Possible |
| File create/delete/modify |
Block in PostToolUse |
| MCP/HTTP/WebSocket calls |
Direct Claude context modification |
| UserPromptSubmit stdout to context |
Delete existing context |
| PreToolUse/PermissionRequest input modification |
Cancel already-executed tools |
| Continue work from Stop |
Unlimited forcing (infinite loop risk) |
Data Passing Methods (Important)
stdin JSON (Verified)
All session/project info is passed via stdin JSON:
session_id - Session UUID
cwd - Project directory
transcript_path - Session log file path
tool_use_id - Tool call ID (PreToolUse/PostToolUse)
stdin JSON Structure by Event
# UserPromptSubmit
{"prompt": "user message", "session_id": "...", "cwd": "/path"}
# PreToolUse / PostToolUse
{"tool_name": "Bash", "tool_input": {"command": "npm test"}, "session_id": "..."}
# PermissionRequest
{"tool_name": "Bash", "tool_input": {...}, "permission_type": "execute"}
# Stop
{"stop_reason": "end_turn", "session_id": "..."}
# SubagentStop
{"agent_name": "backend-dev", "result": "...", "session_id": "..."}
Environment Variables (Verified)
CLAUDE_PROJECT_DIR, CLAUDE_SESSION_ID etc. are NOT environment variables!
Actually set environment variables:
CLAUDE_CODE_ENABLE_CFC="false"
CLAUDE_CODE_ENTRYPOINT="cli"
Settings Reload
settings.json changes only apply in new sessions
Exit Code Reference
| Exit Code |
Meaning |
Behavior |
| 0 |
Success/Allow |
Normal proceed |
| 1 |
Error |
Hook failure, show warning |
| 2 |
Block/Continue |
Varies by event |
Exit 2 behavior by event:
| Event |
exit 2 Behavior |
| PreToolUse |
Block tool execution |
| PostToolUse |
Ignore result (prompt retry) |
| PermissionRequest |
Deny permission request |
| Stop |
Force Claude to continue |
| UserPromptSubmit |
Abort prompt processing |
Hook Execution Order
Multiple hooks on same event → Sequential execution (definition order)
One hook exits 2 → Subsequent hooks don't run
Timeout Setting
{"type": "command", "command": "script.sh", "timeout": 10000}
Default: 60000ms (1 minute)
Common Mistakes
| Mistake |
Problem |
Solution |
| Not reading stdin |
Missing JSON input |
INPUT=$(cat) required |
| stdout debug output |
Context pollution |
Use stderr (>&2) |
| exit 1 vs exit 2 confusion |
Unintended behavior |
exit 1=error, exit 2=block |
| Parsing without jq |
Unstable |
Install and use jq |
References