Claude Code Hooks Automation Guide: Automate Every Step of Your Workflow
Complete guide to Claude Code hooks — automate testing, linting, deployments, and notifications. With real-world hook recipes for pre-command, post-command, and pipeline integration.
What Are Claude Code Hooks?
Claude Code hooks are scripts that run automatically at specific points in your Claude Code session. They let you:
- Run tests before Claude edits files (pre-edit validation) - Auto-save session state (prevent data loss) - Send notifications when Claude finishes a task - Integrate with CI/CD (auto-deploy after changes) - Enforce code quality (lint on every write)
Think of them as git hooks for your AI coding session — they run automatically at key moments to enforce rules, save state, and trigger actions.
---
Hook Types and When They Fire
Claude Code supports these hooks, configured in .claude/settings.json:
{
"hooks": {
"preMessage": "pre-message-script.sh",
"postMessage": "post-message-script.sh",
"preToolUse": {
"Read": "pre-read-hook.sh",
"Edit": "pre-edit-hook.sh",
"Bash": "pre-bash-hook.sh"
},
"postToolUse": {
"Read": "post-read-hook.sh",
"Edit": "post-edit-hook.sh",
"Bash": "post-bash-hook.sh"
}
}
}
| Hook | When It Fires | Use Case |
|------|--------------|----------|
| preMessage | Before Claude responds | Log the user's input, set context |
| postMessage | After Claude responds | Save session, send notifications |
| preToolUse.Read | Before reading a file | Audit file access |
| preToolUse.Edit | Before editing a file | Run linter, check permissions |
| postToolUse.Edit | After editing a file | Auto-commit, run tests |
| preToolUse.Bash | Before running a command | Validate command safety |
| postToolUse.Bash | After running a command | Log output, notify |
---
Hook Recipe 1: Auto-Save Session State
Prevent data loss from crashes or context resets:
File: .claude/hooks/post-message.sh
#!/bin/bash
# Auto-save session state after every message
SESSION_LOG=".claude/session-log.md"# Copy the log if it exists
if [ -f "$SESSION_LOG" ]; then
cp "$SESSION_LOG" ".claude/backups/$(date +%Y%m%d-%H%M%S).md"
fi
Config:
{
"hooks": {
"postMessage": ".claude/hooks/post-message.sh"
}
}
> 💡 Pro tip: Create the backup directory: mkdir -p .claude/backups
---
Hook Recipe 2: Auto-Run Tests After Changes
Ensure Claude doesn't break your code:
File: .claude/hooks/post-edit.sh
#!/bin/bash
# Run tests after every file edit# Only run if package.json exists (JS/TS project)
if [ -f "package.json" ]; then
# Run relevant tests — adjust for your test runner
if grep -q '"test"' package.json 2>/dev/null; then
npm test -- --changedSince=HEAD 2>&1 | tail -20
fi
fi
Config:
{
"hooks": {
"postToolUse": {
"Edit": ".claude/hooks/post-edit.sh"
}
}
}
> ⚠️ Caution: Running full test suites on every edit can slow Claude significantly. Use --changedSince=HEAD or target specific test files.
---
Hook Recipe 3: Enforce Code Style on Every Edit
Auto-format code before Claude commits changes:
File: .claude/hooks/pre-edit.sh
#!/bin/bash
# Run linter on files before Claude edits them
# Collects pre-edit lint errors for comparisonTARGET_FILE=$(echo "$@" | grep -oP '(?<=")[^"]+(?=")' | head -1)
if [ -n "$TARGET_FILE" ] && [ -f "$TARGET_FILE" ]; then
echo "Pre-edit lint check: $TARGET_FILE"
npx eslint "$TARGET_FILE" 2>/dev/null || true
fi
Config:
{
"hooks": {
"preToolUse": {
"Edit": ".claude/hooks/pre-edit.sh"
}
}
}
---
Hook Recipe 4: Slack/Telegram Notifications
Get notified when Claude completes a long task:
File: .claude/hooks/post-message-notify.sh
#!/bin/bash
# Send notification for completed tasks
# Requires a webhook URL in .envif [ -f ".env" ]; then
source .env
fi
WEBHOOK_URL="${SLACK_WEBHOOK_URL:-$TELEGRAM_WEBHOOK_URL}"
if [ -n "$WEBHOOK_URL" ]; then
curl -s -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"text\": \"✅ Claude Code completed work in $(pwd)\"}" &
fi
External Links: - Slack Incoming Webhooks - Telegram Bot API
---
Hook Recipe 5: Auto-Commit Changes
Create automatic checkpoints:
File: .claude/hooks/auto-commit.sh
#!/bin/bash
# Auto-commit changes with a descriptive message# Check if there are changes to commit
if [ -n "$(git status --porcelain)" ]; then
git add -A
git commit -m "🤖 Claude Code checkpoint: $(date '+%Y-%m-%d %H:%M')" \
--no-verify 2>/dev/null || true
fi
Config:
{
"hooks": {
"postToolUse": {
"Edit": ".claude/hooks/auto-commit.sh"
}
}
}
> ⚠️ Caution: Auto-committing can clutter your git history. Use sparingly — every 5-10 edits, not every single one.
---
Hook Recipe 6: Safety Check for Sensitive Operations
Prevent accidental rm -rf or git pushes to main:
File: .claude/hooks/pre-bash.sh
#!/bin/bash
# Safety checks before dangerous commandsCOMMAND="$*"
# Block dangerous commands
if echo "$COMMAND" | grep -qE "rm -rf /|:(){ :\|:& };:"; then
echo "⛔ Blocked: potentially dangerous command detected"
exit 1
fi
# Warn on git push to main
if echo "$COMMAND" | grep -qE "git push origin main"; then
echo "⚠️ Warning: Pushing to main branch!"
echo "Are you sure? (yes/no)"
read -r response
if [ "$response" != "yes" ]; then
echo "Push cancelled"
exit 1
fi
fi
Config:
{
"hooks": {
"preToolUse": {
"Bash": ".claude/hooks/pre-bash.sh"
}
}
}
---
Hook Recipe 7: Custom ESLint Rules File
Generate or update eslint config when project changes:
File: .claude/hooks/generate-eslint.sh
#!/bin/bash
# Generate project-specific eslint rules# If .eslintrc.json doesn't exist, create a starter
if [ ! -f ".eslintrc.json" ] && [ -f "package.json" ]; then
if grep -q "typescript" package.json 2>/dev/null; then
cat > .eslintrc.json << 'EOF'
{
"extends": ["next/core-web-vitals", "prettier"],
"rules": {
"no-unused-vars": "warn",
"no-console": "warn",
"@typescript-eslint/no-explicit-any": "warn"
}
}
EOF
fi
fi
---
Hook Recipe 8: Project Context Injection
Auto-inject relevant context before every message:
File: .claude/hooks/pre-message.sh
#!/bin/bash
# Inject project context from a context fileCONTEXT_FILE=".claude/context.md"
if [ -f "$CONTEXT_FILE" ]; then
echo "📋 Current context loaded from $CONTEXT_FILE"
fi
Create the context file:
# .claude/context.md
Current Sprint
Building payment integration (Sprint 4)Active Branch
feature/stripe-checkoutRelated Files
- src/app/api/stripe/create-checkout/route.ts
- src/components/CheckoutForm.tsx
- src/lib/stripe.ts
---
Setting Up Hooks: Step by Step
1. Create the Hooks Directory
mkdir -p .claude/hooks
mkdir -p .claude/backups
2. Create Your First Hook Script
cat > .claude/hooks/post-message.sh << 'EOF'
#!/bin/bash
echo "✅ Message processed at $(date)"
EOFchmod +x .claude/hooks/post-message.sh
3. Register the Hook
// .claude/settings.json
{
"hooks": {
"postMessage": ".claude/hooks/post-message.sh"
}
}
4. Test It
claude
> Hello
# You should see: ✅ Message processed at 2026-05-11 14:30:00
5. Debug Hooks
Hook output goes to stderr. Check Claude Code logs:
cat ~/.claude/logs/claude-code-*.log | grep -i hook
---
Best Practices
DO:
- ✅ Keep hooks fast — under 500ms if possible. Slow hooks make Claude feel sluggish. - ✅ Make hooks idempotent — running them multiple times should be safe. - ✅ Test hooks independently before registering them:bash .claude/hooks/post-message.sh
- ✅ Version control your hooks directory: commit .claude/hooks/ to git.
- ✅ Use conditional logic — only run tests if package.json exists.DON'T:
- ❌ Don't make hooks interactive — Claude can't answer prompts. - ❌ Don't use hooks to modify Claude's output — the hook is just a side-effect script. - ❌ Don't put secrets in hook scripts — use environment variables. - ❌ Don't modify files being edited during a pre-edit hook — this can cause race conditions.---
Hook Performance Budget
| Hook Type | Max Time | Impact on Claude | |-----------|----------|------------------| | preMessage | <500ms | Delays initial response | | postMessage | <2s | No delay (runs after response) | | preToolUse | <300ms | Delays tool execution | | postToolUse | <2s | No visible delay |
If your hook takes longer, run it in background:
# Background the expensive part:
( sleep 5 && npm test ) &
Related Articles: - Claude Code Memory Systems Explained — hooks can save session state - Claude Code Hooks vs MCP Servers — when to use each - 7 Ways to Speed Up Claude Code — hooks should be fast! - Agent Skills for Claude Code — extend Claude Code beyond hooks
Related Articles
Claude Code Hooks vs MCP Servers: When to Use Each
Understand the difference between Claude Code hooks and MCP servers. When to use each, how they work together, and real-world examples of both approaches.
GitHub Actions CI/CD for AI Coding Projects: Complete Setup Guide
Set up GitHub Actions CI/CD for projects built with AI coding tools. Covers automated testing, linting, type checking, deployment, and AI code review in your pipeline. Real examples included.
10 Productivity Hacks for Claude Code: Work Smarter, Not Harder
10 proven productivity techniques for Claude Code that save you hours each day. From prompt templates to keyboard shortcuts to workflow optimizations.