Zum Hauptinhalt springen
Hooks sind benutzerdefinierte Shell-Befehle, die an bestimmten Punkten im Lebenszyklus von Claude Code ausgeführt werden. Sie bieten deterministische Kontrolle über das Verhalten von Claude Code und stellen sicher, dass bestimmte Aktionen immer stattfinden, anstatt sich darauf zu verlassen, dass das LLM sich dafür entscheidet, sie auszuführen. Verwenden Sie Hooks, um Projektregeln durchzusetzen, sich wiederholende Aufgaben zu automatisieren und Claude Code mit Ihren vorhandenen Tools zu integrieren. Für Entscheidungen, die Urteilsvermögen erfordern, anstatt deterministischer Regeln, können Sie auch Prompt-basierte Hooks oder Agent-basierte Hooks verwenden, die ein Claude-Modell zur Bewertung von Bedingungen nutzen. Für andere Möglichkeiten, Claude Code zu erweitern, siehe skills zum Geben zusätzlicher Anweisungen und ausführbarer Befehle, subagents zum Ausführen von Aufgaben in isolierten Kontexten und plugins zum Verpacken von Erweiterungen, die über Projekte hinweg freigegeben werden können.
Dieser Leitfaden behandelt häufige Anwendungsfälle und wie Sie anfangen. Für vollständige Event-Schemas, JSON-Ein-/Ausgabeformate und erweiterte Funktionen wie asynchrone Hooks und MCP-Tool-Hooks siehe die Hooks-Referenz.

Richten Sie Ihren ersten Hook ein

Um einen Hook zu erstellen, fügen Sie einen hooks-Block zu einer Einstellungsdatei hinzu. Diese Anleitung erstellt einen Desktop-Benachrichtigungs-Hook, damit Sie benachrichtigt werden, wenn Claude auf Ihre Eingabe wartet, anstatt das Terminal zu beobachten.
1

Fügen Sie den Hook zu Ihren Einstellungen hinzu

Öffnen Sie ~/.claude/settings.json und fügen Sie einen Notification-Hook hinzu. Das Beispiel unten verwendet osascript für macOS; siehe Benachrichtigung erhalten, wenn Claude Eingaben benötigt für Linux- und Windows-Befehle.
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
Wenn Ihre Einstellungsdatei bereits einen hooks-Schlüssel hat, führen Sie den Notification-Eintrag darin zusammen, anstatt das ganze Objekt zu ersetzen. Sie können Claude auch bitten, den Hook für Sie zu schreiben, indem Sie beschreiben, was Sie in der CLI möchten.
2

Überprüfen Sie die Konfiguration

Geben Sie /hooks ein, um den Hooks-Browser zu öffnen. Sie sehen eine Liste aller verfügbaren Hook-Events mit einer Anzahl neben jedem Event, das Hooks konfiguriert hat. Wählen Sie Notification aus, um zu bestätigen, dass Ihr neuer Hook in der Liste angezeigt wird. Wenn Sie den Hook auswählen, werden seine Details angezeigt: das Event, der Matcher, der Typ, die Quelldatei und der Befehl.
3

Testen Sie den Hook

Drücken Sie Esc, um zur CLI zurückzukehren. Bitten Sie Claude, etwas zu tun, das eine Berechtigung erfordert, und wechseln Sie dann weg vom Terminal. Sie sollten eine Desktop-Benachrichtigung erhalten.
Das Menü /hooks ist schreibgeschützt. Um Hooks hinzuzufügen, zu ändern oder zu entfernen, bearbeiten Sie Ihre Einstellungs-JSON direkt oder bitten Sie Claude, die Änderung vorzunehmen.

Was Sie automatisieren können

Hooks ermöglichen es Ihnen, Code an Schlüsselpunkten im Lebenszyklus von Claude Code auszuführen: Dateien nach Bearbeitungen formatieren, Befehle vor der Ausführung blockieren, Benachrichtigungen senden, wenn Claude Eingaben benötigt, Kontext beim Sitzungsstart injizieren und vieles mehr. Für die vollständige Liste der Hook-Events siehe die Hooks-Referenz. Jedes Beispiel enthält einen einsatzbereiten Konfigurationsblock, den Sie einer Einstellungsdatei hinzufügen. Die häufigsten Muster:

