Hooks System Intermediate
Hooks let you run shell commands automatically when specific events occur in Claude Code. They are the simplest way to extend Claude Code's behavior without writing complex integrations.
Hook Types
| Hook | When It Fires | Use Cases |
|---|---|---|
| preToolUse | Before Claude executes a tool | Validation, blocking dangerous operations, logging |
| postToolUse | After Claude executes a tool | Auto-formatting, linting, notifications |
| afterMessage | After Claude sends a complete response | Logging, analytics, follow-up actions |
| notification | When Claude generates a notification | Desktop notifications, Slack alerts |
Hook Configuration
Hooks are configured in your Claude Code settings file. You can set them at the user or project level:
{
"hooks": {
"postToolUse": [
{
"matcher": "Write",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
}
{
"hooks": {
"postToolUse": [
{
"matcher": "Write",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\""
},
{
"matcher": "Edit",
"command": "npx eslint --fix \"$CLAUDE_FILE_PATH\""
}
],
"afterMessage": [
{
"command": "echo \"$(date): Claude responded\" >> .claude/activity.log"
}
],
"notification": [
{
"command": "notify-send 'Claude Code' \"$CLAUDE_NOTIFICATION\""
}
]
}
}
Matchers
Matchers filter which tool invocations trigger a hook. Without a matcher, the hook fires for every tool use:
# Match a specific tool "matcher": "Write" → fires only for the Write tool "matcher": "Edit" → fires only for the Edit tool "matcher": "Bash" → fires only for the Bash tool # Match file patterns (in the tool's arguments) "matcher": "*.ts" → fires for TypeScript files "matcher": "*.py" → fires for Python files "matcher": "src/**/*.js" → fires for JS files in src/
Practical Examples
Auto-Format After Edit
{
"hooks": {
"postToolUse": [
{
"matcher": "Write",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
},
{
"matcher": "Edit",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\""
}
]
}
}
Lint After Code Changes
{
"hooks": {
"postToolUse": [
{
"matcher": "Write",
"command": "npx eslint \"$CLAUDE_FILE_PATH\" --fix --quiet 2>/dev/null || true"
}
]
}
}
Desktop Notifications
{
"hooks": {
"notification": [
{
"command": "osascript -e 'display notification \"$CLAUDE_NOTIFICATION\" with title \"Claude Code\"'"
}
]
}
}
Activity Logging
{
"hooks": {
"postToolUse": [
{
"command": "echo \"$(date -Iseconds) | Tool: $CLAUDE_TOOL_NAME | File: $CLAUDE_FILE_PATH\" >> /tmp/claude-activity.log"
}
]
}
}
&.
- The command works when run manually in the terminal
- The matcher string matches the expected tool name exactly
- Environment variables like
$CLAUDE_FILE_PATHare available - The settings.json is valid JSON (use a JSON validator)
Ready to Go Deeper?
Live instructor-led courses from our partners. Affiliate disclosure.
AI & ML Courses - 30% Off
Live instructor-led AI, machine learning, data science, and cloud courses for working professionals. Use code Limited30 at checkout.
EdurekaDataCamp - AI & Data Science
Hands-on Python, machine learning, and AI courses with interactive exercises and real projects.
DataCampedX - Top AI Courses
University-level AI courses from MIT, Harvard, Stanford. Earn certificates that employers recognize.
edX