✻Founding-member pricing: every lesson for $19/mo. The first 3 lessons are free. Start lesson 1 →
Unit 7 · Hooks & Enforcement · Lesson 31 of 40

Hook Recipes: Format, Protect & Notify

Build the essential Claude Code hooks: auto-format after edits, block edits to protected files, desktop notifications and session-start context.

ACADEMY12 min+74 XP4-question quiz

🎯 By the end of this lesson you'll be able to

  • Auto-format every edit with a PostToolUse hook
  • Protect sensitive files with a PreToolUse script
  • Get notified when Claude needs you
  • Inject fresh context at session start

Recipe 1: Auto-format every edit

.claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "f=$(jq -r '.tool_input.file_path') && npx prettier --write --ignore-unknown \"$f\"" }
        ]
      }
    ]
  }
}

Every file Claude touches is formatted, every time. No more "please run prettier" in CLAUDE.md. Swap in black, gofmt, rustfmt or ruff format for your stack.

Recipe 2: Protect sensitive files

A small script checks the target path and blocks matches:

.claude/hooks/protect-files.sh
#!/usr/bin/env bash
file=$(jq -r '.tool_input.file_path // empty')
PROTECTED=(".env" "package-lock.json" ".git/" "migrations/applied/")
for p in "${PROTECTED[@]}"; do
  if [[ "$file" == *"$p"* ]]; then
    echo "Blocked: $file is protected. Explain what you need and I'll make the change myself." >&2
    exit 2
  fi
done
exit 0
bash
chmod +x .claude/hooks/protect-files.sh
.claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" }]
      }
    ]
  }
}
▶Watch it runThe hook in action
The hook in action
!
Defense in depth

A hook on Edit|Write doesn't stop echo "x" > .env through Bash. For sensitive files, combine the hook with permissions.deny rules like Edit(./.env) and Read(./.env), plus sandboxing.

Recipe 3: Notify me when Claude needs input

Put this in your user settings so it works in every project:

~/.claude/settings.json
{
  "hooks": {
    "Notification": [
      { "matcher": "", "hooks": [{ "type": "command", "command": "notify-send 'Claude Code' 'Claude Code needs your attention'" }] }
    ]
  }
}

On macOS, use osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'. Start a long task, go get coffee, and get pinged when it's your turn.

Recipe 4: Fresh context at session start

SessionStart hooks can print text that's added to Claude's context:

json
{
  "hooks": {
    "SessionStart": [
      { "matcher": "startup", "hooks": [{ "type": "command", "command": "echo \"Open PRs:\"; gh pr list --limit 5" }] }
    ]
  }
}

The compact matcher fires after compaction, which makes it a neat way to re-inject critical context that a summary might drop.

◎Which event fits the recipe?pick the best fit
Run the formatter after every edit.
After the edit succeeds, format it.
Stop Claude from touching the lockfile.
Block before the edit happens.
Ping my phone when Claude is waiting on me.
It fires when Claude needs attention.
Show the list of open PRs when I start a session.
Its stdout is added as context.

Check your understanding

?Lesson quiz10 XP per correct answer · +25 for a perfect score
QUESTION 1 OF 4

Which event should run a formatter?

Why: Format after the edit succeeds: PostToolUse with an Edit|Write matcher.
QUESTION 2 OF 4

Why reference scripts with "$CLAUDE_PROJECT_DIR"?

Why: Hooks may run from different directories, and the env var anchors the path.
QUESTION 3 OF 4

Why isn't an Edit|Write hook alone enough to protect .env?

Why: Layer your defenses: hook + deny rules + sandbox.
QUESTION 4 OF 4

Where should a personal notification hook live?

Why: User settings apply to every project and aren't forced on teammates.
0 / 4 correct
Academy lesson

Unlock lesson 31 and the next 9

You've finished the free lessons. Join the Academy for $19/month to unlock every lesson, quiz, terminal simulation and puzzle, plus the final exam and your certificate of completion.

  • All 40 lessons across 9 units
  • 165+ quiz questions
  • Final exam + certificate
  • New lessons as Claude Code evolves
  • XP, streaks and badges
  • Cancel anytime

Already a member? Log in to continue.

Key takeaways

  • PostToolUse + Edit|Write = guaranteed formatting.
  • PreToolUse scripts block protected paths. Exit 2 with a helpful reason.
  • Notification hooks free you from babysitting long tasks.
  • SessionStart output becomes context. Layer hooks with deny rules for real protection.

Nice work. Lesson 31 done?

Mark it complete to earn +74 XP, keep your streak alive and unlock badges.

Written by Curtis Cornell from Anthropic's public Claude Code documentation. Last reviewed November 14, 2026. Claude Code changes fast; if something here differs from your version, the official docs win.

Start lesson 1 free →