Hooks Configuration Guide
This guide explains how to configure and customize the hooks system for your project.
Overview
Hooks Configuration Guide
This guide explains how to configure and customize the hooks system for your project.
Quick Start Configuration
1. Register Hooks in .claude/settings.json
Create or update .claude/settings.json in your project root:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/skill-activation-prompt.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-use-tracker.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-prettier-formatter.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-build-check-enhanced.sh"
},
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/error-handling-reminder.sh"
}
]
}
]
}
}
2. Install Dependencies
cd .claude/hooks
npm install
3. Set Execute Permissions
chmod +x .claude/hooks/*.sh
Customization Options
Project Structure Detection
By default, hooks detect these directory patterns:
Frontend: frontend/, client/, web/, app/, ui/
Backend: backend/, server/, api/, src/, services/
Database: database/, prisma/, migrations/
Monorepo: packages/*, examples/*
Adding Custom Directory Patterns
Edit .claude/hooks/post-tool-use-tracker.sh, function detect_repo():
case "$repo" in
# Add your custom directories here
my-custom-service)
echo "$repo"
;;
admin-panel)
echo "$repo"
;;
# ... existing patterns
esac
Build Command Detection
The hooks auto-detect build commands based on:
- Presence of
package.jsonwith "build" script - Package manager (pnpm > npm > yarn)
- Special cases (Prisma schemas)
Customizing Build Commands
Edit .claude/hooks/post-tool-use-tracker.sh, function get_build_command():
# Add custom build logic
if [[ "$repo" == "my-service" ]]; then
echo "cd $repo_path && make build"
return
fi
TypeScript Configuration
Hooks automatically detect:
tsconfig.jsonfor standard TypeScript projectstsconfig.app.jsonfor Vite/React projects
Custom TypeScript Configs
Edit .claude/hooks/post-tool-use-tracker.sh, function get_tsc_command():
if [[ "$repo" == "my-service" ]]; then
echo "cd $repo_path && npx tsc --project tsconfig.build.json --noEmit"
return
fi
Prettier Configuration
The prettier hook searches for configs in this order:
- Current file directory (walking upward)
- Project root
- Falls back to Prettier defaults
Custom Prettier Config Search
Edit .claude/hooks/stop-prettier-formatter.sh, function get_prettier_config():
# Add custom config locations
if [[ -f "$project_root/config/.prettierrc" ]]; then
echo "$project_root/config/.prettierrc"
return
fi
Error Handling Reminders
Configure file category detection in .claude/hooks/error-handling-reminder.ts:
function getFileCategory(filePath: string): 'backend' | 'frontend' | 'database' | 'other' {
// Add custom patterns
if (filePath.includes('/my-custom-dir/')) return 'backend';
// ... existing patterns
}
Error Threshold Configuration
Change when to recommend the auto-error-resolver agent.
Edit .claude/hooks/stop-build-check-enhanced.sh:
# Default is 5 errors - change to your preference
if [[ $total_errors -ge 10 ]]; then # Now requires 10+ errors
# Recommend agent
fi
Environment Variables
Global Environment Variables
Set in your shell profile (.bashrc, .zshrc, etc.):
# Disable error handling reminders
# Custom project directory (if not using default)
Per-Session Environment Variables
Set before starting Claude Code:
SKIP_ERROR_REMINDER=1 claude-code
Hook Execution Order
Stop hooks run in the order specified in settings.json:
"Stop": [
{
"hooks": [
{ "command": "...formatter.sh" }, // Runs FIRST
{ "command": "...build-check.sh" }, // Runs SECOND
{ "command": "...reminder.sh" } // Runs THIRD
]
}
]
Why this order matters:
- Format files first (clean code)
- Then check for errors
- Finally show reminders
Selective Hook Enabling
You don't need all hooks. Choose what works for your project:
Minimal Setup (Skill Activation Only)
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/skill-activation-prompt.sh"
}
]
}
]
}
}
Build Checking Only (No Formatting)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-use-tracker.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-build-check-enhanced.sh"
}
]
}
]
}
}
Formatting Only (No Build Checking)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-use-tracker.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-prettier-formatter.sh"
}
]
}
]
}
}
Cache Management
Cache Location
$CLAUDE_PROJECT_DIR/.claude/tsc-cache/[session_id]/
Manual Cache Cleanup
# Remove all cached data
rm -rf $CLAUDE_PROJECT_DIR/.claude/tsc-cache/*
# Remove specific session
rm -rf $CLAUDE_PROJECT_DIR/.claude/tsc-cache/[session-id]
Automatic Cleanup
The build-check hook automatically cleans up session cache on successful builds.
Troubleshooting Configuration
Hook Not Executing
- Check registration: Verify hook is in
.claude/settings.json - Check permissions: Run
chmod +x .claude/hooks/*.sh - Check path: Ensure
$CLAUDE_PROJECT_DIRis set correctly - Check TypeScript: Run
cd .claude/hooks && npx tscto check for errors
False Positive Detections
Issue: Hook triggers for files it shouldn't
Solution: Add skip conditions in the relevant hook:
# In post-tool-use-tracker.sh
if [[ "$file_path" =~ /generated/ ]]; then
exit 0 # Skip generated files
fi
Performance Issues
Issue: Hooks are slow
Solutions:
- Limit TypeScript checks to changed files only
- Use faster package managers (pnpm > npm)
- Add more skip conditions
- Disable Prettier for large files
# Skip large files in stop-prettier-formatter.sh
file_size=$(wc -c < "$file" 2>/dev/null || echo 0)
if [[ $file_size -gt 100000 ]]; then # Skip files > 100KB
continue
fi
Debugging Hooks
Add debug output to any hook:
# At the top of the hook script
set -x # Enable debug mode
# Or add specific debug lines
echo "DEBUG: file_path=$file_path" >&2
echo "DEBUG: repo=$repo" >&2
View hook execution in Claude Code's logs.
Advanced Configuration
Custom Hook Event Handlers
You can create your own hooks for other events:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/my-custom-bash-guard.sh"
}
]
}
]
}
}
Monorepo Configuration
For monorepos with multiple packages:
# In post-tool-use-tracker.sh, detect_repo()
case "$repo" in
packages)
# Get the package name
local package=$(echo "$relative_path" | cut -d'/' -f2)
if [[ -n "$package" ]]; then
echo "packages/$package"
else
echo "$repo"
fi
;;
esac
Docker/Container Projects
If your build commands need to run in containers:
# In post-tool-use-tracker.sh, get_build_command()
if [[ "$repo" == "api" ]]; then
echo "docker-compose exec api npm run build"
return
fi
Best Practices
- Start minimal - Enable hooks one at a time
- Test thoroughly - Make changes and verify hooks work
- Document customizations - Add comments to explain custom logic
- Version control - Commit
.claude/directory to git - Team consistency - Share configuration across team
See Also
- README.md - Hooks overview
- ../../docs/HOOKS_SYSTEM.md - Complete hooks reference
- ../../docs/SKILLS_SYSTEM.md - Skills integration