Claude Code Hooks Complete Guide¶
Update Information
Comprehensive guide covering Claude Code Hooks from basics to advanced usage, including differences from CLAUDE.md and practical implementation tips.
What You Can Achieve¶
Automation
Automate code formatting, test execution, and lint fixes
Quality Assurance
Automatically check and fix code quality issues
Error Prevention
Block dangerous commands or operations proactively
Efficiency
Reduce manual work and improve development speed
What are Claude Code Hooks?¶
Claude Code Hooks are a feature that automatically executes shell commands at specific points in Claude Code's lifecycle.
Traditional Problems¶
- Need to ask "please format this" repeatedly
- Claude sometimes forgets to apply rules
- Manual operations lead to mistakes and oversights
- Lack of consistency across team members
Solutions with Hooks¶
- Automatic execution: Reliable execution at specified timing
- Deterministic: Consistent behavior independent of AI judgment
- Uniformity: Same rules automatically applied across the entire team
Differences from CLAUDE.md¶
Comparison | Claude Code Hooks | CLAUDE.md |
---|---|---|
Purpose | Automation & Enforcement | Context Provision & Guidance |
Execution | Automatic shell command execution | Claude interprets & decides |
Reliability | 100% execution guaranteed | Uncertain if Claude follows |
Configuration | TOML configuration file | Markdown documentation |
Use Cases | Rule enforcement, workflow automation | Project knowledge, coding standards |
When to Use Each¶
Use Claude Code Hooks when: - You have processes that must always run - You want to automate quality checks - You need to block dangerous operations - You require CI/CD-like automation
Use CLAUDE.md when: - You want to share project-specific knowledge - You need to communicate coding styles - You want to document team conventions - You need to provide decision criteria to Claude
Basic Hook Configuration¶
Configuration File Location¶
Configure hooks in the .claude/settings.toml
file.
Basic Syntax¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = "black $CLAUDE_FILE_PATHS"
Available Events¶
- PreToolUse: Before tool execution
- PostToolUse: After tool execution
- Notification: On notification
- Stop: When response generation completes
Environment Variables¶
Claude Code provides several environment variables for use in hooks:
$CLAUDE_FILE_PATHS
: Paths of files being operated on$CLAUDE_TOOL_NAME
: Name of the tool being used$CLAUDE_WORKING_DIR
: Current working directory$CLAUDE_SESSION_ID
: Current session identifier
Practical Hook Examples¶
1. Python Code Formatting (Black)¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = "black $CLAUDE_FILE_PATHS"
Effect: Automatically formats Python files after editing
2. JavaScript/TypeScript Formatting (Prettier)¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.js", "*.ts", "*.tsx", "*.jsx"]
command = "prettier --write $CLAUDE_FILE_PATHS"
3. Rust Code Formatting¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.rs"]
command = "rustfmt $CLAUDE_FILE_PATHS"
4. Git Auto-commit¶
[[hooks]]
event = "Stop"
run_in_background = false
command = "git add . && git commit -m 'Auto-commit via Claude Code'"
Effect: Automatically commits all changes when Claude completes
5. Test Execution¶
[[hooks]]
event = "PostToolUse"
run_in_background = true
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.py", "tests/**/*.py"]
command = "python -m pytest tests/ -v"
Effect: Runs tests in background when Python files are modified
6. Lint Checking¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = "flake8 $CLAUDE_FILE_PATHS || echo 'Lint errors found'"
7. Blocking Dangerous Commands¶
[[hooks]]
event = "PreToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "bash"
command = '''
if echo "$CLAUDE_COMMAND" | grep -E "(rm -rf|sudo|chmod 777)" > /dev/null; then
echo "❌ Dangerous command blocked"
exit 1
fi
'''
Effect: Prevents execution of potentially dangerous commands
Advanced Configuration¶
1. Conditional Execution¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = '''
if [ -f "requirements.txt" ]; then
black $CLAUDE_FILE_PATHS
isort $CLAUDE_FILE_PATHS
echo "✅ Python code formatted"
else
echo "⚠️ No requirements.txt found, skipping format"
fi
'''
2. Multi-language Support¶
# Python formatting
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = "black $CLAUDE_FILE_PATHS && isort $CLAUDE_FILE_PATHS"
# JavaScript formatting
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.js", "*.ts"]
command = "prettier --write $CLAUDE_FILE_PATHS"
# Go formatting
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.go"]
command = "go fmt $CLAUDE_FILE_PATHS"
3. Complex Workflow¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.py"]
command = '''
echo "🔄 Starting Python workflow..."
# Format code
black $CLAUDE_FILE_PATHS
isort $CLAUDE_FILE_PATHS
# Run type checking
mypy $CLAUDE_FILE_PATHS || echo "Type check warnings found"
# Run tests
python -m pytest tests/ -x
# Security check
bandit -r $CLAUDE_FILE_PATHS
echo "✅ Python workflow completed"
'''
Development Environment-Specific Hooks¶
For Django Projects¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*/models.py", "*/migrations/*.py"]
command = '''
echo "🔄 Django workflow started..."
# Format code
black $CLAUDE_FILE_PATHS
# Check migrations
python manage.py makemigrations --check --dry-run
# Run Django system checks
python manage.py check
echo "✅ Django workflow completed"
'''
For React Projects¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.tsx", "src/**/*.jsx", "src/**/*.ts", "src/**/*.js"]
command = '''
echo "🔄 React workflow started..."
# Format code
prettier --write $CLAUDE_FILE_PATHS
# Lint check
eslint $CLAUDE_FILE_PATHS --fix
# Type check (if TypeScript)
if [ -f "tsconfig.json" ]; then
npx tsc --noEmit
fi
echo "✅ React workflow completed"
'''
For Rust Projects¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.rs", "Cargo.toml"]
command = '''
echo "🔄 Rust workflow started..."
# Format code
cargo fmt
# Lint check
cargo clippy -- -D warnings
# Build check
cargo check
echo "✅ Rust workflow completed"
'''
Best Practices¶
1. Performance Considerations¶
- Use
run_in_background = true
for long-running tasks - Combine multiple quick operations in one hook
- Avoid hooks that significantly slow down development
2. Error Handling¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = '''
if black $CLAUDE_FILE_PATHS; then
echo "✅ Code formatted successfully"
else
echo "❌ Formatting failed, please check syntax"
exit 1
fi
'''
3. Logging and Debugging¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = '''
echo "$(date): Formatting $CLAUDE_FILE_PATHS" >> .claude/format.log
black $CLAUDE_FILE_PATHS
echo "$(date): Formatting completed" >> .claude/format.log
'''
4. Team Configuration¶
Create a shared .claude/settings.toml
template:
# Team-wide hooks configuration
# Copy this to your project and customize as needed
# Universal code formatting
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
command = "black $CLAUDE_FILE_PATHS && isort $CLAUDE_FILE_PATHS"
# Security checks
[[hooks]]
event = "PreToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "bash"
command = '''
if echo "$CLAUDE_COMMAND" | grep -E "(rm -rf /|sudo rm|chmod 777)" > /dev/null; then
echo "❌ Potentially dangerous command blocked by team policy"
exit 1
fi
'''
Troubleshooting¶
Common Issues¶
- Hook not executing
- Check file path matching in
file_paths
- Verify event type is correct
Ensure command has execution permissions
Command not found errors
- Check if required tools are installed
- Verify PATH environment variable
Use absolute paths if necessary
Performance issues
- Set
run_in_background = true
for slow commands - Reduce scope of file matching
- Combine multiple operations efficiently
Debugging Commands¶
# Check hook configuration
cat .claude/settings.toml
# Test command manually
black your_file.py
# Check available tools
which black prettier rustfmt
# View hook logs (if logging is configured)
tail -f .claude/hooks.log
Security Considerations¶
1. Command Injection Prevention¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["*.py"]
# Safe: Using predefined environment variables
command = "black $CLAUDE_FILE_PATHS"
# Unsafe: Don't use user input directly in commands
# command = "black $USER_INPUT" # ❌ Never do this
2. Restrict Execution Scope¶
[[hooks]]
event = "PostToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "edit_file"
file_paths = ["src/**/*.py"] # Specific to src directory only
command = "black $CLAUDE_FILE_PATHS"
3. Validate Commands¶
[[hooks]]
event = "PreToolUse"
run_in_background = false
[hooks.matcher]
tool_name = "bash"
command = '''
# Whitelist allowed commands
if echo "$CLAUDE_COMMAND" | grep -E "^(ls|cat|grep|find)" > /dev/null; then
echo "✅ Command allowed"
else
echo "❌ Command not in whitelist"
exit 1
fi
'''
Integration with CI/CD¶
GitHub Actions Integration¶
name: Claude Code Quality Check
on: [push, pull_request]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install black isort flake8
- name: Run same checks as Claude Hooks
run: |
black --check .
isort --check-only .
flake8 .
Pre-commit Integration¶
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
Conclusion¶
Claude Code Hooks provide powerful automation capabilities that:
- Ensure consistency across team development
- Reduce manual errors through automation
- Integrate seamlessly with existing workflows
- Scale effectively from individual to team use
By implementing hooks strategically, you can create a robust, automated development environment that maintains high code quality while improving developer productivity.