Advanced Hook Development
Boost productivity using this skill, should, used, user. Includes structured workflows, validation checks, and reusable patterns for development.
Hook Development for Claude Code
A Claude Code skill for building event-driven automation hooks — scripts that execute in response to Claude Code events like tool calls, file changes, and code generation, enabling validation, logging, and custom workflows.
When to Use This Skill
Choose this skill when:
- Automating validation before file writes or commits
- Logging Claude Code actions for auditing or analytics
- Enforcing project-specific rules (no secrets, file naming, etc.)
- Running formatters or linters automatically after code generation
- Building custom integrations triggered by Claude Code events
- Adding pre/post hooks for any Claude Code tool execution
Consider alternatives when:
- You need git hooks specifically (use git hooks directly)
- You need CI/CD automation (use GitHub Actions)
- You need IDE-specific extensions (use VS Code extension API)
Quick Start
# Configure hooks in your settings claude settings
// .claude/settings.json { "hooks": { "PreToolUse": [ { "matcher": "Write|Edit", "command": "node .claude/hooks/validate-write.js $FILE_PATH" } ], "PostToolUse": [ { "matcher": "Write|Edit", "command": "npx prettier --write $FILE_PATH" } ], "Notification": [ { "matcher": ".*", "command": "node .claude/hooks/log-action.js" } ] } }
Core Concepts
Hook Event Types
| Event | Fires When | Common Use |
|---|---|---|
PreToolUse | Before a tool executes | Validate inputs, block operations |
PostToolUse | After a tool completes | Format code, run checks |
Notification | On any notable action | Logging, analytics |
Stop | Session ends | Cleanup, summary generation |
Hook Script Examples
// .claude/hooks/validate-write.js // Block writes to protected files const protectedFiles = ['.env', 'package-lock.json', 'credentials.json']; const filePath = process.argv[2]; if (protectedFiles.some(f => filePath.endsWith(f))) { console.error(`BLOCKED: Cannot modify protected file: ${filePath}`); process.exit(1); // Non-zero exit blocks the operation } process.exit(0); // Zero exit allows the operation
// .claude/hooks/auto-format.js // Auto-format files after write const { execSync } = require('child_process'); const filePath = process.argv[2]; if (filePath.match(/\.(ts|tsx|js|jsx)$/)) { execSync(`npx prettier --write "${filePath}"`, { stdio: 'inherit' }); } if (filePath.match(/\.(py)$/)) { execSync(`black "${filePath}"`, { stdio: 'inherit' }); }
// .claude/hooks/no-secrets.js // Scan for secrets before allowing writes const fs = require('fs'); const filePath = process.argv[2]; const content = fs.readFileSync(filePath, 'utf-8'); const secretPatterns = [ /sk[-_]live[-_][a-zA-Z0-9]{20,}/, // Stripe live keys /AKIA[0-9A-Z]{16}/, // AWS access keys /ghp_[a-zA-Z0-9]{36}/, // GitHub personal tokens /-----BEGIN (RSA )?PRIVATE KEY-----/, // Private keys ]; for (const pattern of secretPatterns) { if (pattern.test(content)) { console.error(`BLOCKED: Potential secret detected in ${filePath}`); process.exit(1); } }
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
matcher | string | ".*" | Regex pattern matching tool names to hook |
command | string | — | Shell command to execute (required) |
timeout | number | 10000 | Maximum execution time in milliseconds |
cwd | string | "." | Working directory for the hook command |
env | object | {} | Additional environment variables |
Available Environment Variables
| Variable | Description |
|---|---|
$TOOL_NAME | Name of the tool being executed |
$FILE_PATH | File path being read/written (if applicable) |
$SESSION_ID | Current Claude Code session identifier |
$PROJECT_DIR | Root directory of the project |
Best Practices
-
Keep hooks fast (under 2 seconds) — hooks run synchronously and block Claude Code execution; slow hooks degrade the interactive experience. Move heavy processing to background jobs.
-
Use non-zero exit codes to block operations — return
exit(1)from PreToolUse hooks to prevent the operation; returnexit(0)to allow it. Use stderr for error messages. -
Match specific tools, not everything — use precise matchers like
Write|Editinstead of.*to avoid running hooks on irrelevant operations. -
Test hooks in isolation before configuring — run the hook script manually with test inputs before adding it to settings; a broken hook can block all Claude Code operations.
-
Log actions to a file for debugging — PostToolUse hooks that append to a
.claude/hooks.logfile make it easy to review what happened during a session.
Common Issues
Hook blocks all operations unexpectedly — A bug in the hook script causes non-zero exit on valid operations. Test with specific file paths and tool names. Add error handling so the hook fails gracefully.
Hook runs on wrong tool calls — The matcher regex is too broad. Use ^Write$ to match only the Write tool, not Write which would also match NotebookWrite or TodoWrite.
Hooks don't run in VS Code extension — Hooks configured in CLI settings may not apply in the VS Code extension. Verify the settings file location and ensure hooks are configured at the project level (.claude/settings.json).
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.