Claude Code Hooks

July 30, 2026 · View on GitHub

Hooks are scripts that execute automatically on Claude Code events. They enable automation, block dangerous operations, and enrich context.

Available Hooks

HookEventPurposePlatform
bm25-routing/bm25-suggest.jsUserPromptSubmitBM25 lexical skill routing with self-calibrating thresholdsNode.js
bash/smart-suggest.shUserPromptSubmitRegex-based behavioral coach with 3-tier priority (enforcement/discovery/contextual)Bash
dangerous-actions-blocker.shPreToolUseBlock dangerous commands/editsBash
security-check.shPreToolUseBlock secrets in commandsBash
prompt-injection-detector.shPreToolUseDetect injection attempts (+ANSI, null bytes, nested cmd)Bash
unicode-injection-scanner.shPreToolUseDetect zero-width, RTL override, ANSI escape, null bytesBash
repo-integrity-scanner.shPreToolUseScan README/package.json for hidden injectionBash
mcp-config-integrity.shSessionStartVerify MCP config hash (CVE-2025-54135/54136)Bash
claudemd-scanner.shSessionStartDetect CLAUDE.md injection attacksBash
output-secrets-scanner.shPostToolUseDetect secrets + env leakage in tool outputsBash
auto-format.shPostToolUseAuto-format after editsBash
rtk-baseline.shSessionStartSave RTK baseline for session savings trackingBash
session-summary.shSessionEndFull session analytics (15 configurable sections)Bash
session-summary-config.shCLI toolConfigure session-summary sections, order, previewBash
learning-capture.shStopPrompt for daily learning captureBash
sandbox-validation.shPreToolUseValidate sandbox isolationBash
file-guard.shPreToolUseProtect sensitive files from modificationBash
permission-request.shPreToolUseExplicit permission flow for risky opsBash
rtk-auto-wrapper.shPreToolUseAuto-wrap commands with RTK for token savingsBash
setup-init.shSessionStartInitialize session environmentBash
auto-checkpoint.shPostToolUseAuto-checkpoint work at intervalsBash
typecheck-on-save.shPostToolUseRun TypeScript checks on saveBash
test-on-change.shPostToolUseRun tests on file changesBash
output-validator.shPostToolUseHeuristic output validationBash
session-logger.shPostToolUseLog operations for monitoringBash
privacy-warning.shPostToolUseWarn on potential privacy leaksBash
tts-selective.shPostToolUseText-to-speech for selected outputsBash
subagent-stop.shStopClean up sub-agent resourcesBash
pre-commit-secrets.shGit hookBlock secrets from entering commitsBash
pre-commit-evaluator.shGit hookLLM-as-a-Judge pre-commit validationBash
notification.shNotificationContextual macOS sound alertsBash (macOS)
auto-rename-session.shSessionEndAI-powered session title generation via HaikuBash
security-gate.shPreToolUseDetect vulnerable code patterns before writing to source filesBash
velocity-governor.shPreToolUseRate-limit tool calls to avoid API throttlingBash
security-check.ps1PreToolUseBlock secrets in commandsPowerShell
auto-format.ps1PostToolUseAuto-format after editsPowerShell

Hook Events

30 events in 8 groups. Events marked [B] can block (exit 2 or decision: "block").

Lifecycle

EventWhenTypical Use Cases
SessionStartSession begins or resumesInitialization, environment setup, config scanning
SetupOne-time init via --init-only or --init/--maintenance in -p modeInstall deps, validate prerequisites
SessionEndSession terminatesCleanup, session summary

Agent actions

EventWhenTypical Use Cases
Stop [B]Claude finishes respondingPost-response quality gates, continue loops
StopFailureTurn ends due to API errorAlert on rate limits, observability
PreToolUse [B]Before a tool executesValidation, blocking dangerous operations
PostToolUseAfter a tool succeedsFormatting, logging, cleanup
PostToolUseFailureAfter a tool failsError logging, recovery actions
PostToolBatch [B]After a full batch of parallel tool calls, before next model callBatch-level context injection, policy enforcement

Permissions

