Comprehensive documentation for all Claude Code hook events.
PreToolUse Hook → Deny Rules → Allow Rules → Ask Rules → Permission Check → [Tool Execution] → PostToolUse Hook
Fires before a tool is executed. Can block or modify the operation.
Input Schema:
{
"session_id": "abc123",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file contents..."
}
}
Use Cases:
Example:
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Block writes to protected directories
if [[ "$FILE" == /etc/* ]] || [[ "$FILE" == /usr/* ]]; then
echo "Cannot write to system directories" >&2
exit 2
fi
Fires after a tool completes. Cannot block but can log or notify.
Input Schema:
{
"session_id": "abc123",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
},
"tool_output": {
"stdout": "...",
"stderr": "...",
"exit_code": 0
}
}
Use Cases:
Example:
#!/bin/bash
INPUT=$(cat)
LOG_FILE="$CLAUDE_PROJECT_DIR/.claude/audit.log"
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIME | $TOOL | $(echo "$INPUT" | jq -c '.')" >> "$LOG_FILE"
Fires when Claude Code shows a permission dialog.
Input Schema:
{
"session_id": "abc123",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules"
},
"permission_type": "tool_use"
}
Use Cases:
Fires when Claude Code sends a notification.
Input Schema:
{
"session_id": "abc123",
"notification_type": "task_complete",
"message": "Build completed successfully"
}
Use Cases:
Fires when user submits a prompt. No matcher support.
Input Schema:
{
"session_id": "abc123",
"prompt": "User's message text"
}
Use Cases:
Fires when the main agent finishes. No matcher support.
Input Schema:
{
"session_id": "abc123",
"reason": "completed",
"final_message": "Task completed successfully"
}
Use Cases:
Fires when a subagent finishes. No matcher support.
Input Schema:
{
"session_id": "abc123",
"subagent_id": "xyz789",
"subagent_type": "python-expert",
"result": "Analysis complete"
}
Use Cases:
Fires before context window compaction. No matcher support.
Input Schema:
{
"session_id": "abc123",
"current_tokens": 150000,
"max_tokens": 200000
}
Use Cases:
Fires when a session begins or resumes. No matcher support.
Input Schema:
{
"session_id": "abc123",
"is_resume": false,
"project_dir": "/path/to/project"
}
Use Cases:
Example:
#!/bin/bash
# Load project-specific environment
source "$CLAUDE_PROJECT_DIR/.env.local" 2>/dev/null || true
echo "Session initialized for $(basename "$CLAUDE_PROJECT_DIR")"
Fires when a session ends. No matcher support.
Input Schema:
{
"session_id": "abc123",
"duration_ms": 3600000,
"total_cost_usd": 0.05
}
Use Cases:
| Code | Meaning | Effect |
|---|---|---|
| 0 | Success | Continue execution |
| 2 | Blocking error | Stop, show stderr to Claude |
| Other | Non-blocking error | Log warning, continue |
Available in all hook scripts:
| Variable | Description |
|---|---|
CLAUDE_PROJECT_DIR |
Current project directory |
CLAUDE_SESSION_ID |
Current session identifier |
CLAUDE_TOOL_NAME |
Tool being executed (PreToolUse/PostToolUse only) |