Das Hook-System von Claude Code erklaert
AI generated
Claude
>_
Claude Code · Hooks · Automatisierung · Sicherheitsmodell
Das Hook-System von Claude Code erklaert
Deterministische Kontrolle statt hoffnungsvoller Prompt-Instruktion

Hooks in Claude Code sind Shell-Befehle, die bei genau definierten Ereignissen wie einem Werkzeugaufruf automatisch ausgefuehrt werden, unabhaengig davon, ob der Modell-Kontext gerade an eine CLAUDE.md-Regel erinnert oder nicht. Waehrend eine Prompt-Instruktion nur eine Wahrscheinlichkeit erhoeht, erzwingt ein Hook ein Verhalten deterministisch, auf Betriebssystemebene, nicht auf Sprachmodell-Ebene.

18 Min. Lesezeit PreToolUse · PostToolUse · settings.json · Exit-Codes Claude Code · Claude Sonnet 5 · Anthropic

1. Welches Problem Hooks loesen

Ein Hook in Claude Code ist ein Shell-Befehl, der von der CLI selbst, nicht vom Sprachmodell, bei einem festgelegten Zeitpunkt im Ablauf ausgefuehrt wird. Das loest ein grundlegendes Problem von Prompt-basierten Anweisungen: Eine Regel in CLAUDE.md wie "fuehre nach jeder Aenderung den Formatter aus" ist eine Instruktion an ein Sprachmodell, das sie mit hoher, aber nicht garantierter Wahrscheinlichkeit befolgt. Ein Hook dagegen wird vom Betriebssystem ausgefuehrt, unabhaengig davon, ob das Modell gerade an diese Regel gedacht hat oder nicht.

Der Unterschied wird besonders bei sicherheitsrelevanten Regeln sichtbar. Ein Prompt-Hinweis wie "fuehre niemals rm -rf aus" verringert das Risiko, verhindert es aber nicht garantiert, weil ein Sprachmodell in seltenen Faellen von seinen eigenen Instruktionen abweicht. Ein Hook, der jeden Bash-Aufruf vor der Ausfuehrung prueft und bei einem Treffer auf ein gefaehrliches Muster den Exit-Code 2 zurueckgibt, blockiert die Ausfuehrung zuverlaessig, unabhaengig vom Modellverhalten. Diese Verschiebung von Wahrscheinlichkeit zu Determinismus ist der zentrale Wert des Hook-Systems.

2. Die Hook-Events im Ueberblick

Claude Code stellt mehrere Hook-Events an unterschiedlichen Punkten im Ablauf bereit. PreToolUse feuert, bevor ein Werkzeug wie Bash, Edit oder Write ausgefuehrt wird, und kann die Ausfuehrung noch verhindern. PostToolUse feuert direkt danach und eignet sich fuer Nacharbeiten wie automatisches Formatieren oder Linting. UserPromptSubmit feuert, sobald ein Nutzer eine Eingabe absendet, noch bevor Claude sie verarbeitet, und kann zusaetzlichen Kontext injizieren oder die Eingabe komplett blockieren.

Weitere Events runden das Bild ab: Stop feuert, wenn der Hauptagent seine Antwort beendet, SubagentStop analog fuer einen Subagenten, Notification bei Systembenachrichtigungen, und SessionStart beim Start einer neuen Session, ideal um Umgebungsinformationen einmalig zu laden. Jedes dieser Hook-Events erhaelt strukturierte JSON-Daten ueber stdin, etwa den Namen des aufgerufenen Werkzeugs und dessen Parameter bei PreToolUse, und kommuniziert seine Entscheidung ueber den Exit-Code und optional strukturierte JSON-Ausgabe zurueck an Claude Code.


#!/usr/bin/env bash
# .claude/hooks/load-env-info.sh -- SessionStart hook, runs once per session
set -euo pipefail

echo "--- Environment info loaded at session start ---"
echo "PHP version: $(php -v | head -n1)"
echo "Git branch:  $(git branch --show-current 2>/dev/null || echo 'n/a')"
echo "Docker:      $(docker compose ps --status running --quiet 2>/dev/null | wc -l) containers running"

exit 0

3. Hooks konfigurieren: settings.json und Matcher

Hooks werden in der Datei settings.json konfiguriert, entweder projektweit unter .claude/settings.json oder persoenlich unter ~/.claude/settings.json. Jeder Eintrag besteht aus einem Event-Namen, einem optionalen matcher-Muster, das nur bestimmte Werkzeuge oder Dateipfade erfasst, und einer Liste auszufuehrender Befehle. Der matcher nutzt dabei einfache Muster wie Bash, Edit|Write oder Wildcard-Ausdruecke, um den Hook gezielt auf relevante Faelle zu begrenzen statt bei jedem einzelnen Werkzeugaufruf zu feuern.

