Hooks & Automation
What hooks are, the events that trigger them, practical examples you'll actually use, and how to configure them without breaking anything.
CLAUDE.md gives Claude instructions. Skills give Claude patterns. Hooks make things happen automatically — without you having to remember to ask.
The "Why First" Scenario
Every time Claude edits a file, you want it formatted consistently. Every time Claude writes a new component, you want the TypeScript types checked. Every time you start a session on the EduTrack project, you want Claude reminded to read the project brief.
You could include these instructions in every single prompt. "After you edit this file, also run Prettier. Oh and run the type check too. And don't forget to—"
Or you configure a hook once, and it happens automatically forever.
Hooks are shell commands that Claude Code runs at specific moments in its workflow — triggered by events, not by your reminders.
The Excel Analogy
In Excel, you can create macros that run automatically when certain events happen — a macro that runs when you open the file, another that runs when you save, another when a cell changes. You configure them once, and Excel handles them from then on.
Hooks are Claude Code's event macros. You define which event triggers the hook and which command runs. Claude Code handles the rest.
The Five Hook Events
| Event | When it fires |
|---|---|
PreToolUse | Just before Claude uses any tool (reads a file, runs a command, edits code) |
PostToolUse | Just after Claude finishes using a tool |
Stop | When Claude finishes its response and stops working |
SessionStart | At the beginning of a new Claude Code session |
PreCompact | Before Claude compacts the session context |
For most practical purposes, you'll use PostToolUse and SessionStart. The others are for advanced workflows.
Where Hooks Are Configured
Hooks live in a settings.json file. There are two locations:
Global hooks — apply to every project on your machine:
Project hooks — apply only to the current project:
If the .claude/ folder doesn't exist in your project, create it:
Project hooks override global hooks when there's a conflict. Use global hooks for universal behaviors (formatting, type checking). Use project hooks for project-specific behaviors (running a specific test suite, loading a project briefing).
The Hook Configuration Format
Here is the JSON structure for a settings file with hooks:
Breaking this down:
"PostToolUse"— the event that triggers this hook"matcher": "Write|Edit"— only fire when Claude uses the Write or Edit tool (not on reads)"command"— the shell command to run$CLAUDE_FILE_PATH— a special variable Claude Code provides: the path of the file that was just modified
Practical Hooks You'll Actually Use
1. Auto-Format After File Edits
Every file Claude edits gets automatically formatted with Prettier. No more manually running Prettier or having inconsistent whitespace.
The || true at the end ensures the hook doesn't fail loudly if Prettier isn't installed — it just silently does nothing.
2. TypeScript Type Check After Changes
Every time Claude creates or edits a TypeScript file, run a quick type check to catch any type errors immediately:
This only runs when the file is a TypeScript file (.ts or .tsx). It shows the first 20 lines of type errors so you catch problems immediately.
3. Session Start Reminder
At the start of every session in a specific project, remind Claude to read the project brief and check for any recent decisions:
This is a project-level hook that lives in .claude/settings.json. It injects a reminder into Claude's context at session start — no need to type it yourself.
4. Run Related Tests After Changes
When Claude edits a component file, automatically run the related tests to catch regressions:
This runs your test suite silently after every file change and shows the last 10 lines of output — enough to see pass/fail without overwhelming the terminal.
A Complete settings.json for a Typical Project
This is a practical starting point for .claude/settings.json in a React + TypeScript project:
Keep it simple to start. Add hooks as you find yourself repeating the same reminders or manual steps.
How to Test a Hook Before Committing
Before you rely on a hook, test it manually. If your hook runs npx prettier --write, run that command yourself in the terminal first:
If it works from the terminal, it'll work from the hook. If it errors, fix the command in the terminal before putting it in the hook.
Start with just one hook — the Prettier auto-format. Use it for a week. Then add another. Adding too many hooks at once makes it hard to debug when something doesn't behave as expected.
Hooks vs CLAUDE.md Instructions
This distinction matters:
| CLAUDE.md | Hooks | |
|---|---|---|
| What it is | Instructions Claude reads | Shell commands that run automatically |
| Who executes it | Claude (as context) | Claude Code's shell (your machine) |
| When it applies | During Claude's reasoning | At specific tool events |
| Example | "Always use TypeScript strict mode" | Auto-format every file Claude edits |
| Can it fail silently? | Yes (Claude can ignore instructions) | No — commands either succeed or fail |
CLAUDE.md instructions rely on Claude paying attention. Hooks are mechanical — they run regardless of what Claude was thinking. For things that must always happen (formatting, type checking), hooks are more reliable. For things that require judgment (code style, naming conventions), CLAUDE.md instructions are the right tool.
Use both together. CLAUDE.md for Claude's understanding. Hooks for guaranteed automation.