Claude Code: Hooks System
Last updated: 2026-08-31
Hooks let you insert custom logic at Claude Code's key points — auto-backup before modifications, auto-test before commits, auto-rollback on errors.
💡 Tip: Hooks are "interceptors" in Claude Code's lifecycle — you execute custom scripts when specific events occur, implementing automated workflows.
📋 Prerequisites: Chapter 17 - Output Styles
1. What You'll Learn
- Hook lifecycle and event types
- Built-in and custom hooks
- Hook configuration methods
- Practical scenarios
- Hook debugging and troubleshooting
2. Hook Lifecycle
(1) Event Types
| Event | Trigger Time | Common Use |
|---|---|---|
| before:prompt | Before processing user input | Input preprocessing |
| before:tool:write | Before writing file | Auto-backup |
| after:tool:write | After writing file | Auto-format |
| before:tool:bash | Before executing command | Security check |
| after:tool:bash | After executing command | Result post-processing |
| after:response | After generating response | Send notification |
(2) Hook Context
Each hook receives a context object with event name, timestamp, file path, command, content, and session ID.
▶ Example 1: Hook Trigger Flow
TEXT
📖 Display only
> Modify src/auth/jwt.ts
Triggered hooks:
1. [before:tool:write] → Auto-backup jwt.ts
2. [File written]
3. [after:tool:write] → Run ESLint --fix
4. [before:tool:bash] → Check command safety
5. [Execute: npm test]
6. [after:tool:bash] → Parse test results
7. [after:response] → Send Slack notification
3. Hook Configuration
(1) Global Hook Configuration
JSON
// ~/.claude/hooks.json
{
"hooks": {
"before:tool:write": [
{
"name": "auto-backup",
"command": "cp ${filePath} ${filePath}.bak",
"enabled": true
}
],
"after:tool:write": [
{
"name": "auto-format",
"command": "npx prettier --write ${filePath}",
"enabled": true
}
]
}
}
(2) Project-Level Hooks
JSON
// .claude/hooks.json
{
"hooks": {
"before:tool:write": [
{
"name": "protect-config",
"condition": "filePath.endsWith('.env')",
"command": "echo 'Config file modification blocked' && exit 1",
"enabled": true
}
]
}
}
4. Practical Scenarios
▶ Example 2: Auto-Backup Hook
JSON
{
"hooks": {
"before:tool:write": [
{
"name": "git-backup",
"command": "git stash push -m 'auto-backup-before-claude' -- ${filePath} 2>/dev/null || true",
"enabled": true
}
]
}
}
▶ Example 3: Security Audit Hook
JSON
{
"hooks": {
"before:tool:bash": [
{
"name": "block-dangerous-commands",
"condition": "command.includes('rm -rf') || command.includes('DROP TABLE')",
"command": "echo '⚠️ Dangerous command blocked' && exit 1",
"enabled": true
}
]
}
}
▶ Example 4: Auto-Test Hook
JSON
{
"hooks": {
"after:tool:write": [
{
"name": "auto-test",
"condition": "filePath.includes('src/') && filePath.endsWith('.ts')",
"command": "npm test 2>&1 | tail -5",
"enabled": true
}
]
}
}
5. Hook Debugging
BASH
# Enable hook debugging
export CLAUDE_HOOK_DEBUG=1
# View hook execution logs
cat ~/.claude/hooks.log
# Temporarily disable all hooks
claude --no-hooks
Common Issues
| Problem | Cause | Solution |
|---|---|---|
| Hook not triggering | enabled: false | Check config |
| Hook errors | Command path issues | Use absolute paths |
| Hook slow | Script execution time | Async or simplify logic |
| Loop triggering | Hook triggers another hook | Add conditions to avoid |
6. Comprehensive Example: Complete Hook Solution
JSON
{
"hooks": {
"before:tool:write": [
{
"name": "auto-backup",
"command": "cp ${filePath} /tmp/claude-backup/$(basename ${filePath}).$(date +%s)",
"enabled": true
},
{
"name": "protect-env",
"condition": "filePath.endsWith('.env')",
"command": "echo '❌ Env file modification blocked' && exit 1",
"enabled": true
}
],
"after:tool:write": [
{
"name": "format",
"command": "npx prettier --write ${filePath} 2>/dev/null; npx eslint --fix ${filePath} 2>/dev/null; true",
"enabled": true,
"files": ["src/**/*.ts"]
}
],
"before:tool:bash": [
{
"name": "block-dangerous",
"condition": "command.match(/rm -rf|DROP|npm publish/)",
"command": "echo '⛔ Dangerous command blocked' && exit 1",
"enabled": true
}
]
}
}
❓ FAQ
Q Do hooks slow down Claude Code?
A Yes. Each hook executes a command; slow hooks noticeably impact experience. Keep hook scripts under 1 second.
Q Does hook failure block operations?
A before hooks that fail (exit 1) block operations; after hook failures don't affect completed operations.
Q Can hooks modify Claude Code's output?
A No. Hooks only perform side effects (backup, format, notify), not change returned content.
Q Hook vs Plugin?
A Hooks are lightweight event responses (execute commands); plugins are complete feature extensions (register tools, modify behavior). Simple needs: hooks; complex needs: plugins.
📖 Summary
- Hooks trigger custom logic at Claude Code lifecycle key points
- Core events: before/after:tool:write/read/bash
- Auto-backup, security audit, auto-format are most common scenarios
- before hook failure blocks operations; after hook failure doesn't
- Keep hooks fast (<1 second)
📝 Exercises
- Basic (⭐): Configure an after:tool:write hook that auto-runs Prettier on file modification.
- Intermediate (⭐⭐): Configure security hooks to block
rm -rfandnpm publish. - Advanced (⭐⭐⭐): Design complete hook solution covering backup, format, security check, and notification.