CloudCodeTree LogoCloudCodeTree
AI NewsTutorialsAbout
CloudCodeTree Logo
CloudCodeTree
  • AI News
  • Tutorials
  • About
← Back to AI News
Your Claude Code Safety Rules Are Suggestions Until You Use Hooks

Photo: Zayed Hossain / Pexels

Your Claude Code Safety Rules Are Suggestions Until You Use Hooks

Chris Harper

2 min read

Aug 9, 2026 · 04:07 UTC

AI
Workflow
Claude Code
Best Practices

CLAUDE.md instructions drift when context grows long — hooks are deterministic shell commands the harness runs on every matching event, unconditionally. That's the difference between a suggestion and a rule.

Your CLAUDE.md can say "never use rm -rf" or "always run lint after editing." The model follows those when it's paying attention. A hook fires whether it's paying attention or not. The two surfaces are complementary: CLAUDE.md sets intent, hooks enforce the constraint.

The two hook types you'll use most

PreToolUse fires before the tool runs. Exit code 2 = block (Claude sees the stderr output and retries without that action). Any other non-zero = warn but proceed. Use for guards.

PostToolUse fires after the tool completes — it can't undo what happened, but it runs unconditionally. Use for formatting, test runs, audit logging.

Configure in .claude/settings.json committed to the project root so every teammate gets it:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/block-danger.sh" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "~/.claude/hooks/auto-format.sh" }]
      }
    ]
  }
}

Three patterns to wire up now

1. Block dangerous Bash (PreToolUse, matcher Bash)

#!/usr/bin/env bash
cmd=$(cat | jq -r '.command')
if echo "$cmd" | grep -qE 'rm -rf|git push --force|DROP TABLE'; then
  echo "BLOCKED: $cmd" >&2; exit 2
fi

Exit 2 causes Claude to explain what it tried and propose a safer alternative.

2. Auto-format on every file write (PostToolUse, matcher Edit|Write)

#!/usr/bin/env bash
file=$(cat | jq -r '.path // empty')
[[ -z "$file" ]] && exit 0
[[ "$file" == *.py ]]                     && { black --quiet "$file"; exit 0; }
[[ "$file" == *.ts || "$file" == *.tsx ]] && npx prettier --write "$file"

3. Run affected tests after edits (PostToolUse, matcher Edit|Write)

#!/usr/bin/env bash
file=$(cat | jq -r '.path // empty')
[[ -z "$file" ]] && exit 0
pnpm test --passWithNoTests --testPathPattern="$(basename "$file")" 2>&1 | tail -5

The model sees hook stdout as context — when block-danger fires, Claude explains what it tried and proposes a safer alternative automatically.

Sources: Claude Code Hooks — Anthropic Docs · Claude Code Settings Reference — code.claude.com · Claude Code Hooks Setup with Examples — kjetilfuras.com