Hooks

2026-01-12 Event System ultrathink

Configuration

Location: .claude/settings.json in the project root.

Schema

{ "hooks": { "PostToolUse": [ { "matcher": "Edit", "hooks": [{"type": "command", "command": "your-script"}] } ] } }
  • Outer "hooks" wrapper required
  • matcher is tool name (case-sensitive): Edit, Write, Bash
  • Use "matcher": "" or "*" to match all tools

Hook Input

Command receives JSON on stdin:

Field Description
session_idSession UUID
cwdCurrent working directory
hook_event_nameEvent type (e.g., "PostToolUse")
tool_nameTool that was called
tool_inputTool call arguments
tool_responseTool call response
tool_use_idUnique tool use ID

Exit Codes (Critical)

This is the only way to give Claude feedback:

Exit Code Behavior
0Silent success. Claude does NOT see stdout.
2Blocking error. stderr shown to Claude immediately.
OtherNon-blocking error. stderr shown to user only.
Important
Exit code 2 + stderr is the ONLY way for Claude to see hook output. Exit 0 is completely silent.

Available Events

Event When
PreToolUseBefore tool execution (can block)
PostToolUseAfter tool completion
PostToolUseFailureAfter tool fails
NotificationWhen notifications sent
UserPromptSubmitWhen user submits prompt
StopWhen agent finishes
SubagentStopWhen subagent finishes
SessionStartSession begins
SessionEndSession terminates

Environment Variables

  • $CLAUDE_PROJECT_DIR - Absolute path to project root
  • $CLAUDE_TOOL_INPUT_FILE_PATH - For Edit/Write, the file path being modified

Gotchas

  • Settings must be in actual project root, not subdirectory
  • Hooks snapshot at session start - changes need /hooks command or session restart
  • PostToolUse can't block - tool already executed. Use PreToolUse to prevent.
  • Exit 0 gives NO feedback to Claude