Skip to content

9.2 Hooks: Automation at the Seams

A session has seams — moments where one thing ends and another begins: a tool is about to run, an edit just landed, the session is wrapping up. Hooks are commands you attach to those seams. The agent doesn't invoke them; the event does. This is level-3 mechanism in its purest form, and this lesson builds your first three.

What you will learn

  • Name the seams: the main hook events and what each is for.
  • Write hooks in settings: matcher + command, with the current syntax habit of checking docs.
  • Build three patterns: auto-check after edits, guard before actions, and a deliberate wrap/end-of-session record.

Builder principle

Put the check where the event is. A check that fires on the seam can't be forgotten, skipped, or charmed past.

The seams

Claude Code exposes hook points around a session's lifecycle. The ones that carry most real-world weight:

Event Fires Canonical use
PreToolUse Before a tool call (edit, command, …) runs Guard: block or warn on policy violations
PostToolUse After a tool call completes Verify: run checks against what just changed
Stop When the agent finishes a response/turn Turn-level checks or notifications; not session termination
SessionEnd When a session terminates Cleanup or end-of-session processing
SessionStart New session begins Prime: load state, surface reminders

A hook is: an event + an optional matcher (which tools it applies to) + a command to run. Configured in your settings file (project-level .claude/settings.json — shipping with the repo like everything else in your stack, or user-level for personal invariants: the layering rule, one last time).

Syntax lives in the docs

Hook configuration is exact-syntax config, and config evolves. The concepts here are stable; for field names and current examples, open the hooks docs when building. Better yet — the meta-move below.

The starter trio

1. The after-edit check (PostToolUse). Your quick-win site has a validator by now (if not — next lesson builds it). Hook it to edits: every time the agent modifies a file, the checker runs and the result lands in the agent's context automatically. Failures become something the agent sees and fixes in the same turn — the self-correction loop from 9.1, wired shut.

2. The guard (PreToolUse). Your CLAUDE.md boundaries are polite requests; a PreToolUse hook is a locked door. The classic: block edits to protected paths (assets/logo.svg, .env, published/), and flag no-undo commands (8.5's list) for extra scrutiny. The instruction asks; the hook enforces. Both is professional — instructions for understanding, hooks for certainty.

3. The wrap record. Stop fires at the end of an agent turn, not only when the session closes, so it is a poor trigger for one final session summary. Keep /wrap as the explicit, reviewable path, or build a SessionEnd/transcript-processing workflow that is idempotent and tested against duplicate or incomplete records. Hooks do not know which narrative summary you intended.

Build them with the agent — the meta-move

Hooks are config + small scripts, which means your agent builds them well. This is the recommended path, not a shortcut:

I want a PostToolUse hook: after any file edit in this project,
run scripts/check.sh and surface failures. Read the current hooks
documentation first if you need it, then set it up in
.claude/settings.json. Explain each field as you go — I want to
understand what I'm installing, not just have it.

That last clause matters beyond learning: a hook runs with your permissions, automatically, forever. You are the review gate for anything that gets to do that (8.5's judgment, aimed inward). Never install hook config — yours, the agent's, or copied from the internet — that you couldn't explain back.

Then verify mechanically, because hooks are mechanism: break something on purpose (introduce a deliberate error, watch the after-edit hook catch it; try to edit a protected file, watch the guard refuse). A hook you haven't seen fire is a hook you believe in, not one you've verified — and you know which of those this course trades in (4.4, forever).

You're configuring, not coding — and the agent-as-installer path means plain English in, reviewed mechanism out. Start with a harmless turn notification or keep explicit /wrap; automatic transcript-derived logging needs more care because hooks can duplicate, expose, or record incomplete session data.

Patterns that earn their keep at work: PostToolUse running your linter/typechecker scoped to changed files; PreToolUse enforcing the team no-touch list; and a deliberately designed SessionEnd/transcript processor when policy permits summaries. Treat hook scripts as production code — they run unattended with your credentials and may process sensitive paths or transcripts.

Try it now

Your 9.1 conversion queue, executed:

  1. Install the starter trio via the meta-move — one at a time, explain-back rule enforced on yourself.
  2. Verify each mechanically: deliberate error → caught; protected edit → blocked; wrap/SessionEnd path → one reviewed, non-duplicated record with no sensitive transcript data.
  3. Commit .claude/settings.json and the hook scripts. Mechanism ships with the project now.
  4. Journal: which practice from your queue just stopped depending on you? Cross it off — ceremonially. That's the whole chapter's point, felt.

Check your understanding

  • Distinguish Stop from SessionEnd. Which one is end-of-turn, and why does summary logging still need deliberate design?
  • Why does the after-edit check close the self-correction loop, in 9.1's terms?
  • What's the difference between a CLAUDE.md boundary and a PreToolUse guard — and why keep both?
  • Why the explain-back rule, and why must every hook be seen firing before it's trusted?