Eine haeufige Praxis ist die Trennung nach Umgebung: projektspezifische Hooks, etwa ein Linter, der zum konkreten Projekt passt, gehoeren in .claude/settings.json und werden mit dem Repository versioniert. Persoenliche Hooks, etwa eine Desktop-Benachrichtigung bei Sessionende, gehoeren in die persoenliche Konfiguration. Das folgende Beispiel zeigt eine minimale settings.json mit zwei Hook-Eintraegen fuer unterschiedliche Events.


{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-dangerous-commands.sh" }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format-changed-file.sh" }
        ]
      }
    ]
  }
}

4. Ein PreToolUse-Hook fuer Sicherheitsprueffungen

Der praktisch wichtigste Anwendungsfall fuer PreToolUse-Hooks ist das Blockieren gefaehrlicher Befehle, bevor sie ausgefuehrt werden. Der Hook erhaelt ueber stdin ein JSON-Objekt mit dem Namen des Werkzeugs und dessen Eingabeparametern, im Fall von Bash also den kompletten Befehlsstring. Ein Skript kann diesen String gegen eine Liste kritischer Muster wie rm -rf /, DROP TABLE oder ein Schreiben in .env-Dateien pruefen und bei einem Treffer die Ausfuehrung mit Exit-Code 2 verhindern.

Wichtig dabei: Der Exit-Code 2 signalisiert Claude Code, dass der Werkzeugaufruf nicht ausgefuehrt werden soll, und die stderr-Ausgabe des Hooks wird dem Modell als Fehlermeldung zurueckgegeben, sodass es einen alternativen Weg vorschlagen kann. Das folgende Beispiel zeigt ein einfaches Bash-Skript, das genau dieses Muster fuer einen Sicherheits-Hook umsetzt.


#!/usr/bin/env bash
# .claude/hooks/check-dangerous-commands.sh
# Reads PreToolUse hook input (JSON) from stdin, blocks dangerous bash commands
set -euo pipefail

input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command // empty')

dangerous_patterns=("rm -rf /" "DROP TABLE" "> /dev/sda" ":(){ :|:& };:")

for pattern in "${dangerous_patterns[@]}"; do
  if [[ "$command" == *"$pattern"* ]]; then
    echo "Blocked: command matches dangerous pattern '$pattern'" >&2
    exit 2   # exit code 2 blocks the tool call in Claude Code
  fi
done

exit 0   # allow the tool call to proceed

5. Ein PostToolUse-Hook fuer automatisches Formatieren

PostToolUse-Hooks eignen sich fuer Nacharbeiten, die nach jeder Dateiaenderung zuverlaessig laufen sollen, ohne dass Claude sich daran "erinnern" muss. Ein typisches Beispiel ist automatisches Formatieren: Nach jedem Edit- oder Write-Aufruf prueft der Hook, welche Datei geaendert wurde, und ruft je nach Dateiendung den passenden Formatter auf, etwa php-cs-fixer fuer PHP-Dateien oder prettier fuer JavaScript und TypeScript.

Der entscheidende Vorteil gegenueber einer Prompt-Instruktion wie "formatiere nach jeder Aenderung" ist Konsistenz: Ein Hook laeuft garantiert bei jeder passenden Dateiaenderung, unabhaengig davon, wie lang die Konversation bereits ist oder wie stark der Kontext bereits mit anderen Themen gefuellt ist. Gerade in langen Sessions mit vielen Werkzeugaufrufen ist diese Zuverlaessigkeit ein messbarer Unterschied zu rein Prompt-basierter Steuerung.


#!/usr/bin/env bash
# .claude/hooks/format-changed-file.sh
# Reads PostToolUse hook input (JSON) from stdin, formats the touched file
set -euo pipefail

input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')

[[ -z "$file_path" || ! -f "$file_path" ]] && exit 0

case "$file_path" in
  *.php)
    vendor/bin/php-cs-fixer fix "$file_path" --quiet
    ;;
  *.js|*.ts|*.tsx)
    npx prettier --write "$file_path" --loglevel silent
    ;;
esac

exit 0

6. Hook-Input und Exit-Codes verstehen

Jeder Hook kommuniziert mit Claude Code ueber genau zwei Kanaele: den Exit-Code des Prozesses und optional strukturierte JSON-Ausgabe auf stdout. Exit-Code 0 bedeutet Erfolg, die Ausfuehrung geht normal weiter. Exit-Code 2 bei PreToolUse blockiert den Werkzeugaufruf, die stderr-Meldung wird dem Modell als Kontext mitgegeben. Andere Exit-Codes werden als nicht-blockierender Fehler behandelt, der Nutzer sieht eine Warnung, aber die Ausfuehrung wird nicht gestoppt.