EventWhenTypical Use Cases
PermissionRequest [B]Permission dialog appearsCustom approval logic, auto-approve safe ops
PermissionDeniedTool call denied by auto modeAudit classifier denials, optionally signal retry

Compaction

EventWhenTypical Use Cases
PreCompact [B]Before context compactionBlock unwanted auto-compact, save state
PostCompactAfter compaction completesRestore context, log compaction summary

Multi-agent

EventWhenTypical Use Cases
SubagentStartSub-agent spawnsInject context into subagent
SubagentStop [B]Sub-agent finishesCleanup, quality gate before subagent exits
TeammateIdle [B]Agent teammate about to go idleTeam coordination, quality gates
TaskCreated [B]Task created via TaskCreateEnforce naming conventions, audit
TaskCompleted [B]Task marked completedEnforce completion criteria (tests, lint)

Configuration

EventWhenTypical Use Cases
ConfigChange [B]Config file changes during sessionEnterprise audit, block unauthorized changes
InstructionsLoadedCLAUDE.md or rules file loadedAudit which instruction files are active

File system

EventWhenTypical Use Cases
CwdChangedWorking directory changesdirenv reload, toolchain switching
FileChangedA watched file changes on diskReload env, trigger watchers
WorktreeCreate [B]Worktree being createdCustom VCS setup (SVN, Perforce)
WorktreeRemoveWorktree being removedClean up VCS state, credentials

User interaction

EventWhenTypical Use Cases
UserPromptSubmit [B]User sends a messageContext enrichment, prompt validation
UserPromptExpansion [B]Slash command expands to a promptBlock a command, inject skill context
NotificationClaude sends a notificationSound alerts, external notifications
MessageDisplayWhile assistant text is displayedStrip markdown on screen, redact secrets
Elicitation [B]MCP server requests user inputPre-answer in headless automation
ElicitationResult [B]User responds to an elicitationAudit or modify responses before they go to MCP

Advanced Guardrails (NEW in v3.3.0)

Advanced protection patterns inspired by production LLM systems.

prompt-injection-detector.sh

Event: PreToolUse

Detects and blocks prompt injection attempts before they reach Claude:

Detected Patterns:

  • Role override: "ignore previous instructions", "you are now", "pretend to be"
  • Jailbreak attempts: "DAN mode", "developer mode", "no restrictions"
  • Delimiter injection: </system>, [INST], <<SYS>>
  • Authority impersonation: "anthropic employee", "authorized to bypass"
  • Base64-encoded payloads (decoded and scanned)
  • Context manipulation: false claims about previous messages

Configuration:

{
  "hooks": {
    "PreToolUse": [{
      "hooks": [{
        "type": "command",
        "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/prompt-injection-detector.sh",
        "timeout": 5000
      }]
    }]
  }
}

output-validator.sh

Event: PostToolUse

Heuristic validation of Claude's outputs (no LLM call, pure bash):

Validation Checks:

  • Placeholder paths: /path/to/, /your/project/
  • Placeholder content: TODO:, your-api-key, example.com
  • Potential secrets in output (regex patterns)
  • Uncertainty indicators (multiple "I'm not sure", "probably")
  • Incomplete implementations: NotImplementedError, throw new Error
  • Unverified reference claims

Behavior: Warns via systemMessage, does not block. For deeper validation, use the output-evaluator agent.

session-logger.sh

Event: PostToolUse

Logs all Claude operations to JSONL files for monitoring and cost tracking:

Log Location: ~/.claude/logs/activity-YYYY-MM-DD.jsonl

Logged Data:

  • Timestamp, session ID, tool name
  • File paths and commands (truncated)
  • Project name
  • Token estimates (input/output)

Analysis: Use session-stats.sh script to analyze logs.

Environment Variables:

VariableDefaultDescription
CLAUDE_LOG_DIR~/.claude/logsLog directory
CLAUDE_LOG_TOKENStrueEnable token estimation
CLAUDE_SESSION_IDautoCustom session ID

See Observability Guide for full documentation.

pre-commit-evaluator.sh

Type: Git pre-commit hook (not Claude hook)

LLM-as-a-Judge evaluation before every commit. Opt-in only due to API costs.

Installation:

cp pre-commit-evaluator.sh .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
export CLAUDE_PRECOMMIT_EVAL=1  # Enable evaluation

Cost: ~$0.01-0.05 per commit (Haiku model)

Bypass: git commit --no-verify or CLAUDE_SKIP_EVAL=1 git commit


Security Hooks

dangerous-actions-blocker.sh

Event: PreToolUse (Bash, Edit, Write)

Comprehensive protection against dangerous operations:

Bash - Blocked Commands:

  • System destruction: rm -rf /, rm -rf ~, sudo rm
  • Disk operations: dd if=, mkfs, > /dev/sda
  • Fork bombs: :(){:|:&};:
  • Database drops: DROP DATABASE, DROP TABLE
  • Force pushes: git push --force main/master
  • Package publishing: npm publish, pnpm publish
  • Secret patterns: password=, api_key=, token=

Edit/Write - Protected Files:

  • Environment: .env, .env.local, .env.production
  • Credentials: credentials.json, serviceAccountKey.json
  • SSH keys: id_rsa, id_ed25519, id_ecdsa
  • Config: .npmrc, .pypirc, secrets.yml

Edit/Write - Allowed Paths:

  • $CLAUDE_PROJECT_DIR (current project)
  • ~/.claude/ (Claude config)
  • /tmp/ (temporary files)
  • Additional paths via $ALLOWED_PATHS environment variable

Exit Codes:

exit 0  # Allow operation
exit 2  # Block (stderr message shown to Claude)

Configuration:

# Add custom allowed paths (colon-separated)
export ALLOWED_PATHS="/custom/path:/another/path"

security-check.sh

Event: PreToolUse (Bash)

Focused on detecting secrets in commands:

  • Password patterns
  • API keys (common formats like sk-xxx, pk-xxx)
  • AWS credentials
  • Private keys
  • Hardcoded tokens

claudemd-scanner.sh

Event: SessionStart

Scans CLAUDE.md files at session start for potential prompt injection attacks:

