返回 Skill 列表
extension
分类: 开发与工程无需 API Key

hooks-mastery

当用户要求“创建一个钩子”、“配置钩子”、“验证钩子配置”、“添加PreToolUse钩子”、“添加PostToolUse钩子”、“添加SessionStart钩子”,提及钩子事件(如PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, UserPromptSubmit, PermissionRequest, Notification, PreCompact, SessionEnd),或者需要关于Claude Code钩子协议的帮助时,应使用此技能。根据官方协议规范提供创建、配置和验证钩子的全面指导。

person作者: jakexiaohubgithub

Claude Code Hooks Mastery

Overview

Claude Code hooks are event-driven extensions that execute commands or LLM evaluations at specific lifecycle points. This skill provides guidance for creating production-ready hooks following the official protocol specification.

Core Concepts

Hook Types

Command Hooks: Execute bash scripts with JSON input via stdin

{
  "type": "command",
  "command": "python3 /path/to/script.py",
  "timeout": 60
}

Prompt-Based Hooks: Use LLM (Haiku) for intelligent evaluation

{
  "type": "prompt",
  "prompt": "Evaluate if Claude should stop: $ARGUMENTS",
  "timeout": 30
}

Hook Events

| Event | Matcher | Purpose | Common Use Cases | |-------|---------|---------|------------------| | PreToolUse | Yes | Before tool execution | Validation, modification, blocking | | PermissionRequest | Yes | Permission dialog | Auto-approve/deny | | PostToolUse | Yes | After tool execution | Formatting, validation | | UserPromptSubmit | No | Before prompt processing | Context injection, validation | | Stop/SubagentStop | No | Agent finishing | Determine if work complete | | SessionStart | Yes | Session start/resume | Environment setup, context loading | | SessionEnd | No | Session end | Cleanup, logging | | Notification | Yes | Notifications sent | External alerting | | PreCompact | Yes | Before compact | Validation, logging |

Configuration Structure

Hooks are configured in settings files (user, project, or local scope):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validator.py",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Creating Hooks

Step 1: Choose Hook Event

Identify which lifecycle point to hook into:

  • Validation before action: PreToolUse, PermissionRequest
  • Processing after action: PostToolUse
  • Context enhancement: UserPromptSubmit, SessionStart
  • Flow control: Stop, SubagentStop

Step 2: Write Hook Script

Input Protocol: Hooks receive JSON via stdin with these common fields:

{
  "session_id": "string",
  "transcript_path": "string",
  "cwd": "string",
  "permission_mode": "default|plan|acceptEdits|bypassPermissions",
  "hook_event_name": "EventName",
  // Event-specific fields...
}

Output Protocol: Respond via exit codes and stdout:

Exit Code 0 (Success):

  • stdout: Plain text or JSON for structured control
  • JSON enables advanced decisions

Exit Code 2 (Blocking):

  • stderr: Error message fed to Claude
  • Blocks the action (behavior varies by event)

Exit Code 1+ (Non-blocking):

  • stderr: Logged to verbose mode
  • Execution continues

Step 3: Configure Hook

Add to appropriate settings file:

  • ~/.claude/settings.json - User-level
  • .claude/settings.json - Project-level (team-shared)
  • .claude/settings.local.json - Local (git-ignored)

Step 4: Test Hook

Enable debug mode to see hook execution:

claude --debug

Use verbose mode (Ctrl+O) during session to see hook output.

Common Patterns

Pattern 1: Validation Hook (PreToolUse)

Validate and potentially block tool calls:

#!/usr/bin/env python3
import json
import sys

# Read input
input_data = json.load(sys.stdin)

# Validate
if should_block(input_data):
    print("Validation failed: reason", file=sys.stderr)
    sys.exit(2)  # Block execution

# Allow with optional modification
output = {
    "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "allow",
        "updatedInput": {
            "modified_field": "new_value"
        }
    }
}
print(json.dumps(output))
sys.exit(0)

Pattern 2: Context Enrichment (UserPromptSubmit)

Add context before Claude processes prompt:

#!/usr/bin/env python3
import json
import sys
import datetime

input_data = json.load(sys.stdin)