Fuer feingranularere Kontrolle kann ein Hook statt eines einfachen Exit-Codes ein JSON-Objekt auf stdout ausgeben, das Felder wie decision und reason enthaelt. Das erlaubt differenzierte Antworten, etwa "erlauben, aber mit Warnung an das Modell" statt nur "erlauben oder blockieren". Diese Struktur macht das Hook-System flexibel genug fuer einfache Ja-Nein-Entscheidungen ebenso wie fuer komplexere Policy-Logik mit mehreren Abstufungen.


# Manually testing a hook script with a synthetic JSON payload on stdin
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' \
  | .claude/hooks/check-dangerous-commands.sh
echo "Exit code: $?"   # expect 2, command blocked

echo '{"tool_name":"Bash","tool_input":{"command":"npm test"}}' \
  | .claude/hooks/check-dangerous-commands.sh
echo "Exit code: $?"   # expect 0, command allowed

7. Hooks versus CLAUDE.md: deterministisch statt Vorschlag

Der zentrale konzeptionelle Unterschied zwischen Hooks und einer Regel in CLAUDE.md ist die Ebene, auf der die Regel durchgesetzt wird. CLAUDE.md wird Teil des Modell-Kontexts und beeinflusst, was das Modell wahrscheinlich als naechstes tut, es bleibt aber eine Instruktion, der das Modell folgen kann, aber nicht muss. Ein Hook laeuft ausserhalb des Modells, auf Betriebssystemebene, und wird unabhaengig vom aktuellen Zustand der Konversation garantiert ausgefuehrt.

Daraus folgt eine klare Faustregel: Alles, was garantiert passieren muss, etwa das Blockieren destruktiver Befehle oder das erzwungene Formatieren vor jedem Commit, gehoert in einen Hook. Alles, was eine Empfehlung oder ein Kontextwissen ist, etwa "dieses Projekt nutzt Repository statt Model direkt", gehoert in CLAUDE.md. Viele produktive Setups kombinieren beides: CLAUDE.md fuer Wissen und Stilrichtlinien, Hooks fuer harte Sicherheits- und Qualitaetsgrenzen, die niemals uebersprungen werden duerfen.

8. Sicherheitsaspekte und typische Fallstricke

Weil Hooks mit den vollen Rechten des aktuellen Nutzers ausgefuehrt werden, tragen sie reales Risiko, wenn sie unbedacht geschrieben werden. Ein Hook-Skript, das selbst nicht validierte Eingaben aus dem Hook-Input ungeprueft in einen weiteren Shell-Befehl einsetzt, kann eine Command-Injection-Luecke oeffnen, genau das Problem, das der Hook eigentlich verhindern sollte. Eingaben aus dem JSON-Input muessen deshalb immer als nicht vertrauenswuerdig behandelt und korrekt gequotet werden.

Ein zweiter haeufiger Fallstrick ist Performance: Ein Hook, der bei jedem PostToolUse-Ereignis einen langsamen, vollstaendigen Test-Lauf startet, verlangsamt jede einzelne Dateiaenderung spuerbar. Besser ist ein gezielter, schneller Formatter statt eines kompletten Test-Durchlaufs, waehrend vollstaendige Tests einem separaten Stop-Hook am Ende einer Antwort vorbehalten bleiben. Ein dritter Fallstrick: Hooks ohne Timeout koennen eine Session blockieren, ein explizites Timeout im Skript selbst verhindert, dass ein haengender Prozess die gesamte Interaktion einfriert.

9. Hook-Events im direkten Vergleich

Die Wahl des richtigen Hook-Events entscheidet, ob eine Automatisierung praeventiv, reaktiv oder informativ wirkt. Die folgende Uebersicht ordnet die wichtigsten Events nach typischem Einsatzzweck ein.

Event Zeitpunkt Kann blockieren Typischer Einsatz
PreToolUse Vor dem Werkzeugaufruf Ja Sicherheitsprueffungen, verbotene Befehle
PostToolUse Nach dem Werkzeugaufruf Nein Formatieren, Linting, Logging
UserPromptSubmit Bei Eingabe des Nutzers Ja Kontext injizieren, Eingabe validieren
Stop Nach Antwortende Teilweise Vollstaendige Test-Laeufe, Zusammenfassung
SessionStart Bei Session-Beginn Nein Umgebungsinfo einmalig laden

