## Hooks Configuration Hooks run commands at specific points in Claude Code's lifecycle. ### Hook Structure \`\`\`json { "hooks": { "EVENT_NAME": [ { "matcher": "ToolName|OtherTool", "hooks": [ { "type": "command", "command": "your-command-here", "timeout": 60, "statusMessage": "Running..." } ] } ] } } \`\`\` ### Hook Events | Event | Matcher | Purpose | |-------|---------|---------| | PermissionRequest | Tool name | Run before permission prompt | | PreToolUse | Tool name | Run before tool, can block | | PostToolUse | Tool name | Run after successful tool | | PostToolUseFailure | Tool name | Run after tool fails | | Notification | Notification type | Run on notifications | | Stop | - | Run when Claude stops (including clear, resume, compact) | | PreCompact | "manual"/"auto" | Before compaction | | UserPromptSubmit | - | When user submits | | SessionStart | - | When session starts | **Common tool matchers:** \`Bash\`, \`Write\`, \`Edit\`, \`Read\`, \`Glob\`, \`Grep\` ### Hook Types **1. Command Hook** - Runs a shell command: \`\`\`json { "type": "command", "command": "prettier --write $FILE", "timeout": 30 } \`\`\` **2. Prompt Hook** - Evaluates a condition with LLM: \`\`\`json { "type": "prompt", "prompt": "Is this safe? $ARGUMENTS" } \`\`\` Only available for tool events: PreToolUse, PostToolUse, PermissionRequest. **3. Agent Hook** - Runs an agent with tools: \`\`\`json { "type": "agent", "prompt": "Verify tests pass: $ARGUMENTS" } \`\`\` Only available for tool events: PreToolUse, PostToolUse, PermissionRequest. ### Hook Input (stdin JSON) \`\`\`json { "session_id": "abc123", "tool_name": "Write", "tool_input": { "file_path": "/path/to/file.txt", "content": "..." }, "tool_response": { "success": true } // PostToolUse only } \`\`\` ### Hook JSON Output Hooks can return JSON to control behavior: \`\`\`json { "systemMessage": "Warning shown to user in UI", "continue": false, "stopReason": "Message shown when blocking", "suppressOutput": false, "decision": "block", "reason": "Explanation for decision", "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": "Context injected back to model" } } \`\`\` **Fields:** - \`systemMessage\` - Display a message to the user (all hooks) - \`continue\` - Set to \`false\` to block/stop (default: true) - \`stopReason\` - Message shown when \`continue\` is false - \`suppressOutput\` - Hide stdout from transcript (default: false) - \`decision\` - "block" for PostToolUse/Stop/UserPromptSubmit hooks (deprecated for PreToolUse, use hookSpecificOutput.permissionDecision instead) - \`reason\` - Explanation for decision - \`hookSpecificOutput\` - Event-specific output (must include \`hookEventName\`): - \`additionalContext\` - Text injected into model context - \`permissionDecision\` - "allow", "deny", or "ask" (PreToolUse only) - \`permissionDecisionReason\` - Reason for the permission decision (PreToolUse only) - \`updatedInput\` - Modified tool input (PreToolUse only) ### Common Patterns **Auto-format after writes:** \`\`\`json { "hooks": { "PostToolUse": [{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "jq -r '.tool_response.filePath // .tool_input.file_path' | xargs prettier --write 2>/dev/null || true" }] }] } } \`\`\` **Log all bash commands:** \`\`\`json { "hooks": { "PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "jq -r '.tool_input.command' >> ~/.claude/bash-log.txt" }] }] } } \`\`\` **Stop hook that displays message to user:** Command must output JSON with \`systemMessage\` field: \`\`\`bash # Example command that outputs: {"systemMessage": "Session complete!"} echo '{"systemMessage": "Session complete!"}' \`\`\` **Run tests after code changes:** \`\`\`json { "hooks": { "PostToolUse": [{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path // .tool_response.filePath' | grep -E '\\\\.(ts|js)$' && npm test || true" }] }] } } \`\`\`