Skip to content
Tech42 Software Solutions GmbH

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.

Jan Raddatz · 13 Min. Lesezeit · Claude Code / KI / Engineering / Tooling
Dashboard von Claude Code Hooks als automatisierte Quality-Gates: ein User-Prompt durchläuft Pre-Tool- und Post-Tool-Hooks mit Format-, Test- und Security-Checks, die mit OK oder Blockieren entscheiden

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.

EventFeuertKann blockieren?
PreToolUsebevor ein Tool ausgeführt wirdJa — der Call wird verhindert
PostToolUsenachdem ein Tool erfolgreich warNein (lief schon), aber Feedback möglich
Stopwenn Claude meint, fertig zu seinJa — der Agent muss weiterarbeiten
UserPromptSubmitbevor ein Prompt verarbeitet wirdJa, plus Kontext-Injektion
SessionStartbei Start/Resume einer SessionNein, 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ür PreToolUse/PostToolUse ist das der Tool-Name: Bash, Edit, Write, Read — oder eine Pipe-Alternative wie Edit|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_path bei Edit/Write, tool_input.command bei Bash), dazu session_id, cwd und transcript_path.

Wie ein Hook entscheidet, läuft über zwei Mechanismen — einen einfachen und einen feingranularen.

Exit-Codes (der einfache Weg):

Exit-CodeBedeutung
0Erfolg. Bei UserPromptSubmit/SessionStart wird stdout in den Kontext übernommen.
2Blockieren. stderr wird als Feedback an die KI zurückgegeben (bei Events, die blockieren können).
sonstigeNicht-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:

AnforderungMechanismus
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 VerhaltenRule (CLAUDE.md)
Aufrufbarer, wiederholbarer WorkflowSkill

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 PreToolUsePostToolUse 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.

Lust auf ein Gespräch?

Wenn Sie hier weitergelesen haben, lohnt sich vielleicht auch ein direktes Gespräch. Erstgespräch unverbindlich.