Skip to main content
Version: 1.1.1

Hooks

Hooks are shell commands that execute automatically at specific points in Claude Code's lifecycle. Unlike model decisions (which can vary), hooks are deterministic: they run when their trigger condition is met. Well-designed hooks can save context and reduce repeated manual steps.

Last reviewed: February 26, 2026. Event names and schema details may change across versions.

Common use cases

  • Auto-format files after every edit
  • Block edits to protected files. For example .env, lock files
  • Send desktop notifications when Claude needs attention
  • Run linters or validators after code changes
  • Log all shell commands for auditing

Supported events

EventFires whenExample use
PreToolUseBefore a tool executesBlock dangerous commands
PostToolUseAfter a tool succeedsAuto-format edited files
NotificationClaude needs attentionDesktop notification
StopClaude finishes respondingVerify task completion
SubagentStopA subagent completesPost-process subagent output
PreCompactBefore context compactionPreserve key context before summarization
SessionEndSession exits/endsCleanup and export logs
SessionStartSession begins/resumesRe-inject context
UserPromptSubmitBefore processing a promptValidate input

Configuration

Hooks live in .claude/settings.json (project-scoped, shareable) or ~/.claude/settings.json (personal, all projects).

Auto-format files after edits:

{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs ruff format"
}
]
}
]
}
}

Desktop notification (macOS):

{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude needs attention\" with title \"Claude Code\"'"
}
]
}
]
}
}

Block edits to protected files:

{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path'); case \"$FILE\" in *.env*|*requirements*.txt|*lock*) echo \"Blocked: $FILE is protected\" >&2; exit 2;; esac"
}
]
}
]
}
}

How hooks communicate

  • Input: Hook receives JSON on stdin with session info, tool name, and tool input
  • Exit code 0: Action allowed (stdout added to context for SessionStart/UserPromptSubmit)
  • Exit code 2: Action blocked — stderr is sent back to Claude as feedback
  • Other exit codes: Action allowed, stderr logged silently

Matchers

The matcher field filters which tool or event triggers the hook:

  • "Edit|Write" — matches Edit or Write tools
  • "Bash" — matches only Bash tool calls
  • "mcp__github__.*" — matches any GitHub MCP tool (regex)
  • "" (empty) — matches everything

Source: Anthropic Claude Code hooks reference