Live
Black Hat USADark ReadingBlack Hat AsiaAI BusinessOpenAI Is Bleeding Cash. Its Solution? Military Contracts. - jacobin.comGoogle News: OpenAI‘Cognitive Surrender’ Is a New and Useful Term for How AI Melts Brains - GizmodoGoogle News: AI‘Cognitive Surrender’ Is a New and Useful Term for How AI Melts BrainsGizmodoPositional Restructuring of System Prompts: Mitigating Transformer Attention Bias in Sub-Frontier Modelsdiscuss.huggingface.coNORD Drivesystems launches industrial gear units for the mining industryThe Robot ReportShould we be polite to voice assistants and AIs? - The GuardianGoogle News: AIUp to $200: Claude AI giving away free credits for Pro & Max users - NotebookcheckGoogle News: ClaudeAbu Dhabi’s Presight signs AI deals with three African nations - iAfrica.comGNews AI UAEHow an Anthropic's Claude Code leak became a "massive sharing party" - LinkedInGoogle News: ClaudeSilent killers : How AI start-ups are trying to solve one of the retail industry s biggest problemsCNBC Technology'Silent killers': How AI start-ups are trying to solve one of the retail industry's biggest problems - CNBCGoogle News: Generative AIHow the Amazon Echo learned to talk — and listenThe Verge AIBlack Hat USADark ReadingBlack Hat AsiaAI BusinessOpenAI Is Bleeding Cash. Its Solution? Military Contracts. - jacobin.comGoogle News: OpenAI‘Cognitive Surrender’ Is a New and Useful Term for How AI Melts Brains - GizmodoGoogle News: AI‘Cognitive Surrender’ Is a New and Useful Term for How AI Melts BrainsGizmodoPositional Restructuring of System Prompts: Mitigating Transformer Attention Bias in Sub-Frontier Modelsdiscuss.huggingface.coNORD Drivesystems launches industrial gear units for the mining industryThe Robot ReportShould we be polite to voice assistants and AIs? - The GuardianGoogle News: AIUp to $200: Claude AI giving away free credits for Pro & Max users - NotebookcheckGoogle News: ClaudeAbu Dhabi’s Presight signs AI deals with three African nations - iAfrica.comGNews AI UAEHow an Anthropic's Claude Code leak became a "massive sharing party" - LinkedInGoogle News: ClaudeSilent killers : How AI start-ups are trying to solve one of the retail industry s biggest problemsCNBC Technology'Silent killers': How AI start-ups are trying to solve one of the retail industry's biggest problems - CNBCGoogle News: Generative AIHow the Amazon Echo learned to talk — and listenThe Verge AI
AI NEWS HUBbyEIGENVECTOREigenvector

Claude Code hooks: auto-format, auto-test, and self-heal on every file save

Dev.to AIby brian austinApril 5, 20265 min read0 views
Source Quiz

Claude Code hooks: auto-format, auto-test, and self-heal on every file save Claude Code hooks let you run shell commands automatically at key moments in your session — before Claude reads a file, after it writes one, or when a tool call completes. This is how you build a self-healing loop where Claude formats, tests, and fixes code without you having to ask. What are hooks? Hooks are defined in your .claude/settings.json file. They fire at lifecycle events during Claude's execution. { "hooks" : { "PostToolUse" : [ { "matcher" : "Write|Edit|MultiEdit" , "hooks" : [ { "type" : "command" , "command" : "npm run lint --silent" } ] } ] } } Every time Claude writes or edits a file, this runs npm run lint automatically. Claude sees the output and fixes any lint errors before moving on. The four ho

Claude Code hooks: auto-format, auto-test, and self-heal on every file save

Claude Code hooks let you run shell commands automatically at key moments in your session — before Claude reads a file, after it writes one, or when a tool call completes. This is how you build a self-healing loop where Claude formats, tests, and fixes code without you having to ask.

What are hooks?

