Skip to content
English
Level 11: Extend & Automate
Lesson 5 · +15 XP

Your first hook

Let’s make one. We’ll write a hook that scribbles a note in a log file every time Claude edits something — harmless, and you’ll be able to see it fire.

Hooks live in your settings file, which you met in Level 9. Open the project one at .claude/settings.json (or your personal ~/.claude/settings.json) and add:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date): Claude edited a file\" >> ~/claude-edits.log"
          }
        ]
      }
    ]
  }
}

Four pieces, reading inward:

  • PostToolUse — the moment: just after Claude uses a tool (Lesson 11.4).
  • matcher: "Edit|Write"which tools count. Only the ones that change files. The | means “Edit or Write.”
  • type: "command" — what kind of hook. A shell command.
  • command — the actual line that runs: append the date and a note to ~/claude-edits.log.

Watch it fire

Start a session, and ask Claude to make any small edit — “add a blank line to the bottom of README.” Then look at your log:

cat ~/claude-edits.log
Mon May 24 14:02:11 2026: Claude edited a file

You never typed the echo. You never reminded Claude. The harness saw a file get edited and ran your command on its own.

That’s the feeling to remember: you wired a behavior into the machine, and now it happens every time, forever, with zero attention from you.

From toy to useful

Swap the command line and the same skeleton does real work. Two of the most common:

Auto-format edited files — never review a messy diff again:

"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"

(The harness hands your hook a little packet of JSON on its standard input describing what just changed; jq plucks out the edited file’s path and passes it to the formatter.)

Block something dangerous — switch the event to PreToolUse (which runs before the action and can stop it), match the Bash tool, and exit with an error if the command looks scary. That’s a guardrail Claude physically cannot talk its way past, because the harness, not the model, enforces it.

A gentler way to set them up

You don’t have to hand-edit JSON every time. Inside a session, run:

/hooks

It walks you through choosing an event, a matcher, and a command — then writes the JSON for you. Handy once you know what the pieces mean, which now you do.

One caution: a hook runs automatically, so a careless one bites automatically. Test new hooks on a throwaway project first — a hook that deletes files on every edit will do exactly that, every edit.

What’s next

Hooks automate things inside a session. The next two lessons leave the session entirely: headless mode, where Claude runs with no chat window at all — just a command you can pipe into or drop in a script.