Hooks System

Verified 高级 Advanced 参考型 Reference ⚡ Claude Code 专属 ⚡ Claude Code Optimized
5 min read · 236 lines

Claude Code Hooks guide: 25+ lifecycle events × 4 handler types = deterministic automation

Hooks System

Overview

Hooks are user-defined automated actions that execute at specific lifecycle points in Claude Code. They are deterministic (not advisory) — once configured, they execute strictly and cannot be skipped by Claude.

Four Handler Types

1. Command (Shell)

Runs a local shell command, receives JSON on stdin:

{
  "hooks": {
    "PreToolUse": [{
      "type": "command",
      "command": "python3 ~/.claude/hooks/lint-check.py"
    }]
  }
}

2. HTTP (Network Request)

Sends POST to URL, supports env var interpolation in headers:

{
  "hooks": {
    "Stop": [{
      "type": "http",
      "url": "https://hooks.example.com/notify",
      "headers": {
        "Authorization": "Bearer ${API_TOKEN}"
      }
    }]
  }
}

3. Prompt (LLM Evaluation)

Uses a Claude model to evaluate conditions, returns {ok, reason}:

{
  "hooks": {
    "PreToolUse": [{
      "type": "prompt",
      "prompt": "Is this Bash command safe? No delete operations or rm -rf allowed."
    }]
  }
}

4. Agent (Subagent Verification)

Spawns a subagent with tool access for complex verification:

{
  "hooks": {
    "PostToolUse": [{
      "type": "agent",
      "prompt": "Verify the just-edited file passes type checking and linting.",
      "tools": ["Bash", "Read"]
    }]
  }
}

Lifecycle Events

Session Events

Event When It Fires Typical Use
SessionStart Session begins or resumes Initialize env vars, logging
SessionEnd Session terminates Cleanup, send analytics
InstructionsLoaded CLAUDE.md or rule file loaded Debug which instructions load
ConfigChange Config file changes during session Hot-reload configuration

Tool Events

Event When It Fires Typical Use
PreToolUse Before tool call executes (can block) Security validation, parameter modification
PostToolUse After tool call succeeds Auto-formatting, notifications
PostToolUseFailure After tool call fails Error logging, auto-repair
PermissionRequest Permission dialog appears Auto-allow/deny policies

Subagent Events

Event When It Fires Typical Use
SubagentStart Subagent spawned Log subagent activity
SubagentStop Subagent finished Result validation
TeammateIdle Team member about to go idle Assign new work
TaskCompleted Task marked complete Quality gates

Context Events

Event When It Fires Typical Use
PreCompact Before context compaction Save critical info
PostCompact After context compaction Restore critical info
UserPromptSubmit Prompt submitted, before processing Input validation
Stop Claude finishes responding Desktop notifications
Notification Notification sent Custom notification channels

Other Events

Event When It Fires
WorktreeCreate / WorktreeRemove Worktree created/removed
Elicitation / ElicitationResult MCP server requests user input

Exit Code Behavior

Exit Code Effect
0 Success, stdout parsed as JSON output
2 Blocking error — blocks tool calls, denies permissions, prevents stopping
Other Non-blocking error, stderr shown in verbose mode

PreToolUse JSON Output

PreToolUse is the most powerful hook event — it can return permission decisions and modify parameters:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Passed safety check",
    "updatedInput": { "command": "npm test -- --coverage" },
    "additionalContext": "Added coverage flag"
  }
}

Permission decision options:

  • allow: Allow execution (skip user confirmation)
  • deny: Deny execution
  • ask: Defer to user decision

Hook Configuration Locations

Location Scope
~/.claude/settings.json All projects
.claude/settings.json Single project (shareable)
.claude/settings.local.json Single project (local only)
Managed policy settings Organization-wide
Plugin hooks/hooks.json When plugin enabled
Skill/Agent frontmatter While component active

Environment Variables

Variable Description
$CLAUDE_PROJECT_DIR Project root directory
${CLAUDE_PLUGIN_ROOT} Plugin root directory
$CLAUDE_ENV_FILE Write export VAR=val to persist env vars (in SessionStart)

Common Input Fields

Every hook receives JSON with these fields:

{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.jsonl",
  "cwd": "/current/working/directory",
  "permission_mode": "default",
  "hook_event_name": "EventName",
  "agent_id": "agent-xyz",
  "agent_type": "AgentName"
}

Practical Recipes

Auto-format Saved Files

{
  "hooks": {
    "PostToolUse": [{
      "type": "command",
      "command": "jq -r '.tool_input.file_path // empty' | xargs -I {} prettier --write {}",
      "matcher": { "tool_name": "Edit|Write" }
    }]
  }
}

Desktop Notification on Completion

{
  "hooks": {
    "Stop": [{
      "type": "command",
      "command": "osascript -e 'display notification \"Claude is done\" with title \"Claude Code\"'"
    }]
  }
}

Block Dangerous Shell Commands

{
  "hooks": {
    "PreToolUse": [{
      "type": "prompt",
      "prompt": "Check if this Bash command contains dangerous operations (rm -rf, git push --force, DROP TABLE, etc). Reject if dangerous.",
      "matcher": { "tool_name": "Bash" }
    }]
  }
}

MCP Tool Naming Pattern

MCP tools in hooks use mcp__<server>__<tool> naming — e.g., mcp__memory__create_entities.

相关技能 Related Skills