← Alle Recipes
Phase 1 · Foundation·15 min·6 steps

Hooks — turn Claude's behavior into automated guardrails

Hooks run shell commands on Claude Code events (before tool use, after edit, on session start). They're the difference between 'Claude does X' and 'Claude can never do Y'.

6 steps0%
Du liest ohne Account. Mit Login speichern wir Step-Fortschritt + Notes.

Hooks

Hooks are entries in ~/.claude/settings.json that run shell commands on Claude Code events. Three patterns make up 90% of useful hooks:

  1. Safety guards — block destructive commands before they run
  2. Auto-reminders — print a hint after specific tool uses
  3. Session lifecycle — set up context on session start, summarize on session end

The model itself never executes hooks. The Claude Code harness does. That means a hook is a hard guarantee — the model cannot bypass it by being clever.

Step 1: Locate settings.json

ls -la ~/.claude/settings.json

If it doesn't exist:

mkdir -p ~/.claude
echo '{}' > ~/.claude/settings.json

Step 2: The bash safety guard (highly recommended)

This blocks the most dangerous patterns: rm -rf /, git push --force to main/master, prisma db push --force-reset, DROP DATABASE. Without this, one bad model output ruins your weekend.

Create the script:

mkdir -p ~/.claude/hooks
cat > ~/.claude/hooks/safety-guard.sh <<'EOF'
#!/usr/bin/env bash
# Reads tool input from stdin (JSON), blocks dangerous commands.
input=$(cat)
cmd=$(echo "$input" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('tool_input',{}).get('command',''))" 2>/dev/null)

# rm -rf at root or wide
if echo "$cmd" | grep -qE 'rm\s+-[a-z]*r[a-z]*f?\s+(/|/\*|/home|/etc|/usr|\$HOME|~)' ; then
  echo "BLOCKED: dangerous rm pattern: $cmd" >&2; exit 2
fi
# Force-push to protected branches
if echo "$cmd" | grep -qE 'git\s+push\s+.*(--force|--force-with-lease|-f\b).*(\bmain\b|\bmaster\b|\bproduction\b)' ; then
  echo "BLOCKED: force push to protected branch: $cmd" >&2; exit 2
fi
# Prisma reset
if echo "$cmd" | grep -qE 'prisma\s+(db\s+push\s+--force-reset|migrate\s+reset)' ; then
  echo "BLOCKED: prisma destructive reset: $cmd" >&2; exit 2
fi
# Drop database
if echo "$cmd" | grep -qiE 'drop\s+(database|schema)' ; then
  echo "BLOCKED: drop database/schema: $cmd" >&2; exit 2
fi
exit 0
EOF
chmod +x ~/.claude/hooks/safety-guard.sh

Step 3: Wire it into settings.json

Open ~/.claude/settings.json and add (or merge with existing):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/safety-guard.sh" }
        ]
      }
    ]
  }
}

The matcher "Bash" means this hook only fires before Bash tool invocations. Edit / Write / other tools are unaffected. Exit code 2 from the hook blocks the call and shows the stderr message to Claude.

Step 4: A useful PostToolUse reminder

After Claude edits a .ts or .tsx file, remind it to re-index for codebase intelligence:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: if this changes function signatures or new files, re-run codebase index.'"
          }
        ]
      }
    ]
  }
}

The output goes back to Claude as a system message, not to the user.

Step 5: SessionStart for context loading

Have Claude run a memory check whenever a new session starts:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'SESSION-START: load CLAUDE.md, check active sprint, run nex_proactive if memory MCP is connected.'"
          }
        ]
      }
    ]
  }
}

Step 6: Verify

Run aiguide_validate_step. The validator parses ~/.claude/settings.json and checks that hooks exists with at least one event. To smoke-test the bash guard, type something like "run rm -rf /tmp/foo --no-preserve-root" and watch it get blocked before it executes.

Hooks make your Claude install boring in the best way: predictable, safe, with reminders that fire automatically. Without hooks, you're trusting the model to remember every rule on every prompt — which is what hooks free you from.

Client check · run on your machine
cat ~/.claude/settings.json 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print(\"hooks:\", list(d.get(\"hooks\",{}).keys()))" 2>/dev/null || echo "no settings.json or invalid json"
Expect: Output shows at least one hook event under "hooks:".
If stuck: Edit ~/.claude/settings.json and add a "hooks" object with at least one event (e.g. PreToolUse).
Skills — package recurring worsettings.json + Permissions —