Hook-Events & Handler
Wissen
Die wichtigsten Hook-Events
Claude Code feuert an 24 Stellen im Workflow Events. Jedes Event ist ein Eingriffspunkt, an dem du deterministisches Verhalten erzwingen kannst. Hier die wichtigsten:
| Event | Wann feuert es? | Typischer Einsatz |
|---|---|---|
| PreToolUse | Vor jeder Tool-Ausführung | Validierung, Blockieren gefährlicher Aktionen |
| PostToolUse | Nach jeder Tool-Ausführung | Auto-Formatierung, Linting, Type-Checks |
| SessionStart | Beim Start einer neuen Session | Kontext laden, Environment prüfen |
| Stop | Claude ist fertig mit der Aufgabe | Qualitätsgates, finale Prüfungen |
| UserPromptSubmit | Bevor ein Prompt verarbeitet wird | Kontext-Injection, Prompt-Enrichment |
| SubagentStart | Subagent wird gestartet | Monitoring, Konfiguration |
| SubagentStop | Subagent hat Ergebnis | Ergebnis-Validierung |
| TaskCreated | Neue Task in Agent-Teams | Koordination, Logging |
| TaskCompleted | Task abgeschlossen | Qualitätskontrolle |
| PreCompact | Vor Context-Komprimierung | Wichtige Infos sichern |
| PostCompact | Nach Context-Komprimierung | Kontext wiederherstellen |
| WorktreeCreate | Git-Worktree erstellt | Setup, Initialisierung |
| WorktreeRemove | Git-Worktree entfernt | Cleanup, Aufräumen |
| Notification | Claude wartet auf Eingabe | Desktop-Benachrichtigung |
iPreToolUse und PostToolUse sind die Stars
Diese beiden Events decken 80% aller Anwendungsfälle ab. PreToolUse blockiert gefährliche Aktionen, PostToolUse sorgt für automatische Qualitätssicherung nach jeder Änderung.
Die 4 Handler-Typen
Jeder Hook braucht einen Handler -- die Logik, die beim Event ausgeführt wird:
1. Command-Handler (Standard)
Der häufigste Typ. Führt ein Shell-Script aus und empfängt den Event-Kontext als JSON über stdin.
{
"type": "command",
"command": "npx prettier --write $TOOL_INPUT_FILE_PATH"
}
Das Script erhält alle relevanten Informationen: welches Tool aufgerufen wurde, mit welchen Argumenten, und was das Ergebnis war. Perfekt für Linting, Tests, Formatierung und Sicherheitschecks.
2. HTTP-Handler
Sendet einen POST-Request an einen HTTP-Endpoint. Ideal für Logging, Webhooks oder die Integration mit externen Systemen.
{
"type": "http",
"url": "https://your-server.com/hooks/log",
"headers": { "Authorization": "Bearer $TOKEN" }
}
3. Prompt-Handler
Nutzt ein leichtgewichtiges LLM (Haiku) für einen einzelnen Evaluations-Turn. Gut für Entscheidungen, die menschliches Urteil simulieren.
{
"type": "prompt",
"prompt": "Prüfe ob dieser Code-Änderung die bestehende API bricht. Antworte nur mit PASS oder FAIL."
}
!Prompt-Handler sind nicht deterministisch
Der Prompt-Handler nutzt ein LLM -- das heißt, seine Antworten können variieren. Für harte Regeln wie "kein force push" ist ein Command-Handler besser geeignet.
4. Agent-Handler
Der mächtigste Typ: Ein Multi-Turn LLM mit Tool-Zugriff, der bis zu 50 Turns ausführen kann. Für komplexe Prüfungen wie "Hat diese Änderung alle Tests aktualisiert?"
{
"type": "agent",
"prompt": "Prüfe ob die geänderten Dateien entsprechende Test-Updates haben. Führe die Tests aus und berichte.",
"maxTurns": 10
}
Exit-Codes: Die Sprache der Hooks
Hooks kommunizieren über Exit-Codes mit Claude Code:
| Exit-Code | Bedeutung | Verhalten |
|---|---|---|
| 0 | Alles OK | Aktion fortsetzen. stdout wird dem Context hinzugefügt |
| 2 | Blockieren | Aktion wird VERHINDERT. stderr wird als Feedback an Claude zurückgegeben |
| Anderer | Nicht-blockierender Fehler | Aktion wird fortgesetzt. stderr wird im Verbose-Modus (Ctrl+O) angezeigt |
Das ist elegant: Exit-Code 0 heißt "weitermachen", Exit-Code 2 heißt "stopp". Alles andere wird als nicht-kritischer Fehler behandelt und läuft weiter.
#!/bin/bash
# Beispiel: Blockiere force-push
if echo "$1" | grep -q "push.*--force"; then
echo "Force-push ist nicht erlaubt!" >&2
exit 2
fi
exit 0
Matcher und if-Filter
Nicht jeder Hook soll bei jedem Tool-Aufruf feuern. Dafür gibt es zwei Filtermechanismen:
Matcher: Regex auf den Tool-Namen
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "npx prettier --write" }]
}
Dieser Hook feuert nur bei Edit- und Write-Aufrufen, nicht bei Bash oder Read.
if-Filter: Tool + Argument
{
"matcher": "Bash",
"if": "Bash(git commit*)",
"hooks": [{ "type": "command", "command": "npm test" }]
}
Der if-Filter ist mächtig: Er matcht nicht nur den Tool-Namen, sondern auch die Argumente. Bash(git commit*) feuert nur, wenn Claude einen git commit-Befehl ausführen will -- nicht bei jedem Bash-Aufruf.
*Matcher + if kombinieren
Der matcher filtert grob nach Tool-Typ, der if-Filter verfeinert nach Argumenten. Zusammen ergibt das präzise Kontrolle ohne Overhead.
Wo Hooks gespeichert werden
Hooks können an vier Orten definiert werden, mit aufsteigender Priorität:
- Global (
~/.claude/settings.json) -- Gilt für alle Projekte. Ideal für persönliche Präferenzen wie Formatierung oder Notifications. - Projekt (
.claude/settings.json) -- Gilt für das gesamte Team. Wird ins Git-Repository committed. - Lokal (
.claude/settings.local.json) -- Persönliche Projekt-Overrides. Wird NICHT committed (in .gitignore). - Skill/Agent Frontmatter -- Hooks innerhalb eines Skills oder Agent-Definitions. Gilt nur für diesen Skill.
iTeam-Hooks vs. persönliche Hooks
Qualitäts-Hooks wie Linting und Tests gehören in die Projekt-Settings (.claude/settings.json), damit das ganze Team davon profitiert. Desktop-Notifications oder persönliche Formatierungs-Präferenzen gehören in die lokale oder globale Config.
Verstehen
Probiere den Hook-Event-Simulator aus: Wähle ein Szenario und beobachte, welche Events in welcher Reihenfolge feuern. Klicke auf einzelne Events, um Details und Beispiel-Konfigurationen zu sehen.
Claude Code schreibt eine Datei mit dem Write-Tool.
Klicke auf einen Hook-Event, um Details zu sehen. Pfeiltasten zur Navigation.
Anwenden
Überlege für dein aktuelles Projekt: Welche Aktionen sollen IMMER nach einer Dateiänderung laufen? Welche Befehle sollen NIEMALS ohne Prüfung ausgeführt werden? Die Antworten darauf zeigen dir, welche Events und Handler du brauchst. Im nächsten Abschnitt bekommst du fertige Rezepte zum Kopieren.