Detected Patterns:

  • "ignore previous instructions" variants
  • Shell injection: curl | bash, wget | sh, eval(
  • Base64 encoded content (potential obfuscation)
  • Hidden instructions in HTML comments
  • Suspicious long lines (>500 chars)
  • Non-ASCII characters near sensitive keywords (homoglyph attacks)

Files Scanned:

  • CLAUDE.md (project root)
  • .claude/CLAUDE.md (local override)
  • Any .md files in .claude/ directory

Why This Matters: When you clone an unfamiliar repository, a malicious CLAUDE.md could inject instructions that compromise your system. This hook warns you before Claude processes potentially dangerous instructions.

Configuration:

{
  "hooks": {
    "SessionStart": [{
      "hooks": [{
        "type": "command",
        "command": ".claude/hooks/claudemd-scanner.sh",
        "timeout": 5000
      }]
    }]
  }
}

output-secrets-scanner.sh

Event: PostToolUse

Complements security-check.sh by scanning tool outputs (not inputs) for leaked secrets.

Detected Patterns:

  • API Keys: OpenAI, Anthropic, AWS, GCP, Azure, Stripe, Twilio, SendGrid
  • Tokens: GitHub, GitLab, NPM, PyPI, JWT
  • Private Keys: RSA, EC, DSA, OpenSSH, PGP
  • Database URLs with embedded passwords
  • Generic api_key=, secret=, password= patterns

Why This Matters: Claude might read a .env file and include credentials in its response or a commit. This hook catches secrets before they leak.

Configuration:

{
  "hooks": {
    "PostToolUse": [{
      "hooks": [{
        "type": "command",
        "command": ".claude/hooks/output-secrets-scanner.sh",
        "timeout": 5000
      }]
    }]
  }
}

Productivity Hooks

rtk-baseline.sh

Event: SessionStart

Captures RTK cumulative stats at session start for delta tracking. Paired with session-summary.sh which computes per-session RTK savings at session end.

Configuration:

{
  "hooks": {
    "SessionStart": [{
      "hooks": [{
        "type": "command",
        "command": "~/.claude/hooks/rtk-baseline.sh",
        "timeout": 5000
      }]
    }]
  }
}

session-summary.sh (v3)

Event: SessionEnd

Full session analytics with 15 configurable sections, CLI config tool, and JSONL logging.

Plugin Install (Recommended):

claude plugin marketplace add FlorianBruniaux/claude-code-plugins
claude plugin install session-summary@florian-claude-tools

Hooks are auto-wired, no manual configuration needed. See the plugin repo for details.

Sections (all configurable via env vars or config file):

SectionDefaultDescription
metaalwaysSession ID, name, branch
durationalwaysWall time, active time, turns, exit reason
toolsalwaysTool calls breakdown (OK/ERR)
errorsonError details grouped by tool
filesonFiles read/edited/created with top edited
featuresonMCP servers, agents, skills, teams, plan mode
gitonGit diff summary (+/- lines, files changed)
loconLines of code written via Edit/Write
modelsalwaysModel usage (requests, tokens)
cachealwaysCache hit rate
costalwaysEstimated cost (ccusage or pricing table)
rtkonRTK token savings (delta from session start)
ratioonConversation ratio (interactive/auto turns)
thinkingoffThinking blocks count
contextoffContext window estimate (peak %)

Log File: ~/.claude/logs/session-summaries.jsonl (structured JSONL with all metrics)

Configuration Priority: env vars (SESSION_SUMMARY_*) > config file (~/.config/session-summary/config.sh) > defaults

Environment Variables:

VariableDefaultDescription
NO_COLOR-Disable ANSI colors
SESSION_SUMMARY_SKIP0Set to 1 to disable summary
SESSION_SUMMARY_LOG~/.claude/logsOverride log directory
SESSION_SUMMARY_FILES1Files section toggle
SESSION_SUMMARY_RTKautoauto / 1 / 0
SESSION_SUMMARY_GIT1Git diff toggle
SESSION_SUMMARY_ERRORS1Error details toggle
SESSION_SUMMARY_LOC1Lines of code toggle
SESSION_SUMMARY_RATIO1Conversation ratio toggle
SESSION_SUMMARY_FEATURES1Features used toggle
SESSION_SUMMARY_THINKING0Thinking blocks toggle
SESSION_SUMMARY_CONTEXT0Context estimate toggle
SESSION_SUMMARY_SECTIONS(all)Comma-separated section order

CLI Config Tool (session-summary-config.sh):

session-summary-config show              # Current config with section status
session-summary-config set git=0         # Disable a section
session-summary-config set thinking=1    # Enable a section
session-summary-config reset             # Reset to defaults
session-summary-config sections          # Show section order
session-summary-config sections "meta,duration,tools,cost"  # Minimal output
session-summary-config preview           # Demo output with current config
session-summary-config install           # Install hooks in settings.json
session-summary-config log 5             # Last 5 session summaries

Requirements:

  • jq (required for JSON parsing)
  • ccusage (optional, for accurate cost calculation)
  • rtk (optional, for token savings tracking)

Screenshot (real session output):

Session Summary v3

Example Output (all sections enabled):

═══ Session Summary ═══════════════════
ID:       abc-123-def-456...
Name:     Fix session summary hook
Branch:   main
Duration: Wall 5m 28s | Active 1m 33s | 12 turns | Exit: user

Tool Calls: 29 (OK 27 / ERR 2)
  Edit: 13  Bash: 8  Read: 6  Grep: 1  Glob: 1

Errors: 2
  Bash: "command not found: rtk" (x1)
  Edit: "old_string not unique" (x1)

Files: 3 read · 2 edited · 1 created
  session-summary.sh (8 edits), settings.json (3 edits)

Features: MCP (perplexity x4, chrome x12) · Agents (Explore x3, Plan x1) · Skills (commit)

Git: +142 -37 lines · 4 files changed
Code: +87 -12 net (via Edit/Write)

Model Usage         Reqs    Input    Output
claude-opus-4-6       59      93K      628
Cache: 85% hit rate (3.9M read / 322K created)
Est. Cost: \$0.045

RTK Savings: 24 cmds · ~12.4K tokens saved (73%)
Turns: 12 (8 interactive · 4 auto) · Avg 6.7s/turn
═══════════════════════════════════════

Configuration:

{
  "hooks": {
    "SessionEnd": [{
      "hooks": [{
        "type": "command",
        "command": "~/.claude/hooks/session-summary.sh"
      }]
    }]
  }
}

Quick Install: Plugin system (see above) or manual: session-summary-config.sh install (copies hooks + updates settings.json)

How it compares to tweakcc's /cost patch:

tweakcc (1K+ stars) patches Claude Code's cli.js to re-enable /cost for Pro/Max subscribers. Different approach, different trade-offs:

tweakcc /costsession-summary.sh
ApproachPatches Claude Code binaryOfficial hooks API (no modification)
Survives CC updatesNo (re-apply each update)Yes
TriggerManual (/cost command)Automatic on session exit
MetricsCost, duration, tokens, LOC15 sections (cost, tokens, tools, errors, files, features, git diff, LOC, cache, RTK, ratio...)
HistoryNoJSONL log with all metrics
DependenciesNode.jsjq (bash native)

tweakcc is a broader tool (themes, prompts, toolsets) — the /cost patch is one feature among many. This hook focuses specifically on session analytics with deeper metrics and zero modification of Claude Code internals.

auto-format.sh / auto-format.ps1

Event: PostToolUse (Edit, Write)

Automatically format files after editing:

ExtensionFormatter
.ts, .tsx, .js, .jsxPrettier
.json, .css, .scss, .mdPrettier
.prismaprisma format
.pyBlack / autopep8
.gogo fmt

Silent Operation: No output, failures ignored to avoid blocking Claude.

Requirements: Install formatters in your project:

# Node.js projects
npm install -D prettier

# Python projects
pip install black

# Go projects (built-in)
go fmt

notification.sh

Event: Notification (macOS only)

Contextual sound alerts based on notification content:

ContextSoundTriggered By
SuccessHero.aiff"completed", "done", "success"
ErrorBasso.aiff"error", "failed", "problem"
WaitingSubmarine.aiff"waiting", "permission", "input"
WarningSosumi.aiff"warning", "attention", "alert"
DefaultPing.aiffOther notifications

Features:

  • Non-blocking (plays in background)
  • Native macOS notifications
  • Automatic context detection via keywords
  • Multi-language support (English/French)

Requirements: macOS with afplay and osascript (built-in)

Configuration

Hooks are configured in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/dangerous-actions-blocker.sh",
          "timeout": 5000
        }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/auto-format.sh",
          "timeout": 10000
        }]
      }
    ],
    "Notification": [
      {
        "hooks": [{
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/notification.sh",
          "timeout": 5000
        }]
      }
    ]
  }
}