Wer diese Tabelle als Ausgangspunkt nutzt, vermeidet den haeufigsten Konfigurationsfehler: teure, blockierende Logik in einem Event zu platzieren, das eigentlich fuer schnelle, nicht-blockierende Nacharbeit gedacht ist, oder umgekehrt eine Sicherheitspruefung in ein Event zu legen, das gar keine Blockade mehr ermoeglicht.

Mironsoft

Claude Code Setup, Sicherheitsmodelle und Magento/Hyva-Entwicklung mit KI

Verbindliche Regeln statt hoffnungsvoller Prompts?

Wir richten fuer euer Team Hooks fuer Formatierung, Sicherheitsprueffungen und Test-Automatisierung ein, sodass kritische Regeln deterministisch durchgesetzt werden statt nur wahrscheinlich befolgt zu werden.

Sicherheits-Hooks

Gefaehrliche Befehle zuverlaessig blockieren, bevor sie ausgefuehrt werden

Format-Automatisierung

Konsistente Formatierung nach jeder Dateiaenderung ohne manuelles Eingreifen

CI-Integration

Hook-Logik in Pipelines spiegeln fuer konsistente Qualitaetssicherung

10. Zusammenfassung

Das Hook-System von Claude Code loest ein Problem, das reine Prompt-Instruktionen nicht loesen koennen: garantierte, deterministische Durchsetzung von Regeln statt bloss wahrscheinlicher Befolgung. PreToolUse-Hooks blockieren gefaehrliche Befehle vor der Ausfuehrung, PostToolUse-Hooks erzwingen konsistentes Nacharbeiten wie Formatieren, weitere Events wie UserPromptSubmit und SessionStart decken zusaetzliche Steuerungspunkte ab. Konfiguriert werden alle Hooks zentral in settings.json mit Event, Matcher und Befehl.

Der Exit-Code des Hook-Skripts entscheidet ueber Erfolg, Blockade oder nicht-blockierenden Fehler, strukturierte JSON-Ausgabe ermoeglicht feinere Entscheidungen. Wichtig bleibt, Hook-Input niemals ungeprueft in weitere Shell-Befehle einzusetzen und teure Logik nicht in performance-kritische Events zu legen. Wer Hooks fuer harte Sicherheits- und Qualitaetsgrenzen nutzt und CLAUDE.md fuer Wissen und Stil, kombiniert beide Staerken sinnvoll.

Das Hook-System von Claude Code — Das Wichtigste auf einen Blick

Kernidee

Shell-Befehle, die bei definierten Events deterministisch laufen, unabhaengig vom Modellverhalten.

Wichtigste Events

PreToolUse kann blockieren, PostToolUse fuer Nacharbeit, UserPromptSubmit fuer Kontext.

Konfiguration

Zentral in settings.json mit Event, Matcher-Muster und auszufuehrendem Befehl.

Exit-Codes

0 erlaubt, 2 blockiert bei PreToolUse, andere Codes gelten als nicht-blockierender Fehler.

11. FAQ: Das Hook-System von Claude Code

1Was ist ein Hook?
Ein Shell-Befehl, den die CLI selbst bei einem definierten Ereignis ausfuehrt, unabhaengig vom Modellzustand.
2Unterschied zu CLAUDE.md?
CLAUDE.md ist eine Instruktion an das Modell, ein Hook laeuft auf Betriebssystemebene und wird immer ausgefuehrt.
3Welche Events gibt es?
PreToolUse, PostToolUse, UserPromptSubmit, Stop, SubagentStop, Notification und SessionStart.
4Wo konfiguriere ich Hooks?
In settings.json, projektweit unter .claude/settings.json oder persoenlich unter ~/.claude/settings.json.
5Was bedeutet Exit-Code 2?
Der Werkzeugaufruf wird blockiert, stderr wird dem Modell als Fehlermeldung zurueckgegeben.
6Kann PostToolUse rueckgaengig machen?
Nein, es laeuft danach. Fuer Blockaden ist PreToolUse zustaendig.
7Was ist der matcher?
Ein Muster wie Bash oder Edit|Write, das festlegt, fuer welche Werkzeuge der Hook feuert.
8Welches Risiko bei schlechten Hooks?
Ungeprueft eingesetzter Hook-Input kann eine Command-Injection-Luecke oeffnen.
9Tests in PostToolUse laufen lassen?
Besser nicht, verlangsamt jede Dateiaenderung. Ein Stop-Hook ist dafuer geeigneter.
10Was bei haengendem Hook ohne Timeout?
Die Session kann blockiert werden. Ein explizites Timeout im Skript verhindert das.