Claude Code hooks: auto-lint, auto-test, and self-healing loops
One of Claude Code's most underused features is hooks — shell commands that run automatically before or after Claude takes actions.
Set them up once. Get clean, tested code every session.
What are Claude Code hooks?
Hooks are shell commands defined in your settings.json that Claude Code runs at specific lifecycle events:
- PreToolUse — before Claude reads/writes a file
- PostToolUse — after Claude writes a file
- Stop — when Claude finishes a response
This means you can attach lint, format, and test commands to fire automatically.
Setup: where hooks live
Global hooks (all projects):
~/.claude/settings.json
Project hooks (this repo only):
.claude/settings.json
Example 1: Auto-format after every file write
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "prettier --write $CLAUDE_TOOL_INPUT_PATH 2>/dev/null || true"
}
]
}
]
}
}
Every file Claude writes gets formatted. No more manual prettier runs.
Example 2: Auto-lint and fix on save
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "eslint --fix $CLAUDE_TOOL_INPUT_PATH 2>/dev/null || true"
}
]
}
]
}
}
Claude writes a file → ESLint fixes it immediately → Claude's next read sees the clean version.
Example 3: Run tests automatically after edits
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "cd $(git rev-parse --show-toplevel) && npm test -- --testPathPattern=$(basename $CLAUDE_TOOL_INPUT_PATH) 2>&1 | tail -20"
}
]
}
]
}
}
Claude edits a file → tests for that file run → output appears in Claude's context → Claude sees failures and fixes them automatically.
This is the self-healing loop.
Example 4: The full auto-pilot stack
Combine all three:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "prettier --write $CLAUDE_TOOL_INPUT_PATH 2>/dev/null || true && eslint --fix $CLAUDE_TOOL_INPUT_PATH 2>/dev/null || true"
},
{
"type": "command",
"command": "cd $(git rev-parse --show-toplevel) && npm test -- --testPathPattern=$(basename $CLAUDE_TOOL_INPUT_PATH) 2>&1 | tail -20"
}
]
}
]
}
}
Workflow:
- Claude writes a file
- Prettier formats it
- ESLint fixes style issues
- Tests run
- Output feeds back to Claude
- Claude fixes any failures
- Repeat until green
You watch. Code gets better.
Available hook variables
| Variable | Value |
|---|---|
$CLAUDE_TOOL_INPUT_PATH |
The file being read/written |
$CLAUDE_TOOL_NAME |
The tool being used (Write, Read, Bash, etc.) |
$CLAUDE_SESSION_ID |
Current session ID |
Stop hook: commit when done
Run a git commit automatically when Claude finishes:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "cd $(git rev-parse --show-toplevel) && git add -A && git diff --cached --quiet || git commit -m 'Claude Code session: $(date +%Y-%m-%d-%H%M)'"
}
]
}
]
}
}
Every completed Claude session = an automatic commit. Clean history.
Rate limits interrupt the loop
The hook loop breaks when Claude hits its rate limit mid-session.
Fix: point Claude at a proxy that removes rate limits.
export ANTHROPIC_BASE_URL=https://simplylouie.com/api/proxy
SimplyLouie routes your Claude Code traffic for ✌️$2/month (vs $20/month for Claude Pro). Rate limit interruptions disappear. Your hook loops keep running.
7-day free trial. Card required, not charged for 7 days.
Summary
| Hook type | When it fires | Best use |
|---|---|---|
PostToolUse: Write |
After every file write | Format, lint, test |
PreToolUse: Write |
Before every write | Validate, backup |
Stop |
Session ends | Commit, notify, summarize |
Hooks turn Claude Code from a chat assistant into a fully automated dev pipeline. Set them up once.
Running Claude Code? Try the self-healing test loop above. Hit rate limits before it completes? SimplyLouie fixes that for $2/month.
Top comments (0)