Matcher Patterns:

  • ".*" - Match all tools
  • "Bash" - Match only Bash tool
  • "Edit|Write" - Match Edit OR Write tools
  • "Bash|Edit|Write" - Match multiple tools

Creating Custom Hooks

Basic Template

#!/bin/bash
# Hook: [EventType] - Description
# Exit 0 = success/allow, Exit 2 = block (PreToolUse only)

set -e

# Read JSON from stdin
INPUT=$(cat)

# Extract data
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input // empty')

# Your logic here...

# Return optional JSON
cat << EOF
{
  "systemMessage": "Message displayed to Claude",
  "hookSpecificOutput": {
    "additionalContext": "Extra context added"
  }
}
EOF

exit 0

Environment Variables

Available in hook scripts:

VariableDescription
CLAUDE_PROJECT_DIRCurrent project path
CLAUDE_FILE_PATHSFiles passed with -f flag
CLAUDE_TOOL_INPUTTool input as JSON
HOMEUser home directory

Best Practices

  1. Short Timeout: Max 5-10s to avoid blocking Claude
  2. Fail Gracefully: Use || true for non-critical operations
  3. Minimal Logging: Avoid stdout except structured JSON
  4. Require jq: Parse JSON with jq for reliability
  5. Test Thoroughly: Test with various inputs before deploying
  6. Document Behavior: Clear comments on what hook does
  7. Handle Errors: Proper error messages for debugging

Example: Git Context Enrichment

