Find my path ↗
FREE LIVE WORKSHOP FOR WOMEN · OCTOBER 24Bring your idea. Make your first move. Reserve my free seat ↗
All articles

Claude Code Hooks: Automate Your Workflow So You Stop Repeating Yourself

Hooks make Claude behave a certain way automatically, every time, without you asking. Four patterns worth setting up today, including the one that blocks dangerous commands before they run.

Claude Code Hooks: Automate Your Workflow So You Stop Repeating Yourself

CLAUDE.md tells Claude what your project is. Hooks tell it how to behave — automatically, every single time, without you asking. If CLAUDE.md is intent, hooks are enforcement. You'll eventually want both, but hooks are where the "wait, it can do that?" moments live.

What a hook actually is

A hook is a shell command that runs at a specific moment — before a tool fires, after a file gets edited, when a session starts or ends. If something should happen every time, a hook is how you stop relying on remembering to ask for it.

They live in ~/.claude/settings.json (personal, every project) or .claude/settings.json (project-level, checked into git so your whole team gets the same behavior).

The one to set up today: auto-format on save

You know the loop. Claude edits a file. The indentation's off, or it didn't run your linter. You ask it to fix formatting. It does. You've now spent a whole turn on something a tool should've caught.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command", "command": "npx prettier --write \"$tool_path\"" }
        ]
      }
    ]
  }
}

$tool_path holds whatever file Claude just touched. Swap prettier for eslint, ruff, gofmt — whatever you already run on save. This one hook removes an entire category of back-and-forth, permanently.

The one that surprises people: blocking dangerous commands

Hooks can say no. Return a non-zero exit code from a PreToolUse hook and the tool call gets blocked before it runs — not undone after, blocked before it happens.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "scripts/validate-bash-command.sh" }
        ]
      }
    ]
  }
}

Your script reads the command Claude wants to run, exits 1 to block it, and prints to stderr explaining why. Claude reads that explanation and adjusts course in the same turn — it's not stuck, it's redirected.

This is the pattern for real guardrails: stop Claude from running rm -rf anywhere near a production directory, stop a migration from firing outside staging. You write the rule once. It holds forever, whether you remembered to mention it or not.

Two more worth having

Run tests on every meaningful edit — surface a failure immediately so Claude can self-correct in the same turn instead of you discovering it three edits later:

"PostToolUse": [{
  "matcher": "Edit",
  "hooks": [
    { "type": "command", "command": "npm test -- --findRelatedTests \"$tool_path\"" }
  ]
}]

Get notified when a long job finishes — so you're not babysitting an 8-minute build:

"Stop": [{
  "hooks": [
    { "type": "command", "command": "osascript -e 'display notification \"Claude session done\" with title \"Claude Code\"'" }
  ]
}]

(That's macOS. Linux: notify-send. Or point it at your own Slack webhook.)

What to avoid

  • A hook that blocks silently. Always print to stderr why. Otherwise Claude's just guessing, and the loop gets worse, not better.
  • A hook that takes more than a few seconds. They run synchronously — every tool call waits on them. A slow hook makes every edit feel sluggish.
  • A hook that rewrites logic mid-edit. Reformatting a file after Claude finishes is fine. Rewriting what Claude was actively reasoning about mid-turn will just confuse it.

Copy this one right now

Paste this into your project's .claude/settings.json — it's the single highest-leverage hook, and it's copy-paste ready:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          { "type": "command", "command": "npx prettier --write \"$tool_path\"" }
        ]
      }
    ]
  }
}

Commit it. Now everyone on your team gets it too, without a Slack message explaining why.

The instinct behind "block dangerous commands automatically" is the same instinct behind Cameron's validation stage — a rule that holds even when you forget to check it yourself. If you've ever shipped something before it was actually ready, that's the human version of the bug this hook fixes for code. See how Cameron validates before you build →

Ready to put this into action? Waymaker helps you go from idea to your first paying customer, with AI doing the heavy lifting alongside you.

Start building free
Ashley Kays

Ashley Kays

Founder

Founder of Waymaker. BigCo veteran (NCR, Walt Disney World, Wyndham Worldwide) turned solo operator. Building the operating layer above AI building tools.

Related articles