Hooks: make Claude Code react to events
Most of the time you won’t need hooks — but when you think “I wish it would just do that automatically every time,” hooks are the answer. They’re how Ralph loops work under the hood, and they turn our reviewer into something that runs itself.
A hook connects an event (something happening inside Claude Code) to an action (something you want to run automatically). Don’t memorise all of this — just get the gist, and know where to look when you need it.
01What a hook is
In a certain circumstance — Claude is about to run a shell command, or it just finished its work — you want something to happen, guaranteed, without asking. That circumstance is the event; the guaranteed thing is the hook.
02The events you can catch
Open the /hooks menu and you’ll see the full list. The useful mental sample:
| Event | Fires when… |
|---|---|
PreToolUse / PostToolUse | Just before / after Claude runs a tool (e.g. a shell command). |
UserPromptSubmit | You submit a prompt. |
Notification | Claude wants your attention (e.g. asking permission). |
Stop | Claude finishes its work — the one we’ll use. |
SubagentStop, PreCompact, SessionStart/End | Sub-agent finishes, before a compact, session boundaries… |
(1) On PreToolUse, catch when it’s about to call bare python and insist on uv run instead — fixing a habit it keeps forgetting. (2) On Notification, ping your phone so you can leave it running and step away without it silently waiting for you.
03Three things a hook can do
When the event fires, a hook runs one of three action types:
Run a shell command
The most reliable by far. Predictable and bullet-proof — start here.
Send Claude an instruction
Handy, but fiddlier — permission constraints (e.g. it can’t just write a file).
Spawn a sub-agent
Keeps the work off the main context, but takes experimenting to make robust.
04Build a stop-hook that reviews your work
Hooks live in .claude/settings.json (or via the /hooks menu). We’ll fire an automatic code review whenever Claude finishes — using our friend codex exec as the command.
{
"hooks": {
"Stop": [
{ "hooks": [
{ "type": "command",
"command": "codex exec \"review changes since the last commit, write results to planning/review.md\"" }
] }
]
}
}> please make a concise README.md for the project # Claude writes the README, then finishes → the Stop event fires → # the hook launches codex in the background → codex writes review.md. # Claude doesn’t even know the review happened.
The command action just runs a shell command — rock solid. The prompt and agent actions have permission quirks that take fiddling to get right. When you can express what you want as a shell command, do.
05When (not) to use hooks
Hooks add complexity — more moving parts, more that can silently misfire. Don’t sprinkle them everywhere. Wait until you have a real, repeated “do this every time” itch. Then skim the docs (/hooks or search “Claude Code hooks”), set one up, and move on.
You now know the shape: an event triggers a hook, which runs a command (most reliable), a prompt, or an agent. That’s enough to find your way when the need arises — and it sets up the last piece: bundling all of this into a shareable plugin.
✓ Key takeaways
- A hook links an event (e.g.
Stop) to an action that runs automatically. - Events include tool use, notifications, prompt submit, session boundaries — see
/hooks. - Actions are command (most reliable), prompt, or agent.
- Hooks live in
.claude/settings.json; aStophook can auto-run a review — and Ralph loops are built this way. - Use them sparingly — only when you have a genuine “do this every time” need.