Benachrichtigung erhalten, wenn Claude Eingaben benötigt

Erhalten Sie eine Desktop-Benachrichtigung, wenn Claude die Arbeit beendet und Ihre Eingabe benötigt, damit Sie zu anderen Aufgaben wechseln können, ohne das Terminal zu überprüfen. Dieser Hook verwendet das Notification-Event, das ausgelöst wird, wenn Claude auf Eingaben oder Berechtigungen wartet. Jede Registerkarte unten verwendet den nativen Benachrichtigungsbefehl der Plattform. Fügen Sie dies zu ~/.claude/settings.json hinzu:
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Code nach Bearbeitungen automatisch formatieren

Führen Sie Prettier automatisch auf jeder Datei aus, die Claude bearbeitet, damit die Formatierung konsistent bleibt, ohne manuelle Eingriffe. Dieser Hook verwendet das PostToolUse-Event mit einem Edit|Write-Matcher, sodass er nur nach Datei-Bearbeitungs-Tools ausgeführt wird. Der Befehl extrahiert den bearbeiteten Dateipfad mit jq und übergibt ihn an Prettier. Fügen Sie dies zu .claude/settings.json in Ihrem Projektverzeichnis hinzu:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
Die Bash-Beispiele auf dieser Seite verwenden jq zum Parsen von JSON. Installieren Sie es mit brew install jq (macOS), apt-get install jq (Debian/Ubuntu), oder siehe jq-Downloads.

Bearbeitungen geschützter Dateien blockieren

Verhindern Sie, dass Claude sensible Dateien wie .env, package-lock.json oder alles in .git/ ändert. Claude erhält Feedback, das erklärt, warum die Bearbeitung blockiert wurde, sodass es seinen Ansatz anpassen kann. Dieses Beispiel verwendet eine separate Skriptdatei, die der Hook aufruft. Das Skript überprüft den Zieldateipfad gegen eine Liste geschützter Muster und beendet sich mit Code 2, um die Bearbeitung zu blockieren.
1

Erstellen Sie das Hook-Skript

Speichern Sie dies unter .claude/hooks/protect-files.sh:
#!/bin/bash
# protect-files.sh

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

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
2

Machen Sie das Skript ausführbar (macOS/Linux)

Hook-Skripte müssen ausführbar sein, damit Claude Code sie ausführen kann:
chmod +x .claude/hooks/protect-files.sh
3

Registrieren Sie den Hook

Fügen Sie einen PreToolUse-Hook zu .claude/settings.json hinzu, der das Skript vor jedem Edit- oder Write-Tool-Aufruf ausführt:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Kontext nach Komprimierung erneut injizieren

Wenn Claudes Kontextfenster voll wird, fasst die Komprimierung das Gespräch zusammen, um Platz freizugeben. Dies kann wichtige Details verlieren. Verwenden Sie einen SessionStart-Hook mit einem compact-Matcher, um nach jeder Komprimierung kritischen Kontext erneut zu injizieren. Jeder Text, den Ihr Befehl auf stdout schreibt, wird zu Claudes Kontext hinzugefügt. Dieses Beispiel erinnert Claude an Projektkonventionen und aktuelle Arbeiten. Fügen Sie dies zu .claude/settings.json in Ihrem Projektverzeichnis hinzu:
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
          }
        ]
      }
    ]
  }
}
Sie können das echo durch jeden Befehl ersetzen, der dynamische Ausgabe erzeugt, wie git log --oneline -5, um aktuelle Commits anzuzeigen. Zum Injizieren von Kontext bei jedem Sitzungsstart sollten Sie stattdessen CLAUDE.md verwenden. Für Umgebungsvariablen siehe CLAUDE_ENV_FILE in der Referenz.

Konfigurationsänderungen prüfen

Verfolgen Sie, wenn sich Einstellungs- oder Skills-Dateien während einer Sitzung ändern. Das ConfigChange-Event wird ausgelöst, wenn ein externer Prozess oder Editor eine Konfigurationsdatei ändert, sodass Sie Änderungen für Compliance protokollieren oder nicht autorisierte Änderungen blockieren können. Dieses Beispiel hängt jede Änderung an ein Audit-Protokoll an. Fügen Sie dies zu ~/.claude/settings.json hinzu:
{
  "hooks": {
    "ConfigChange": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log"
          }
        ]
      }
    ]
  }
}
Der Matcher filtert nach Konfigurationstyp: user_settings, project_settings, local_settings, policy_settings oder skills. Um eine Änderung zu blockieren, beenden Sie mit Code 2 oder geben Sie {"decision": "block"} zurück. Siehe die ConfigChange-Referenz für das vollständige Eingabe-Schema.