Hooks are defined in your .claude/settings.json file. They fire at lifecycle events during Claude's execution.

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [  {  "type": "command",  "command": "npm run lint --silent"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

Every time Claude writes or edits a file, this runs npm run lint automatically. Claude sees the output and fixes any lint errors before moving on.

The four hook events

Event When it fires

PreToolUse Before Claude calls a tool

PostToolUse After Claude calls a tool

Notification When Claude sends a notification

Stop When Claude finishes responding

Hook 1: Auto-format on write

This runs Prettier after every file write:

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [  {  "type": "command",  "command": "npx prettier --write $CLAUDE_TOOL_INPUT_FILE_PATH 2>/dev/null || true"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

$CLAUDE_TOOL_INPUT_FILE_PATH is the path of the file Claude just wrote. Prettier runs on exactly that file, not your whole project.

Hook 2: Auto-test on write

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [  {  "type": "command",  "command": "npm test -- --testPathPattern=$(basename $CLAUDE_TOOL_INPUT_FILE_PATH .ts) --passWithNoTests 2>&1 | tail -20"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

This runs tests related to whatever file Claude just edited. If the test fails, Claude sees the failure output and fixes it immediately — no prompting needed.

Hook 3: Type-check after every edit

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [  {  "type": "command",  "command": "npx tsc --noEmit 2>&1 | head -30"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

TypeScript errors appear after every file write. Claude catches type regressions the moment they happen, not at the end of a long session.

The full self-healing loop

Combine all three:

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [  {  "type": "command",  "command": "npx prettier --write $CLAUDE_TOOL_INPUT_FILE_PATH 2>/dev/null; npx tsc --noEmit 2>&1 | head -20; npm test -- --passWithNoTests 2>&1 | tail -10"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

Now every file write triggers:

  • Prettier formats it

  • TypeScript checks for type errors

  • Tests run and output the last 10 lines

Claude reads all of this output and continues fixing until everything is green.

Hook 4: Block dangerous commands

Use PreToolUse to prevent Claude from running commands you don't want:

{  "hooks": {  "PreToolUse": [  {  "matcher": "Bash",  "hooks": [  {  "type": "command",  "command": "echo $CLAUDE_TOOL_INPUT_COMMAND | grep -qE 'rm -rf|DROP TABLE|truncate' && echo 'BLOCKED: dangerous command' && exit 1 || exit 0"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

If the command matches a dangerous pattern, the hook exits with code 1 and Claude sees BLOCKED: dangerous command. The tool call is cancelled.

Hook 5: Notify when Claude finishes

{  "hooks": {  "Stop": [  {  "matcher": "",  "hooks": [  {  "type": "command",  "command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"' 2>/dev/null || notify-send 'Claude Code' 'Claude finished' 2>/dev/null || true"  }  ]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

Mac users get a system notification. Linux users get notify-send. You can step away from your desk and come back when Claude is done.

Where to put hooks

Project-level (applies to this repo only):

.claude/settings.json

Enter fullscreen mode

Exit fullscreen mode

Global (applies to all Claude Code sessions):

~/.claude/settings.json

Enter fullscreen mode

Exit fullscreen mode

Start with project-level. The commands will be different per project — your Python project's linter isn't the same as your Node project's linter.

Practical tip: keep hooks fast

Hooks run synchronously. If your test suite takes 3 minutes, don't run all tests on every write. Run only the test file matching the edited file:

npm test -- --testPathPattern=$(basename $CLAUDE_TOOL_INPUT_FILE_PATH .ts) --passWithNoTests 2>&1 | tail -10

Enter fullscreen mode

Exit fullscreen mode

Or run just the linter (fast) on write, and full tests only at Stop:

{  "hooks": {  "PostToolUse": [  {  "matcher": "Write|Edit|MultiEdit",  "hooks": [{"type": "command", "command": "npx prettier --write $CLAUDE_TOOL_INPUT_FILE_PATH 2>/dev/null"}]  }  ],  "Stop": [  {  "matcher": "",  "hooks": [{"type": "command", "command": "npm test 2>&1 | tail -20"}]  }  ]  } }

Enter fullscreen mode

Exit fullscreen mode

Rate limits break the loop

The self-healing loop depends on Claude staying in the session. If you hit Claude's rate limit mid-session, the loop breaks. You're back to manually running lint and tests.

The fix: set ANTHROPIC_BASE_URL to a proxy that removes rate limits.

export ANTHROPIC_BASE_URL=https://simplylouie.com claude

Enter fullscreen mode

Exit fullscreen mode

SimplyLouie is ✌️$2/month. The hooks loop runs uninterrupted — Claude writes, formats, tests, fixes, and finishes without hitting a wall.

Summary

Hook type Use for

PostToolUse + Write matcher Auto-format, auto-test, type-check

PreToolUse + Bash matcher Block dangerous commands

Stop Notifications, full test suite

Hooks turn Claude Code from an AI you prompt into a system that enforces quality automatically. Set them up once, forget about formatting and type errors forever.

Was this article helpful?

Sign in to highlight and annotate this article

AI
Ask AI about this article
Powered by Eigenvector · full article context loaded
Ready

Conversation starters

Ask anything about this article…

Daily AI Digest

Get the top 5 AI stories delivered to your inbox every morning.

Knowledge Map

Knowledge Map
TopicsEntitiesSource
Claude Code…claudeglobalclaude codeDev.to AI

Connected Articles — Knowledge Graph

This article is connected to other articles through shared AI topics and tags.

Knowledge Graph100 articles · 113 connections
Scroll to zoom · drag to pan · click to open

Discussion

Sign in to join the discussion

No comments yet — be the first to share your thoughts!