Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for developing lifecycle hooks for Claude Code plugins from the official Anthropic repository.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/patterns.md
1# Common Hook Patterns23This reference provides common, proven patterns for implementing Claude Code hooks. Use these patterns as starting points for typical hook use cases.45## Pattern 1: Security Validation67Block dangerous file writes using prompt-based hooks:89```json10{11"PreToolUse": [12{13"matcher": "Write|Edit",14"hooks": [15{16"type": "prompt",17"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'."18}19]20}21]22}23```2425**Use for:** Preventing writes to sensitive files or system directories.2627## Pattern 2: Test Enforcement2829Ensure tests run before stopping:3031```json32{33"Stop": [34{35"matcher": "*",36"hooks": [37{38"type": "prompt",39"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'."40}41]42}43]44}45```4647**Use for:** Enforcing quality standards and preventing incomplete work.4849## Pattern 3: Context Loading5051Load project-specific context at session start:5253```json54{55"SessionStart": [56{57"matcher": "*",58"hooks": [59{60"type": "command",61"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh"62}63]64}65]66}67```6869**Example script (load-context.sh):**70```bash71#!/bin/bash72cd "$CLAUDE_PROJECT_DIR" || exit 17374# Detect project type75if [ -f "package.json" ]; then76echo "📦 Node.js project detected"77echo "export PROJECT_TYPE=nodejs" >> "$CLAUDE_ENV_FILE"78elif [ -f "Cargo.toml" ]; then79echo "🦀 Rust project detected"80echo "export PROJECT_TYPE=rust" >> "$CLAUDE_ENV_FILE"81fi82```8384**Use for:** Automatically detecting and configuring project-specific settings.8586## Pattern 4: Notification Logging8788Log all notifications for audit or analysis:8990```json91{92"Notification": [93{94"matcher": "*",95"hooks": [96{97"type": "command",98"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/log-notification.sh"99}100]101}102]103}104```105106**Use for:** Tracking user notifications or integration with external logging systems.107108## Pattern 5: MCP Tool Monitoring109110Monitor and validate MCP tool usage:111112```json113{114"PreToolUse": [115{116"matcher": "mcp__.*__delete.*",117"hooks": [118{119"type": "prompt",120"prompt": "Deletion operation detected. Verify: Is this deletion intentional? Can it be undone? Are there backups? Return 'approve' only if safe."121}122]123}124]125}126```127128**Use for:** Protecting against destructive MCP operations.129130## Pattern 6: Build Verification131132Ensure project builds after code changes:133134```json135{136"Stop": [137{138"matcher": "*",139"hooks": [140{141"type": "prompt",142"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."143}144]145}146]147}148```149150**Use for:** Catching build errors before committing or stopping work.151152## Pattern 7: Permission Confirmation153154Ask user before dangerous operations:155156```json157{158"PreToolUse": [159{160"matcher": "Bash",161"hooks": [162{163"type": "prompt",164"prompt": "Command: $TOOL_INPUT.command. If command contains 'rm', 'delete', 'drop', or other destructive operations, return 'ask' to confirm with user. Otherwise 'approve'."165}166]167}168]169}170```171172**Use for:** User confirmation on potentially destructive commands.173174## Pattern 8: Code Quality Checks175176Run linters or formatters on file edits:177178```json179{180"PostToolUse": [181{182"matcher": "Write|Edit",183"hooks": [184{185"type": "command",186"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/check-quality.sh"187}188]189}190]191}192```193194**Example script (check-quality.sh):**195```bash196#!/bin/bash197input=$(cat)198file_path=$(echo "$input" | jq -r '.tool_input.file_path')199200# Run linter if applicable201if [[ "$file_path" == *.js ]] || [[ "$file_path" == *.ts ]]; then202npx eslint "$file_path" 2>&1 || true203fi204```205206**Use for:** Automatic code quality enforcement.207208## Pattern Combinations209210Combine multiple patterns for comprehensive protection:211212```json213{214"PreToolUse": [215{216"matcher": "Write|Edit",217"hooks": [218{219"type": "prompt",220"prompt": "Validate file write safety"221}222]223},224{225"matcher": "Bash",226"hooks": [227{228"type": "prompt",229"prompt": "Validate bash command safety"230}231]232}233],234"Stop": [235{236"matcher": "*",237"hooks": [238{239"type": "prompt",240"prompt": "Verify tests run and build succeeded"241}242]243}244],245"SessionStart": [246{247"matcher": "*",248"hooks": [249{250"type": "command",251"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/load-context.sh"252}253]254}255]256}257```258259This provides multi-layered protection and automation.260261## Pattern 9: Temporarily Active Hooks262263Create hooks that only run when explicitly enabled via flag files:264265```bash266#!/bin/bash267# Hook only active when flag file exists268FLAG_FILE="$CLAUDE_PROJECT_DIR/.enable-security-scan"269270if [ ! -f "$FLAG_FILE" ]; then271# Quick exit when disabled272exit 0273fi274275# Flag present, run validation276input=$(cat)277file_path=$(echo "$input" | jq -r '.tool_input.file_path')278279# Run security scan280security-scanner "$file_path"281```282283**Activation:**284```bash285# Enable the hook286touch .enable-security-scan287288# Disable the hook289rm .enable-security-scan290```291292**Use for:**293- Temporary debugging hooks294- Feature flags for development295- Project-specific validation that's opt-in296- Performance-intensive checks only when needed297298**Note:** Must restart Claude Code after creating/removing flag files for hooks to recognize changes.299300## Pattern 10: Configuration-Driven Hooks301302Use JSON configuration to control hook behavior:303304```bash305#!/bin/bash306CONFIG_FILE="$CLAUDE_PROJECT_DIR/.claude/my-plugin.local.json"307308# Read configuration309if [ -f "$CONFIG_FILE" ]; then310strict_mode=$(jq -r '.strictMode // false' "$CONFIG_FILE")311max_file_size=$(jq -r '.maxFileSize // 1000000' "$CONFIG_FILE")312else313# Defaults314strict_mode=false315max_file_size=1000000316fi317318# Skip if not in strict mode319if [ "$strict_mode" != "true" ]; then320exit 0321fi322323# Apply configured limits324input=$(cat)325file_size=$(echo "$input" | jq -r '.tool_input.content | length')326327if [ "$file_size" -gt "$max_file_size" ]; then328echo '{"decision": "deny", "reason": "File exceeds configured size limit"}' >&2329exit 2330fi331```332333**Configuration file (.claude/my-plugin.local.json):**334```json335{336"strictMode": true,337"maxFileSize": 500000,338"allowedPaths": ["/tmp", "/home/user/projects"]339}340```341342**Use for:**343- User-configurable hook behavior344- Per-project settings345- Team-specific rules346- Dynamic validation criteria347