Journal
Tutorials

5 Useful Claude Code Hooks (with Copy-Paste Config)

C

Clearly Team

Engineering

6 min read
Jul 10, 2026

5 Useful Claude Code Hooks (with Copy-Paste Config)

Hooks are what turn Claude Code from an assistant into an assistant that follows your rules — automatically, every time, without the model having to remember. Here are five worth keeping, each a paste-in settings.json block. (New to hooks? Start with the complete guide.)

1. Get notified when it's done (or needs you)

The one you'll use most: a desktop ping when Claude finishes a turn or hits a permission prompt, so you can tab away. It's a Stop + Notification hook — and we packaged it as a free, standalone plugin so you don't have to write it:

/plugin marketplace add clearly-sh/mwah-notify
/plugin install mwah-notify@mwah

(Full walkthrough: get a desktop notification when Claude Code finishes.)

2. Auto-format after every edit

A PostToolUse hook on Edit/Write that runs your formatter on the file Claude just touched — so its output always matches your style:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "jq -r '.tool_input.file_path' | xargs -r prettier --write" }
        ]
      }
    ]
  }
}

Swap prettier --write for ruff format, gofmt -w, or whatever your project uses.

3. Block dangerous commands

A PreToolUse hook on Bash that refuses destructive commands before they run — exit 2 blocks the tool and tells Claude why:

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$CMD" | grep -qiE 'rm -rf /|git push --force|drop table'; then
  echo "Blocked: that command is on the no-fly list." >&2
  exit 2
fi
exit 0

Point a PreToolUse / Bash matcher at it, and no agent nukes your repo at 2am.

4. Protect your secrets

A PreToolUse hook on Read that refuses to let Claude read .env and friends, so secrets never enter the context in the first place:

#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path')
case "$FILE" in
  *.env|*.env.*|*/secrets/*|*id_rsa*)
    echo "Blocked: that file may contain secrets." >&2
    exit 2 ;;
esac
exit 0

5. Don't let it stop until tests pass

A Stop hook that keeps Claude working while tests fail — with the loop guard (stop_hook_active) so it can't get wedged:

#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then exit 0; fi
if npm test >/dev/null 2>&1; then
  exit 0
else
  echo '{"decision":"block","reason":"Tests are failing — keep going until they pass."}'
  exit 0
fi

The pattern

Hooks are deterministic guardrails: format, block, protect, gate, notify. The model can forget; a hook can't. Wire the ones that match how you work, and Claude Code stops surprising you.

And when you're running several sessions with all these guardrails firing at once, Mwah shows you the whole board — every live session as a robot, flagged the moment one goes stuck. Feed the good ones, retire the stuck ones.


Related: Claude Code hooks: the complete guide · Get notified when Claude Code finishes

#claude code#hooks#automation#developer workflow#cli