Claude Code Hooks: Automatisierte Quality-Gates im KI-Workflow
Mit Claude Code Hooks bauen wir deterministische Quality-Gates: Auto-Format nach Edits, gefährliche Befehle blocken, Tests grün vor Schluss. Teil 3 der Serie.
In Teil 2 der Claude-Code-Serie
haben wir Subagents direkt auf main pushen lassen — halbe Wand-Zeit für die
gleiche Liefermenge, aber zu einem Preis: Wo vorher ein Pull-Request-Review die
letzte Kontrolle war, committen jetzt mehrere KI-Agents ohne menschlichen Gate.
Diese Lücke schließt man nicht mit mehr Vertrauen, sondern mit automatisierten
Quality-Gates. Genau dafür gibt es Claude Code Hooks: deterministische
Shell-Skripte, die vor oder nach jedem Tool-Call laufen — und die der KI nicht
raten lassen, ob eine Änderung sauber ist, sondern es erzwingen.
Hooks sind der dritte und letzte Hebel dieser Serie. In Teil 1 ging es um Permissions, Rules und Skills — die Governance-Schicht. In Teil 2 um Subagents und Orchestrierung — die Parallelisierungs-Schicht. Dieser Teil schließt die Klammer mit der Absicherungs-Schicht: Checks, die unabhängig vom Modell laufen und nicht verhandelbar sind.
Was Hooks sind — und was sie nicht sind
Ein Hook ist ein Kommando, das Claude Code zu einem bestimmten Zeitpunkt im
Lebenszyklus einer Session automatisch ausführt — typischerweise ein
Shell-Skript, das vor oder nach einem Tool-Call feuert. Konfiguriert werden
Hooks in der settings.json, also in genau den Settings-Ebenen, die wir in
Teil 1 schon für Permissions genutzt haben: geteilt im Repo
(.claude/settings.json), persönlich und lokal (.claude/settings.local.json)
oder global (~/.claude/settings.json).
Der entscheidende Unterschied zu den anderen beiden Hebeln liegt in der Verbindlichkeit:
- Eine Rule (CLAUDE.md) ist eine Bitte an die KI. Das Modell liest sie, gewichtet sie — und hält sich meistens daran. Meistens.
- Eine Permission ist ein Schalter.
Bash(git push --force:*)auf der Deny-Liste, und der Befehl wird nie ohne Rückfrage ausgeführt. Statisch, zuverlässig, aber ohne Logik. - Ein Hook ist ein Programm. Er bekommt den vollständigen Kontext des Tool-Calls als JSON, kann beliebige Prüfungen anstellen — Muster matchen, Dateiinhalte lesen, ein externes Tool aufrufen — und auf dieser Basis entscheiden: durchlassen, blockieren, oder die Änderung sogar selbst korrigieren.
Kurzform: Eine Permission ist ein Schalter, ein Hook ist ein Programm, eine Rule ist eine Bitte. Quality-Gates brauchen die Verbindlichkeit eines Programms — deshalb sind Hooks dafür das richtige Werkzeug.
Was Hooks nicht sind: kein Ersatz für menschliches Review bei Architektur-Entscheidungen, keine KI-Komponente (sie sind stumpfer, deterministischer Code), und kein Weg, der KI neue Fähigkeiten zu geben. Sie sind Leitplanken, keine Lenkung.
Die Hook-Events, die zählen
Claude Code kennt eine ganze Reihe von Lifecycle-Events. Für Quality-Gates sind drei davon zentral; zwei weitere sind für Kontext-Injektion nützlich. Wir konzentrieren uns bewusst auf den stabilen Kern, statt jeden exotischen Event-Typ aufzuzählen.
| Event | Feuert | Kann blockieren? |
|---|---|---|
PreToolUse | bevor ein Tool ausgeführt wird | Ja — der Call wird verhindert |
PostToolUse | nachdem ein Tool erfolgreich war | Nein (lief schon), aber Feedback möglich |
Stop | wenn Claude meint, fertig zu sein | Ja — der Agent muss weiterarbeiten |
UserPromptSubmit | bevor ein Prompt verarbeitet wird | Ja, plus Kontext-Injektion |
SessionStart | bei Start/Resume einer Session | Nein, aber Kontext-Injektion |
Die wichtigste Unterscheidung: PreToolUse ist ein Gate vor der Aktion — hier
verhindert man Schaden, bevor er passiert. PostToolUse ist eine Reaktion
nach der Aktion — der Tool-Call lief bereits, man kann ihn nicht ungeschehen
machen, aber man kann aufräumen (formatieren, loggen) oder den nächsten Schritt
beeinflussen. Stop ist der Abschluss-Check — bevor der Agent die Hände hebt
und „fertig” sagt.
Für die drei Quality-Gates weiter unten brauchen wir genau diese drei:
PostToolUse zum Formatieren, PreToolUse zum Blocken, Stop zum Verifizieren.
Anatomie eines Hooks
Hooks leben unter dem Schlüssel hooks in der settings.json. Pro Event eine
Liste von Matcher-Gruppen, pro Gruppe eine Liste konkreter Kommandos. Ein
minimales, vollständiges Beispiel:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/format.sh"
}
]
}
]
}
}
Die vier Teile, die man verstehen muss:
- Event-Key (
PostToolUse) — wann der Hook feuert. matcher— auf welche Tools er reagiert. FürPreToolUse/PostToolUseist das der Tool-Name:Bash,Edit,Write,Read— oder eine Pipe-Alternative wieEdit|Write. Ein leerer String oder*matcht alles.command— was ausgeführt wird.${CLAUDE_PROJECT_DIR}zeigt auf den Projekt-Root, damit Skript-Pfade unabhängig vom aktuellen Arbeitsverzeichnis stimmen.- stdin — das Kommando bekommt ein JSON-Objekt auf der Standardeingabe:
tool_name,tool_input(z. B.tool_input.file_pathbei Edit/Write,tool_input.commandbei Bash), dazusession_id,cwdundtranscript_path.
Wie ein Hook entscheidet, läuft über zwei Mechanismen — einen einfachen und einen feingranularen.
Exit-Codes (der einfache Weg):
| Exit-Code | Bedeutung |
|---|---|
0 | Erfolg. Bei UserPromptSubmit/SessionStart wird stdout in den Kontext übernommen. |
2 | Blockieren. stderr wird als Feedback an die KI zurückgegeben (bei Events, die blockieren können). |
| sonstige | Nicht-blockierender Fehler. stderr landet im Log, die Aktion läuft weiter. |
Für die meisten Quality-Gates reicht exit 2 mit einer Fehlermeldung auf
stderr. Die KI sieht die Meldung und passt ihr Verhalten an.
JSON auf stdout (der feingranulare Weg): Schreibt der Hook bei Exit 0
gültiges JSON, kann er gezielter steuern. Bei PreToolUse etwa über
permissionDecision (allow, deny, ask):
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Schreibzugriff auf .env ist gesperrt."
}
}
allow überspringt die Rückfrage, ask erzwingt den normalen
Permission-Dialog, deny bricht ab und erklärt der KI den Grund. Bei
PostToolUse und Stop gibt es analog decision: "block" mit einem reason.
Für den Einstieg genügt aber fast immer der Exit-Code.
Drei Quality-Gates aus unserer Praxis
Theorie genug. Hier sind die drei Gates, die in unserem .NET-/React-Setup tatsächlich laufen — jeder mit der konkreten Konfiguration und dem Skript.
Gate 1 — Auto-Format nach jedem Edit
Das billigste, wirksamste Gate zuerst. Jedes Mal, wenn die KI eine Datei
schreibt oder ändert, formatieren wir sie automatisch nach. Kein „bitte halte
dich an unseren Style” in einer Rule — sondern ein Formatter, der nach jedem
Edit/Write deterministisch durchläuft.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/format.sh"
}
]
}
]
}
}
#!/usr/bin/env bash
# Liest das Hook-Input-JSON von stdin, zieht den Dateipfad heraus
# und formatiert die Datei je nach Endung.
file=$(jq -r '.tool_input.file_path // empty')
[ -z "$file" ] && exit 0
case "$file" in
*.ts|*.tsx|*.js|*.jsx|*.json|*.css) npx prettier --write "$file" ;;
*.cs) dotnet format --include "$file" ;;
esac
exit 0
Warum das mehr ist als Bequemlichkeit: Der KI-generierte Diff ist damit immer im
Projekt-Style, bevor er überhaupt zum Commit kommt. Das eliminiert eine ganze
Klasse von Review-Reibung — niemand kommentiert mehr Einrückungen oder
Anführungszeichen, weil der Formatter das längst geklärt hat. Und weil der Hook
im geteilten .claude/settings.json liegt, gilt er für jeden im Team und für
jeden Subagent automatisch.
Gate 2 — Gefährliche Befehle hart blocken
Die Deny-Liste aus Teil 1 ist statisch: ein Befehl ist drauf oder nicht. Ein
PreToolUse-Hook kann mehr — er sieht den vollständigen Befehl und kann mit
echter Logik entscheiden.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-bash.sh"
}
]
}
]
}
}
#!/usr/bin/env bash
# Bricht den Bash-Call ab, wenn der Befehl ein gesperrtes Muster trifft.
cmd=$(jq -r '.tool_input.command // empty')
patterns='rm -rf|git push.*--force|git reset --hard|cat .*\.env'
if printf '%s' "$cmd" | grep -Eq "$patterns"; then
echo "Blockiert: Befehl trifft auf ein gesperrtes Muster." >&2
echo "Befehl war: $cmd" >&2
exit 2
fi
exit 0
exit 2 bricht den Tool-Call ab, und die Meldung auf stderr geht zurück an die
KI — die daraufhin einen anderen Weg sucht, statt blind weiterzulaufen. Der
Unterschied zur Permission-Deny-Liste: Hier lässt sich kombinieren und
kontextualisieren. Man kann etwa nur dann blocken, wenn der Befehl ein
Force-Push und der Ziel-Branch main ist; man kann das gelesene .env-File
prüfen; man kann je nach Tageszeit oder Umgebung anders entscheiden. Logik, die
ein statischer Schalter nicht leisten kann.
Gate 3 — Tests grün, bevor der Agent fertig ist
Das ist das Gate, das die Lücke aus Teil 2 schließt. Wenn Subagents direkt auf
main pushen, fehlt das PR-Review als letzter Check. Ein Stop-Hook setzt
genau hier an: Bevor der Agent „fertig” sagen darf, läuft die Test-Suite — und
sind die Tests rot, wird der Agent mit exit 2 zurück an die Arbeit gezwungen.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/verify.sh"
}
]
}
]
}
}
#!/usr/bin/env bash
# Läuft, wenn Claude meint, fertig zu sein. Schlagen die Tests fehl,
# zwingt exit 2 den Agent zurück, statt ihn abschließen zu lassen.
if dotnet test --nologo --verbosity quiet > /tmp/claude-tests.log 2>&1; then
exit 0
fi
echo "Tests sind rot. Bitte zuerst die fehlschlagenden Tests grün machen." >&2
echo "Auszug:" >&2
tail -n 20 /tmp/claude-tests.log >&2
exit 2
Das verändert die Dynamik einer Agent-Session grundlegend. Ohne dieses Gate endet ein Lauf mit „Ich habe die Änderung implementiert” — und ob die Tests durchlaufen, merkt man erst beim nächsten CI-Build. Mit dem Gate kann die Session gar nicht erst sauber enden, solange etwas rot ist. Der Agent bekommt den Test-Output direkt zurück und korrigiert in derselben Session.
Ein Wort zur Performance: Ein Stop-Hook, der bei jedem Turn-Ende die volle
Suite fährt, bremst. In der Praxis begrenzt man das — nur das betroffene
Test-Projekt, nur eine schnelle Teilmenge, oder nur wenn überhaupt Quellcode
geändert wurde. Das Gate soll absichern, nicht den Flow zäh machen.
Hooks vs. Permissions vs. Rules — wann was
Drei Mechanismen, drei Einsatzgebiete. Die Faustregel:
| Anforderung | Mechanismus |
|---|---|
| Statischer Befehls-Gate (immer erlauben/verbieten) | Permission (allow/deny) |
| Deterministischer Check mit Logik (Muster, Dateiinhalt, externes Tool) | Hook (PreToolUse) |
| Automatik nach jeder Änderung (Format, Lint, Log) | Hook (PostToolUse) |
| Abschluss-Check vor „fertig” (Tests, Build) | Hook (Stop) |
| Kontextabhängiges, urteilsbasiertes Verhalten | Rule (CLAUDE.md) |
| Aufrufbarer, wiederholbarer Workflow | Skill |
Der häufigste Fehler ist, alles in Rules zu schreiben. „Formatiere immer nach unserem Style”, „führe vor dem Commit die Tests aus”, „pushe niemals mit Force” — das sind Bitten an ein probabilistisches Modell. In neun von zehn Fällen funktioniert es. Der zehnte Fall ist der, der in Produktion landet. Was nicht scheitern darf, gehört nicht in eine Rule, sondern in einen Hook oder eine Permission.
Trade-offs und Grenzen
Hooks sind mächtig, und genau deshalb muss man ihre Kosten ehrlich auf den Tisch legen.
1. Hooks führen beliebigen Shell-Code mit deinen Rechten aus. Das ist kein Implementierungsdetail, sondern das zentrale Sicherheitsthema. Ein Hook läuft ungesandboxt mit deinen Credentials und deinem Dateisystem-Zugriff. Wer eine Hook-Konfiguration aus einem Plugin, einem fremden Repo oder von einem Teammitglied übernimmt, sollte sie lesen, bevor er sie aktiviert — die offizielle Claude-Code-Dokumentation weist ausdrücklich darauf hin. Geteilte Hooks im Repo sind ein Vorteil für Konsistenz und ein Angriffsvektor zugleich; beides gilt.
2. PostToolUse kann nichts ungeschehen machen. Der Tool-Call ist gelaufen,
bevor der Hook feuert. Wer eine Aktion verhindern will, braucht PreToolUse —
PostToolUse ist für Reaktion, nicht für Prävention. Ein häufiges
Missverständnis: exit 2 in einem PostToolUse-Hook macht den Edit nicht
rückgängig.
3. Ein hängender oder flakiger Hook blockiert den Agent. Ein Hook, der auf ein langsames externes Tool wartet oder gelegentlich falsch-positiv blockt, bremst jede Session aus. Hooks sollten schnell, deterministisch und single-purpose sein — je kleiner, desto leichter zu auditieren und zu vertrauen.
4. Cross-Plattform ist real. Die Beispiele hier sind Bash. Wer im Team Windows-Maschinen hat, muss die Hooks entweder PowerShell-tauglich schreiben oder auf eine plattformneutrale Laufzeit setzen. Ein Hook, der nur auf dem macOS-Laptop des Tech-Leads läuft, ist kein Team-Gate.
5. Hooks ersetzen kein menschliches Urteil. Sie fangen das Mechanische ab — Format, offensichtlich gefährliche Befehle, rote Tests. Ob die Architektur einer Lösung trägt, ob ein Feature das richtige Problem löst, ob ein Trade-off zur Domäne passt: Das bleibt menschliche Arbeit. Quality-Gates senken die Last des Offensichtlichen, damit im Review Raum für das Wesentliche bleibt.
Fazit
Damit schließt sich die Klammer der Serie. Drei Schichten machen aus Claude Code ein Werkzeug, dem man auch im Team und bei paralleler Arbeit trauen kann:
- Governance (Teil 1): Permissions, path-scoped Rules und Skills geben der KI Konventionen und Leitplanken.
- Parallelität (Teil 2): Subagents mit Worktree-Isolation und ein Orchestrierungs-Skill liefern mehrere Stories gleichzeitig.
- Absicherung (Teil 3): Hooks als deterministische Quality-Gates fangen das ab, was nicht scheitern darf — Format, gefährliche Befehle, rote Tests.
Zusammen ergibt das einen KI-Workflow, der nicht auf Vertrauen baut, sondern auf überprüfbaren Schienen läuft. Genau das ist die Voraussetzung dafür, KI im Engineering ernsthaft einzusetzen, ohne bei der Qualität Abstriche zu machen: nicht weniger Sorgfalt, sondern Sorgfalt, die automatisiert immer greift.
Wer 2026 über die Auswahl eines KI-fähigen Software-Partners nachdenkt — wir haben dazu sechs Kriterien aufgeschrieben. Wenn Sie Claude Code in Ihrem Team produktiv und sicher aufsetzen wollen und einen Sparringspartner suchen, der das schon mehrfach durchgezogen hat — buchen Sie gerne ein kostenloses Erstgespräch.
Tech42 baut individuelle Softwareentwicklung mit modernen KI-Tools im Engineering-Alltag — nicht als Marketing-Begriff, sondern als Teil unseres Stacks. Wie sich die Senior-Entwickler-Rolle dabei verschiebt, beschreibt unser Artikel Wie KI die moderne Softwareentwicklung verändert.
Weiterlesen
Verwandte Artikel
-
25. Mai 2026
Claude Code Subagents: Parallele Tasks mit Worktree-Isolation
Wie Subagents mit Worktree-Isolation parallele Coding-Tasks ermöglichen — Backend, Frontend und Review gleichzeitig. Teil 2 der Tech42 Claude-Code-Serie.
Artikel lesen -
14. Mai 2026
Claude Code im Team einrichten: Rules, Permissions und Skills
Wie wir Claude Code im Team-Alltag einsetzen: Setup, Permissions, path-scoped Rules und eigene Skills — mit Beispielen aus unserem Workflow.
Artikel lesen -
24. Mai 2026
Wie evaluiert man einen KI-Software-Partner 2026? Sechs Kriterien
Sechs Kriterien für die Auswahl eines Software-Partners 2026 — von KI-Kompetenz über Datenschutz bis Skalierbarkeit. Praxisleitfaden für Entscheider.
Artikel lesen