Umgebung neu laden, wenn sich Verzeichnis oder Dateien ändern

Einige Projekte setzen unterschiedliche Umgebungsvariablen je nachdem, in welchem Verzeichnis Sie sich befinden. Tools wie direnv tun dies automatisch in Ihrer Shell, aber Claudes Bash-Tool übernimmt diese Änderungen nicht automatisch. Ein CwdChanged-Hook behebt dies: Er wird jedes Mal ausgeführt, wenn Claude das Verzeichnis wechselt, sodass Sie die korrekten Variablen für den neuen Speicherort neu laden können. Der Hook schreibt die aktualisierten Werte in CLAUDE_ENV_FILE, die Claude Code vor jedem Bash-Befehl anwendet. Fügen Sie dies zu ~/.claude/settings.json hinzu:
{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Um auf bestimmte Dateien statt auf jeden Verzeichniswechsel zu reagieren, verwenden Sie FileChanged mit einem matcher, der die zu überwachenden Dateinamen auflistet (durch Pipe getrennt). Der matcher konfiguriert sowohl, welche Dateien zu überwachen sind, als auch filtert, welche Hooks ausgeführt werden. Dieses Beispiel überwacht .envrc und .env auf Änderungen im aktuellen Verzeichnis:
{
  "hooks": {
    "FileChanged": [
      {
        "matcher": ".envrc|.env",
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\""
          }
        ]
      }
    ]
  }
}
Siehe die CwdChanged- und FileChanged-Referenzeinträge für Eingabe-Schemas, watchPaths-Ausgabe und CLAUDE_ENV_FILE-Details.

Bestimmte Berechtigungsaufforderungen automatisch genehmigen

Überspringen Sie den Genehmigungsdialog für Tool-Aufrufe, die Sie immer zulassen. Dieses Beispiel genehmigt automatisch ExitPlanMode, das Tool, das Claude aufruft, wenn es fertig ist, einen Plan zu präsentieren und fragt, ob es fortfahren soll, sodass Sie nicht jedes Mal aufgefordert werden, wenn ein Plan bereit ist. Im Gegensatz zu den Exit-Code-Beispielen oben erfordert die automatische Genehmigung, dass Ihr Hook eine JSON-Entscheidung auf stdout schreibt. Ein PermissionRequest-Hook wird ausgelöst, wenn Claude Code einen Berechtigungsdialog anzeigen wird, und die Rückgabe von "behavior": "allow" beantwortet ihn in Ihrem Namen. Der Matcher beschränkt den Hook nur auf ExitPlanMode, sodass keine anderen Aufforderungen betroffen sind. Fügen Sie dies zu ~/.claude/settings.json hinzu:
{
  "hooks": {
    "PermissionRequest": [
      {
        "matcher": "ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
          }
        ]
      }
    ]
  }
}
Wenn der Hook genehmigt, beendet Claude Code den Plan-Modus und stellt den Berechtigungsmodus wieder her, der vor dem Eintritt in den Plan-Modus aktiv war. Das Transkript zeigt „Allowed by PermissionRequest hook” an der Stelle, an der der Dialog angezeigt worden wäre. Der Hook-Pfad behält immer das aktuelle Gespräch: Er kann den Kontext nicht löschen und eine neue Implementierungssitzung auf die Weise starten, wie der Dialog es kann. Um stattdessen einen bestimmten Berechtigungsmodus festzulegen, kann die Ausgabe Ihres Hooks ein Array updatedPermissions mit einem setMode-Eintrag enthalten. Der Wert mode ist ein beliebiger Berechtigungsmodus wie default, acceptEdits oder bypassPermissions, und destination: "session" wendet ihn nur für die aktuelle Sitzung an. Um die Sitzung zu acceptEdits zu wechseln, schreibt Ihr Hook dieses JSON auf stdout:
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedPermissions": [
        { "type": "setMode", "mode": "acceptEdits", "destination": "session" }
      ]
    }
  }
}
Halten Sie den Matcher so eng wie möglich. Das Abgleichen von .* oder das Lassen des Matchers leer würde jede Berechtigungsaufforderung automatisch genehmigen, einschließlich Dateischreibvorgänge und Shell-Befehle. Siehe die PermissionRequest-Referenz für den vollständigen Satz von Entscheidungsfeldern.

