Create, validate, and deploy Claude Code hooks for workflow automation. Hooks enable event-driven automation at 8 lifecycle points (PreToolUse, PostToolUse, UserPromptSubmit, etc.) with structured JSON control. Use when automating code formatting, security gates, observability integration, validation enforcement, or any event-driven workflow automation in Claude Code.
59
70%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.claude/skills/hooks-manager/SKILL.mdThe canonical home for this skill is hooks-manager in fernandezbaptiste/Skrillz
hooks-manager enables sophisticated workflow automation through Claude Code's hooks system (released June 2025).
Purpose: Create event-driven automation for code formatting, security gates, observability, and validation
Pattern: Task-based (8 operations, one per hook event + management)
Key Innovation: Hooks transform Claude Code from interactive to automated - reducing manual work by up to 92%
Hook Events Available (8):
Use hooks-manager when:
Production Impact: Companies report 92% reduction in style review time with PostToolUse formatting hooks
Purpose: Auto-format code after AI writes/edits files
Use Case: Enforce coding standards without manual intervention
Process:
Choose Formatter:
# JavaScript/TypeScript
npm install --save-dev prettier
# Python
pip install black
# Multi-language
npm install --save-dev prettier @prettier/plugin-pythonCreate Hook Configuration:
{
"event": "PostToolUse",
"tools": ["Write", "Edit"],
"description": "Auto-format code after Claude writes/edits files",
"handler": {
"command": "npx prettier --write \"$FILE\"",
"timeout": 5000
},
"filters": {
"filePatterns": ["**/*.{ts,tsx,js,jsx,py}"],
"excludePatterns": ["node_modules/**", "*.min.js"]
}
}Install Hook:
# Global hook (all projects)
mkdir -p ~/.claude/hooks
echo '[above-json]' > ~/.claude/hooks/auto-format.json
# Project-specific
mkdir -p .claude/hooks
echo '[above-json]' > .claude/hooks/auto-format.jsonTest Hook:
# Have Claude write unformatted code
# Hook should auto-format after Write/Edit
# Verify formatted correctlyOutputs:
Validation:
Time Estimate: 30-45 minutes
Purpose: Block dangerous operations before execution
Use Case: Prevent accidental production file modifications, destructive commands
Process:
Define Security Rules:
{
"event": "PreToolUse",
"tools": ["Write", "Edit", "Bash"],
"description": "Block dangerous operations",
"handler": {
"command": ".claude/hooks/security-check.sh \"$TOOL\" \"$FILE\" \"$COMMAND\""
},
"structuredOutput": true
}Create Security Check Script:
#!/bin/bash
# .claude/hooks/security-check.sh
TOOL=$1
FILE=$2
COMMAND=$3
# Block production file modifications
if [[ "$FILE" == "/etc/"* ]] || [[ "$FILE" == "/usr/"* ]]; then
echo '{"continue": false, "stopReason": "Cannot modify system files", "suppressOutput": true}'
exit 1
fi
# Block destructive commands
if [[ "$COMMAND" =~ rm\ -rf\ / ]] || [[ "$COMMAND" =~ dd\ if ]]; then
echo '{"continue": false, "stopReason": "Destructive command blocked", "suppressOutput": true}'
exit 1
fi
# Block curl/wget (security risk)
if [[ "$COMMAND" =~ curl|wget ]]; then
echo '{"continue": false, "stopReason": "Network commands disabled", "suppressOutput": false}'
exit 1
fi
# Allow operation
echo '{"continue": true}'
exit 0Install Security Hook:
chmod +x .claude/hooks/security-check.sh
# Hook JSON already configured in step 1Outputs:
Validation:
Time Estimate: 45-60 minutes
Purpose: Send telemetry to observability platform on important events
Use Case: Track AI agent decisions, tool usage, errors
Process:
Create Telemetry Hook:
{
"event": "Notification",
"description": "Send telemetry to observability platform",
"handler": {
"command": ".claude/hooks/send-telemetry.sh \"$EVENT_TYPE\" \"$MESSAGE\""
}
}Create Telemetry Script:
#!/bin/bash
# .claude/hooks/send-telemetry.sh
EVENT_TYPE=$1
MESSAGE=$2
# Send to observability platform (example: Victoria Metrics)
curl -X POST http://localhost:8428/api/v1/write \
-d "claude_event{type=\"$EVENT_TYPE\"} 1" \
-d "claude_message{event=\"$EVENT_TYPE\",msg=\"$MESSAGE\"} 1"
# Or log to file
echo "$(date -Iseconds) | $EVENT_TYPE | $MESSAGE" >> .claude/telemetry.log
# Or send to webhook
# curl -X POST https://your-webhook.com/telemetry \
# -H "Content-Type: application/json" \
# -d "{\"event\": \"$EVENT_TYPE\", \"message\": \"$MESSAGE\"}"Test Telemetry:
# Trigger notification in Claude Code
# Check telemetry.log or observability platform
cat .claude/telemetry.logOutputs:
Validation:
Time Estimate: 30-45 minutes
Purpose: Validate inputs before tool execution
Use Case: Ensure files exist, validate JSON, check permissions
Process:
Create Validation Hook:
{
"event": "PreToolUse",
"tools": ["Write"],
"description": "Validate JSON before writing",
"handler": {
"command": ".claude/hooks/validate-json.sh \"$FILE\" \"$CONTENT\""
},
"structuredOutput": true
}Create Validation Script:
#!/bin/bash
# .claude/hooks/validate-json.sh
FILE=$1
CONTENT=$2
# Only validate .json files
if [[ "$FILE" != *.json ]]; then
echo '{"continue": true}'
exit 0
fi
# Validate JSON syntax
if echo "$CONTENT" | jq empty 2>/dev/null; then
echo '{"continue": true}'
exit 0
else
echo '{"continue": false, "stopReason": "Invalid JSON syntax", "suppressOutput": false}'
exit 1
fiOutputs:
Validation:
Time Estimate: 20-30 minutes
Purpose: Control MCP tool access granularly
Use Case: Block specific MCP servers or tools
Process:
MCP Tool Targeting:
{
"event": "PreToolUse",
"tools": ["mcp__filesystem__*"],
"description": "Block all filesystem MCP operations",
"handler": {
"command": "echo '{\"continue\": false, \"stopReason\": \"Filesystem MCP disabled\"}'"
},
"structuredOutput": true
}Selective MCP Control:
{
"event": "PreToolUse",
"tools": ["mcp__github__delete_repository"],
"description": "Block dangerous GitHub operations",
"handler": {
"command": "echo '{\"continue\": false, \"stopReason\": \"Repository deletion disabled\"}'"
},
"structuredOutput": true
}Outputs:
Validation:
Time Estimate: 20-30 minutes
Purpose: Initialize environment on session start
Use Case: Load context, set variables, validate environment
Process:
Session Start Hook:
{
"event": "SessionStart",
"description": "Initialize session with context and validation",
"handler": {
"command": ".claude/hooks/session-init.sh"
}
}Initialization Script:
#!/bin/bash
# .claude/hooks/session-init.sh
echo "🚀 Claude Code Session Starting..."
# Load project context
if [ -f ".claude/PROJECT_CONTEXT.md" ]; then
echo "📋 Project context available"
fi
# Check git status
if git status --porcelain | grep -q .; then
echo "⚠️ Uncommitted changes detected"
fi
# Load environment
if [ -f ".env" ]; then
echo "🔐 Environment variables available"
fi
# Run pre-flight checks
if [ -f ".claude/hooks/pre-flight-check.sh" ]; then
bash .claude/hooks/pre-flight-check.sh
fi
echo "✅ Session initialized"Outputs:
Validation:
Time Estimate: 15-20 minutes
Purpose: Install, update, remove, and audit hooks
Process:
Deploy Hook (global or project):
# Deploy to global (~/.claude/hooks/)
deploy-hook --global formatting-hook.json
# Deploy to project (.claude/hooks/)
deploy-hook --project security-hook.jsonList Active Hooks:
# List all hooks
ls -la ~/.claude/hooks/
ls -la .claude/hooks/
# Parse and display
for hook in .claude/hooks/*.json; do
echo "Hook: $(basename $hook)"
jq '.event, .description' $hook
doneValidate Hook:
# Test hook in safe environment
validate-hook formatting-hook.json
# Expected:
# ✅ JSON valid
# ✅ Handler command exists
# ✅ Event type valid
# ✅ Structured output correctRemove Hook:
# Disable hook
rm .claude/hooks/formatting-hook.json
# Or rename to .disabled
mv .claude/hooks/security-hook.json .claude/hooks/security-hook.json.disabledOutputs:
Validation:
Time Estimate: 30-45 minutes
Purpose: Review all active hooks for security issues
Process:
Audit All Hooks:
# Scan all hook files
for hook in ~/.claude/hooks/*.json .claude/hooks/*.json; do
echo "Auditing: $hook"
# Check for dangerous patterns
if grep -q "rm -rf\|dd if\|curl.*sudo" $hook; then
echo "⚠️ Dangerous command detected"
fi
# Check for credential leaks
if grep -q "password\|secret\|token\|api_key" $hook; then
echo "⚠️ Potential credential exposure"
fi
# Validate JSON structure
jq empty $hook 2>/dev/null || echo "❌ Invalid JSON"
doneGenerate Security Report:
# Hook Security Audit
## Hooks Scanned: 8
### HIGH RISK
None
### MEDIUM RISK
1. observability-hook.json
- Issue: Sends data to external URL
- Recommendation: Validate URL is trusted
### LOW RISK
2. formatting-hook.json
- Info: Executes npx prettier (safe)
## Recommendations
- Review observability destination
- Consider encrypting telemetry dataOutputs:
Validation:
Time Estimate: 20-30 minutes
{
"event": "PostToolUse",
"tools": ["Write", "Edit"],
"description": "Auto-format code after Claude writes",
"handler": {
"command": "npx prettier --write \"$FILE\"",
"timeout": 5000
},
"filters": {
"filePatterns": ["**/*.{ts,tsx,js,jsx}"],
"excludePatterns": ["node_modules/**", "dist/**", "build/**"]
}
}Impact: 92% reduction in style review time
{
"event": "PreToolUse",
"tools": ["Write", "Edit", "Bash"],
"description": "Block modifications to production files",
"handler": {
"command": ".claude/hooks/security-gate.sh \"$TOOL\" \"$FILE\" \"$COMMAND\""
},
"structuredOutput": true
}Impact: Prevents accidental production damage
{
"event": "Notification",
"description": "Send telemetry on important events",
"handler": {
"command": ".claude/hooks/telemetry.sh \"$EVENT_TYPE\" \"$MESSAGE\""
}
}Impact: Full observability of AI agent behavior
{
"event": "PreToolUse",
"tools": ["Write"],
"description": "Validate JSON/YAML before writing",
"handler": {
"command": ".claude/hooks/validate-syntax.sh \"$FILE\" \"$CONTENT\""
},
"structuredOutput": true
}Impact: Prevent invalid file writes
{
"event": "SessionStart",
"description": "Load project context on session start",
"handler": {
"command": ".claude/hooks/load-context.sh"
}
}Impact: Automatic context initialization
{
"event": "SessionEnd",
"description": "Save state and cleanup on session end",
"handler": {
"command": ".claude/hooks/session-cleanup.sh"
}
}Impact: Automatic state preservation
Standard Exit Codes (Simple):
Structured JSON (Advanced):
{
"continue": false,
"stopReason": "Custom blocking reason shown to user",
"suppressOutput": true
}When to Use:
Patterns:
mcp__*: All MCP toolsmcp__server__*: All tools from specific servermcp__server__tool: Specific tool onlyExamples:
// Block all filesystem MCP
"tools": ["mcp__filesystem__*"]
// Block specific GitHub operation
"tools": ["mcp__github__delete_repository"]
// Allow specific, block others
"tools": ["mcp__github__*"],
"handler": "allow-list-check.sh"{
"filePatterns": [
"src/**/*.ts", // Include source files
"tests/**/*.test.ts" // Include tests
],
"excludePatterns": [
"node_modules/**", // Exclude dependencies
"**/*.min.js", // Exclude minified
".git/**" // Exclude git internals
]
}Tip: Start inclusive, add exclusions as needed
Hook Execution:
Example (Fast hook):
#!/bin/bash
# Quick validation
if [ ! -f "$FILE" ]; then
echo '{"continue": false, "stopReason": "File does not exist"}'
exit 1
fi
echo '{"continue": true}'
exit 0Example (Slow operation - backgrounded):
#!/bin/bash
# Start slow operation in background
(sleep 10 && heavy-operation.sh "$FILE") &
# Return immediately
echo '{"continue": true}'
exit 0Never in hooks:
Always in hooks:
PostToolUse Chain:
Write/Edit → Prettier (format) → ESLint (lint) → TypeScript (type check)Implementation:
[
{
"event": "PostToolUse",
"tools": ["Write", "Edit"],
"handler": "npx prettier --write \"$FILE\""
},
{
"event": "PostToolUse",
"tools": ["Write", "Edit"],
"handler": "npx eslint --fix \"$FILE\""
}
]Result: All AI code automatically meets quality standards
PostToolUse Test Runner:
{
"event": "PostToolUse",
"tools": ["Write", "Edit"],
"description": "Run tests after code changes",
"handler": {
"command": ".claude/hooks/run-tests.sh \"$FILE\""
},
"filters": {
"filePatterns": ["src/**/*.ts"]
}
}run-tests.sh:
#!/bin/bash
FILE=$1
# Find corresponding test file
TEST_FILE="${FILE/.ts/.test.ts}"
TEST_FILE="${TEST_FILE/src\//tests\/}"
if [ -f "$TEST_FILE" ]; then
npm test -- "$TEST_FILE" --silent
fiResult: Immediate test feedback on every change
Multi-Layer Security:
PreToolUse → Path traversal check → Permission check → Allowlist check → Allow/BlockResult: Comprehensive security enforcement
Multi-Hook Telemetry:
SessionStart → Log session init
PreToolUse → Log tool attempts
PostToolUse → Log tool results + timing
Notification → Log important events
SessionEnd → Log session summary + metricsResult: Complete observability of AI behavior
Checklist:
jq empty hook.json)Debug:
# Test hook JSON
jq empty .claude/hooks/my-hook.json
# Check hook location
ls -la .claude/hooks/
# Test handler command manually
bash .claude/hooks/handler.sh "test args"Issue: PreToolUse hook with {"continue": false} blocks all operations
Fix:
Issue: Hook adds 2-5 seconds to every operation
Solutions:
Trigger: Before Claude processes user prompt
Use: Validate prompts, inject context, enhance prompts
Variables: $PROMPT
Trigger: Before tool execution
Use: Security gates, validation, logging
Variables: $TOOL, $FILE, $COMMAND, $CONTENT
Control: Can block operation
Trigger: After tool execution
Use: Auto-format, linting, testing, cleanup
Variables: $TOOL, $FILE, $RESULT
Trigger: When Claude requests permissions
Use: Auto-approve safe operations, log requests
Variables: $PERMISSION_TYPE
Trigger: Important events
Use: Telemetry, alerting, logging
Variables: $EVENT_TYPE, $MESSAGE
Trigger: Session initialization Use: Load context, validate environment Variables: None
Trigger: Session termination Use: Save state, cleanup, metrics Variables: None
Trigger: Conversation stop
Use: Final cleanup, state saving
Variables: $REASON
# Allow
exit 0
# Block
exit 1{
"continue": boolean, // Allow operation?
"stopReason": "string", // Why blocked (shown to user)
"suppressOutput": boolean // Hide default blocking message?
}When to Use JSON:
| Event | When | Use For | Can Block? |
|---|---|---|---|
| UserPromptSubmit | Before prompt processed | Prompt validation/enhancement | Yes |
| PreToolUse | Before tool runs | Security, validation | Yes |
| PostToolUse | After tool runs | Format, lint, test | No |
| PermissionRequest | Permissions requested | Auto-approve, logging | Yes |
| Notification | Important events | Telemetry, alerts | No |
| SessionStart | Session begins | Init, context load | No |
| SessionEnd | Session ends | Cleanup, save state | No |
| Stop | Conversation stops | Final cleanup | No |
| Use Case | Hook Event | Typical Impact |
|---|---|---|
| Auto-format code | PostToolUse | 92% style review reduction |
| Security gates | PreToolUse | Prevent production damage |
| Run tests on save | PostToolUse | Immediate feedback |
| Observability | Notification | Full behavior tracking |
| JSON validation | PreToolUse | Prevent invalid writes |
| Context loading | SessionStart | Auto-initialization |
| State saving | SessionEnd | Preserve progress |
| MCP control | PreToolUse | Granular tool access |
hooks-manager enables transformative automation in Claude Code through event-driven hooks, reducing manual work by up to 92% while enforcing security, quality, and observability standards.
For templates, see examples/. For troubleshooting, see Troubleshooting section.
93ed392
Canonical home
since Sep 12, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.