configuration.md 4.4 KB

Hook Configuration Patterns

Advanced configuration for Claude Code hooks.

Configuration Locations

File Scope Priority
~/.claude/settings.json Global (all projects) Lower
.claude/settings.local.json Project-specific Higher

Project settings are additive to global settings.

Full Configuration Schema

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "path/to/script.sh",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}

Multiple Hooks Per Event

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          { "type": "command", "command": "validate-write.sh" }
        ]
      },
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "validate-bash.sh" }
        ]
      },
      {
        "matcher": "*",
        "hooks": [
          { "type": "command", "command": "log-all-tools.sh" }
        ]
      }
    ]
  }
}

Matcher Patterns

Simple Matchers

{"matcher": "Write"}      // Exact tool name
{"matcher": "Bash"}       // Bash commands
{"matcher": "Read"}       // File reads

Wildcard Matchers

{"matcher": "*"}          // All tools
{"matcher": ""}           // All tools (empty = wildcard)
{"matcher": "mcp__*"}     // All MCP tools

MCP Tool Matchers

{"matcher": "mcp__filesystem__*"}     // All filesystem MCP tools
{"matcher": "mcp__github__create_*"}  // GitHub create operations

Chaining Multiple Commands

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          { "type": "command", "command": "lint-check.sh", "timeout": 3000 },
          { "type": "command", "command": "security-scan.sh", "timeout": 10000 }
        ]
      }
    ]
  }
}

Hooks execute sequentially. If any hook exits with code 2, execution stops.

Timeout Configuration

{
  "type": "command",
  "command": "slow-check.sh",
  "timeout": 30000  // 30 seconds (milliseconds)
}

Default timeout: 5000ms (5 seconds)

Path Variables

Use $CLAUDE_PROJECT_DIR for portable paths:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate.sh"
      }]
    }]
  }
}

Conditional Hooks

Handle conditions in the script, not configuration:

#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')

# Only process Write and Edit
case "$TOOL" in
  Write|Edit)
    # Validation logic
    ;;
  *)
    exit 0  # Skip other tools
    ;;
esac

Environment-Specific Hooks

Development vs Production

#!/bin/bash
if [[ "${CLAUDE_ENV:-development}" == "production" ]]; then
    # Stricter validation
    strict_validate.sh
else
    # Lenient for development
    exit 0
fi

Per-Project Override

Project .claude/settings.local.json can add project-specific hooks:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/scripts/project-validate.sh"
      }]
    }]
  }
}

Common Configuration Patterns

Audit Logging

{
  "hooks": {
    "PostToolUse": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/audit-log.sh"
      }]
    }]
  }
}

Block Dangerous Commands

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-dangerous.sh",
        "timeout": 1000
      }]
    }]
  }
}

Session Initialization

{
  "hooks": {
    "SessionStart": [{
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/init-session.sh"
      }]
    }]
  }
}

Debugging Configuration

  1. Check JSON validity:

    jq '.' ~/.claude/settings.json
    
  2. Test hook script:

    echo '{"tool_name":"Bash","tool_input":{}}' | ./hook.sh
    echo $?  # Check exit code
    
  3. Enable debug mode:

    claude --debug
    
  4. List registered hooks:

    /hooks