Hooks Guide β Claude Code
Run shell commands automatically on Claude Code lifecycle events
πͺ Hooks Guide
Wire shell commands to Claude Code lifecycle events β enforce policies, run linters, send notifications, and automate governance without changing your agent's prompts.
1. Hook Event Types
Claude Code fires hooks at four key lifecycle points:
PreToolUse
Fires before a tool is called. Can block the tool call by exiting with code 2. Use for security validation, dry-run checks, approval gates.
PostToolUse
Fires after a tool completes. Use for logging, metrics, post-processing, notifications.
Notification
Fires when Claude sends a notification (needs input, task complete, etc.). Use for desktop alerts, Slack pings, sound effects.
Stop
Fires when Claude finishes or is interrupted. Use for cleanup, summaries, post-session reporting.
2. Configuring Hooks
Hooks are configured in settings.json (global: ~/.claude/settings.json, project: .claude/settings.json):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash /path/to/validate-command.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix $CLAUDE_FILE_PATHS"
}
]
}
],
"Notification": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude needs input\" with title \"Claude Code\"'"
}
]
}
]
}
}
3. Hook Input & Output
Claude Code passes a JSON object via stdin to every hook:
# PreToolUse stdin example
{
"session_id": "abc123",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf /tmp/build"
}
}
# Hook can write JSON to stdout to modify behavior:
# exit 0 β allow (optionally provide context to Claude)
# exit 2 β block the tool call (output shown to Claude as error)
4. Practical Examples
Block dangerous bash commands
PreToolUse β Bash: scan input for rm -rf /, DROP TABLE, etc.
Auto-format on file write
PostToolUse β Write: run Prettier/ESLint on saved files automatically
Audit log all tool calls
PostToolUse β *: append JSON to audit.log for compliance
Desktop notification when idle
Notification event β trigger OS notification when Claude needs input
5. Best Practices
- β Keep hooks fast β hook scripts block the agent. Aim for <100ms; offload slow work to background processes.
- β Use exit codes correctly β only exit 2 to block; use exit 0 for warnings that Claude should see but not be blocked by.
-
β
Prefer project-scoped hooks β commit
.claude/settings.jsonso the whole team benefits from the same guardrails. - β Test hooks independently β pass synthetic JSON via stdin to validate behavior before enabling in live sessions.