Skill Locker
All posts
byJames Cooper

Claude Code Hooks: The Complete Guide with Examples

Claude Code hooks explained — every hook event, how to configure them in settings.json, practical examples (auto-format, notifications), and the security catch.

Claude CodeHooksAutomation

Claude Code hooks let you run your own shell commands automatically at specific points in a Claude Code session — before a tool runs, after a file is edited, when a session starts, when Claude stops. They're how you enforce things deterministically instead of hoping Claude remembers: auto-format every file it touches, block edits to protected paths, ping you when a long task finishes. This guide covers every hook event, how to configure them, real examples, and the security catch that matters more than any of it.

Hook event names and the exact settings.json schema occasionally change as Claude Code evolves. The model and use-cases below are stable; confirm the precise current configuration in the official Claude Code hooks documentation. This guide is about understanding and using hooks well, not memorising syntax that may shift.

What are Claude Code hooks?

A hook is a shell command Claude Code runs automatically when a specific event fires. You define hooks in your settings, matched to events. When the event happens, your command runs — with context about what triggered it passed in via environment variables and stdin.

The key word is deterministic. Asking Claude "please run Prettier after editing" works most of the time. A PostToolUse hook that runs Prettier works every time, because it's not Claude's judgement — it's a rule the harness enforces.

If you've used skills and subagents, hooks are the third layer: skills shape how Claude works, subagents delegate work, hooks enforce deterministic actions around the work.

How hooks are configured

Hooks live in your settings file (project or user level), as event-to-command mappings, typically with a matcher so a hook only fires for relevant tools or paths. The shape is roughly:

  • An event (when to run)
  • An optional matcher (which tool/path it applies to)
  • A command (what to run)

Project-level hooks are shared with everyone in the repo; user-level hooks follow you everywhere. Check the official docs for the exact JSON structure for your version — it's the kind of thing that gets refined release to release.

The hook events

These are the points you can hook into. Each one is a different intent people search for, so here's what each is actually for:

PreToolUse

Fires before Claude runs a tool. The big one for guardrails: inspect what Claude is about to do and block it if it violates a rule (e.g. editing .env, running a destructive command). Your command's exit behaviour decides whether the tool call proceeds.

PostToolUse

Fires after a tool completes. The workhorse for automation: a file was just edited, so run the formatter, the linter, the type-checker. This is where "auto-format everything Claude touches" lives.

UserPromptSubmit

Fires when you submit a prompt, before Claude processes it. Useful for injecting context or logging.

Stop

Fires when Claude finishes responding and is about to hand control back. Common use: notifications — play a sound or send a message so you know a long task is done.

SubagentStop

Like Stop, but for when a subagent finishes. Useful in multi-agent workflows.

SessionStart

Fires when a Claude Code session begins. Good for setup: load environment context, print a project reminder, warm a cache.

Notification

Fires when Claude Code sends a notification (e.g. it needs your input). Route these to Slack, a desktop notification, or a sound.

PreCompact

Fires before Claude Code compacts the conversation context. Useful for logging or preserving state before the window is summarised.

Practical examples

The long tail of "how do I use hooks for X" comes down to a few patterns:

Auto-format on every edit

A PostToolUse hook matched to file edits that runs Prettier, Ruff, gofmt, or your formatter of choice. Claude edits a file → it's formatted automatically, every time. The single most popular hook.

Block edits to protected files

A PreToolUse hook that checks the target path and blocks edits to .env, lockfiles, generated code, or anything you don't want touched. Deterministic guardrails beat hoping Claude won't.

Notify when a long task finishes

A Stop or Notification hook that plays a sound, sends a desktop notification, or posts to Slack. Start a big refactor, walk away, get pinged when it's done.

Run the linter / type-checker after changes

A PostToolUse hook running ESLint, tsc --noEmit, or your test subset — so Claude (and you) see breakage immediately, not three steps later.

Project context on session start

