Skip to content

Hooks System

Hooks run shell commands at specific lifecycle points — for automation, enforcement, and extension.

{
"hooks": [
{
"event": "PostToolUse",
"if": { "tool": "Edit" },
"run": "sh",
"args": ["-c", "npm run format -- $file_path"],
"continueOnError": false
}
]
}
EventWhen it fires
SessionStartWhen a session begins
SetupAfter initial setup
InstructionsLoadedAfter CLAUDE.md loads
SessionEndWhen the session ends
EventWhen it fires
PreToolUseBefore Claude runs a tool — can block/allow
PostToolUseAfter a tool succeeds
PostToolUseFailureAfter a tool fails
PostToolBatchAfter a batch of tools completes
EventWhen it fires
FileChangedWhen a file is modified
CwdChangedWhen the working directory changes
EventWhen it fires
NotificationWhen Claude emits a notification
StopBefore Claude stops working
SubagentStartWhen a subagent spawns
SubagentStopWhen a subagent completes
Exit codeMeaning
0Success — continue
1Error — stop Claude
2Deny this specific tool call
{
"if": {
"tool": "Edit", // match tool name
"command": "npm test", // Bash: match command text
"path": "src/**/*.ts", // match file path
"param:isolation": "worktree" // match by parameter value
}
}
{
"hooks": [{
"event": "PostToolUse",
"if": { "tool": "Edit" },
"run": "sh",
"args": ["-c", "prettier --write $file_path 2>/dev/null || true"],
"continueOnError": true
}]
}
{
"hooks": [{
"event": "PostToolUse",
"if": { "tool": "Edit", "path": "**/*.ts" },
"run": "sh",
"args": ["-c", "npx tsc --noEmit 2>&1 | head -20"],
"continueOnError": true
}]
}

Block edits to protected files (exit 2 = deny)

Section titled “Block edits to protected files (exit 2 = deny)”
{
"hooks": [{
"event": "PreToolUse",
"if": { "tool": "Edit" },
"run": "bash",
"args": ["-c", "if [[ $file_path =~ 'secrets' ]]; then exit 2; fi"]
}]
}
{
"hooks": [{
"event": "Stop",
"run": "sh",
"args": ["-c", "osascript -e 'display notification \"Claude stopped\" with title \"Claude Code\"'"]
}]
}
{
"hooks": [{
"event": "FileChanged",
"if": { "path": ".env" },
"run": "sh",
"args": ["-c", "set -a; source .env; set +a"]
}]
}

Hooks receive context as environment variables:

  • $file_path — path of the file being operated on
  • $tool — name of the tool
  • $command — bash command (for Bash tool)
  • $message — notification message (for Notification event)

They also receive JSON via stdin with the full event payload.

Terminal window
/hooks # in-session view of configured hooks
  • Trick: “Hooks are law; prompts are advice.” (The harness runs them — the model can’t skip them.)
  • Exit code 2 = block the action + explain why.
  • Show: a PostToolUse format-on-edit hook firing after a sloppy edit.
  • They’ll trip on: expecting AI judgment in a hook — it’s your script, deterministic.

Learning path:22-skills-real-examples.md · Index · ➡ 24-hooks-real-examples.md

Written by Fenil Patel