Zum Hauptinhalt springen

Hooks: Deterministische Automatisierung

Experte

Hooks sind Shell-Befehle, die Claude Code automatisch ausführt an definierten Punkten seines Lebenszyklus. Während Berechtigungen entscheiden, ob eine Aktion erlaubt ist, lassen Hooks dich deterministische Logik darum herum ausführen — Formatierung, Validierung, Protokollierung, Gates. So machst du Verhalten garantiert statt „bitte daran denken".

What you'll learn
  • Wann du zu einem Hook greifst statt zu einer Anweisung oder einer Berechtigung
  • Wie ein Hook verdrahtet wird: Ereignis, Matcher und die JSON-Payload auf stdin
  • Die zwei Arten, wie ein Hook eine Aktion blockiert — Exit-Code 2 vs. JSON auf stdout
  • Die guten Praktiken und häufigen Fehler, die schnelle, sichere Hooks von trägen, stummen unterscheiden

Wann du zu einem Hook greifst

Greif zu einem Hook, wenn du willst, dass ein Verhalten garantiert ist, nicht nur erbeten. Jede gängige Aufgabe entspricht einem Lebenszyklus-Ereignis:

  • Auto-Format / Lint nach jeder Dateibearbeitung (PostToolUse).
  • Blockieren einer Aktion, die eine Regel verletzt, bevor sie ausgeführt wird (PreToolUse).
  • Benachrichtigen oder protokollieren, wenn eine Sitzung endet oder eine Aufgabe abgeschlossen wird (Stop).
  • Kontext einfügen beim Sitzungsstart.
Hook-Ereignisse auf einen Blick
Drücke Enter oder die Leertaste, um die Karte umzudrehen. Nutze die Pfeiltasten links und rechts, um zwischen den Karten zu wechseln.Begriff angezeigt.
1 / 4

Wie sie funktionieren

Du registrierst Hooks in settings.json, wobei du ein Ereignis (und oft einen Tool-Matcher) zuordnest. Wenn das Ereignis ausgelöst wird, führt Claude deinen Befehl aus und übergibt eine JSON-Payload auf stdin (den Tool-Namen, seine Eingaben, die Sitzung). Der Exit-Code und die Ausgabe deines Befehls entscheiden, was als Nächstes passiert.

Guided walkthrough1 of 4
  1. Registriere den Hook in settings.json unter dem Lebenszyklus-Ereignis, das dich interessiert — zum Beispiel PostToolUse.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}

Der Hook oben liest den Pfad der bearbeiteten Datei aus dem stdin-JSON (.tool_input.file_path) und formatiert sie. Geh nicht davon aus, dass eine Umgebungsvariable den Pfad enthält — lies ihn von stdin. Nützliche Pfad-Platzhalter wie ${CLAUDE_PROJECT_DIR} sind verfügbar, um Skripte zu finden.

Wie ein Hook blockiert

Zwei Arten, je nach Ereignis:

  • Exit-Code 2 — der Hook lässt die Aktion scheitern, und was er auf stderr geschrieben hat, wird zur Nachricht, die Claude sieht. Einfach und funktioniert für Befehls-Hooks.
  • JSON auf stdout (Exit 0) — gib eine strukturierte Entscheidung zurück. Für PreToolUse ist das ein permissionDecision von deny; für PostToolUse/Stop/usw. ist es {"decision": "block", "reason": "…"}.

Das Skript unten ist ein PreToolUse-Hook auf dem Bash-Tool. Lies es von oben nach unten: Es zieht den Befehl aus stdin, und wenn er destruktiv aussieht, schreibt es einen Grund auf stderr und beendet sich mit 2, um zu blockieren.

#!/usr/bin/env bash
# PreToolUse hook on the Bash tool: refuse to delete things.
command=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm\ * || "$command" == *"rm -rf"* ]]; then
echo "Blocked: destructive 'rm' is not allowed by policy." >&2
exit 2
fi
exit 0

Das mentale Modell

Ein PreToolUse-Hook läuft vor der Aktion und kann sie blockieren; ein PostToolUse-Hook läuft nachdem sie erfolgreich war und reagiert auf das Ergebnis.

Gute Praktiken

  • Halte Hooks schnell und idempotent — sie laufen oft.
  • Schlag bei echten Problemen laut Alarm, aber blockiere nicht bei kosmetischen Mängeln.
  • Behandle die Hook-Ausgabe als Feedback an Claude — eine klare Nachricht hilft ihm, sich selbst zu korrigieren.
  • Hooks laufen mit den Rechten deiner Shell — prüfe jeden Hook, den du nicht selbst geschrieben hast (Code von Dritten prüfen).

Häufige Fehler

  • Den Dateipfad aus einer Umgebungsvariablen lesen. Der Pfad lebt im stdin-JSON (.tool_input.file_path), nicht in $CLAUDE_FILE_PATH. Leite stdin durch jq.
  • Stumme Blockaden. Wenn ein PreToolUse-Hook mit 2 endet, aber nichts auf stderr steht, ist Claude blockiert, weiß aber nicht warum und kann sich nicht anpassen. Schreib immer einen klaren Grund.
  • Langsame Hooks. Ein PostToolUse-Hook läuft nach jeder passenden Bearbeitung. Ein 3-Sekunden-Linter lässt die ganze Sitzung träge wirken — halte Hooks schnell und reagiere idealerweise nur auf das, was sich geändert hat.
  • Zu breite Matcher. matcher: ".*" löst bei jedem Tool aus. Grenz mit einem exakten Namen ein, einer Edit|Write-Liste oder dem Pro-Handler-if-Feld (z. B. "if": "Bash(git push *)").
  • Hooks vertrauen, die du nicht geschrieben hast. Ein Hook führt beliebige Shell-Befehle mit deinen Rechten aus. Prüfe jeden Hook aus einem Plugin oder Template zuerst — siehe Code von Dritten prüfen.
Watch out
  • Ein Hook führt beliebige Shell-Befehle mit deinen Rechten aus — verdrahte niemals einen Hook aus einem Plugin oder Template, ohne ihn zuerst zu lesen.

Copy-Paste-Starter findest du in Hooks & settings.json Rezepte.

Bearbeitete Dateien automatisch formatieren (PostToolUse auf Edit|Write)

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

Teste dich selbst

0/3
  1. Wo findet ein Hook den Pfad der gerade bearbeiteten Datei?
  2. Ein PreToolUse-Hook endet mit Code 2. Was passiert?
  3. Warum gilt matcher ".*" als häufiger Fehler?
Key takeaways
  • Hooks machen Verhalten garantiert, nicht erbeten — sie führen deterministische Logik um Aktionen herum aus, die Berechtigungen nur erlauben oder verweigern.
  • Registriere einen Hook in settings.json gegen ein Ereignis plus einen Matcher; Claude leitet eine JSON-Payload auf stdin durch und liest deinen Exit-Code und deine Ausgabe.
  • Lies den Dateipfad von stdin (.tool_input.file_path) — nicht aus einer Umgebungsvariablen.
  • Blockiere mit Exit-Code 2 (stderr wird zur Nachricht) oder mit strukturiertem JSON auf stdout (Exit 0); füge immer einen klaren Grund hinzu.
  • Halte Hooks schnell, idempotent und eng zugeordnet — und prüfe jeden Hook, den du nicht geschrieben hast, da er mit den Rechten deiner Shell läuft.

Weiter