Wie Hooks funktionieren

Hook-Events werden an bestimmten Lebenszykluspunkten in Claude Code ausgelöst. Wenn ein Event ausgelöst wird, werden alle übereinstimmenden Hooks parallel ausgeführt, und identische Hook-Befehle werden automatisch dedupliziert. Die folgende Tabelle zeigt jedes Event und wann es ausgelöst wird:
EventWhen it fires
SessionStartWhen a session begins or resumes
UserPromptSubmitWhen you submit a prompt, before Claude processes it
PreToolUseBefore a tool call executes. Can block it
PermissionRequestWhen a permission dialog appears
PermissionDeniedWhen a tool call is denied by the auto mode classifier. Return {retry: true} to tell the model it may retry the denied tool call
PostToolUseAfter a tool call succeeds
PostToolUseFailureAfter a tool call fails
NotificationWhen Claude Code sends a notification
SubagentStartWhen a subagent is spawned
SubagentStopWhen a subagent finishes
TaskCreatedWhen a task is being created via TaskCreate
TaskCompletedWhen a task is being marked as completed
StopWhen Claude finishes responding
StopFailureWhen the turn ends due to an API error. Output and exit code are ignored
TeammateIdleWhen an agent team teammate is about to go idle
InstructionsLoadedWhen a CLAUDE.md or .claude/rules/*.md file is loaded into context. Fires at session start and when files are lazily loaded during a session
ConfigChangeWhen a configuration file changes during a session
CwdChangedWhen the working directory changes, for example when Claude executes a cd command. Useful for reactive environment management with tools like direnv
FileChangedWhen a watched file changes on disk. The matcher field specifies which filenames to watch
WorktreeCreateWhen a worktree is being created via --worktree or isolation: "worktree". Replaces default git behavior
WorktreeRemoveWhen a worktree is being removed, either at session exit or when a subagent finishes
PreCompactBefore context compaction
PostCompactAfter context compaction completes
ElicitationWhen an MCP server requests user input during a tool call
ElicitationResultAfter a user responds to an MCP elicitation, before the response is sent back to the server
SessionEndWhen a session terminates
Jeder Hook hat einen type, der bestimmt, wie er ausgeführt wird. Die meisten Hooks verwenden "type": "command", was einen Shell-Befehl ausführt. Drei weitere Typen sind verfügbar:

Eingabe lesen und Ausgabe zurückgeben

Hooks kommunizieren mit Claude Code über stdin, stdout, stderr und Exit-Codes. Wenn ein Event ausgelöst wird, übergibt Claude Code Event-spezifische Daten als JSON an stdin Ihres Skripts. Ihr Skript liest diese Daten, führt seine Arbeit aus und teilt Claude Code mit, was als nächstes zu tun ist, über den Exit-Code.

Hook-Eingabe

Jedes Event enthält gemeinsame Felder wie session_id und cwd, aber jeder Event-Typ fügt unterschiedliche Daten hinzu. Wenn Claude beispielsweise einen Bash-Befehl ausführt, erhält ein PreToolUse-Hook etwa folgendes auf stdin:
{
  "session_id": "abc123",          // eindeutige ID für diese Sitzung
  "cwd": "/Users/sarah/myproject", // Arbeitsverzeichnis, wenn das Event ausgelöst wurde
  "hook_event_name": "PreToolUse", // welches Event diesen Hook ausgelöst hat
  "tool_name": "Bash",             // das Tool, das Claude verwenden wird
  "tool_input": {                  // die Argumente, die Claude an das Tool übergeben hat
    "command": "npm test"          // für Bash ist dies der Shell-Befehl
  }
}
Ihr Skript kann dieses JSON parsen und auf alle diese Felder reagieren. UserPromptSubmit-Hooks erhalten stattdessen den prompt-Text, SessionStart-Hooks erhalten die source (startup, resume, clear, compact) und so weiter. Siehe Gemeinsame Eingabefelder in der Referenz für gemeinsame Felder und jeden Event-Abschnitt für Event-spezifische Schemas.

Hook-Ausgabe

Ihr Skript teilt Claude Code mit, was als nächstes zu tun ist, indem es auf stdout oder stderr schreibt und mit einem bestimmten Code beendet wird. Beispielsweise ein PreToolUse-Hook, der einen Befehl blockieren möchte:
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q "drop table"; then
  echo "Blocked: dropping tables is not allowed" >&2  # stderr wird zu Claudes Feedback
  exit 2 # exit 2 = Aktion blockieren
fi

exit 0  # exit 0 = fortfahren
Der Exit-Code bestimmt, was als nächstes passiert:
  • Exit 0: die Aktion wird fortgesetzt. Für UserPromptSubmit- und SessionStart-Hooks wird alles, was Sie auf stdout schreiben, zu Claudes Kontext hinzugefügt.
  • Exit 2: die Aktion wird blockiert. Schreiben Sie einen Grund auf stderr, und Claude erhält ihn als Feedback, sodass er sich anpassen kann.
  • Jeder andere Exit-Code: die Aktion wird fortgesetzt. Stderr wird protokolliert, aber nicht Claude angezeigt. Schalten Sie den ausführlichen Modus mit Ctrl+O um, um diese Meldungen im Transkript zu sehen.

Strukturierte JSON-Ausgabe

Exit-Codes geben Ihnen zwei Optionen: zulassen oder blockieren. Für mehr Kontrolle beenden Sie mit 0 und geben stattdessen ein JSON-Objekt auf stdout aus.
Verwenden Sie exit 2, um mit einer stderr-Meldung zu blockieren, oder exit 0 mit JSON für strukturierte Kontrolle. Mischen Sie sie nicht: Claude Code ignoriert JSON, wenn Sie mit 2 beenden.
Beispielsweise kann ein PreToolUse-Hook einen Tool-Aufruf ablehnen und Claude mitteilen, warum, oder ihn dem Benutzer zur Genehmigung eskalieren:
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
Claude Code liest permissionDecision und bricht den Tool-Aufruf ab, dann gibt permissionDecisionReason an Claude als Feedback zurück. Diese drei Optionen sind spezifisch für PreToolUse:
  • "allow": fortfahren, ohne eine Berechtigungsaufforderung anzuzeigen
  • "deny": Tool-Aufruf abbrechen und den Grund an Claude senden
  • "ask": Berechtigungsaufforderung dem Benutzer wie gewohnt anzeigen
Andere Events verwenden unterschiedliche Entscheidungsmuster. Beispielsweise verwenden PostToolUse- und Stop-Hooks ein Top-Level-Feld decision: "block", während PermissionRequest hookSpecificOutput.decision.behavior verwendet. Siehe die Zusammenfassungstabelle in der Referenz für eine vollständige Aufschlüsselung nach Event. Für UserPromptSubmit-Hooks verwenden Sie stattdessen additionalContext, um Text in Claudes Kontext zu injizieren. Prompt-basierte Hooks (type: "prompt") handhaben die Ausgabe anders: siehe Prompt-basierte Hooks.

Hooks mit Matchern filtern

Ohne einen Matcher wird ein Hook bei jedem Auftreten seines Events ausgelöst. Matcher ermöglichen es Ihnen, das einzugrenzen. Wenn Sie beispielsweise einen Formatter nur nach Datei-Bearbeitungen ausführen möchten (nicht nach jedem Tool-Aufruf), fügen Sie einen Matcher zu Ihrem PostToolUse-Hook hinzu:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "prettier --write ..." }
        ]
      }
    ]
  }
}
Der "Edit|Write"-Matcher ist ein Regex-Muster, das den Tool-Namen abgleicht. Der Hook wird nur ausgelöst, wenn Claude das Edit- oder Write-Tool verwendet, nicht wenn es Bash, Read oder ein anderes Tool verwendet. Jeder Event-Typ gleicht ein bestimmtes Feld ab. Matcher unterstützen exakte Strings und Regex-Muster:
EventWorauf der Matcher filtertBeispiel-Matcher-Werte
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequestTool-NameBash, Edit|Write, mcp__.*
SessionStartwie die Sitzung gestartet wurdestartup, resume, clear, compact
SessionEndwarum die Sitzung endeteclear, resume, logout, prompt_input_exit, bypass_permissions_disabled, other
NotificationBenachrichtigungstyppermission_prompt, idle_prompt, auth_success, elicitation_dialog
SubagentStartAgent-TypBash, Explore, Plan oder benutzerdefinierte Agent-Namen
PreCompact, PostCompactwas die Komprimierung ausgelöst hatmanual, auto
SubagentStopAgent-Typgleiche Werte wie SubagentStart
ConfigChangeKonfigurationsquelleuser_settings, project_settings, local_settings, policy_settings, skills
StopFailureFehlertyprate_limit, authentication_failed, billing_error, invalid_request, server_error, max_output_tokens, unknown
InstructionsLoadedLadegrundsession_start, nested_traversal, path_glob_match, include, compact
ElicitationMCP-ServernameIhre konfigurierten MCP-Servernamen
ElicitationResultMCP-Servernamegleiche Werte wie Elicitation
FileChangedDateiname (Basisname der geänderten Datei).envrc, .env, jeder Dateiname, den Sie überwachen möchten
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, CwdChangedkeine Matcher-Unterstützungwird immer bei jedem Auftreten ausgelöst
Ein paar weitere Beispiele, die Matcher auf verschiedene Event-Typen zeigen:
Gleichen Sie nur Bash-Tool-Aufrufe ab und protokollieren Sie jeden Befehl in einer Datei. Das PostToolUse-Event wird ausgelöst, nachdem der Befehl abgeschlossen ist, sodass tool_input.command enthält, was ausgeführt wurde. Der Hook erhält die Event-Daten als JSON auf stdin, und jq -r '.tool_input.command' extrahiert nur die Befehlszeichenfolge, die >> an die Protokolldatei anhängt:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
          }
        ]
      }
    ]
  }
}
Für die vollständige Matcher-Syntax siehe die Hooks-Referenz.

Hook-Speicherort konfigurieren

Wo Sie einen Hook hinzufügen, bestimmt seinen Bereich:
SpeicherortBereichFreigegeben
~/.claude/settings.jsonAlle Ihre ProjekteNein, lokal auf Ihrem Computer
.claude/settings.jsonEinzelnes ProjektJa, kann im Repo committed werden
.claude/settings.local.jsonEinzelnes ProjektNein, gitignoriert
Verwaltete RichtlinieneinstellungenOrganisationsweitJa, von Admin kontrolliert
Plugin hooks/hooks.jsonWenn Plugin aktiviert istJa, mit dem Plugin gebündelt
Skill oder Agent FrontmatterWährend der Skill oder Agent aktiv istJa, in der Komponentendatei definiert
Führen Sie /hooks in Claude Code aus, um alle konfigurierten Hooks nach Event gruppiert zu durchsuchen. Um alle Hooks auf einmal zu deaktivieren, setzen Sie "disableAllHooks": true in Ihrer Einstellungsdatei. Wenn Sie Einstellungsdateien direkt bearbeiten, während Claude Code läuft, werden Hook-Änderungen normalerweise automatisch vom Datei-Watcher aufgegriffen.

Prompt-basierte Hooks

Für Entscheidungen, die Urteilsvermögen erfordern, anstatt deterministischer Regeln, verwenden Sie type: "prompt"-Hooks. Anstatt einen Shell-Befehl auszuführen, sendet Claude Code Ihren Prompt und die Hook-Eingabedaten an ein Claude-Modell (standardmäßig Haiku), um die Entscheidung zu treffen. Sie können ein anderes Modell mit dem Feld model angeben, wenn Sie mehr Leistung benötigen. Die einzige Aufgabe des Modells ist, eine Ja/Nein-Entscheidung als JSON zurückzugeben:
  • "ok": true: die Aktion wird fortgesetzt
  • "ok": false: die Aktion wird blockiert. Der "reason" des Modells wird an Claude zurückgegeben, sodass es sich anpassen kann.
Dieses Beispiel verwendet einen Stop-Hook, um das Modell zu fragen, ob alle angeforderten Aufgaben abgeschlossen sind. Wenn das Modell "ok": false zurückgibt, arbeitet Claude weiter und verwendet den reason als nächste Anweisung:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
          }
        ]
      }
    ]
  }
}
Für vollständige Konfigurationsoptionen siehe Prompt-basierte Hooks in der Referenz.

Agent-basierte Hooks

Wenn die Verifizierung das Inspizieren von Dateien oder das Ausführen von Befehlen erfordert, verwenden Sie type: "agent"-Hooks. Im Gegensatz zu Prompt-Hooks, die einen einzelnen LLM-Aufruf tätigen, spawnen Agent-Hooks einen Subagent, der Dateien lesen, Code durchsuchen und andere Tools verwenden kann, um Bedingungen zu überprüfen, bevor eine Entscheidung zurückgegeben wird. Agent-Hooks verwenden das gleiche "ok" / "reason"-Antwortformat wie Prompt-Hooks, aber mit einem längeren Standard-Timeout von 60 Sekunden und bis zu 50 Tool-Use-Turns. Dieses Beispiel überprüft, dass Tests bestanden werden, bevor Claude beendet werden darf:
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
Verwenden Sie Prompt-Hooks, wenn die Hook-Eingabedaten allein ausreichen, um eine Entscheidung zu treffen. Verwenden Sie Agent-Hooks, wenn Sie etwas gegen den tatsächlichen Zustand der Codebasis überprüfen müssen. Für vollständige Konfigurationsoptionen siehe Agent-basierte Hooks in der Referenz.

HTTP-Hooks

Verwenden Sie type: "http"-Hooks, um Event-Daten an einen HTTP-Endpunkt zu POSTen, anstatt einen Shell-Befehl auszuführen. Der Endpunkt erhält die gleichen JSON-Daten, die ein Command-Hook auf stdin erhalten würde, und gibt Ergebnisse über den HTTP-Antwortkörper mit dem gleichen JSON-Format zurück. HTTP-Hooks sind nützlich, wenn Sie möchten, dass ein Webserver, eine Cloud-Funktion oder ein externer Service Hook-Logik handhabt: beispielsweise ein gemeinsamer Audit-Service, der Tool-Use-Events über ein Team hinweg protokolliert. Dieses Beispiel POSTet jeden Tool-Use an einen lokalen Logging-Service:
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/tool-use",
            "headers": {
              "Authorization": "Bearer $MY_TOKEN"
            },
            "allowedEnvVars": ["MY_TOKEN"]
          }
        ]
      }
    ]
  }
}
Der Endpunkt sollte einen JSON-Antwortkörper mit dem gleichen Ausgabeformat wie Command-Hooks zurückgeben. Um einen Tool-Aufruf zu blockieren, geben Sie eine 2xx-Antwort mit den entsprechenden hookSpecificOutput-Feldern zurück. HTTP-Statuscodes allein können Aktionen nicht blockieren. Header-Werte unterstützen Umgebungsvariablen-Interpolation mit $VAR_NAME oder ${VAR_NAME}-Syntax. Nur Variablen, die im Array allowedEnvVars aufgelistet sind, werden aufgelöst; alle anderen $VAR-Referenzen bleiben leer. Für vollständige Konfigurationsoptionen und Response-Handling siehe HTTP-Hooks in der Referenz.

Einschränkungen und Fehlerbehebung

Einschränkungen

  • Command-Hooks kommunizieren nur über stdout, stderr und Exit-Codes. Sie können Befehle oder Tool-Aufrufe nicht direkt auslösen. HTTP-Hooks kommunizieren stattdessen über den Response-Body.
  • Hook-Timeout beträgt standardmäßig 10 Minuten, konfigurierbar pro Hook mit dem Feld timeout (in Sekunden).
  • PostToolUse-Hooks können Aktionen nicht rückgängig machen, da das Tool bereits ausgeführt wurde.
  • PermissionRequest-Hooks werden nicht im nicht-interaktiven Modus (-p) ausgelöst. Verwenden Sie stattdessen PreToolUse-Hooks für automatisierte Berechtigungsentscheidungen.
  • Stop-Hooks werden ausgelöst, wenn Claude antwortet, nicht nur bei Aufgabenabschluss. Sie werden nicht bei Benutzerunterbrechungen ausgelöst. API-Fehler lösen stattdessen StopFailure aus.

Hook wird nicht ausgelöst

Der Hook ist konfiguriert, wird aber nie ausgeführt.
  • Führen Sie /hooks aus und bestätigen Sie, dass der Hook unter dem richtigen Event angezeigt wird
  • Überprüfen Sie, dass das Matcher-Muster den Tool-Namen genau abgleicht (Matcher sind Groß-/Kleinschreibung-empfindlich)
  • Überprüfen Sie, dass Sie den richtigen Event-Typ auslösen (z. B. PreToolUse wird vor der Tool-Ausführung ausgelöst, PostToolUse wird danach ausgelöst)
  • Wenn Sie PermissionRequest-Hooks im nicht-interaktiven Modus (-p) verwenden, wechseln Sie stattdessen zu PreToolUse

Hook-Fehler in der Ausgabe

Sie sehen eine Meldung wie “PreToolUse hook error: …” im Transkript.
  • Ihr Skript wurde unerwartet mit einem Nicht-Null-Code beendet. Testen Sie es manuell, indem Sie Beispiel-JSON pipen:
    echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
    echo $?  # Überprüfen Sie den Exit-Code
    
  • Wenn Sie “command not found” sehen, verwenden Sie absolute Pfade oder $CLAUDE_PROJECT_DIR, um Skripte zu referenzieren
  • Wenn Sie “jq: command not found” sehen, installieren Sie jq oder verwenden Sie Python/Node.js zum Parsen von JSON
  • Wenn das Skript überhaupt nicht ausgeführt wird, machen Sie es ausführbar: chmod +x ./my-hook.sh

/hooks zeigt keine konfigurierten Hooks

Sie haben eine Einstellungsdatei bearbeitet, aber die Hooks werden nicht im Menü angezeigt.
  • Datei-Bearbeitungen werden normalerweise automatisch aufgegriffen. Wenn sie nach ein paar Sekunden nicht angezeigt wurden, hat der Datei-Watcher die Änderung möglicherweise verpasst: Starten Sie Ihre Sitzung neu, um ein Neuladen zu erzwingen.
  • Überprüfen Sie, dass Ihr JSON gültig ist (nachfolgende Kommas und Kommentare sind nicht zulässig)
  • Bestätigen Sie, dass die Einstellungsdatei am richtigen Speicherort ist: .claude/settings.json für Projekt-Hooks, ~/.claude/settings.json für globale Hooks

Stop-Hook läuft endlos

Claude arbeitet in einer Endlosschleife weiter, anstatt zu stoppen. Ihr Stop-Hook-Skript muss überprüfen, ob es bereits eine Fortsetzung ausgelöst hat. Parsen Sie das Feld stop_hook_active aus der JSON-Eingabe und beenden Sie früh, wenn es true ist:
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0  # Erlauben Sie Claude zu stoppen
fi
# ... Rest Ihrer Hook-Logik

JSON-Validierung fehlgeschlagen

Claude Code zeigt einen JSON-Parsing-Fehler an, obwohl Ihr Hook-Skript gültiges JSON ausgibt. Wenn Claude Code einen Hook ausführt, spawnt es eine Shell, die Ihr Profil sourced (~/.zshrc oder ~/.bashrc). Wenn Ihr Profil bedingungslose echo-Anweisungen enthält, wird diese Ausgabe Ihrem Hook-JSON vorangestellt:
Shell ready on arm64
{"decision": "block", "reason": "Not allowed"}
Claude Code versucht, dies als JSON zu parsen, und schlägt fehl. Um dies zu beheben, wrappen Sie Echo-Anweisungen in Ihrem Shell-Profil, sodass sie nur in interaktiven Shells ausgeführt werden:
# In ~/.zshrc oder ~/.bashrc
if [[ $- == *i* ]]; then
  echo "Shell ready"
fi
Die Variable $- enthält Shell-Flags, und i bedeutet interaktiv. Hooks werden in nicht-interaktiven Shells ausgeführt, sodass das Echo übersprungen wird.

Debug-Techniken

Schalten Sie den ausführlichen Modus mit Ctrl+O um, um Hook-Ausgabe im Transkript zu sehen, oder führen Sie claude --debug aus, um vollständige Ausführungsdetails einschließlich der Hooks zu sehen, die abgeglichen wurden, und ihrer Exit-Codes.

Weitere Informationen