What Are Claude Code Stop Hooks and How Do They Work?
Problem
I kept forgetting to run the linter after Claude edited my code. Every time Claude finished writing a feature, I’d move on to the next task, only to discover linting errors later during CI. The back-and-forth was exhausting: “Claude, run the linter. Oh, there are errors. Fix them. Run it again.”
I needed a way to automate these follow-up actions. I didn’t want to manually request quality checks after every single Claude action.
Environment
- Claude Code CLI
- Node.js project with ESLint and Prettier configured
- macOS development environment
What Happened
I discovered Claude Code hooks while browsing Reddit. Someone mentioned they use “stop hooks” to automatically run linters after code changes. This sounded exactly like what I needed.
But the documentation was sparse. I tried configuring hooks in various places before understanding the correct structure.
My first attempt failed:
{ "stopHooks": { "afterEdit": ["npm run lint"] }}Nothing happened. Claude edited files, but no linter ran.
After digging through examples, I realized hooks are configured under a hooks object with specific action types. The correct structure uses PostToolUse for actions after tool execution.
Solution
The correct configuration looks like this:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": ["npm run lint", "npm run format"] } ] }}The key components:
PostToolUse- Hooks that run after a tool completesmatcher- Regex pattern matching tool names (EditandWritefor file changes)hooks- Array of commands to execute
For plan auditing, I added another hook:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": ["npm run lint", "npm run format"] }, { "matcher": "TodoWrite", "hooks": ["echo 'Plan created - check for edge cases'"] } ] }}Reason
Claude Code hooks work by intercepting tool execution at specific points:
- PreToolUse - Before a tool runs (for validation or parameter modification)
- PostToolUse - After a tool completes (for follow-up actions)
- Stop - When the session ends (for final verification)
When Claude uses a tool that matches the matcher pattern, the configured hooks execute automatically. This transforms the workflow:
Before hooks:
User: "Write a function"Claude: *writes code*User: "Run linter"Claude: *runs linter*User: "Fix errors"Claude: *fixes errors*User: "Run linter again"Claude: *runs linter*After hooks:
User: "Write a function"Claude: *writes code*[linter runs automatically, errors caught immediately]The cognitive load difference is significant. Instead of remembering to request follow-ups, the guardrails are just… there.
Common Hook Use Cases
| Hook Type | Matcher | Use Case |
|---|---|---|
| PostToolUse | Edit|Write | Lint/format after file changes |
| PostToolUse | Bash | Validate command output |
| Stop | * | Final audit before session ends |
Why This Matters
- Consistency - Hooks run every time, no exceptions
- Reduced Context Switching - No mental overhead for routine checks
- Quality Enforcement - Impossible to forget linting or testing
- Workflow Automation - Manual back-and-forth becomes automatic pipeline
The Reddit thread that started this journey had a great summary: “It turns a back-and-forth workflow into something that is less demanding. You set it once and the guardrails are just… there.”
Summary
Claude Code stop hooks automate repetitive follow-up tasks. Configure them once in ~/.claude/settings.json to run linters, tests, or validations automatically after Claude completes actions.
The setup requires:
hooksobject with action types (PostToolUse,PreToolUse,Stop)matcherregex to target specific toolshooksarray with commands to execute
This transforms Claude from a smart autocomplete into a reliable collaborator with built-in quality checks.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments