What are Claude Code Hooks?
Hooks are shell commands that Claude Code executes automatically before or after specific tool calls. They let you enforce coding standards, run tests, send notifications, or perform custom validation — without relying on Claude to remember. Hooks are harness-level automation: they run regardless of what Claude decides.
Answer-Ready: Claude Code Hooks automate shell commands before/after tool calls. Run linting on file writes, tests after changes, notifications on commits. Configured in settings.json. Harness-level enforcement — runs regardless of Claude's decisions. Essential for team standardization.
Best for: Teams wanting automated quality enforcement in Claude Code. Works with: Claude Code (all versions). Setup time: Under 5 minutes.
Hook Events
| Event | When It Fires | Use Case |
|---|---|---|
| PreToolUse | Before a tool runs | Validate, lint, backup |
| PostToolUse | After a tool runs | Test, notify, format |
| Notification | On status changes | Alerts, logging |
| Stop | When Claude stops | Summary, cleanup |
Matchers
Matchers filter which tool triggers the hook:
{
"hooks": {
"PreToolUse": [
{"matcher": "Write", "hooks": ["..."]},
{"matcher": "Edit", "hooks": ["..."]},
{"matcher": "Bash", "hooks": ["..."]}
]
}
}| Matcher | Triggers On |
|---|---|
Write |
File creation |
Edit |
File modification |
Bash |
Shell commands |
Read |
File reads |
* |
All tools |
Practical Examples
1. Auto-Lint on Write
{
"matcher": "Write",
"hooks": ["npx prettier --write $CLAUDE_FILE_PATH"]
}2. Run Related Tests
{
"matcher": "Edit",
"hooks": ["npm test -- --related $CLAUDE_FILE_PATH 2>&1 | tail -20"]
}3. Prevent Writes to Protected Files
{
"matcher": "Write",
"hooks": ["if echo $CLAUDE_FILE_PATH | grep -q '/vendor/'; then echo 'BLOCKED: Cannot write to vendor/' >&2; exit 1; fi"]
}4. TypeScript Type Check
{
"matcher": "Write",
"hooks": ["if echo $CLAUDE_FILE_PATH | grep -qE '\\.tsx?$'; then npx tsc --noEmit 2>&1 | head -20; fi"]
}5. Git Stage After Write
{
"matcher": "Write",
"hooks": ["git add $CLAUDE_FILE_PATH"]
}6. Notification on Completion
{
"hooks": {
"Stop": [
{"hooks": ["osascript -e 'display notification \"Claude Code finished\" with title \"Done\"'"]}
]
}
}Environment Variables
| Variable | Value |
|---|---|
$CLAUDE_FILE_PATH |
Path of the file being written/edited |
$CLAUDE_TOOL_NAME |
Name of the tool being called |
Hook Behavior
- Exit 0: Hook passed, tool proceeds
- Exit non-zero: Hook failed, tool is blocked (PreToolUse) or warning shown (PostToolUse)
- Stdout: Shown to Claude as feedback
- Stderr: Shown as warning/error
- Timeout: Hooks timeout after 30 seconds by default
Best Practices
- Keep hooks fast — They run on every tool call. Slow hooks kill productivity
- Use PreToolUse for blocking — Prevent bad writes before they happen
- Use PostToolUse for validation — Run tests after changes
- Filter with matchers — Don't run expensive hooks on Read operations
- Pipe output — Use
| head -20to limit verbose output - Test locally first — Run your hook command manually before configuring
Hooks vs CLAUDE.md
| Aspect | Hooks | CLAUDE.md |
|---|---|---|
| Type | Shell commands | Text instructions |
| Enforcement | Automatic (harness) | Advisory (Claude reads) |
| Reliability | 100% — always runs | Best effort |
| Use case | Linting, testing, blocking | Conventions, guidance |
FAQ
Q: Can hooks modify Claude's behavior? A: Hooks provide feedback via stdout/stderr. Claude sees this feedback and can adjust. PreToolUse hooks can block operations by exiting non-zero.
Q: Do hooks slow down Claude? A: Yes, hooks add latency. Keep them under 5 seconds. Use matchers to limit which tools trigger them.
Q: Can I use hooks for CI/CD-like workflows? A: Yes, PostToolUse hooks can run test suites, type checking, and linting after every change — like a local CI pipeline.