- Add claude-howto-logo.svg to 12 README files across the project - Use appropriate relative paths for different directory levels - Include new memory guide screenshots - Add personal CLAUDE.md configuration 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Hooks
Hooks are event-driven shell commands that execute automatically in response to Claude Code events. They enable automation, validation, and custom workflows without manual intervention.
Overview
Hooks are shell commands that execute automatically in response to specific events in Claude Code. They enable custom workflows, validation, and automation. Hooks are triggered by:
- Pre-hooks: Run before an action
- Post-hooks: Run after an action
- Validation hooks: Check conditions before proceeding
Hooks enable you to automate repetitive tasks, enforce code quality standards, and create seamless development workflows.
Hook Types
| Hook Type | Event | Use Cases |
|---|---|---|
| Tool Hooks | PreToolUse:, PostToolUse: | Auto-formatting, validation, logging |
| Session Hooks | UserPromptSubmit, SessionStart, SessionEnd | Input validation, initialization, cleanup |
| Git Hooks | PreCommit, PostCommit, PrePush | Testing, linting, notifications |
Available Hook Types (Detailed)
1. Tool Hooks
Execute before/after tool usage:
PreToolUse:{ToolName}- Before a tool is usedPostToolUse:{ToolName}- After a tool completes- Examples:
PreToolUse:Edit,PostToolUse:Bash,PreToolUse:Write
2. Session Hooks
Execute during session lifecycle:
UserPromptSubmit- Before processing user inputSessionStart- When a new session beginsSessionEnd- When a session ends
3. Git Hooks
Execute during git operations:
PreCommit- Before creating a commitPostCommit- After commit completesPrePush- Before pushing to remote
Common Hooks
# Pre-commit hook - run tests
PreCommit: "npm test"
# Post-write hook - format code
PostToolUse:Write: "prettier --write ${file_path}"
# Pre-tool-use hook - validate
PreToolUse:Edit: "eslint ${file_path}"
# User prompt validation
UserPromptSubmit: "~/.claude/hooks/validate-prompt.sh"
Hook Variables
Available variables in hook commands:
${file_path}- Path to file being edited/written${command}- Command being executed (Bash hooks)${tool_name}- Name of the tool being used${session_id}- Current session identifier
Configuration
Hooks are configured in Claude Code settings:
{
"hooks": {
"PreToolUse:Edit": "eslint --fix ${file_path}",
"PostToolUse:Bash": "echo 'Command completed' >> /tmp/bash.log",
"UserPromptSubmit": "~/.claude/hooks/validate-prompt.sh",
"PreCommit": "npm test"
}
}
Examples
Example 1: Auto-format Code on Edit
Hook: PreToolUse:Write
#!/bin/bash
# ~/.claude/hooks/format-code.sh
FILE=$1
# Detect file type and format accordingly
case "$FILE" in
*.js|*.jsx|*.ts|*.tsx)
prettier --write "$FILE"
;;
*.py)
black "$FILE"
;;
*.go)
gofmt -w "$FILE"
;;
esac
Configuration:
{
"hooks": {
"PreToolUse:Write": "~/.claude/hooks/format-code.sh ${file_path}"
}
}
Example 2: Run Tests Before Commit
Hook: PreCommit
#!/bin/bash
# ~/.claude/hooks/pre-commit.sh
echo "Running tests before commit..."
# Run tests
npm test
# Check exit code
if [ $? -ne 0 ]; then
echo "❌ Tests failed! Commit blocked."
exit 1
fi
echo "✅ Tests passed! Proceeding with commit."
exit 0
Configuration:
{
"hooks": {
"PreCommit": "~/.claude/hooks/pre-commit.sh"
}
}
Example 3: Security Scan on File Write
Hook: PostToolUse:Write
#!/bin/bash
# ~/.claude/hooks/security-scan.sh
FILE=$1
# Check for common security issues
if grep -q "password\s*=\s*['\"]" "$FILE"; then
echo "⚠️ WARNING: Potential hardcoded password detected in $FILE"
fi
if grep -q "api[_-]key\s*=\s*['\"]" "$FILE"; then
echo "⚠️ WARNING: Potential hardcoded API key detected in $FILE"
fi
# Scan with semgrep if available
if command -v semgrep &> /dev/null; then
semgrep --config=auto "$FILE" --quiet
fi
Configuration:
{
"hooks": {
"PostToolUse:Write": "~/.claude/hooks/security-scan.sh ${file_path}"
}
}
Example 4: Log All Bash Commands
Hook: PostToolUse:Bash
#!/bin/bash
# ~/.claude/hooks/log-bash.sh
COMMAND=$1
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
LOGFILE="$HOME/.claude/bash-commands.log"
echo "[$TIMESTAMP] $COMMAND" >> "$LOGFILE"
Configuration:
{
"hooks": {
"PostToolUse:Bash": "~/.claude/hooks/log-bash.sh '${command}'"
}
}
Example 5: Validate User Prompts
Hook: UserPromptSubmit
#!/bin/bash
# ~/.claude/hooks/validate-prompt.sh
# Read prompt from stdin
PROMPT=$(cat)
# Check for prohibited patterns
if echo "$PROMPT" | grep -qi "delete database"; then
echo "❌ Blocked: Dangerous operation detected"
exit 1
fi
# Check for required context
if echo "$PROMPT" | grep -qi "deploy to production"; then
if [ ! -f ".deployment-approved" ]; then
echo "❌ Blocked: Production deployment requires approval file"
exit 1
fi
fi
exit 0
Configuration:
{
"hooks": {
"UserPromptSubmit": "~/.claude/hooks/validate-prompt.sh"
}
}
Hook Exit Codes
Hooks communicate results via exit codes:
0- Success, continue operation1- Failure, block operation (for pre-hooks)- Other codes - Treated as warnings
Best Practices
Do's ✅
- Keep hooks fast (< 1 second)
- Use hooks for validation and automation
- Handle errors gracefully
- Use absolute paths
- Log important events
- Make hooks idempotent
- Test hooks independently before deploying
Don'ts ❌
- Make hooks interactive
- Use hooks for long-running tasks
- Hardcode credentials
- Ignore hook failures silently
- Modify files unexpectedly
Common Use Cases
Code Quality
{
"hooks": {
"PreToolUse:Write": "eslint --fix ${file_path}",
"PostToolUse:Write": "prettier --check ${file_path}"
}
}
Security
{
"hooks": {
"PostToolUse:Write": "~/.claude/hooks/security-scan.sh ${file_path}",
"PreCommit": "git secrets --scan"
}
}
Testing
{
"hooks": {
"PreCommit": "npm test",
"PostToolUse:Edit": "jest --findRelatedTests ${file_path}"
}
}
Deployment
{
"hooks": {
"PrePush": "npm run build && npm run test:e2e",
"PostPush": "~/.claude/hooks/notify-team.sh"
}
}
Debugging Hooks
Enable hook debugging:
{
"hooks": {
"debug": true
}
}
View hook execution logs:
tail -f ~/.claude/hooks.log
Installation Instructions
Step 1: Create Hooks Directory
mkdir -p ~/.claude/hooks
Step 2: Copy Example Hooks
cp 07-hooks/*.sh ~/.claude/hooks/
chmod +x ~/.claude/hooks/*.sh
Step 3: Configure in Settings
Edit ~/.claude/settings.json to add hook configurations:
{
"hooks": {
"PreToolUse:Write": "~/.claude/hooks/format-code.sh ${file_path}",
"PostToolUse:Write": "~/.claude/hooks/security-scan.sh ${file_path}",
"PreCommit": "~/.claude/hooks/pre-commit.sh",
"UserPromptSubmit": "~/.claude/hooks/validate-prompt.sh"
}
}
Step 4: Make Scripts Executable
chmod +x ~/.claude/hooks/*.sh
Step 5: Test Your Hooks
# Enable debug mode for testing
# Set "debug": true in hooks configuration
tail -f ~/.claude/hooks.log
Troubleshooting
Hook Not Executing
- Check hook path is correct
- Verify file has execute permissions
- Check hook name matches event exactly
- Enable debug mode
Hook Blocking Operations
- Check hook exit code
- Review hook output/logs
- Test hook independently
- Add error handling
Performance Issues
- Profile hook execution time
- Optimize slow operations
- Consider async execution
- Cache results when possible
Advanced Examples
See the example files in this directory:
format-code.sh- Auto-format code before writingpre-commit.sh- Run tests before commitssecurity-scan.sh- Scan for security issueslog-bash.sh- Log all bash commandsvalidate-prompt.sh- Validate user promptsnotify-team.sh- Send notifications on events
Related Concepts
For more information on related Claude Code features, see:
- Checkpoints and Rewind - Save and restore conversation state
- Custom Commands - Create custom slash commands
- Settings Configuration - Configure Claude Code behavior
- Advanced Features - Explore advanced Claude Code capabilities
- Main Concepts Guide - Complete reference documentation