What Are Hooks?
Hooks are scripts that execute at specific points in Claude Code’s lifecycle:- Before and after tool use (PreToolUse, PostToolUse)
- On user interactions (UserPromptSubmit, PermissionRequest)
- Session lifecycle (SessionStart, SessionEnd)
- Agent lifecycle (SubagentStart, SubagentStop)
- System events (PreCompact, ConfigChange)
Hooks are configured in
.claude/settings.json under the hooks key, or in agent/skill frontmatter.Why Hooks Matter
Hooks enable deterministic automation:- Validation: Block dangerous commands before execution
- Notifications: Sound alerts when agents complete tasks
- Logging: Audit all tool usage and decisions
- Integration: Trigger external systems (CI/CD, monitoring, Slack)
- Context injection: Add dynamic data to prompts
- Decision control: Approve/deny actions programmatically
Hook Events (18 Total)
Claude Code provides 18 hook events:- Tool Events
- User Events
- Agent Events
- Session Events
- Team Events
- System Events
| Hook | When It Fires | Can Block |
|---|---|---|
| PreToolUse | Before every tool call | Yes |
| PostToolUse | After tool succeeds | No |
| PostToolUseFailure | After tool fails | No |
| PermissionRequest | When permission prompt appears | Yes |
Hook Types
Claude Code supports three hook types:Command Hooks
Most commonRuns a shell command. Receives JSON input via stdin, returns via stdout/exit code.
Prompt Hooks
AI-poweredSends a prompt to Claude for single-turn evaluation. Returns
{"ok": true/false}.Agent Hooks
Multi-turnSpawns a subagent with tool access for complex verification.
Configuration
Settings-Based Hooks
Defined in.claude/settings.json:
Agent/Skill Frontmatter Hooks
Scoped to specific agents or skills:Agent hooks support 6 events:
PreToolUse, PostToolUse, PermissionRequest, PostToolUseFailure, Stop (converted to SubagentStop at runtime), SubagentStop.Hook Properties
Hook type:
command, prompt, or agentShell command to execute (for
type: "command").Supports environment variables like ${CLAUDE_PROJECT_DIR}.LLM prompt for evaluation (for
type: "prompt" or type: "agent").Timeout in milliseconds. Hook is killed if it exceeds this duration.
Run hook in background without blocking Claude Code.Use for: Logging, notifications, side effects.
Run only once per session.Use for: SessionStart, SessionEnd, Setup.
Regex pattern to filter events.Examples:
"Bash"— Only Bash tool"Edit|Write"— Edit or Write tools"mcp__.*"— All MCP tools".*"— All events (default)
Model for prompt-based hooks.Accepted values:
haiku, sonnet, opusReal Example: Voice Hook System
From the reference repository at.claude/hooks/:
Structure:
.claude/settings.json:
- Cross-platform sound playback (macOS:
afplay, Linux:paplay, Windows:winsound) - Configurable per-hook enable/disable via
hooks-config.json - Special handling: git commits trigger
pretooluse-git-committingsound - Agent-specific sounds in separate folders
Voice Hook Repository
Complete voice notification system with sound files and cross-platform support
Environment Variables
Available to hook scripts:| Variable | Availability | Description |
|---|---|---|
$CLAUDE_PROJECT_DIR | All hooks | Project root directory |
$CLAUDE_ENV_FILE | SessionStart | File path for persisting environment variables |
${CLAUDE_PLUGIN_ROOT} | Plugin hooks | Plugin’s root directory |
$CLAUDE_CODE_REMOTE | All hooks | Set to "true" in remote web environments |
Hook Matchers
Some hooks support matchers to filter events:| Hook | Matcher Field | Example |
|---|---|---|
| PreToolUse | tool_name | "Bash", "mcp__.*" |
| PostToolUse | tool_name | "Write" |
| PermissionRequest | tool_name | "Edit" |
| Notification | notification_type | "permission_prompt" |
| SubagentStart | agent_type | "Bash", "my-agent" |
| SubagentStop | agent_type | "Bash", "my-agent" |
| SessionStart | source | "startup", "resume" |
| ConfigChange | source | "project_settings" |
Decision Control
Hooks can block operations or modify behavior:PreToolUse (Block Tool Calls)
allow, deny, ask
Stop / SubagentStop (Block Continuation)
UserPromptSubmit (Modify Prompt)
Best Practices
Use async for side effects
Use async for side effects
Logging, notifications, and analytics should run async:This prevents hooks from slowing down Claude Code.
Disable hooks during development
Disable hooks during development
In Or disable individual hooks in
.claude/settings.local.json:hooks-config.json.Use matchers to reduce noise
Use matchers to reduce noise
Only fire hooks for relevant events:
Handle errors gracefully
Handle errors gracefully
Exit codes:
0— Success, continue1— Error (logged, continues)2— Block the operation
Use once: true for session hooks
Use once: true for session hooks
SessionStart, SessionEnd, and Setup should only run once:
Disabling Hooks
Disable All Hooks
In.claude/settings.local.json:
Disable Individual Hooks
In.claude/hooks/config/hooks-config.json:
.claude/hooks/config/hooks-config.local.json (git-ignored) for personal preferences.
Hooks Management
Cross-Links
Settings
Configure hooks in settings.json
Subagents
Add lifecycle hooks to agents
Voice Hooks Example
Complete voice notification system
Settings Best Practice
Full hook configuration reference