# Add context (plain text stdout with exit 0)
context = f"Current time: {datetime.datetime.now()}\n"
context += f"Current directory: {input_data['cwd']}"
print(context)

sys.exit(0)

Pattern 3: Environment Setup (SessionStart)

Initialize environment variables and context:

#!/bin/bash

# Setup environment
source ~/.nvm/nvm.sh
nvm use 20

# Persist variables
if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi

# Add context
echo "Environment initialized: Node $(node --version)"

exit 0

Pattern 4: Intelligent Decision (Stop Hook)

Use LLM for context-aware decisions:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Context: $ARGUMENTS\n\nDetermine if all tasks are complete. Check for:\n1. All user requests fulfilled\n2. No errors requiring fixes\n3. Tests passing\n\nRespond: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
          }
        ]
      }
    ]
  }
}

Matcher Patterns

Matchers determine when hooks execute (PreToolUse, PostToolUse, PermissionRequest, Notification, PreCompact, SessionStart):

Exact match: "matcher": "Write" - Only Write tool Regex: "matcher": "Edit|Write" - Multiple tools All tools: "matcher": "*" or "matcher": "" MCP tools: "matcher": "mcp__github__.*" - All GitHub server tools

Environment Variables

Available in all hooks:

  • CLAUDE_PROJECT_DIR - Project root directory
  • CLAUDE_CODE_REMOTE - "true" if web environment

SessionStart hooks only:

  • CLAUDE_ENV_FILE - File path for persisting environment variables

Plugin hooks only:

  • CLAUDE_PLUGIN_ROOT - Plugin directory

Security Considerations

Input Validation: Always validate and sanitize inputs

if '..' in file_path or file_path.startswith('/'):
    print("Path traversal detected", file=sys.stderr)
    sys.exit(2)

Shell Safety: Quote all variables

command="$CLAUDE_PROJECT_DIR/script.sh"

Sensitive Files: Skip .env, .git/, keys, etc.

sensitive = ['.env', '.git/', 'id_rsa', '*.pem']
if any(p in file_path for p in sensitive):
    sys.exit(2)

Troubleshooting

Hook not executing:

  • Check configuration with /hooks command
  • Verify matcher pattern matches tool name
  • Enable debug mode: claude --debug

Hook timing out:

  • Increase timeout in configuration
  • Default: 60s for command, 30s for prompt
  • Individual timeout doesn't affect other hooks

JSON parsing errors:

  • Validate JSON output with jq
  • Check exit code is 0 for JSON processing
  • Exit code 2 ignores stdout JSON

Permission denied:

  • Make scripts executable: chmod +x script.sh
  • Check file paths are absolute or use $CLAUDE_PROJECT_DIR

Quick Reference

Decision Control by Event

| Event | Allow Action | Block Action | Modify Input | |-------|--------------|--------------|--------------| | PreToolUse | permissionDecision: "allow" | permissionDecision: "deny" | updatedInput: {} | | PermissionRequest | behavior: "allow" | behavior: "deny" | updatedInput: {} | | PostToolUse | - | decision: "block" | - | | UserPromptSubmit | - | decision: "block" | - | | Stop/SubagentStop | - | decision: "block" | - |

Exit Code Behavior

| Code | stdout | stderr | Continues | |------|--------|--------|-----------| | 0 | Parsed as JSON/text | Ignored | Yes | | 2 | Ignored | Fed to Claude/User | Depends | | Other | Ignored | Logged | Yes |

Additional Resources

For detailed protocol specifications:

  • references/protocol-specification.md - Complete protocol documentation
  • references/event-reference.md - Detailed event specifications

For working examples:

  • examples/pretooluse-validator/ - Bash command validation
  • examples/userprompt-enricher/ - Context injection
  • examples/sessionstart-setup/ - Environment initialization
  • examples/stop-evaluator/ - Prompt-based decision making

For validation and testing:

  • scripts/validate-hook-config.py - Validate hooks.json against schema
  • scripts/test-hook-io.py - Test hook input/output locally
  • scripts/generate-hook-template.sh - Generate hook boilerplate

For schema validation:

  • assets/hooks-schema.json - JSON schema for hooks configuration