A SessionStart hook that prints current branch, open TODOs, or a "remember: this project uses X" reminder.

Context-window awareness

A UserPromptSubmit hook that estimates how full the context window is and injects a reminder at thresholds — so Claude can plan a clean /compact instead of getting force-compacted mid-task. There's a free, open-source one that does exactly this: context-window-awareness (MIT). The hook supplies the signal; knowing what to do with it — compacting at committed boundaries, persisting durable state so nothing is lost — is the behavioural layer, which is what our Context Budget Manager skill encodes. Free tool, paid judgement: use either, they compose.

Hooks vs skills vs subagents

These get conflated constantly:

  • Skills — instructions that shape how Claude approaches a task (judgement-based)
  • Subagents — separate agents you delegate whole tasks to (context isolation)
  • Hooks — shell commands the harness runs deterministically on events (not judgement — rules)

Use a skill for "review code well." Use a hook for "always run Prettier after an edit." One is guidance; the other is a guarantee.

The security catch (read this)

Hooks run arbitrary shell commands automatically. That's the power and the danger. A malicious or careless hook — especially a project-scoped one you inherited by cloning a repo — runs on your machine with your permissions, without asking.

Treat hooks like any executable code from a source:

  • Review project-scoped hooks before working in an unfamiliar repo. A hook is code, not config.
  • Keep hook commands simple and auditable. A one-line formatter call is easy to verify; a curl-pipe-to-shell is not.
  • Never put secrets in hook commands that land in a committed settings file.
  • Be cautious with PreToolUse hooks that can block or modify behaviour — they're powerful by design.

This is the hooks equivalent of running an MCP server read-only: the feature is great, but the safe default is deliberate, minimal, reviewed.

Troubleshooting

  • Hook not firing — usually a matcher mismatch or wrong event. Confirm the event name and that the matcher actually matches the tool/path.
  • SessionStart startup error — the command is failing on launch; run it manually to see the real error.
  • Hook works for you, not teammates — it's user-scoped, not project-scoped, or depends on something only on your machine.
  • Hook blocks everything — an over-broad PreToolUse matcher or wrong exit behaviour. Narrow the matcher.

FAQ

What are Claude Code hooks?

Shell commands Claude Code runs automatically at specific events — before/after a tool runs, on session start, when Claude stops. They enforce deterministic actions (like auto-formatting) instead of relying on Claude's judgement.

How do I configure Claude Code hooks?

Define event-to-command mappings in your settings file, optionally with a matcher so the hook only fires for relevant tools or paths. Project-scoped hooks are shared via the repo; user-scoped follow you. Check the official docs for the exact current schema.

What hook events are available?

The main ones are PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, SessionStart, Notification, and PreCompact — each firing at a different point in the session lifecycle.

What's the most useful Claude Code hook?

A PostToolUse hook that auto-formats edited files (Prettier, Ruff, gofmt). It's the most popular because it guarantees consistency without depending on Claude remembering to format.

Are Claude Code hooks safe?

They run arbitrary shell commands automatically, so treat them as code. Review project-scoped hooks before working in an unfamiliar repo, keep commands simple and auditable, and never embed secrets in committed hook config.

What's the difference between hooks and skills?

Skills shape how Claude approaches a task (judgement). Hooks run deterministic shell commands on events (rules). Use a skill for "review code well," a hook for "always run the linter after an edit."

Why aren't my Claude Code hooks working?

Most often a matcher mismatch or the wrong event name. Confirm the event fires for your case, the matcher actually matches the tool or path, and run the command manually to rule out a failing script.

Where hooks fit

Hooks are the deterministic layer of a serious Claude Code setup: skills for craft, subagents for delegation, hooks for guarantees, CLAUDE.md for project rules. Get all four working together and Claude Code stops being a chat tool and becomes a system.

Browse the skill library →

Ready to supercharge Claude Code?

296 pre-built skills across 33 categories. One purchase, lifetime updates.

Browse skills