
Claude Code Hooks: Der komplette Guide (2026)
Ein Skill kann ignoriert werden. Das ist kein Fehler bei Skills, das ist das ganze Design: Claude liest die Beschreibung, entscheidet, ob die aktuelle Aufgabe passt, und lädt den Inhalt nur, wenn es das denkt. Meistens ist dieses Urteil richtig. Manchmal nicht, und die Aufgabe, bei der das am meisten zählt, das Code-Review kurz vor dem Merge, der Log-Eintrag, der egal was existieren muss, ist genau die Aufgabe, bei der „wahrscheinlich" nicht gut genug ist.
Hooks sind die andere Hälfte von Claude Code. Ein Hook ist ein Shell-Befehl, den der Harness ausführt, wenn ein bestimmtes Ereignis feuert, egal ob irgendein Skill daran gedacht hätte. Kein Modellurteil steht zwischen dem Ereignis und dem Befehl. Er läuft, jedes Mal, in Reihenfolge, und sein Exit-Code kann Claude sogar komplett stoppen. Wenn du je „formatiere diese Datei immer nach einem Edit" oder „lass Claude dieses Verzeichnis nie anfassen" sagen wolltest, ist ein Hook das Werkzeug, das für genau diesen Satz gebaut ist.
Dieser Guide behandelt, was Hooks sind, das dahinterliegende settings.json-Schema, sechs Rezepte, die du heute einfügen kannst, wie Hooks und Skills zusammenarbeiten, und die Fehlermuster, die einen Nachmittag fressen, wenn du nicht weißt, worauf du achten musst.
Was ein Hook eigentlich ist
Claude Code feuert benannte Ereignisse während einer Session: bevor ein Tool läuft, nachdem ein Tool gelaufen ist, wenn Claude mit seiner Antwort fertig ist, wenn eine Benachrichtigung angezeigt würde. Ein Hook bindet einen Shell-Befehl an eines dieser Ereignisse, optional gefiltert auf bestimmte Tools. Der Harness führt deinen Befehl aus, gibt ihm Kontext als JSON auf stdin, und liest dann den Exit-Code, um zu entscheiden, was als Nächstes passiert.
Die Ereignisse, die du am meisten nutzen wirst:
- PreToolUse — feuert, bevor ein Tool-Aufruf ausgeführt wird. Ein Hook hier kann den Aufruf komplett blockieren.
- PostToolUse — feuert, nachdem ein Tool-Aufruf fertig ist. Gut für Formatierung, Testen oder das Loggen, was gerade passiert ist.
- Stop — feuert, wenn Claude seinen Zug beendet und im Begriff ist, die Kontrolle an dich zurückzugeben.
- Notification — feuert, wenn Claude Code eine Systembenachrichtigung anzeigen würde (Berechtigungsanfragen, Leerlauf-Prompts).
- UserPromptSubmit — feuert, wenn du eine Nachricht absendest, bevor Claude sie sieht.
Das ist der Mechanismus. Der Grund, warum das zählt, ist die Garantie, die er dir gibt, die ein Skill strukturell nicht geben kann.
Das Denkmodell: deterministisch vs. diskretionär
Das ist die eine Idee, an die du dich erinnern solltest, wenn du dich an nichts anderem aus diesem Guide erinnerst.
Ein Skill ist diskretionär. Claude liest seine Beschreibung am Anfang einer Session und entscheidet später, basierend auf deiner Anfrage, ob er ihn lädt und befolgt. Gute Skills triggern zuverlässig, aber „zuverlässig" ist immer noch eine Wahrscheinlichkeit, keine Garantie. Claude kann einen mehrdeutigen Prompt falsch lesen, oder zwei Skills können sich überlappende Beschreibungen haben, die den Abgleich verwirren, ein Fehlermuster, das wir ausführlicher in unserem Guide dazu, warum Skills nicht triggern behandeln.
Ein Hook ist deterministisch. Er fragt Claude nicht, ob er laufen soll. Er liest keine Beschreibung und beurteilt Relevanz. Der Harness sieht das Ereignis, und der Befehl läuft, Punkt. Wenn das Ereignis PostToolUse beim Edit-Tool ist, läuft dein Formatter nach jedem Edit, einschließlich dem, den Claude gemacht hat, während es an etwas ganz anderes dachte.
Dieser Unterschied bildet sich direkt darauf ab, wann zu welchem greifen:
| Skill | Hook | |
|---|---|---|
| Läuft wann | Claude beurteilt es als relevant | Jedes Mal, wenn das Ereignis feuert |
| Kann übersprungen werden | Ja, durch einen schlechten Match oder vollen Kontext | Nein |
| Am besten für | Urteilsvermögen, Struktur, „wie man X gut macht" | Durchsetzung, „X muss immer passieren" |
| Fehlermodus | Stiller Nicht-Trigger | Stiller schlechter Exit-Code, oder alles blockieren |
Wenn der Satz, den du durchsetzt, mit „Claude sollte immer..." oder „Claude darf nie..." beginnt, willst du einen Hook. Wenn er mit „wenn Claude X macht, sollte es so herangehen..." beginnt, willst du einen Skill. Code nach jedem Edit zu formatieren ist ein Hook; idiomatisches Python zu schreiben ist ein Skill. Commits auf main zu blockieren ist ein Hook; eine gute Commit-Nachricht zu strukturieren ist ein Skill.
Anatomie eines Hooks in settings.json
Hooks leben unter dem Schlüssel hooks in .claude/settings.json (Projektebene) oder ~/.claude/settings.json (Nutzerebene), eine andere Datei als CLAUDE.md und die es sich lohnt, nicht zu verwechseln: CLAUDE.md ist Prosa, die Claude liest, settings.json ist Config, die der Harness ausführt. Falls du noch keins von beiden eingerichtet hast, decken unser CLAUDE.md-Guide und unser vollständiger Setup-Durchlauf den Rest des Stacks ab, in dem diese Datei lebt. Hier ist ein minimales, aber vollständiges Hooks-Beispiel, kommentiert:
{
"hooks": {
// Der Ereignisname — PreToolUse, PostToolUse, Stop, Notification, etc.
"PostToolUse": [
{
// matcher filtert, welche Tool-Aufrufe diesen Hook auslösen.
// Weglassen (oder "*" nutzen), um jedes Tool zu matchen.
"matcher": "Edit|Write",
"hooks": [
{
// "command" ist derzeit der einzige Hook-Typ.
"type": "command",
// Der auszuführende Shell-Befehl. Erhält Ereignis-JSON auf stdin.
"command": "npx prettier --write \"$(echo $CLAUDE_TOOL_INPUT | jq -r .file_path)\"",
// Optional: den Befehl killen, falls er hängt.
"timeout": 15
}
]
}
]
}
}
Ein paar Dinge, die sich zu erwähnen lohnen, weil sie Leute stolpern lassen:
Das matcher-Feld operiert auf dem Tool-Namen, nicht auf Dateipfaden oder Inhalt. "Edit|Write" matcht die Edit- und Write-Tools; "Bash" matcht Shell-Aufrufe. Wenn du nach Dateipfad oder Befehlsinhalt filtern musst, tu das innerhalb deines Skripts, indem du das JSON-Payload liest, nicht im matcher.
Jeder Ereignis-Schlüssel hält ein Array von Matcher-Blöcken, und jeder Matcher-Block hält ein Array von Hook-Befehlen, sodass du mehrere Befehle an einen Matcher hängen kannst, oder einen Befehl an mehrere Matcher, ohne Config zu duplizieren.
Der Befehl erhält das Ereignis-Payload als JSON auf stdin: Tool-Name, Tool-Input, und bei PostToolUse das Ergebnis des Tools. Ein Hook, der auf die spezifische Datei wirkt, die editiert wird, liest dieses JSON, statt anzunehmen, dass das Arbeitsverzeichnis der Shell die ganze Geschichte erzählt.
Exit-Codes tragen Bedeutung. Exit 0 heißt „alles gut, weiter". Ein Exit ungleich null bei einem PreToolUse-Hook blockiert den Tool-Aufruf und speist stderr an Claude als Grund zurück. Ein Exit ungleich null bei PostToolUse wird nur geloggt; das Tool ist schon gelaufen, also gibt es nichts mehr zu blockieren.
Sechs Rezepte, die du heute nutzen kannst
Diese sind absichtlich schmal. Kopier den Block, passe den Befehl an, und bestätige, dass er tut, was du erwartest, an einer Wegwerfdatei, bevor du ihn bei echter Arbeit einsetzt.
1. Auto-Formatierung nach jedem Edit
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npx prettier --write . --ignore-unknown"
}
]
}
]
}
}
Führt Prettier nach jedem Edit oder Write aus. Bei großen Repos ersetze das pauschale . durch einen Pfad, der aus dem JSON-Input des Hooks abgeleitet wird, sodass nur die berührte Datei formatiert wird.
2. Edits an geschützten Pfaden blockieren
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/guard_paths.py"
}
]
}
]
}
}
guard_paths.py liest den Dateipfad aus dem stdin-JSON, prüft ihn gegen eine Sperrliste (migrations/, .env, infra/prod/) und beendet sich mit 1 und einer Nachricht auf stderr, falls er matcht. Das ist das Nächste an einer harten Berechtigungsgrenze, das Claude Code hat.
3. Tests nach Quellcode-Änderungen ausführen
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "cd \"$CLAUDE_PROJECT_DIR\" && npm test -- --onlyChanged --silent"
}
]
}
]
}
}
Gibt Claude ein sofortiges Signal, wenn ein Edit einen Test bricht, statt zu warten, bis du es beim Review bemerkst. Halte den Testbefehl schmal (--onlyChanged, eine schnelle Teilmenge), sonst wird das zu Rezept sechs im Abschnitt „wann nicht" unten.
4. Desktop-Benachrichtigung, wenn Claude fertig ist
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude finished\" with title \"Claude Code\"'"
}
]
}
]
}
}
macOS-spezifisch (für Linux durch notify-send ersetzen). Nützlich, sobald du längere autonome Turns fährst und aufhörst, das ganze Terminal zu beobachten.
5. Jeden Bash-Befehl loggen
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> \"$CLAUDE_PROJECT_DIR/.claude/bash-history.log\""
}
]
}
]
}
}
Ein Audit-Trail, der nicht davon abhängt, dass du dich erinnerst, das Transkript zu prüfen. Auf einer geteilten Maschine oder einem Repo mit Compliance-Anforderung ist das nahezu verpflichtend.
6. Lint-Gate vor Commit
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block_bad_commit.sh"
}
]
}
]
}
}
block_bad_commit.sh liest stdin, prüft, ob der Befehl ein git commit ist, und falls ja, führt es zuerst deinen Linter aus, beendet sich mit ungleich null, falls er fehlschlägt. Das macht „bitte vor dem Commit linten" von einer Bitte, die Claude vergessen könnte, zu einer Regel, an der es nicht vorbeikommt.
GRATIS STARTERPAKET
Richtest du Hooks neben deinen ersten Skills ein? Wir schicken unsere 3 bestbewerteten Skills plus die Install-Checkliste, die wir vor jedem SkillProof-Test durchlaufen. Kostenlos.
Gratis-Starterpaket holenHooks und Skills zusammen
Sie sind keine konkurrierenden Werkzeuge; die besten Setups nutzen beide für das, worin jedes gut ist. Ein durchgearbeitetes Beispiel: Ein Team, das wir getestet haben, wollte jeden Commit im hauseigenen Stil geschrieben haben, Imperativ, ein gescoptes Präfix, ein Body, der das Warum erklärt, und sie wollten auch Commits blockiert haben, wenn der Diff eine Datenbank-Migration ohne passende Rollback-Datei betrifft.
Der Stil-Teil ist Urteilsvermögen. Was als gutes „Warum" zählt, variiert je nach Änderung, und es gibt kein Shell-Skript, das zuverlässig gute Prosa schreibt. Das ist die Aufgabe eines Skills: etwas wie Git Workflow Coach, geladen, wann immer Claude im Begriff ist zu committen, das die Struktur lehrt und Beispiele für gute versus lieblose Commit-Nachrichten gibt. Claude liest es, wendet Urteilsvermögen an und schreibt eine Nachricht, die zum Muster passt, ohne eine Vorlage auszufüllen. Wenn das Team auch strikt Rot-Grün-Refactor fährt, ist Test-Driven Development dieselbe Art von Urteil-statt-Gesetz-Ergänzung: Es formt, wie Claude an die Arbeit herangeht, ein Hook kann das nicht.
Die Migrations-Regel ist kein Urteil, sie ist Gesetz: Entweder existiert die Rollback-Datei oder nicht, und das Team wollte nicht, dass „Claude hat entschieden, diese hier braucht keine" eine Option ist. Das ist der PreToolUse-Hook aus Rezept sechs, angepasst, um auf die gepaarte Datei zu prüfen statt einen Linter auszuführen, blockiert den git commit-Aufruf komplett, falls sie fehlt.
Fährt man beide zusammen, bekommt man eine gute Commit-Nachricht, die auch garantiert die Migrations-Prüfung besteht, weil der Skill den Teil handhabt, der ein Gehirn braucht, und der Hook den Teil, der eine Wand braucht. Keines ersetzt das andere. Der Skill kann Compliance nicht garantieren, und ein Hook, der bei jedem Commit „fix: various changes" schreibt, wäre nutzlos. Unsere Best-Coding-Skills-Seite rankt die Urteilsseite dieser Paarung nach getesteter Bewertung, falls du einen ersten Skill wählst, der neben deinen Hooks laufen soll.
Hooks debuggen
Hooks scheitern öfter still als laut. Was üblicherweise kaputtgeht:
Quoting. Hook-Befehle sind Shell-Strings innerhalb von JSON-Strings, also bricht ein ", das nicht escaped ist, das JSON-Parsing, bevor dein Befehl je läuft. Im Zweifel packe die eigentliche Logik in eine Skript-Datei und lass den Hook-Befehl sie nur aufrufen (bash .claude/hooks/my-hook.sh), statt einen komplexen Einzeiler inline zu schreiben.
Exit-Codes, die nicht bedeuten, was du denkst. Ein Hook-Skript, das auf einen unzusammenhängenden Fehler stößt (fehlende Abhängigkeit, Berechtigung verweigert), beendet sich mit ungleich null genauso wie ein Hook, der absichtlich blockieren will. Wenn ein PreToolUse-Hook anfängt, jeden Tool-Aufruf zu blockieren, und du ihn nicht so streng geschrieben hast, prüfe, ob das Skript tatsächlich fehlschlägt statt zu urteilen.
PATH-Annahmen. Hooks laufen in einer Shell-Umgebung, die möglicherweise nicht deinem interaktiven Terminal entspricht. Ein Befehl, der problemlos funktioniert, wenn du ihn selbst eintippst, kann innerhalb eines Hooks scheitern, weil nvm, ein virtualenv oder ein über ein Shell-Plugin installiertes Tool in diesem Kontext nicht im PATH ist. Nutze absolute Pfade zu Binaries, oder source die richtige Umgebung am Anfang des Skripts.
Stille stdin-Annahmen. Wenn dein Skript JSON auf stdin erwartet und es nicht bekommt, weil du es getestet hast, indem du es direkt ausgeführt hast statt ein Beispiel-Payload einzuspeisen, verhält es sich unter dem Harness anders als in deinem Terminal.
Timeouts. Ein Hook ohne Timeout, der hängt, hängt den ganzen Turn auf. Setze ein explizites timeout auf alles, was das Netzwerk oder einen langsamen Subprozess berührt.
Wann Hooks nicht nutzen
Hooks sind billig zu schreiben und leicht zu überstrapazieren. Das Fehlermuster ist nicht, dass ein Hook das Falsche tut, es ist, dass ein Hook das Richtige zu oft tut. Ein PostToolUse-Hook, der nach jedem einzelnen Edit die volle Testsuite ausführt, macht aus einer Fünf-Sekunden-Änderung eine Zwei-Minuten-Wartezeit, wiederholt für jeden Edit in einer Session, die zwanzig davon macht.
Die Faustregel: Wenn der Befehl eines Hooks mehr als ein, zwei Sekunden braucht, verenge den Matcher, verenge, was er prüft, oder verschiebe ihn auf ein selteneres Ereignis. Test-bei-jedem-Edit wird zu Test-bei-Datei-Schreiben wird zu Test-vor-Commit, während die Prüfung teurer wird. Passe die Kosten des Hooks daran an, wie oft sein Ereignis feuert, und erwäge, ob ein Skill, der nur Kontext lädt und keinen Prozess ausführt, für alles, was nicht strikt Durchsetzung ist, die bessere Wahl ist.
Es lohnt sich auch, nicht zu einem Hook zu greifen, um das Trigger-Problem eines Skills zu beheben. Wenn ein Skill nicht feuert, wenn er sollte, ist die Lösung eine bessere Beschreibung, kein Hook, denn Hooks führen Shell-Befehle aus und können keinen Skill-Inhalt laden. Für dieses Fehlermuster siehe warum Skills nicht triggern.
SKILLPROOF-PAKET
Hooks mit den richtigen Skills zu paaren ist der Großteil eines guten Claude-Code-Setups. Das Developer Toolkit bündelt unsere bestbewerteten Coding-Skills, vorab auf Trigger-Konflikte geprüft, sodass die Skill-Hälfte dieser Paarung für dich erledigt ist.
Developer Toolkit holen — $10FAQ
Verlangsamen Hooks jede Claude-Code-Session?
Nur die Ereignisse, an die du sie hängst, und nur um so lange, wie dein Befehl braucht. Ein Hook auf PostToolUse für Edit läuft einmal pro Edit; ein schneller Formatter ist unmerklich, eine volle Testsuite wird bei jedem Edit gespürt, was der oben unter „wann Hooks nicht nutzen" behandelte Fall ist.
Kann ein Hook Claude komplett davon abhalten, etwas zu tun?
Ja, dafür sind PreToolUse-Hooks da. Beende mit ungleich null, und der Tool-Aufruf wird blockiert, bevor er läuft, wobei stderr typischerweise als Grund an Claude zurückgespielt wird. Das ist der Mechanismus hinter Rezept zwei (geschützte Pfade) und Rezept sechs (Lint-Gate).
Wo lege ich meine Hooks-Config ab, Projekt- oder Nutzer-Settings?
Projektebene (.claude/settings.json, committet), wenn sie für alle in dieser Codebasis gelten soll: Formatierung, geschützte Pfade, Migrations-Prüfungen. Nutzerebene (~/.claude/settings.json) für eine persönliche Präferenz, wie die Desktop-Benachrichtigung in Rezept vier.
Was ist der Unterschied zwischen einem Hook und einem Skill, der sagt „formatiere Code immer"?
Der Hook läuft tatsächlich immer. Ein Skill, der Claude sagt, Code immer zu formatieren, ist immer noch eine Anweisung, die Claude liest und entscheidet zu befolgen; es ist ein starker Anstoß, keine Garantie, und er konkurriert mit anderen Dingen im Kontext um Aufmerksamkeit in jedem gegebenen Turn. Wenn „immer" eine Anforderung statt einer Präferenz ist, nutze einen Hook.
Mein Hook läuft überhaupt nicht. Was prüfe ich zuerst?
Bestätige, dass die Settings-Datei gültiges JSON ist (ein Trailing-Komma oder unescaped Anführungszeichen kann den ganzen Hooks-Block still deaktivieren) und dass Ereignisname und Matcher genau wie erwartet geschrieben sind; beide sind case-sensitive. Danach prüfe, ob du Projekt-Settings editiert hast, während die Session Nutzer-Settings liest, oder umgekehrt.
★ 9.6/10 × 3
Das kostenlose Starterpaket
Die 3 Skills mit unseren besten Testergebnissen plus die Install-Checkliste — das Setup, das wir auf einen frischen Rechner packen würden. Kostenlos, per E-Mail.