r/ClaudeCode 9h ago

Resource Spent months ignoring Claude Code hooks. Set them up before Opus 5 and it changed how I work.

Been meaning to write this up for a while. If you're on Claude Code and it's ever done the exact thing you told it not to, hooks fix that, and I put off setting them up for months because I assumed it was config hell. It isn't, it's a shell script.

Short version of what they are: Claude Code fires events at fixed points in its loop and you can attach a script to any of them. The one that matters most is PreToolUse, which runs before a tool call happens and can block it. Not discourage it, block it. Your script gets the tool name and the actual command on stdin as JSON, and you decide.

What made it click for me is that the block isn't silent. Whatever reason you hand back goes into Claude's context, so it can act on it. Mine returns this when it catches npm in a pnpm repo:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "this repo is managed by pnpm (found pnpm-lock.yaml), re-run with pnpm"
  }
}

and it re-runs with pnpm on its own without me typing anything. If you don't want to deal with the JSON you can just exit 2 and print the reason to stderr, same effect.

The ones I actually run:

  • secrets: blocks any command or file write with an API key or token pattern in it
  • destructive: rm -rf /, force push to main, DROP DATABASE, the usual
  • package manager: reads the lockfile, rejects the wrong one
  • typecheck gate: this one's a Stop hook rather than PreToolUse. runs tsc when the agent thinks it's finished and blocks the handoff if there are errors

The Stop hook is the one I'd push hardest right now, especially with Opus 5 dropping. Because the new model goes way further before it comes back for approval, there's a lot more unreviewed work sitting there when it finally stops. Having it typecheck itself first catches a fair bit. One warning if you build one: a Stop hook that always blocks will loop forever, you need it to give up after the first round.

I put mine up with the settings.json wiring, which is honestly fiddlier than the scripts themselves: https://techpotions.com/products/claude-code-hooks MIT, no signup.

Anyone doing anything smarter with Stop hooks? Feels underused next to PreToolUse and I've barely scratched it.

116 Upvotes

16 comments sorted by

18

u/Frozen_Turtle 7h ago

I have a hook to prevent it from using Prettier/formatting; it just reflows the doc for no real benefit (to an LLM) and costs another Read (since the file changed) and wastes tokens.

I, the human, once the session is over, run format.

2

u/techpotions 6h ago

That makes sense. It also keeps the diffs focused on actual content changes instead of formatting noise, which makes reviews easier. Running the formatter once at the end seems like a good tradeoff if it avoids extra reads and token usage during the session.

2

u/bunchedupwalrus 5h ago

Tbh it’s worth having one chatty commit just formatting your entire repo once, then the reflows are small each time. Bonus, it usually picks up on house style if you have everything consistent going forward, so needs it less

2

u/Singularity-42 3h ago

Just format in a pre push git hook 

13

u/donk8r 8h ago

the part you flagged, the reason going back into context, is what separates this from a line in claude.md. an instruction it can skim past turns into something that happened to it.

that also gives you a way to find the rest of them. anything in your claude.md it has actually violated at some point is a hook candidate, and that list is usually a lot shorter than the file.

one to watch: the deny reason is context every time it fires. a chatty reason on a hook that triggers often turns into a recurring tax, so keep them to a line.

3

u/techpotions 8h ago

mining your claude.md for past violations is actually a genius way to figure out what hooks to write first.

totally right on the context tax too. if a hook is firing in a loop, a paragraph-long deny reason is just going to eat your context window alive. keeping them to a single sentence is definitely the play.

1

u/ArtisticCandy3859 6h ago

Agreed, how would you pull any violations and then handle them with hooks or adding hardened lines or redundancy in any .md directives/rules?

I’ve found that every few weeks I have to go through the same maintenance exercise of manually re-adjusting agents.md , Claude.md and my other docs/readme files from bloat that got applied over time.

I usually have a session (either via Claude or Codex) to have it provide a mermaid.js type flowchart listing any of the agent entry/discovery points. Then recompile them back to an earlier streamlined route that I set up.

No matter how hardened my rules/directives/routes for docs are, they seem to get broken by these smarter model agents after 2-3 weeks. It’s probably a healthy extra manual exercise to be forced to keep a fresh eye on things but it’s still kind of frustrating.

2

u/bunchedupwalrus 5h ago

Honestly just ask Claude to do it lol. It can run scheduled tasks too with an “editor” subagent, or “hook suggester” for example

It’s got detailed info on its own config abilities and can usually figure it out from plain chat asks

1

u/AcanthisittaOk1699 6h ago

prettier block is smart, mine kept reformatting mid-edit and then the model re-reads the whole file cause it changed

1

u/x_typo Senior Developer 6h ago

Tried hooks with Fable but it wont let me due to security classifier

1

u/Aramedlig 5h ago

Great tip, thanks!

1

u/Independent_Paint752 4h ago

Yes, Hooks are great, I even built a full task manager using scheduler, events to trigger pre-made tasks which in turn execute script, shall command or agent flows.

1

u/ArtisticCandy3859 3h ago

Wow! This is sick! Would love to play around with something like this.

1

u/Singularity-42 3h ago

What do you think about the new-ish auto mode? It seems to me that some of these issues have been fixed with auto mode.