Create git-context.sh (UserPromptSubmit event):

#!/bin/bash
# Hook: UserPromptSubmit - Add Git context to prompts

set -e

INPUT=$(cat)

# Get Git information
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
LAST_COMMIT=$(git log -1 --oneline 2>/dev/null || echo "none")
UNCOMMITTED=$(git status --short 2>/dev/null | wc -l | tr -d ' ')
STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')

# Return enriched context
cat << EOF
{
  "systemMessage": "[Git] Branch: $BRANCH | Last: $LAST_COMMIT | Uncommitted: $UNCOMMITTED files | Staged: $STAGED files"
}
EOF

exit 0

Register in settings:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [{
          "type": "command",
          "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/git-context.sh",
          "timeout": 3000
        }]
      }
    ]
  }
}

Installation

Project-Level (Shared with Team)

  1. Create hooks directory:
mkdir -p .claude/hooks
  1. Copy hook from examples:
cp /path/to/examples/hooks/bash/dangerous-actions-blocker.sh .claude/hooks/
chmod +x .claude/hooks/*.sh
  1. Configure in .claude/settings.json (see Configuration section above)

  2. Commit to repository:

git add .claude/hooks/ .claude/settings.json
git commit -m "Add Claude Code hooks"

Personal/Global (Your Machine Only)

  1. Create global hooks directory:
mkdir -p ~/.claude/hooks
  1. Copy hook:
cp /path/to/examples/hooks/bash/notification.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/*.sh
  1. Configure in ~/.claude/settings.json

Priority: Project hooks override global hooks.

Platform-Specific Notes

macOS / Linux (Bash)

  • Use .sh extension
  • Requires chmod +x for execution
  • Path separator: /
  • Home directory: ~ or $HOME

Windows (PowerShell)

  • Use .ps1 extension
  • May require execution policy: Set-ExecutionPolicy RemoteSigned
  • Path separator: \
  • Home directory: $env:USERPROFILE

Troubleshooting

Hook Not Executing

Cause: Not registered in settings.json or wrong path

Fix: Verify configuration and use absolute paths or $CLAUDE_PROJECT_DIR

Permission Denied

Cause: Hook not executable

Fix:

chmod +x .claude/hooks/*.sh

Hook Blocks Everything

Cause: Exit code 2 without conditions

Fix: Check logic, ensure exit 0 is default case

Timeout Errors

Cause: Hook takes too long (>timeout value)

Fix: Optimize hook performance or increase timeout in settings

jq Not Found

Cause: jq not installed

Fix: Install jq:

# macOS
brew install jq

# Ubuntu/Debian
sudo apt-get install jq

# Windows
choco install jq

Advanced Examples

Activity Logger

Log all Claude operations to JSONL file:

#!/bin/bash
# PostToolUse - Log all activities

set -e

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
LOG_FILE="$HOME/.claude/logs/activity-$(date +%Y-%m-%d).jsonl"

mkdir -p "$(dirname "$LOG_FILE")"

# Create log entry
cat << EOF >> "$LOG_FILE"
{"timestamp":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","tool":"$TOOL","session":"$CLAUDE_SESSION_ID"}
EOF

exit 0

Database Migration Detector

Alert when migrations are created:

#!/bin/bash
# PostToolUse - Detect database migrations

set -e

INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')

if [[ "$TOOL" == "Write" ]]; then
    FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path')

    if [[ "$FILE" == *"/migrations/"* ]]; then
        cat << EOF
{
  "systemMessage": "⚠️ Database migration created: $FILE\n\nReminder:\n1. Review migration carefully\n2. Test on dev database first\n3. Run 'prisma migrate deploy' after merge"
}
EOF
    fi
fi

exit 0

Security Considerations

  1. Never Store Secrets in Hooks: Use environment variables
  2. Validate Input: Always sanitize data from stdin
  3. Limit Hook Scope: Use specific matchers, not ".*"
  4. Review Blocked Operations: Log when hooks block actions
  5. Test in Isolation: Test hooks outside Claude first
  6. Version Control: Commit hooks to repository for team sharing

Resources


See the main guide for detailed explanations and advanced patterns.