Use when creating Claude Code hooks - covers hook patterns, composition, testing, progressive enhancement from simple to advanced
/plugin marketplace add withzombies/hyperpowers/plugin install withzombies-hyper@withzombies-hyperThis skill inherits all available tools. When active, it can use any tool Claude has access to.
resources/hook-examples.mdresources/hook-patterns.mdresources/testing-hooks.md<skill_overview> Hooks encode business rules at application level; start with observation, add automation, enforce only when patterns clear. </skill_overview>
<rigidity_level> MEDIUM FREEDOM - Follow progressive enhancement (observe → automate → enforce) strictly. Hook patterns are adaptable, but always start non-blocking and test thoroughly. </rigidity_level>
<quick_reference>
| Phase | Approach | Example |
|---|---|---|
| 1. Observe | Non-blocking, report only | Log edits, display reminders |
| 2. Automate | Background tasks, non-blocking | Auto-format, run builds |
| 3. Enforce | Blocking only when necessary | Block dangerous ops, require fixes |
Most used events: UserPromptSubmit (before processing), Stop (after completion)
Critical: Start Phase 1, observe for a week, then Phase 2. Only add Phase 3 if absolutely necessary. </quick_reference>
<when_to_use> Use hooks for:
Never use hooks for:
<hook_lifecycle_events>
| Event | When Fires | Use Cases |
|---|---|---|
| UserPromptSubmit | Before Claude processes prompt | Validation, context injection, skill activation |
| Stop | After Claude finishes | Build checks, formatting, quality reminders |
| PostToolUse | After each tool execution | Logging, tracking, validation |
| PreToolUse | Before tool execution | Permission checks, validation |
| ToolError | When tool fails | Error handling, fallbacks |
| SessionStart | New session begins | Environment setup, context loading |
| SessionEnd | Session closes | Cleanup, logging |
| Error | Unhandled error | Error recovery, notifications |
| </hook_lifecycle_events> |
<progressive_enhancement>
Goal: Understand patterns before acting
Examples:
Duration: Observe for 1 week minimum
Goal: Automate tedious tasks
Examples:
Requirement: Fast (<2 seconds), non-blocking
Goal: Prevent errors, enforce standards
Examples:
Requirement: Only add when patterns clear from Phase 1-2 </progressive_enhancement>
<common_hook_patterns>
Problem: TypeScript errors left behind
Solution:
#!/bin/bash
# Stop hook - runs after Claude finishes
# Check modified repos
modified_repos=$(grep -h "edited" ~/.claude/edit-log.txt | cut -d: -f1 | sort -u)
for repo in $modified_repos; do
echo "Building $repo..."
cd "$repo" && npm run build 2>&1 | tee /tmp/build-output.txt
error_count=$(grep -c "error TS" /tmp/build-output.txt || echo "0")
if [ "$error_count" -gt 0 ]; then
if [ "$error_count" -ge 5 ]; then
echo "⚠️ Found $error_count errors - consider error-resolver agent"
else
echo "🔴 Found $error_count TypeScript errors:"
grep "error TS" /tmp/build-output.txt
fi
else
echo "✅ Build passed"
fi
done
Configuration:
{
"event": "Stop",
"command": "~/.claude/hooks/build-checker.sh",
"description": "Run builds on modified repos",
"blocking": false
}
Result: Zero errors left behind
Problem: Inconsistent formatting
Solution:
#!/bin/bash
# Stop hook - format all edited files
edited_files=$(tail -20 ~/.claude/edit-log.txt | grep "^/" | sort -u)
for file in $edited_files; do
repo_dir=$(dirname "$file")
while [ "$repo_dir" != "/" ]; do
if [ -f "$repo_dir/.prettierrc" ]; then
echo "Formatting $file..."
cd "$repo_dir" && npx prettier --write "$file"
break
fi
repo_dir=$(dirname "$repo_dir")
done
done
echo "✅ Formatting complete"
Result: All code consistently formatted
Problem: Claude forgets error handling
Solution:
#!/bin/bash
# Stop hook - gentle reminder
edited_files=$(tail -20 ~/.claude/edit-log.txt | grep "^/")
risky_patterns=0
for file in $edited_files; do
if grep -q "try\|catch\|async\|await\|prisma\|router\." "$file"; then
((risky_patterns++))
fi
done
if [ "$risky_patterns" -gt 0 ]; then
cat <<EOF
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 ERROR HANDLING SELF-CHECK
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️ Risky Patterns Detected
$risky_patterns file(s) with async/try-catch/database operations
❓ Did you add proper error handling?
❓ Are errors logged appropriately?
💡 Consider: Sentry.captureException(), proper logging
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF
fi
Result: Claude self-checks without blocking
See: hyperpowers:skills-auto-activation for complete implementation
Summary: Analyzes prompt keywords, injects skill activation reminder before Claude processes. </common_hook_patterns>
<hook_composition>
Multiple hooks for same event run in alphabetical order by filename.
Use numeric prefixes:
hooks/
├── 00-log-prompt.sh # First (logging)
├── 10-inject-context.sh # Second (context)
├── 20-activate-skills.sh # Third (skills)
└── 99-notify.sh # Last (notifications)
If Hook B depends on Hook A's output:
Example:
# 10-track-edits.sh writes to edit-log.txt
# 20-check-builds.sh reads from edit-log.txt
</hook_composition>
<testing_hooks>
# Manually trigger
bash ~/.claude/hooks/build-checker.sh
# Check exit code
echo $? # 0 = success
# Create mock log
echo "/path/to/test/file.ts" > /tmp/test-edit-log.txt
# Run with test data
EDIT_LOG=/tmp/test-edit-log.txt bash ~/.claude/hooks/build-checker.sh
Enable logging:
set -x # Debug output
exec 2>~/.claude/hooks/debug.log
Check execution:
tail -f ~/.claude/logs/hooks.log
Common issues:
#!/bin/bash npm run build
if [ $? -ne 0 ]; then echo "BUILD FAILED - BLOCKING" exit 1 # Blocks Claude fi </code>
<why_it_fails>
#!/bin/bash
# Non-blocking observation
npm run build 2>&1 | tee /tmp/build.log
if grep -q "error TS" /tmp/build.log; then
echo "🔴 Build errors found (not blocking)"
fi
After 1 week, review:
Phase 2: If errors are frequent, automate
#!/bin/bash
# Still non-blocking, but more helpful
npm run build 2>&1 | tee /tmp/build.log
error_count=$(grep -c "error TS" /tmp/build.log || echo "0")
if [ "$error_count" -ge 5 ]; then
echo "⚠️ $error_count errors - consider using error-resolver agent"
elif [ "$error_count" -gt 0 ]; then
echo "🔴 $error_count errors (not blocking):"
grep "error TS" /tmp/build.log | head -5
fi
Phase 3: Only if observation shows blocking is necessary
Never reached - non-blocking works fine!
What you gain:
npm test
npm run lint
npm run build
<why_it_fails>
#!/bin/bash
# Stop hook - fast checks only
# Quick syntax check (< 1 second)
npm run check-syntax
if [ $? -ne 0 ]; then
echo "🔴 Syntax errors found"
echo "💡 Run 'npm test' manually for full test suite"
fi
echo "✅ Quick checks passed (run 'npm test' for full suite)"
Or run slow checks in background:
#!/bin/bash
# Stop hook - trigger background job
# Start tests in background
(
npm test > /tmp/test-results.txt 2>&1
if [ $? -ne 0 ]; then
echo "🔴 Tests failed (see /tmp/test-results.txt)"
fi
) &
echo "⏳ Tests running in background (check /tmp/test-results.txt)"
What you gain:
file=$(tail -1 ~/.claude/edit-log.txt) prettier --write "$file" </code>
<why_it_fails>
#!/bin/bash
set -euo pipefail # Exit on error, undefined vars
# Log execution
echo "[$(date)] Hook started" >> ~/.claude/hooks/formatter.log
# Validate input
if [ ! -f ~/.claude/edit-log.txt ]; then
echo "[$(date)] ERROR: edit-log.txt not found" >> ~/.claude/hooks/formatter.log
exit 1
fi
file=$(tail -1 ~/.claude/edit-log.txt | grep "^/.*\.ts$")
if [ -z "$file" ]; then
echo "[$(date)] No TypeScript file to format" >> ~/.claude/hooks/formatter.log
exit 0
fi
if [ ! -f "$file" ]; then
echo "[$(date)] ERROR: File not found: $file" >> ~/.claude/hooks/formatter.log
exit 1
fi
# Check prettier exists
if ! command -v prettier &> /dev/null; then
echo "[$(date)] ERROR: prettier not installed" >> ~/.claude/hooks/formatter.log
exit 1
fi
# Format
echo "[$(date)] Formatting: $file" >> ~/.claude/hooks/formatter.log
if prettier --write "$file" 2>&1 | tee -a ~/.claude/hooks/formatter.log; then
echo "✅ Formatted $file"
else
echo "🔴 Formatting failed (see ~/.claude/hooks/formatter.log)"
fi
What you gain:
❌ Don't:
# DANGEROUS - executes arbitrary code
cmd=$(tail -1 ~/.claude/edit-log.txt)
eval "$cmd"
✅ Do:
# SAFE - validates and sanitizes
file=$(tail -1 ~/.claude/edit-log.txt | grep "^/.*\.ts$")
if [ -f "$file" ]; then
prettier --write "$file"
fi
</security>
<critical_rules>
All of these mean: STOP. Follow progressive enhancement.
<verification_checklist> Before deploying hook:
Can't check all boxes? Return to development and fix. </verification_checklist>
<integration> **This skill covers:** Hook creation and patternsRelated skills:
Hook patterns support:
Official documentation:
When stuck:
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.