# Common Hook Patterns This reference provides common, proven patterns for implementing Claude Code hooks. Use these patterns as starting points for typical hook use cases. ## Pattern 1: Security Validation Block dangerous file writes using prompt-based hooks: ```json { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "prompt", "prompt": "File path: $TOOL_INPUT.file_path. Verify: 1) Not in /etc or system directories 2) Not .env or credentials 3) Path doesn't contain '..' traversal. Return 'approve' or 'deny'." } ] } ] } ``` **Use for:** Preventing writes to sensitive files or system directories. ## Pattern 2: Test Enforcement Ensure tests run before stopping: ```json { "Stop": [ { "matcher": "*", "hooks": [ { "type": "prompt", "prompt": "Review transcript. If code was modified (Write/Edit tools used), verify tests were executed. If no tests were run, block with reason 'Tests must be run after code changes'." } ] } ] } ``` **Use for:** Enforcing quality standards and preventing incomplete work. ## Pattern 3: Context Loading Load project-specific context at session start: ```json { "SessionStart": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh" } ] } ] } ``` **Example script (load-context.sh):** ```bash #!/bin/bash cd "$CLAUDE_PROJECT_DIR" || exit 1 # Detect project type if [ -f "package.json" ]; then echo "📦 Node.js project detected" echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE" elif [ -f "Cargo.toml" ]; then echo "🦀 Rust project detected" echo "export PROJECT_TYPE=rust" >> "$CLAUDE_ENV_FILE" fi ``` **Use for:** Automatically detecting and configuring project-specific settings. ## Pattern 4: Notification Logging Log all notifications for audit or analysis: ```json { "Notification": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/log-notification.sh" } ] } ] } ``` **Use for:** Tracking user notifications or integration with external logging systems. ## Pattern 5: MCP Tool Monitoring Monitor and validate MCP tool usage: ```json { "PreToolUse": [ { "matcher": "mcp__.*__delete.*", "hooks": [ { "type": "prompt", "prompt": "Deletion operation detected. Verify: Is this deletion intentional? Can it be undone? Are there backups? Return 'approve' only if safe." } ] } ] } ``` **Use for:** Protecting against destructive MCP operations. ## Pattern 6: Build Verification Ensure project builds after code changes: ```json { "Stop": [ { "matcher": "*", "hooks": [ { "type": "prompt", "prompt": "Check if code was modified. If Write/Edit tools were used, verify the project was built (npm run build, cargo build, etc). If not built, block and request build." } ] } ] } ``` **Use for:** Catching build errors before committing or stopping work. ## Pattern 7: Permission Confirmation Ask user before dangerous operations: ```json { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "prompt", "prompt": "Command: $TOOL_INPUT.command. If command contains 'rm', 'delete', 'drop', or other destructive operations, return 'ask' to confirm with user. Otherwise 'approve'." } ] } ] } ``` **Use for:** User confirmation on potentially destructive commands. ## Pattern 8: Code Quality Checks Run linters or formatters on file edits: ```json { "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/check-quality.sh" } ] } ] } ``` **Example script (check-quality.sh):** ```bash #!/bin/bash input=$(cat) file_path=$(echo "$input" | jq -r '.tool_input.file_path') # Run linter if applicable if [[ "$file_path" == *.js ]] || [[ "$file_path" == *.ts ]]; then npx eslint "$file_path" 2>&1 || true fi ``` **Use for:** Automatic code quality enforcement. ## Pattern Combinations Combine multiple patterns for comprehensive protection: ```json { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "prompt", "prompt": "Validate file write safety" } ] }, { "matcher": "Bash", "hooks": [ { "type": "prompt", "prompt": "Validate bash command safety" } ] } ], "Stop": [ { "matcher": "*", "hooks": [ { "type": "prompt", "prompt": "Verify tests run and build succeeded" } ] } ], "SessionStart": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh" } ] } ] } ``` This provides multi-layered protection and automation. ## Pattern 9: Temporarily Active Hooks Create hooks that only run when explicitly enabled via flag files: ```bash #!/bin/bash # Hook only active when flag file exists FLAG_FILE="$CLAUDE_PROJECT_DIR/.enable-security-scan" if [ ! -f "$FLAG_FILE" ]; then # Quick exit when disabled exit 0 fi # Flag present, run validation input=$(cat) file_path=$(echo "$input" | jq -r '.tool_input.file_path') # Run security scan security-scanner "$file_path" ``` **Activation:** ```bash # Enable the hook touch .enable-security-scan # Disable the hook rm .enable-security-scan ``` **Use for:** - Temporary debugging hooks - Feature flags for development - Project-specific validation that's opt-in - Performance-intensive checks only when needed **Note:** Must restart Claude Code after creating/removing flag files for hooks to recognize changes. ## Pattern 10: Configuration-Driven Hooks Use JSON configuration to control hook behavior: ```bash #!/bin/bash CONFIG_FILE="$CLAUDE_PROJECT_DIR/.claude/my-plugin.local.json" # Read configuration if [ -f "$CONFIG_FILE" ]; then strict_mode=$(jq -r '.strictMode // false' "$CONFIG_FILE") max_file_size=$(jq -r '.maxFileSize // 1000000' "$CONFIG_FILE") else # Defaults strict_mode=false max_file_size=1000000 fi # Skip if not in strict mode if [ "$strict_mode" != "true" ]; then exit 0 fi # Apply configured limits input=$(cat) file_size=$(echo "$input" | jq -r '.tool_input.content | length') if [ "$file_size" -gt "$max_file_size" ]; then echo '{"decision": "deny", "reason": "File exceeds configured size limit"}' >&2 exit 2 fi ``` **Configuration file (.claude/my-plugin.local.json):** ```json { "strictMode": true, "maxFileSize": 500000, "allowedPaths": ["/tmp", "/home/user/projects"] } ``` **Use for:** - User-configurable hook behavior - Per-project settings - Team-specific rules - Dynamic validation criteria