Claude Code Hooks erklärt: Die deterministische Schicht um Ihren Agenten
Was sind Claude Code Hooks? Hooks sind benutzerdefinierte Shell-Befehle (dazu HTTP-Endpunkte, MCP-Tools und Modell-Prompts), die Claude Code automatisch an festen Punkten seines Lebenszyklus ausführt: vor einem Tool-Aufruf, nach einer Bearbeitung, beim Sitzungsstart, wenn Claude seine Antwort abschließt.1 Wo CLAUDE.md dem Modell Anweisungen gibt, denen es wahrscheinlich folgt, werden Hooks ausgeführt, ob das Modell kooperiert oder nicht. Geben Sie in einer beliebigen Sitzung /hooks ein, um jedes Lebenszyklus-Ereignis zu sehen und was damit verdrahtet ist.
{.answer-block}
Die meisten Entwickler betreiben Claude Code mit zwei Kontrollschichten: Berechtigungen, die regeln, was der Agent tun darf, und CLAUDE.md, das beschreibt, was er tun soll. Hooks sind die dritte Schicht — und die einzige, die überhaupt etwas garantiert. Im Folgenden: das mentale Modell, jedes Lebenszyklus-Ereignis der aktuellen Dokumentation, der genaue Vertrag für Ein- und Ausgabe, die Konfiguration, fünf funktionierende Muster und ein Entscheidungsrahmen. Jedes API-Detail wurde zum Stand 1. Juli 2026 gegen die offizielle Hooks-Referenz und den Leitfaden geprüft — dieses System entwickelt sich schnell, wo also dieser Beitrag und die Referenz sich widersprechen, gilt die Referenz. (Neu bei Claude Code? Beginnen Sie mit der 5-Minuten-Einrichtung oder dem Einstiegspfad für Claude Code.)
TL;DR: Hooks empfangen JSON über stdin und antworten mit Exit-Codes oder JSON über stdout. Exit 0 erlaubt, Exit 2 blockiert (bei den Ereignissen, die blockieren können), und Exit 1 — der übliche Unix-Fehlercode — blockiert nichts, was die mit Abstand größte Falle bei Hooks ist.2 Konfigurieren Sie sie in settings.json unter Ereignisnamen wie PreToolUse und Stop, gefiltert durch Matcher. Verwenden Sie Hooks für alles, was immer geschehen muss; verwenden Sie CLAUDE.md für alles, was das Modell lediglich wissen sollte.
Das mentale Modell: Garantien um einen nichtdeterministischen Kern
Ein Coding-Agent ist ein probabilistisches System. Bitten Sie ihn, nach jeder Bearbeitung Prettier auszuführen, und er wird es tun — meistens. Er lässt den Schritt womöglich aus, wenn die Änderung trivial wirkt, wenn der Kontext lang wird oder wenn Ihre Formulierung anders ankommt. CLAUDE.md, Skills und Prompts sind allesamt Vorschläge: hochwertig, meist befolgt, nie garantiert.
Hooks sind die deterministische Hülle um diesen Kern. Die offizielle Definition: „benutzerdefinierte Shell-Befehle, HTTP-Endpunkte oder LLM-Prompts, die automatisch an bestimmten Punkten im Lebenszyklus von Claude Code ausgeführt werden” und „deterministische Kontrolle über das Verhalten von Claude Code bieten, indem sie sicherstellen, dass bestimmte Aktionen stets stattfinden, statt sich darauf zu verlassen, dass das LLM sich für ihre Ausführung entscheidet.”3 Der Formatierer läuft bei jeder Bearbeitung. Die Befehlssperre prüft jeden Bash-Aufruf. Die Abschlussprüfung kontrolliert jeden Abschluss.
Die Durchsetzung ist real, nicht kosmetisch: PreToolUse Hooks werden vor jeder Prüfung des Berechtigungsmodus ausgelöst, sodass ein Hook, der permissionDecision: "deny" zurückgibt, das Tool selbst im Modus bypassPermissions oder unter --dangerously-skip-permissions blockiert. Umgekehrt gilt das nicht — ein Hook, der "allow" zurückgibt, kann Deny-Regeln aus den Einstellungen nicht lockern. Hooks können die Richtlinie über das hinaus verschärfen, was die Berechtigungen zulassen, sie aber nie abschwächen.4
Der Lebenszyklus: jedes Hook-Ereignis
Zum Stand 1. Juli 2026 dokumentiert die Referenz 30 Hook-Ereignisse.1 Sie verteilen sich auf drei Taktungen: einmal pro Sitzung (SessionStart, SessionEnd), einmal pro Zug (UserPromptSubmit, Stop, StopFailure) und bei jedem Tool-Aufruf innerhalb der Agentenschleife (PreToolUse, PostToolUse). Die übrigen werden bei bestimmten Bedingungen ausgelöst — Konfigurationsänderungen, Kompaktierung, Subagenten, MCP-Interaktionen.
| Ereignis | Wird ausgelöst | Ein realer Einsatzzweck |
|---|---|---|
SessionStart |
Sitzung beginnt oder wird fortgesetzt | Git-Branch und offene Issues als Kontext einspeisen |
Setup |
--init-only oder --init/--maintenance im -p-Modus |
Abhängigkeiten in CI installieren, bevor der Agent läuft |
UserPromptSubmit |
Sie senden einen Prompt ab, bevor Claude ihn verarbeitet | Das aktuelle Datum anhängen; Prompts mit Secrets ablehnen |
UserPromptExpansion |
Ein eingegebener Befehl wird zu einem Prompt expandiert | Skill-/Befehlsexpansionen prüfen oder unterbinden |
PreToolUse |
Bevor ein Tool-Aufruf ausgeführt wird | Destruktive Shell-Befehle blockieren |
PermissionRequest |
Ein Berechtigungsdialog erscheint | Vertrauenswürdige Befehle automatisch genehmigen, damit Sie nicht gefragt werden |
PermissionDenied |
Der Klassifizierer des Auto-Modus verweigert einen Tool-Aufruf | retry: true zurückgeben, damit das Modell erneut versuchen darf |
PostToolUse |
Nachdem ein Tool-Aufruf erfolgreich war | Jede bearbeitete Datei automatisch formatieren |
PostToolUseFailure |
Nachdem ein Tool-Aufruf fehlschlägt | Fehlgeschlagene Befehle zur Triage protokollieren |
PostToolBatch |
Nach einem Stapel paralleler Tool-Aufrufe, vor dem nächsten Modellaufruf | Die Agentenschleife sichern oder anhalten |
Notification |
Claude Code sendet eine Benachrichtigung | Desktop-Hinweis, wenn Claude Eingaben benötigt |
MessageDisplay |
Während der Nachrichtentext des Assistenten angezeigt wird | Auf dem Bildschirm schwärzen (nur Anzeige; Transkript unverändert) |
SubagentStart |
Ein Subagent wird gestartet | Kontext spezifisch für den Agententyp einspeisen |
SubagentStop |
Ein Subagent schließt ab | Die Ausgabe des Subagenten validieren, bevor sie zurückgegeben wird |
TaskCreated |
Eine Aufgabe wird über TaskCreate erstellt |
Regeln für Aufgabenbenennung oder -umfang durchsetzen |
TaskCompleted |
Eine Aufgabe wird als abgeschlossen markiert | Akzeptanzkriterien prüfen, bevor der Abschluss gilt |
Stop |
Claude schließt seine Antwort ab | Abschlussprüfung: den Abschluss blockieren, bis die Tests bestehen |
StopFailure |
Der Zug endet aufgrund eines API-Fehlers | Bei rate_limit oder billing_error alarmieren (nur Protokoll; Ausgabe wird ignoriert) |
TeammateIdle |
Ein Teammitglied im Agenten-Team steht kurz davor, untätig zu werden | Teammitglieder eine Warteschlange abarbeiten lassen |
InstructionsLoaded |
Eine CLAUDE.md- oder .claude/rules/*.md-Datei wird in den Kontext geladen |
Protokollieren, welche Anweisungen in die Sitzung gelangten |
ConfigChange |
Eine Konfigurationsdatei ändert sich mitten in der Sitzung | Unbefugte Änderungen an den Einstellungen blockieren |
CwdChanged |
Das Arbeitsverzeichnis ändert sich | Umgebungen im direnv-Stil neu laden |
FileChanged |
Eine überwachte Datei ändert sich auf dem Datenträger | Umgebungsvariablen aktualisieren, wenn sich .env ändert |
WorktreeCreate |
Ein Worktree wird über --worktree oder isolation: "worktree" erstellt |
Die standardmäßige Bereitstellung von Git-Worktrees ersetzen |
WorktreeRemove |
Ein Worktree wird entfernt | Eigene Bereinigung beim Ende einer Sitzung oder eines Subagenten |
PreCompact |
Vor der Kompaktierung des Kontexts | Zustand sichern, dessen Verlust Sie sich nicht leisten können |
PostCompact |
Nachdem die Kompaktierung abgeschlossen ist | Kritischen Kontext erneut einspeisen |
Elicitation |
Ein MCP-Server fordert Benutzereingaben an | Formulare in Headless-Läufen automatisch ausfüllen |
ElicitationResult |
Nachdem Sie eine MCP-Anforderung beantwortet haben | Die Antwort validieren oder überschreiben, bevor sie zurückgegeben wird |
SessionEnd |
Die Sitzung endet | Protokolle archivieren, Ressourcen abbauen |
Die meisten davon werden Sie nicht brauchen. Nahezu jede produktive Einrichtung ist aus fünfen aufgebaut: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart und Stop. Der Rest existiert für den Tag, an dem Sie ihn brauchen.
Der Vertrag: JSON hinein, Exit-Codes oder JSON hinaus
Command-Hooks empfangen JSON über stdin und antworten über Exit-Codes, stdout und stderr. (HTTP-Hooks empfangen dasselbe JSON als POST-Body und antworten über den Response-Body.)2
Jedes Ereignis liefert einen gemeinsamen Rahmen — session_id, transcript_path, cwd und hook_event_name, bei den meisten Ereignissen dazu permission_mode — plus ereignisspezifische Felder. Ein PreToolUse Hook für einen Bash-Befehl empfängt:
{
"session_id": "abc123",
"transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
"cwd": "/home/user/my-project",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "npm test" }
}
Andere Ereignisse tauschen den Schluss aus: UserPromptSubmit trägt prompt, SessionStart trägt source (startup/resume/clear/compact), Stop trägt stop_hook_active und last_assistant_message. Hooks, die innerhalb von Subagenten ausgelöst werden, empfangen zusätzlich agent_id und agent_type.2
Exit-Codes
Drei Ergebnisse:2
- Exit 0 — Erfolg. Claude Code wertet stdout auf JSON-Ausgabefelder aus. Bei den meisten Ereignissen geht stdout nur ins Debug-Protokoll; bei
UserPromptSubmit,UserPromptExpansionundSessionStartwird reines stdout als Kontext hinzugefügt, den Claude sehen kann. - Exit 2 — blockierender Fehler. Stdout (einschließlich jeglichem JSON) wird ignoriert; stderr wird Claude als Fehlermeldung zurückgespielt. Was „blockieren” bedeutet, hängt vom Ereignis ab.
- Jeder andere Exit-Code — nicht-blockierender Fehler. Das Transkript zeigt einen Hinweis
<hook name> hook error, und die Ausführung wird fortgesetzt.
Die letzte Zeile verdient Fettdruck: Exit 1 blockiert gar nichts. Die Dokumentation warnt direkt davor — Claude Code behandelt Exit 1 als nicht-blockierenden Fehler und fährt fort, obwohl 1 der übliche Unix-Fehlercode ist. Richtlinien-Hooks müssen exit 2 verwenden.2
Was Exit 2 bewirkt, je Ereignis:2
| Ereignis | Wirkung von Exit 2 |
|---|---|
PreToolUse |
Blockiert den Tool-Aufruf |
PermissionRequest |
Verweigert die Berechtigung |
UserPromptSubmit |
Blockiert die Verarbeitung und löscht den Prompt |
UserPromptExpansion |
Blockiert die Expansion |
Stop / SubagentStop |
Verhindert das Anhalten; die Konversation wird fortgesetzt |
TeammateIdle |
Verhindert, dass das Teammitglied untätig wird |
TaskCreated / TaskCompleted |
Macht die Erstellung rückgängig / verhindert den Abschluss |
ConfigChange |
Blockiert die Konfigurationsänderung (außer policy_settings) |
PreCompact |
Blockiert die Kompaktierung |
PostToolBatch |
Stoppt die Agentenschleife vor dem nächsten Modellaufruf |
Elicitation / ElicitationResult |
Verweigert die Anforderung / verwandelt die Antwort in eine Ablehnung |
WorktreeCreate |
Jeder von null verschiedene Exit bricht die Worktree-Erstellung ab |
Alles andere kann nicht blockieren. PostToolUse und PostToolUseFailure zeigen stderr an Claude (das Tool ist bereits gelaufen); SessionStart, Notification, SessionEnd, CwdChanged, FileChanged, PostCompact, SubagentStart und Setup zeigen stderr nur dem Benutzer; StopFailure, InstructionsLoaded, MessageDisplay und PermissionDenied ignorieren den Exit-Code — bei PermissionDenied ist der einzige Hebel JSON mit retry: true.2
JSON-Ausgabe
Für feinere Kontrolle als bloßes Blockieren-oder-Schweigen: Exit 0 und ein JSON-Objekt auf stdout ausgeben. Eine Regel vorweg: Exit-Codes oder JSON, niemals beides — JSON wird nur bei Exit 0 verarbeitet, und Exit 2 verwirft es.5
Universelle Felder wirken bei jedem Ereignis: continue: false stoppt Claude vollständig (wobei stopReason dem Benutzer angezeigt wird), suppressOutput blendet stdout aus dem Transkript aus, systemMessage zeigt dem Benutzer eine Warnung, und terminalSequence gibt eine freigegebene Terminal-Escape-Sequenz aus (Desktop-Benachrichtigung, Fenstertitel, Signalton). Die Entscheidungsfelder sind ereignisspezifisch:5
| Ereignisse | Entscheidungsmuster | Schlüsselfelder |
|---|---|---|
UserPromptSubmit, UserPromptExpansion, PostToolUse, PostToolUseFailure, PostToolBatch, Stop, SubagentStop, ConfigChange, PreCompact |
decision auf oberster Ebene |
decision: "block" + reason (wird Claude angezeigt). decision weglassen, um zu erlauben |
PreToolUse |
hookSpecificOutput |
permissionDecision: "allow" | "deny" | "ask" | "defer", dazu permissionDecisionReason und updatedInput, um Tool-Argumente vor der Ausführung umzuschreiben |
PermissionRequest |
hookSpecificOutput |
decision.behavior: "allow" | "deny", optional decision.updatedInput |
PermissionDenied |
hookSpecificOutput |
retry: true teilt dem Modell mit, dass es erneut versuchen darf |
PostToolUse |
hookSpecificOutput |
updatedToolOutput ersetzt das Tool-Ergebnis |
Stop / SubagentStop |
hookSpecificOutput |
additionalContext: Rückmeldung ohne Fehlercharakter, die die Konversation fortsetzt, ohne als Hook-Fehler zu zählen |
SessionStart, Setup, SubagentStart |
Nur Kontext | additionalContext, dazu die nur bei SessionStart verfügbaren initialUserMessage, sessionTitle, watchPaths, reloadSkills. Kein Blockieren |
MessageDisplay |
hookSpecificOutput |
displayContent ersetzt nur den Text auf dem Bildschirm |
Elicitation / ElicitationResult |
hookSpecificOutput |
action: "accept" | "decline" | "cancel", dazu content |
WorktreeRemove, Notification, SessionEnd, PostCompact, InstructionsLoaded, StopFailure, CwdChanged, FileChanged |
Keine | Nur Nebeneffekte |
Zwei Details, die Ärger machen. Erstens ist PreToolUse die Ausnahme vom Muster mit decision auf oberster Ebene: Historisch nutzte es decision/reason auf oberster Ebene, doch diese sind für dieses Ereignis veraltet ("approve"/"block" werden auf "allow"/"deny" abgebildet); verwenden Sie hookSpecificOutput.permissionDecision.5 Zweitens gilt, wenn mehrere PreToolUse Hooks uneinig sind, die Rangfolge deny > defer > ask > allow.5
Konfiguration: settings.json, Matcher, Geltungsbereich
Die Hook-Konfiguration verschachtelt drei Ebenen: Wählen Sie ein Ereignis, fügen Sie eine Matcher-Gruppe hinzu, um zu filtern, wann es ausgelöst wird, und definieren Sie einen oder mehrere Hook-Handler, die laufen sollen.6
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "/path/to/lint-check.sh" }
]
}
]
}
}
Wo Sie dies ablegen, bestimmt den Geltungsbereich: ~/.claude/settings.json gilt für alle Ihre Projekte, .claude/settings.json ist projektbezogen und commitfähig, .claude/settings.local.json ist projektbezogen und über gitignore ausgeschlossen, und es gilt die übliche Rangfolge der Einstellungen — verwaltete Richtlinie vor lokal vor Projekt vor Benutzer.9 Hooks lassen sich außerdem in Plugins (hooks/hooks.json) und in der Frontmatter von Skills oder Agenten ausliefern, und Unternehmens-Administratoren können verwaltete Hooks erzwingen, die Benutzer nicht überschreiben können.6
Matcher werden anhand ihrer Zeichen ausgewertet: "*", "" oder ein weggelassener Matcher passt auf alles; ein Wert, der nur Buchstaben, Ziffern, _, -, Leerzeichen, Kommas und | enthält, ist eine exakte Zeichenkette oder Liste (Bash, Edit|Write); alles andere wird zu einer nicht verankerten JavaScript-Regex, sodass Edit.* sowohl Edit als auch NotebookEdit trifft — verankern Sie mit ^Edit$, wenn Sie genau ein Tool meinen. Matcher unterscheiden Groß- und Kleinschreibung, und jedes Ereignis gleicht über sein eigenes Feld ab: Tool-Name bei Tool-Ereignissen, source bei SessionStart, Agententyp bei SubagentStart, Benachrichtigungstyp bei Notification.6 Für schärfere Filterung bei Tool-Ereignissen akzeptiert das handlerspezifische Feld if eine einzelne Berechtigungsregel wie "Bash(git *)" — doch es arbeitet nach bestem Bemühen (bei nicht parsbaren Befehlen fällt es auf „offen” zurück), verwenden Sie also Berechtigungsregeln, nicht if, für harte Garantien.6
Handler gibt es in fünf Typen: command (Shell), http (POST-Endpunkt), mcp_tool, prompt (einzügige Modellauswertung) und agent (ein Subagent mit Read-/Grep-/Glob-Zugriff; experimentell). Standard-Timeouts: 600 Sekunden für command/http/mcp_tool (herabgesetzt auf 30 bei UserPromptSubmit und 10 bei MessageDisplay), 30 für prompt, 60 für agent — pro Hook mit timeout überschreibbar.6 Alle passenden Hooks laufen parallel, wobei identische Handler entdoppelt werden, und $CLAUDE_PROJECT_DIR verweist Skripte auf Ihr Projektstammverzeichnis.
Prüfen Sie mit /hooks: ein schreibgeschützter Browser, der jedes Ereignis, seine konfigurierten Hooks und die Einstellungsdatei zeigt, aus der jeder stammt. Um etwas zu ändern, bearbeiten Sie das JSON (oder bitten Sie Claude darum). Um vorübergehend alles abzuschalten, setzen Sie "disableAllHooks": true.6
Fünf Muster
Generisch gehalten und minimal. Das Hooks-Tutorial baut von mehreren davon ausführlichere Produktionsversionen, und Hooks für die Apple-Entwicklung wendet sie auf die iOS-Toolchain an.
1. Automatisches Formatieren nach Bearbeitungen (PostToolUse)
Direkt aus dem offiziellen Leitfaden — jede Datei, die Claude berührt, wird formatiert, ohne Ausnahme:3
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }
]
}
]
}
}
Tauschen Sie den Befehl gegen ruff format, gofmt oder swiftformat, wie Ihr Stack es verlangt.
2. Gefährliche Befehle blockieren (PreToolUse, Exit 2)
#!/bin/bash
# .claude/hooks/guard-bash.sh — register on PreToolUse, matcher "Bash"
command=$(jq -r '.tool_input.command // empty')
case "$command" in
*"rm -rf"* | *"git push --force"* | *"DROP TABLE"*)
echo "Blocked: matches a destructive pattern. Propose a safer alternative." >&2
exit 2 ;;
esac
exit 0
Exit 2 blockiert den Aufruf und spielt stderr an Claude zurück, das daraufhin den Kurs anpasst, statt blind erneut zu versuchen. Das JSON-Äquivalent — permissionDecision: "deny" mit einer Begründung — leistet dasselbe, mit Spielraum zur Erweiterung auf "ask" (an den Menschen eskalieren) oder updatedInput (den Befehl umschreiben).5
3. Kontext beim Sitzungsstart einspeisen (SessionStart)
Reines stdout aus einem SessionStart Hook wird zu Kontext, den Claude sehen kann — kein JSON erforderlich:1
#!/bin/bash
# .claude/hooks/session-context.sh — register on SessionStart
echo "Current branch: $(git branch --show-current)"
echo "Recent commits:"
git log --oneline -5
echo "Uncommitted files: $(git status --porcelain | wc -l | tr -d ' ')"
exit 0
Verwenden Sie dies für dynamischen Zustand. Statische Konventionen gehören in CLAUDE.md, das die Dokumentation selbst für Kontext empfiehlt, der kein Skript erfordert.1
4. Eine Abschlussprüfung bei Stop
Stop wird ausgelöst, wenn Claude seine Antwort abschließt. Es zu blockieren zwingt den Agenten, weiterzuarbeiten, bis eine Bedingung erfüllt ist:
#!/bin/bash
# .claude/hooks/stop-gate.sh — register on Stop
input=$(cat)
if [ "$(echo "$input" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # already continuing because of this hook; don't loop forever
fi
if ! npm test --silent > /tmp/stop-gate.log 2>&1; then
jq -n '{decision: "block", reason: "Tests are failing. Fix them before finishing. Log: /tmp/stop-gate.log"}'
fi
exit 0
Die Prüfung auf stop_hook_active ist wichtig: Claude Code begrenzt einen Stop-Hook hart auf 8 aufeinanderfolgende Blockierungen, und eine Prüfung, die nie kontrolliert, ob sie bereits eine Fortsetzung ausgelöst hat, wird geradewegs durch sie hindurchbrennen.7 Für sanftere Steuerung geben Sie hookSpecificOutput.additionalContext statt decision: "block" zurück — dieselbe Fortsetzung, aber als gekennzeichnete Rückmeldung statt als Hook-Fehler. Und für einmalige Bedingungen ist der eingebaute Befehl /goal ein sitzungsbezogener, prompt-basierter Stop-Hook ganz ohne Konfiguration.1
5. Der Dispatcher: ein Einstiegspunkt, viele kleine Hooks
Zehn Hooks zu registrieren bedeutet zehn settings.json-Einträge, die über Maschinen und Projekte hinweg auseinanderdriften. Die Alternative: einen Dispatcher pro Ereignis registrieren und per Konvention weiterleiten.
#!/bin/bash
# .claude/hooks/dispatch.sh — register once per event you care about
input=$(cat)
event=$(echo "$input" | jq -r '.hook_event_name')
dir="$CLAUDE_PROJECT_DIR/.claude/hooks/$event"
[ -d "$dir" ] || exit 0
for hook in "$dir"/*.sh; do
[ -x "$hook" ] || continue
echo "$input" | "$hook" || exit $?
done
exit 0
Eine Sperre hinzuzufügen ist nun chmod +x auf einer neuen Datei in .claude/hooks/PreToolUse/ — settings.json ändert sich nie, jedes Skript bleibt klein genug, um es isoliert zu testen, und der erste Exit 2 pflanzt sich fort. Ein Vorbehalt: Der Dispatcher serialisiert, was Claude Code parallel laufen ließe, und er eignet sich am besten für Exit-Code-Hooks — ein Hook, der JSON ausgibt, sollte eigenständig bleiben, da stdout genau ein JSON-Objekt enthalten muss.5
Hook vs. CLAUDE.md vs. Skill vs. Memory
Vier Mechanismen, vier Aufgaben:
| Mechanismus | Aufgabe | Regel für die Wahl |
|---|---|---|
| Hook | Durchsetzung | Wenn das Auslassen unmöglich sein muss — Formatierung, Sicherheit, Prüfgrenzen — ist es ein Hook |
| CLAUDE.md | Orientierung | Wenn es eine Konvention ist, die das Modell in jeder Sitzung kennen sollte — Stack, Stil, Befehle — ist es CLAUDE.md |
| Skill | Fähigkeit | Wenn es eine Prozedur mit eigenen Anweisungen und Skripten ist, die bei Bedarf aufgerufen wird, ist es ein Skill |
| Memory | Erinnerung | Wenn es eine in einer Sitzung gelernte Tatsache ist, die künftige Sitzungen brauchen, ist es Memory |
Der Fehlerfall verläuft in beide Richtungen. Konventionen als Hooks zu kodieren beschert Ihnen brüchige Skripte, die etwas erzwingen, das ein Satz Orientierung problemlos erledigt. Richtlinien als CLAUDE.md-Prosa zu kodieren beschert Ihnen einen Agenten, der an dem einen Tag, an dem es zählt, einen Force-Push auf main macht. Die Prüfung: Was kostet es, wenn das Modell dies einmal ignoriert? Ärgernis → CLAUDE.md. Zwischenfall → Hook.
Was Hooks nicht können
Ehrliche Grenzen, allesamt aus der offiziellen Dokumentation:7
- Hooks können keine Tools oder Slash-Befehle aufrufen. Command-Hooks sprechen stdout, stderr und Exit-Codes — nichts sonst. Über
additionalContextzurückgegebener Kontext wird als reiner Text eingespeist. PostToolUsekann nichts rückgängig machen. Das Tool ist bereits gelaufen. Die Vorbeugung liegt inPreToolUse.Stopwird bei jedem Antwortende ausgelöst, nicht nur bei „Aufgabe abgeschlossen”, und nie bei Benutzerunterbrechungen (API-Fehler lösen stattdessenStopFailureaus). Die Prüflogik muss Stopps mitten in der Aufgabe verkraften.PermissionRequestwird im Headless-Modus (-p) nicht ausgelöst. Verwenden SiePreToolUsefür automatisierte Berechtigungsentscheidungen.PreToolUsesieht keine über@referenzierten Dateien. Dateien, die über@in Ihren Prompt gezogen werden, sind mit keinem Tool-Aufruf verbunden; verwenden SieRead-Deny-Regeln, um Pfade vor diesem Weg zu schützen.1- Paralleles
updatedInputist nichtdeterministisch. Wenn mehrere PreToolUse Hooks die Argumente desselben Tools umschreiben, gewinnt der, der zuletzt fertig wird. Lassen Sie jede Umschreibung von genau einem Hook verantworten. - Timeouts brechen den Hook ab. 600 Sekunden Standard für Command-Hooks (30 bei
UserPromptSubmit, 10 beiMessageDisplay); eine langsame Prüfung, die das Timeout überschreitet, ist eine Prüfung, die nicht gelaufen ist. - Die Ausgabe ist auf 10.000 Zeichen begrenzt — der Überschuss wird in eine Datei geschrieben und durch eine Vorschau ersetzt.
- Hooks laufen mit Ihren vollen Benutzerrechten. Die Warnung der Referenz selbst: Sie „können alle Dateien ändern, löschen oder darauf zugreifen, auf die Ihr Benutzerkonto zugreifen kann. Prüfen und testen Sie alle Hook-Befehle, bevor Sie sie Ihrer Konfiguration hinzufügen.”8 Setzen Sie Ihre Variablen in Anführungszeichen, verwenden Sie absolute Pfade, lassen Sie sensible Dateien aus.
- Ein defekter Hook beeinträchtigt jede Sitzung, bis er behoben ist. Debuggen Sie mit der Transkriptansicht (
Ctrl+O),claude --debug-file /tmp/claude.logoder/debugmitten in der Sitzung; ein klassischer Stolperstein ist ein Shell-Profil, das beim Start etwas ausgibt und die JSON-Ausgabe Ihres Hooks beschädigt.7
FAQ
Was sind Claude Code Hooks?
Hooks sind benutzerdefinierte Befehle — Shell-Skripte, HTTP-Endpunkte, MCP-Tools oder Modell-Prompts —, die Claude Code automatisch an bestimmten Punkten des Lebenszyklus ausführt.3 Sie empfangen Ereignis-JSON über stdin und antworten mit Exit-Codes oder JSON: einen Tool-Aufruf blockieren, Kontext einspeisen, Argumente umschreiben, den Agenten am Arbeiten halten. Anders als CLAUDE.md-Anweisungen werden sie jedes Mal ausgeführt, unabhängig vom Verhalten des Modells.
Was ist der Unterschied zwischen PreToolUse Hooks und Berechtigungen?
Berechtigungsregeln sind deklarativ: statische Allow-/Deny-/Ask-Muster, die Claude Code selbst auswertet. PreToolUse Hooks sind programmierbar: Ihr Code prüft die vollständige Tool-Eingabe und entscheidet. Hooks werden vor den Prüfungen des Berechtigungsmodus ausgelöst, sodass das "deny" eines Hooks selbst im Modus bypassPermissions gilt — doch das "allow" eines Hooks kann eine Deny-Regel aus den Einstellungen nicht außer Kraft setzen.4 Verwenden Sie Berechtigungsregeln für alles, was ein Muster ausdrücken kann; greifen Sie zu einem Hook, wenn die Entscheidung Logik, externen Zustand oder das Umschreiben der Eingabe erfordert.
Funktionieren Hooks im Headless-Modus (-p)?
Ja — mit einer dokumentierten Ausnahme: PermissionRequest Hooks werden im nicht-interaktiven Modus nicht ausgelöst, automatisierte Berechtigungsentscheidungen gehören daher in PreToolUse.7 Der Headless-Modus schaltet zudem eine Option frei, die interaktive Sitzungen ignorieren: permissionDecision: "defer", das einen Tool-Aufruf pausiert, damit ein umschließender Prozess (eine Agent-SDK-App, eine eigene UI) Eingaben sammeln und die Sitzung später fortsetzen kann.5
Warum läuft mein Hook, blockiert aber nichts?
Fast immer eine Vertragsverletzung. Exit 1 blockiert nicht — nur Exit 2 tut es, und nur bei Ereignissen, die Blockieren unterstützen.2 JSON-Entscheidungen werden nur bei Exit 0 ausgewertet — bei einem Skript, das {"decision": "block"} ausgibt und dann mit Exit 2 endet, wird sein JSON verworfen. Und Matcher unterscheiden Groß- und Kleinschreibung — bash passt nie auf Bash. Bestätigen Sie die Registrierung mit /hooks, und testen Sie dann, indem Sie beispielhaftes JSON in das Skript leiten und echo $? prüfen.7
Quellen
Geprüft gegen die offizielle Dokumentation am 1. Juli 2026. Die Hooks-API hat sich über die Claude Code v2.1.x-Releases hinweg wesentlich verändert (neue Ereignisse, neue Felder, Matcher-Semantik), behandeln Sie versionssensible Details daher als „Stand zu diesem Datum.”
Auf dieser Website verwandt: der Hooks-Abschnitt des Claude Code-Leitfadens für die Gesamtsicht des Systems einschließlich Prompt- und Agenten-Hooks, das Hooks-Tutorial für fünf Produktionsbeispiele mit vollständigen Konfigurationen, Hooks für die Apple-Entwicklung für die angewandten iOS-Muster und der Quickstart, falls Sie Claude Code noch nicht installiert haben.
-
Anthropic, “Hooks reference — Hook lifecycle and hook events.” code.claude.com/docs/en/hooks#hook-events ↩↩↩↩↩↩
-
Anthropic, “Hooks reference — Hook input and output; exit code output; exit code 2 behavior per event.” code.claude.com/docs/en/hooks#exit-code-output ↩↩↩↩↩↩↩↩
-
Anthropic, “Automate actions with hooks.” code.claude.com/docs/en/hooks-guide ↩↩↩
-
Anthropic, “Hooks guide — Hooks and permission modes.” code.claude.com/docs/en/hooks-guide#hooks-and-permission-modes ↩↩
-
Anthropic, “Hooks reference — JSON output and decision control.” code.claude.com/docs/en/hooks#json-output ↩↩↩↩↩↩↩
-
Anthropic, “Hooks reference — Configuration: hook locations, matcher patterns, hook handler fields, the /hooks menu.” code.claude.com/docs/en/hooks#configuration ↩↩↩↩↩↩
-
Anthropic, “Hooks guide — Limitations and troubleshooting.” code.claude.com/docs/en/hooks-guide#limitations-and-troubleshooting ↩↩↩↩↩
-
Anthropic, “Hooks reference — Security considerations.” code.claude.com/docs/en/hooks#security-considerations ↩
-
Anthropic, “Claude Code settings.” code.claude.com/docs/en/settings ↩