Hooks sind benutzerdefinierte Shell-Befehle, HTTP-Endpunkte oder LLM-Prompts, die automatisch an bestimmten Punkten im Lebenszyklus von Claude Code ausgeführt werden. Verwenden Sie diese Referenz, um Ereignisschemas, Konfigurationsoptionen, JSON-Ein-/Ausgabeformate und erweiterte Funktionen wie asynchrone Hooks, HTTP-Hooks und MCP-Tool-Hooks nachzuschlagen. Wenn Sie Hooks zum ersten Mal einrichten, beginnen Sie stattdessen mit der Anleitung.
Hook-Lebenszyklus
Hooks werden an bestimmten Punkten während einer Claude Code-Sitzung ausgelöst. Wenn ein Ereignis ausgelöst wird und ein Matcher passt, übergibt Claude Code JSON-Kontext über das Ereignis an Ihren Hook-Handler. Bei Command-Hooks kommt die Eingabe über stdin an. Bei HTTP-Hooks kommt sie als POST-Request-Body an. Ihr Handler kann dann die Eingabe überprüfen, Maßnahmen ergreifen und optional eine Entscheidung zurückgeben. Einige Ereignisse werden einmal pro Sitzung ausgelöst, während andere wiederholt in der agentengesteuerten Schleife ausgelöst werden:
Die folgende Tabelle fasst zusammen, wann jedes Ereignis ausgelöst wird. Der Abschnitt Hook-Ereignisse dokumentiert das vollständige Eingabeschema und die Optionen zur Entscheidungskontrolle für jedes Ereignis.
| Event | When it fires |
|---|
SessionStart | When a session begins or resumes |
UserPromptSubmit | When you submit a prompt, before Claude processes it |
PreToolUse | Before a tool call executes. Can block it |
PermissionRequest | When a permission dialog appears |
PostToolUse | After a tool call succeeds |
PostToolUseFailure | After a tool call fails |
Notification | When Claude Code sends a notification |
SubagentStart | When a subagent is spawned |
SubagentStop | When a subagent finishes |
Stop | When Claude finishes responding |
TeammateIdle | When an agent team teammate is about to go idle |
TaskCompleted | When a task is being marked as completed |
InstructionsLoaded | When 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 |
ConfigChange | When a configuration file changes during a session |
WorktreeCreate | When a worktree is being created via --worktree or isolation: "worktree". Replaces default git behavior |
WorktreeRemove | When a worktree is being removed, either at session exit or when a subagent finishes |
PreCompact | Before context compaction |
SessionEnd | When a session terminates |
Wie ein Hook aufgelöst wird
Um zu sehen, wie diese Teile zusammenpassen, betrachten Sie diesen PreToolUse-Hook, der destruktive Shell-Befehle blockiert. Der Hook führt block-rm.sh vor jedem Bash-Tool-Aufruf aus:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-rm.sh"
}
]
}
]
}
}
Das Skript liest die JSON-Eingabe von stdin, extrahiert den Befehl und gibt eine permissionDecision von "deny" zurück, wenn es rm -rf enthält:
#!/bin/bash
# .claude/hooks/block-rm.sh
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked by hook"
}
}'
else
exit 0 # allow the command
fi
Angenommen, Claude Code entscheidet sich, Bash "rm -rf /tmp/build" auszuführen. Hier ist, was passiert:
Ereignis wird ausgelöst
Das PreToolUse-Ereignis wird ausgelöst. Claude Code sendet die Tool-Eingabe als JSON über stdin an den Hook:{ "tool_name": "Bash", "tool_input": { "command": "rm -rf /tmp/build" }, ... }
Matcher prüft
Der Matcher "Bash" passt zum Tool-Namen, daher wird block-rm.sh ausgeführt. Wenn Sie den Matcher weglassen oder "*" verwenden, wird der Hook bei jedem Auftreten des Ereignisses ausgeführt. Hooks werden nur übersprungen, wenn ein Matcher definiert ist und nicht passt.
Hook-Handler wird ausgeführt
Das Skript extrahiert "rm -rf /tmp/build" aus der Eingabe und findet rm -rf, daher gibt es eine Entscheidung auf stdout aus:{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook"
}
}
Wenn der Befehl sicher gewesen wäre (wie npm test), würde das Skript stattdessen exit 0 treffen, was Claude Code mitteilt, den Tool-Aufruf ohne weitere Maßnahmen zuzulassen. Claude Code handelt nach dem Ergebnis
Claude Code liest die JSON-Entscheidung, blockiert den Tool-Aufruf und zeigt Claude den Grund an.
Der Abschnitt Konfiguration unten dokumentiert das vollständige Schema, und jeder Abschnitt Hook-Ereignis dokumentiert, welche Eingabe Ihr Befehl erhält und welche Ausgabe er zurückgeben kann.
Konfiguration
Hooks werden in JSON-Einstellungsdateien definiert. Die Konfiguration hat drei Verschachtelungsebenen:
- Wählen Sie ein Hook-Ereignis aus, auf das Sie reagieren möchten, wie
PreToolUse oder Stop
- Fügen Sie eine Matcher-Gruppe hinzu, um zu filtern, wann es ausgelöst wird, wie ‘nur für das Bash-Tool”
- Definieren Sie einen oder mehrere Hook-Handler, die ausgeführt werden, wenn sie passen
Siehe Wie ein Hook aufgelöst wird oben für eine vollständige Anleitung mit einem kommentierten Beispiel.
Diese Seite verwendet spezifische Begriffe für jede Ebene: Hook-Ereignis für den Lebenszyklus-Punkt, Matcher-Gruppe für den Filter und Hook-Handler für den Shell-Befehl, HTTP-Endpunkt, Prompt oder Agent, der ausgeführt wird. „Hook” allein bezieht sich auf die allgemeine Funktion.
Hook-Speicherorte
Der Ort, an dem Sie einen Hook definieren, bestimmt seinen Umfang:
| Speicherort | Umfang | Teilbar |
|---|
~/.claude/settings.json | Alle Ihre Projekte | Nein, lokal auf Ihrem Computer |
.claude/settings.json | Einzelnes Projekt | Ja, kann im Repo committed werden |
.claude/settings.local.json | Einzelnes Projekt | Nein, gitignored |
| Verwaltete Richtlinieneinstellungen | Organisationsweit | Ja, von Admin kontrolliert |
Plugin hooks/hooks.json | Wenn Plugin aktiviert ist | Ja, mit dem Plugin gebündelt |
| Skill oder Agent Frontmatter | Während die Komponente aktiv ist | Ja, in der Komponentendatei definiert |
Weitere Informationen zur Auflösung von Einstellungsdateien finden Sie unter Einstellungen. Unternehmensadministratoren können allowManagedHooksOnly verwenden, um Benutzer-, Projekt- und Plugin-Hooks zu blockieren. Siehe Hook-Konfiguration.
Matcher-Muster
Das Feld matcher ist eine Regex-Zeichenkette, die filtert, wann Hooks ausgelöst werden. Verwenden Sie "*", "" oder lassen Sie matcher ganz weg, um alle Vorkommen zu treffen. Jeder Ereignistyp passt auf ein anderes Feld:
| Ereignis | Worauf der Matcher filtert | Beispiel-Matcher-Werte |
|---|
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest | Tool-Name | Bash, Edit|Write, mcp__.* |
SessionStart | Wie die Sitzung gestartet wurde | startup, resume, clear, compact |
SessionEnd | Warum die Sitzung endete | clear, logout, prompt_input_exit, bypass_permissions_disabled, other |
Notification | Benachrichtigungstyp | permission_prompt, idle_prompt, auth_success, elicitation_dialog |
SubagentStart | Agent-Typ | Bash, Explore, Plan oder benutzerdefinierte Agent-Namen |
PreCompact | Was die Komprimierung ausgelöst hat | manual, auto |
SubagentStop | Agent-Typ | gleiche Werte wie SubagentStart |
ConfigChange | Konfigurationsquelle | user_settings, project_settings, local_settings, policy_settings, skills |
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove | Keine Matcher-Unterstützung | wird immer bei jedem Auftreten ausgelöst |
Der Matcher ist ein Regex, daher passt Edit|Write zu beiden Tools und Notebook.* passt zu jedem Tool, das mit Notebook beginnt. Der Matcher wird gegen ein Feld aus der JSON-Eingabe ausgeführt, die Claude Code an Ihren Hook über stdin sendet. Bei Tool-Ereignissen ist dieses Feld tool_name. Jeder Abschnitt Hook-Ereignis listet den vollständigen Satz von Matcher-Werten und das Eingabeschema für dieses Ereignis auf.
Dieses Beispiel führt ein Linting-Skript nur aus, wenn Claude eine Datei schreibt oder bearbeitet:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate und WorktreeRemove unterstützen keine Matcher und werden immer bei jedem Auftreten ausgelöst. Wenn Sie ein matcher-Feld zu diesen Ereignissen hinzufügen, wird es stillschweigend ignoriert.
MCP-Server-Tools erscheinen als reguläre Tools in Tool-Ereignissen (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest), daher können Sie sie auf die gleiche Weise abgleichen wie jeden anderen Tool-Namen.
MCP-Tools folgen dem Benennungsmuster mcp__<server>__<tool>, zum Beispiel:
mcp__memory__create_entities: Memory-Server-Tool zum Erstellen von Entitäten
mcp__filesystem__read_file: Filesystem-Server-Tool zum Lesen von Dateien
mcp__github__search_repositories: GitHub-Server-Suchtool
Verwenden Sie Regex-Muster, um bestimmte MCP-Tools oder Gruppen von Tools zu targetieren:
mcp__memory__.* passt zu allen Tools vom memory-Server
mcp__.*__write.* passt zu jedem Tool, das „write” enthält, von jedem Server
Dieses Beispiel protokolliert alle Memory-Server-Operationen und validiert Schreibvorgänge von jedem MCP-Server:
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}
Hook-Handler-Felder
Jedes Objekt im inneren hooks-Array ist ein Hook-Handler: der Shell-Befehl, HTTP-Endpunkt, LLM-Prompt oder Agent, der ausgeführt wird, wenn der Matcher passt. Es gibt vier Typen:
- Command-Hooks (
type: "command"): Führen einen Shell-Befehl aus. Ihr Skript erhält die JSON-Eingabe des Ereignisses über stdin und kommuniziert Ergebnisse über Exit-Codes und stdout zurück.
- HTTP-Hooks (
type: "http"): Senden Sie die JSON-Eingabe des Ereignisses als HTTP-POST-Request an eine URL. Der Endpunkt kommuniziert Ergebnisse über den Response-Body mit dem gleichen JSON-Ausgabeformat wie Command-Hooks zurück.
- Prompt-Hooks (
type: "prompt"): Senden Sie einen Prompt an ein Claude-Modell zur einmaligen Evaluierung. Das Modell gibt eine Ja/Nein-Entscheidung als JSON zurück. Siehe Prompt-basierte Hooks.
- Agent-Hooks (
type: "agent"): Spawnen Sie einen Subagenten, der Tools wie Read, Grep und Glob verwenden kann, um Bedingungen zu überprüfen, bevor eine Entscheidung zurückgegeben wird. Siehe Agent-basierte Hooks.
Gemeinsame Felder
Diese Felder gelten für alle Hook-Typen:
| Feld | Erforderlich | Beschreibung |
|---|
type | ja | "command", "http", "prompt" oder "agent" |
timeout | nein | Sekunden vor dem Abbruch. Standardwerte: 600 für Command, 30 für Prompt, 60 für Agent |
statusMessage | nein | Benutzerdefinierte Spinner-Nachricht, die angezeigt wird, während der Hook ausgeführt wird |
once | nein | Wenn true, wird nur einmal pro Sitzung ausgeführt und dann entfernt. Nur Skills, nicht Agents. Siehe Hooks in Skills und Agents |
Command-Hook-Felder
Zusätzlich zu den gemeinsamen Feldern akzeptieren Command-Hooks diese Felder:
| Feld | Erforderlich | Beschreibung |
|---|
command | ja | Shell-Befehl zum Ausführen |
async | nein | Wenn true, wird im Hintergrund ohne Blockierung ausgeführt. Siehe Hooks im Hintergrund ausführen |
HTTP-Hook-Felder
Zusätzlich zu den gemeinsamen Feldern akzeptieren HTTP-Hooks diese Felder:
| Feld | Erforderlich | Beschreibung |
|---|
url | ja | URL, an die der POST-Request gesendet werden soll |
headers | nein | Zusätzliche HTTP-Header als Schlüssel-Wert-Paare. Werte unterstützen Umgebungsvariablen-Interpolation mit $VAR_NAME oder ${VAR_NAME} Syntax. Nur Variablen, die in allowedEnvVars aufgelistet sind, werden aufgelöst |
allowedEnvVars | nein | Liste von Umgebungsvariablennamen, die in Header-Werte interpoliert werden dürfen. Verweise auf nicht aufgelistete Variablen werden durch leere Zeichenketten ersetzt. Erforderlich für jede Umgebungsvariablen-Interpolation |
Claude Code sendet die JSON-Eingabe des Hooks als POST-Request-Body mit Content-Type: application/json. Der Response-Body verwendet das gleiche JSON-Ausgabeformat wie Command-Hooks.
Die Fehlerbehandlung unterscheidet sich von Command-Hooks: Nicht-2xx-Responses, Verbindungsfehler und Timeouts führen alle zu nicht-blockierenden Fehlern, die die Ausführung fortsetzen lassen. Um einen Tool-Aufruf zu blockieren oder eine Berechtigung zu verweigern, geben Sie eine 2xx-Response mit einem JSON-Body zurück, der decision: "block" oder ein hookSpecificOutput mit permissionDecision: "deny" enthält.
Dieses Beispiel sendet PreToolUse-Ereignisse an einen lokalen Validierungsdienst und authentifiziert sich mit einem Token aus der MY_TOKEN-Umgebungsvariable:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "http",
"url": "http://localhost:8080/hooks/pre-tool-use",
"timeout": 30,
"headers": {
"Authorization": "Bearer $MY_TOKEN"
},
"allowedEnvVars": ["MY_TOKEN"]
}
]
}
]
}
}
HTTP-Hooks müssen durch direktes Bearbeiten von Einstellungs-JSON konfiguriert werden. Das interaktive /hooks-Menü unterstützt nur das Hinzufügen von Command-Hooks.
Prompt- und Agent-Hook-Felder
Zusätzlich zu den gemeinsamen Feldern akzeptieren Prompt- und Agent-Hooks diese Felder:
| Feld | Erforderlich | Beschreibung |
|---|
prompt | ja | Prompt-Text zum Senden an das Modell. Verwenden Sie $ARGUMENTS als Platzhalter für die Hook-Eingabe JSON |
model | nein | Modell zur Verwendung für die Evaluierung. Standardwert ist ein schnelles Modell |
Alle passenden Hooks werden parallel ausgeführt, und identische Handler werden automatisch dedupliziert. Command-Hooks werden nach Befehlszeichenkette dedupliziert, und HTTP-Hooks werden nach URL dedupliziert. Handler werden im aktuellen Verzeichnis mit Claude Codes Umgebung ausgeführt. Die $CLAUDE_CODE_REMOTE-Umgebungsvariable wird in Remote-Web-Umgebungen auf "true" gesetzt und ist in der lokalen CLI nicht gesetzt.
Hook-Skripte nach Pfad referenzieren
Verwenden Sie Umgebungsvariablen, um Hook-Skripte relativ zum Projekt- oder Plugin-Root zu referenzieren, unabhängig vom Arbeitsverzeichnis, wenn der Hook ausgeführt wird:
$CLAUDE_PROJECT_DIR: das Projekt-Root. In Anführungszeichen setzen, um Pfade mit Leerzeichen zu handhaben.
${CLAUDE_PLUGIN_ROOT}: das Root-Verzeichnis des Plugins, für Skripte, die mit einem Plugin gebündelt sind.
Projekt-Skripte
Plugin-Skripte
Dieses Beispiel verwendet $CLAUDE_PROJECT_DIR, um einen Style-Checker aus dem .claude/hooks/-Verzeichnis des Projekts nach jedem Write- oder Edit-Tool-Aufruf auszuführen:{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
Definieren Sie Plugin-Hooks in hooks/hooks.json mit einem optionalen description-Feld auf oberster Ebene. Wenn ein Plugin aktiviert ist, werden seine Hooks mit Ihren Benutzer- und Projekt-Hooks zusammengeführt.Dieses Beispiel führt ein Formatierungsskript aus, das mit dem Plugin gebündelt ist:{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 30
}
]
}
]
}
}
Siehe die Plugin-Komponenten-Referenz für Details zum Erstellen von Plugin-Hooks.
Hooks in Skills und Agents
Zusätzlich zu Einstellungsdateien und Plugins können Hooks direkt in Skills und Subagenten mit Frontmatter definiert werden. Diese Hooks sind auf den Lebenszyklus der Komponente beschränkt und werden nur ausgeführt, wenn diese Komponente aktiv ist.
Alle Hook-Ereignisse werden unterstützt. Für Subagenten werden Stop-Hooks automatisch in SubagentStop konvertiert, da dies das Ereignis ist, das ausgelöst wird, wenn ein Subagent abgeschlossen ist.
Hooks verwenden das gleiche Konfigurationsformat wie einstellungsbasierte Hooks, sind aber auf die Lebensdauer der Komponente beschränkt und werden bereinigt, wenn sie beendet wird.
Dieser Skill definiert einen PreToolUse-Hook, der ein Sicherheitsvalidierungsskript vor jedem Bash-Befehl ausführt:
---
name: secure-operations
description: Perform operations with security checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/security-check.sh"
---
Agents verwenden das gleiche Format in ihrem YAML-Frontmatter.
Das /hooks-Menü
Geben Sie /hooks in Claude Code ein, um den interaktiven Hooks-Manager zu öffnen, in dem Sie Hooks anzeigen, hinzufügen und löschen können, ohne Einstellungsdateien direkt zu bearbeiten. Eine Schritt-für-Schritt-Anleitung finden Sie unter Richten Sie Ihren ersten Hook ein in der Anleitung.
Jeder Hook im Menü ist mit einem Klammer-Präfix gekennzeichnet, das seine Quelle angibt:
[User]: aus ~/.claude/settings.json
[Project]: aus .claude/settings.json
[Local]: aus .claude/settings.local.json
[Plugin]: aus einem Plugin hooks/hooks.json, schreibgeschützt
Hooks deaktivieren oder entfernen
Um einen Hook zu entfernen, löschen Sie seinen Eintrag aus der Einstellungs-JSON-Datei, oder verwenden Sie das /hooks-Menü und wählen Sie den Hook aus, um ihn zu löschen.
Um alle Hooks vorübergehend zu deaktivieren, ohne sie zu entfernen, setzen Sie "disableAllHooks": true in Ihrer Einstellungsdatei oder verwenden Sie den Schalter im /hooks-Menü. Es gibt keine Möglichkeit, einen einzelnen Hook zu deaktivieren, während er in der Konfiguration bleibt.
Die disableAllHooks-Einstellung respektiert die Hierarchie der verwalteten Einstellungen. Wenn ein Administrator Hooks durch verwaltete Richtlinieneinstellungen konfiguriert hat, kann disableAllHooks, das in Benutzer-, Projekt- oder lokalen Einstellungen gesetzt ist, diese verwalteten Hooks nicht deaktivieren. Nur disableAllHooks, das auf der Ebene der verwalteten Einstellungen gesetzt ist, kann verwaltete Hooks deaktivieren.
Direkte Bearbeitungen von Hooks in Einstellungsdateien werden nicht sofort wirksam. Claude Code erstellt einen Snapshot von Hooks beim Start und verwendet ihn während der gesamten Sitzung. Dies verhindert, dass böswillige oder versehentliche Hook-Änderungen ohne Ihre Überprüfung mitten in der Sitzung wirksam werden. Wenn Hooks extern geändert werden, warnt Claude Code Sie und erfordert eine Überprüfung im /hooks-Menü, bevor Änderungen wirksam werden.
Hook-Eingabe und -Ausgabe
Command-Hooks erhalten JSON-Daten über stdin und kommunizieren Ergebnisse über Exit-Codes, stdout und stderr. HTTP-Hooks erhalten die gleiche JSON als POST-Request-Body und kommunizieren Ergebnisse über den HTTP-Response-Body. Dieser Abschnitt behandelt Felder und Verhalten, die allen Ereignissen gemeinsam sind. Jeder Ereignisabschnitt unter Hook-Ereignisse enthält sein spezifisches Eingabeschema und Optionen zur Entscheidungskontrolle.
Gemeinsame Eingabefelder
Alle Hook-Ereignisse erhalten diese Felder als JSON, zusätzlich zu ereignisspezifischen Feldern, die in jedem Abschnitt Hook-Ereignis dokumentiert sind. Bei Command-Hooks kommt diese JSON über stdin an. Bei HTTP-Hooks kommt sie als POST-Request-Body an.
| Feld | Beschreibung |
|---|
session_id | Aktuelle Sitzungs-ID |
transcript_path | Pfad zur Gesprächs-JSON |
cwd | Aktuelles Arbeitsverzeichnis, wenn der Hook aufgerufen wird |
permission_mode | Aktueller Berechtigungsmodus: "default", "plan", "acceptEdits", "dontAsk" oder "bypassPermissions" |
hook_event_name | Name des ausgelösten Ereignisses |
Beispielsweise erhält ein PreToolUse-Hook für einen Bash-Befehl dies über stdin:
{
"session_id": "abc123",
"transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
"cwd": "/home/user/my-project",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}
Die Felder tool_name und tool_input sind ereignisspezifisch. Jeder Abschnitt Hook-Ereignis dokumentiert die zusätzlichen Felder für dieses Ereignis.
Exit-Code-Ausgabe
Der Exit-Code aus Ihrem Hook-Befehl teilt Claude Code mit, ob die Aktion fortgesetzt, blockiert oder ignoriert werden soll.
Exit 0 bedeutet Erfolg. Claude Code analysiert stdout auf JSON-Ausgabefelder. JSON-Ausgabe wird nur bei Exit 0 verarbeitet. Bei den meisten Ereignissen wird stdout nur im ausführlichen Modus (Ctrl+O) angezeigt. Die Ausnahmen sind UserPromptSubmit und SessionStart, wo stdout als Kontext hinzugefügt wird, den Claude sehen und darauf reagieren kann.
Exit 2 bedeutet ein blockierender Fehler. Claude Code ignoriert stdout und jede JSON darin. Stattdessen wird stderr-Text an Claude als Fehlermeldung zurückgegeben. Die Auswirkung hängt vom Ereignis ab: PreToolUse blockiert den Tool-Aufruf, UserPromptSubmit lehnt den Prompt ab, und so weiter. Siehe Exit-Code-2-Verhalten für die vollständige Liste.
Jeder andere Exit-Code ist ein nicht-blockierender Fehler. stderr wird im ausführlichen Modus (Ctrl+O) angezeigt und die Ausführung wird fortgesetzt.
Beispielsweise ein Hook-Befehlsskript, das gefährliche Bash-Befehle blockiert:
#!/bin/bash
# Liest JSON-Eingabe von stdin, prüft den Befehl
command=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm* ]]; then
echo "Blocked: rm commands are not allowed" >&2
exit 2 # Blockierender Fehler: Tool-Aufruf wird verhindert
fi
exit 0 # Erfolg: Tool-Aufruf wird fortgesetzt
Exit-Code-2-Verhalten pro Ereignis
Exit-Code 2 ist die Art, wie ein Hook signalisiert „Stopp, mach das nicht.” Die Auswirkung hängt vom Ereignis ab, da einige Ereignisse Aktionen darstellen, die blockiert werden können (wie ein Tool-Aufruf, der noch nicht stattgefunden hat), und andere Dinge darstellen, die bereits passiert sind oder nicht verhindert werden können.
| Hook-Ereignis | Kann blockiert werden? | Was bei Exit 2 passiert |
|---|
PreToolUse | Ja | Blockiert den Tool-Aufruf |
PermissionRequest | Ja | Verweigert die Berechtigung |
UserPromptSubmit | Ja | Blockiert die Prompt-Verarbeitung und löscht den Prompt |
Stop | Ja | Verhindert, dass Claude stoppt, setzt das Gespräch fort |
SubagentStop | Ja | Verhindert, dass der Subagent stoppt |
TeammateIdle | Ja | Verhindert, dass der Teammate untätig wird (Teammate arbeitet weiter) |
TaskCompleted | Ja | Verhindert, dass die Aufgabe als abgeschlossen markiert wird |
ConfigChange | Ja | Blockiert die Konfigurationsänderung von der Anwendung (außer policy_settings) |
PostToolUse | Nein | Zeigt stderr Claude an (Tool wurde bereits ausgeführt) |
PostToolUseFailure | Nein | Zeigt stderr Claude an (Tool ist bereits fehlgeschlagen) |
Notification | Nein | Zeigt stderr nur dem Benutzer an |
SubagentStart | Nein | Zeigt stderr nur dem Benutzer an |
SessionStart | Nein | Zeigt stderr nur dem Benutzer an |
SessionEnd | Nein | Zeigt stderr nur dem Benutzer an |
PreCompact | Nein | Zeigt stderr nur dem Benutzer an |
WorktreeCreate | Ja | Jeder nicht-null Exit-Code führt zu Fehler bei der Worktree-Erstellung |
WorktreeRemove | Nein | Fehler werden nur im Debug-Modus protokolliert |
HTTP-Response-Behandlung
HTTP-Hooks verwenden HTTP-Statuscodes und Response-Bodies statt Exit-Codes und stdout:
- 2xx mit leerem Body: Erfolg, äquivalent zu Exit-Code 0 ohne Ausgabe
- 2xx mit Plain-Text-Body: Erfolg, der Text wird als Kontext hinzugefügt
- 2xx mit JSON-Body: Erfolg, analysiert mit dem gleichen JSON-Ausgabe-Schema wie Command-Hooks
- Nicht-2xx-Status: Nicht-blockierender Fehler, Ausführung wird fortgesetzt
- Verbindungsfehler oder Timeout: Nicht-blockierender Fehler, Ausführung wird fortgesetzt
Im Gegensatz zu Command-Hooks können HTTP-Hooks nicht allein durch Statuscodes einen blockierenden Fehler signalisieren. Um einen Tool-Aufruf zu blockieren oder eine Berechtigung zu verweigern, geben Sie eine 2xx-Response mit einem JSON-Body zurück, der die entsprechenden Entscheidungsfelder enthält.
JSON-Ausgabe
Exit-Codes lassen Sie zulassen oder blockieren, aber JSON-Ausgabe gibt Ihnen eine feinere Kontrolle. Anstatt mit Code 2 zu beenden, um zu blockieren, beenden Sie mit 0 und geben Sie ein JSON-Objekt auf stdout aus. Claude Code liest spezifische Felder aus diesem JSON, um das Verhalten zu steuern, einschließlich Entscheidungskontrolle zum Blockieren, Zulassen oder Eskalieren an den Benutzer.
Sie müssen einen Ansatz pro Hook wählen, nicht beide: Verwenden Sie entweder Exit-Codes allein zum Signalisieren, oder beenden Sie mit 0 und geben Sie JSON für strukturierte Kontrolle aus. Claude Code verarbeitet JSON nur bei Exit 0. Wenn Sie mit 2 beenden, wird jede JSON ignoriert.
Die stdout Ihres Hooks darf nur das JSON-Objekt enthalten. Wenn Ihr Shell-Profil beim Start Text ausgibt, kann dies die JSON-Analyse beeinträchtigen. Siehe JSON-Validierung fehlgeschlagen im Troubleshooting-Leitfaden.
Das JSON-Objekt unterstützt drei Arten von Feldern:
- Universelle Felder wie
continue funktionieren über alle Ereignisse hinweg. Diese sind in der folgenden Tabelle aufgelistet.
- Top-Level
decision und reason werden von einigen Ereignissen verwendet, um zu blockieren oder Feedback zu geben.
hookSpecificOutput ist ein verschachteltes Objekt für Ereignisse, die reichere Kontrolle benötigen. Es erfordert ein hookEventName-Feld, das auf den Ereignisnamen gesetzt ist.
| Feld | Standard | Beschreibung |
|---|
continue | true | Wenn false, stoppt Claude die Verarbeitung vollständig, nachdem der Hook ausgeführt wurde. Hat Vorrang vor allen ereignisspezifischen Entscheidungsfeldern |
stopReason | keine | Nachricht, die dem Benutzer angezeigt wird, wenn continue false ist. Wird Claude nicht angezeigt |
suppressOutput | false | Wenn true, verbirgt stdout aus der Ausgabe des ausführlichen Modus |
systemMessage | keine | Warnmeldung, die dem Benutzer angezeigt wird |
Um Claude unabhängig vom Ereignistyp vollständig zu stoppen:
{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }
Entscheidungskontrolle
Nicht jedes Ereignis unterstützt Blockierung oder Verhaltenskontrolle durch JSON. Die Ereignisse, die dies tun, verwenden jeweils einen anderen Satz von Feldern, um diese Entscheidung auszudrücken. Verwenden Sie diese Tabelle als schnelle Referenz, bevor Sie einen Hook schreiben:
| Ereignisse | Entscheidungsmuster | Schlüsselfelder |
|---|
| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop, ConfigChange | Top-Level decision | decision: "block", reason |
| TeammateIdle, TaskCompleted | Nur Exit-Code | Exit-Code 2 blockiert die Aktion, stderr wird als Feedback zurückgegeben |
| PreToolUse | hookSpecificOutput | permissionDecision (allow/deny/ask), permissionDecisionReason |
| PermissionRequest | hookSpecificOutput | decision.behavior (allow/deny) |
| WorktreeCreate | stdout-Pfad | Hook gibt absoluten Pfad zum erstellten Worktree aus. Nicht-null Exit-Code schlägt die Erstellung fehl |
| WorktreeRemove, Notification, SessionEnd, PreCompact | Keine | Keine Entscheidungskontrolle. Wird für Nebenwirkungen wie Protokollierung oder Bereinigung verwendet |
Hier sind Beispiele für jedes Muster in Aktion:
Top-Level-Entscheidung
PreToolUse
PermissionRequest
Wird von UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop und ConfigChange verwendet. Der einzige Wert ist "block". Um die Aktion fortzusetzen, lassen Sie decision aus Ihrem JSON weg, oder beenden Sie mit 0 ohne jede JSON:{
"decision": "block",
"reason": "Test suite must pass before proceeding"
}
Verwendet hookSpecificOutput für reichere Kontrolle: zulassen, verweigern oder an den Benutzer eskalieren. Sie können auch die Tool-Eingabe vor der Ausführung ändern oder zusätzlichen Kontext für Claude injizieren. Siehe PreToolUse-Entscheidungskontrolle für den vollständigen Satz von Optionen.{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
Verwendet hookSpecificOutput, um eine Berechtigungsanfrage im Namen des Benutzers zu zulassen oder zu verweigern. Beim Zulassen können Sie auch die Tool-Eingabe ändern oder Berechtigungsregeln anwenden, damit der Benutzer nicht erneut aufgefordert wird. Siehe PermissionRequest-Entscheidungskontrolle für den vollständigen Satz von Optionen.{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}
Erweiterte Beispiele einschließlich Bash-Befehlsvalidierung, Prompt-Filterung und Auto-Approval-Skripte finden Sie unter Was Sie automatisieren können in der Anleitung und der Bash-Befehlsvalidierungs-Referenzimplementierung.
Hook-Ereignisse
Jedes Ereignis entspricht einem Punkt im Lebenszyklus von Claude Code, an dem Hooks ausgeführt werden können. Die folgenden Abschnitte sind so angeordnet, dass sie dem Lebenszyklus entsprechen: vom Session-Setup durch die agentengesteuerte Schleife bis zum Session-Ende. Jeder Abschnitt beschreibt, wann das Ereignis ausgelöst wird, welche Matcher es unterstützt, die JSON-Eingabe, die es erhält, und wie man das Verhalten durch Ausgabe steuert.
SessionStart
Wird ausgelöst, wenn Claude Code eine neue Sitzung startet oder eine bestehende Sitzung fortsetzt. Nützlich zum Laden von Entwicklungskontext wie bestehenden Problemen oder kürzlichen Änderungen an Ihrer Codebasis oder zum Einrichten von Umgebungsvariablen. Für statischen Kontext, der kein Skript erfordert, verwenden Sie stattdessen CLAUDE.md.
SessionStart wird bei jeder Sitzung ausgeführt, daher halten Sie diese Hooks schnell.
Der Matcher-Wert entspricht der Art, wie die Sitzung initiiert wurde:
| Matcher | Wann es ausgelöst wird |
|---|
startup | Neue Sitzung |
resume | --resume, --continue oder /resume |
clear | /clear |
compact | Auto- oder manuelle Komprimierung |
SessionStart-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten SessionStart-Hooks source, model und optional agent_type. Das Feld source gibt an, wie die Sitzung gestartet wurde: "startup" für neue Sitzungen, "resume" für fortgesetzte Sitzungen, "clear" nach /clear oder "compact" nach Komprimierung. Das Feld model enthält die Modell-ID. Wenn Sie Claude Code mit claude --agent <name> starten, enthält ein agent_type-Feld den Agent-Namen.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"source": "startup",
"model": "claude-sonnet-4-6"
}
SessionStart-Entscheidungskontrolle
Jeder Text, den Ihr Hook-Skript auf stdout ausgibt, wird als Kontext für Claude hinzugefügt. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, können Sie diese ereignisspezifischen Felder zurückgeben:
| Feld | Beschreibung |
|---|
additionalContext | Zeichenkette, die zu Claudes Kontext hinzugefügt wird. Werte mehrerer Hooks werden verkettet |
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "My additional context here"
}
}
Umgebungsvariablen beibehalten
SessionStart-Hooks haben Zugriff auf die CLAUDE_ENV_FILE-Umgebungsvariable, die einen Dateipfad bereitstellt, in dem Sie Umgebungsvariablen für nachfolgende Bash-Befehle beibehalten können.
Um einzelne Umgebungsvariablen zu setzen, schreiben Sie export-Anweisungen in CLAUDE_ENV_FILE. Verwenden Sie Anhängen (>>), um Variablen zu bewahren, die von anderen Hooks gesetzt wurden:
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export DEBUG_LOG=true' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0
Um alle Umgebungsänderungen von Setup-Befehlen zu erfassen, vergleichen Sie die exportierten Variablen vor und nach:
#!/bin/bash
ENV_BEFORE=$(export -p | sort)
# Führen Sie Ihre Setup-Befehle aus, die die Umgebung ändern
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
Alle Variablen, die in diese Datei geschrieben werden, sind in allen nachfolgenden Bash-Befehlen verfügbar, die Claude Code während der Sitzung ausführt.
CLAUDE_ENV_FILE ist für SessionStart-Hooks verfügbar. Andere Hook-Typen haben keinen Zugriff auf diese Variable.
UserPromptSubmit
Wird ausgelöst, wenn der Benutzer einen Prompt einreicht, bevor Claude ihn verarbeitet. Dies ermöglicht es Ihnen, zusätzlichen Kontext basierend auf dem Prompt/Gespräch hinzuzufügen, Prompts zu validieren oder bestimmte Arten von Prompts zu blockieren.
UserPromptSubmit-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten UserPromptSubmit-Hooks das Feld prompt, das den Text enthält, den der Benutzer eingereicht hat.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}
UserPromptSubmit-Entscheidungskontrolle
UserPromptSubmit-Hooks können steuern, ob ein Benutzer-Prompt verarbeitet wird und Kontext hinzufügen. Alle JSON-Ausgabefelder sind verfügbar.
Es gibt zwei Möglichkeiten, Kontext zum Gespräch bei Exit-Code 0 hinzuzufügen:
- Plain-Text-stdout: Jeder nicht-JSON-Text, der auf stdout geschrieben wird, wird als Kontext hinzugefügt
- JSON mit
additionalContext: Verwenden Sie das JSON-Format unten für mehr Kontrolle. Das Feld additionalContext wird als Kontext hinzugefügt
Plain-stdout wird als Hook-Ausgabe im Transkript angezeigt. Das Feld additionalContext wird diskreter hinzugefügt.
Um einen Prompt zu blockieren, geben Sie ein JSON-Objekt mit decision auf "block" zurück:
| Feld | Beschreibung |
|---|
decision | "block" verhindert die Verarbeitung des Prompts und löscht ihn aus dem Kontext. Weglassen, um den Prompt fortzusetzen |
reason | Wird dem Benutzer angezeigt, wenn decision "block" ist. Wird nicht zum Kontext hinzugefügt |
additionalContext | Zeichenkette, die zu Claudes Kontext hinzugefügt wird |
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "My additional context here"
}
}
Das JSON-Format ist nicht erforderlich für einfache Anwendungsfälle. Um Kontext hinzuzufügen, können Sie Plain-Text mit Exit-Code 0 auf stdout ausgeben. Verwenden Sie JSON, wenn Sie Prompts blockieren oder mehr strukturierte Kontrolle benötigen.
Wird ausgelöst, nachdem Claude Tool-Parameter erstellt hat und bevor der Tool-Aufruf verarbeitet wird. Passt auf Tool-Namen: Bash, Edit, Write, Read, Glob, Grep, Agent, WebFetch, WebSearch und alle MCP-Tool-Namen.
Verwenden Sie PreToolUse-Entscheidungskontrolle, um die Verwendung des Tools zu zulassen, zu verweigern oder um Berechtigung zu bitten.
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten PreToolUse-Hooks tool_name, tool_input und tool_use_id. Die tool_input-Felder hängen vom Tool ab:
Bash
Führt Shell-Befehle aus.
| Feld | Typ | Beispiel | Beschreibung |
|---|
command | Zeichenkette | "npm test" | Der auszuführende Shell-Befehl |
description | Zeichenkette | "Run test suite" | Optionale Beschreibung, was der Befehl tut |
timeout | Zahl | 120000 | Optionales Timeout in Millisekunden |
run_in_background | Boolesch | false | Ob der Befehl im Hintergrund ausgeführt werden soll |
Write
Erstellt oder überschreibt eine Datei.
| Feld | Typ | Beispiel | Beschreibung |
|---|
file_path | Zeichenkette | "/path/to/file.txt" | Absoluter Pfad zur zu schreibenden Datei |
content | Zeichenkette | "file content" | Inhalt zum Schreiben in die Datei |
Edit
Ersetzt eine Zeichenkette in einer bestehenden Datei.
| Feld | Typ | Beispiel | Beschreibung |
|---|
file_path | Zeichenkette | "/path/to/file.txt" | Absoluter Pfad zur zu bearbeitenden Datei |
old_string | Zeichenkette | "original text" | Text zum Suchen und Ersetzen |
new_string | Zeichenkette | "replacement text" | Ersatztext |
replace_all | Boolesch | false | Ob alle Vorkommen ersetzt werden sollen |
Read
Liest Dateiinhalte.
| Feld | Typ | Beispiel | Beschreibung |
|---|
file_path | Zeichenkette | "/path/to/file.txt" | Absoluter Pfad zur zu lesenden Datei |
offset | Zahl | 10 | Optionale Zeilennummer zum Starten des Lesens |
limit | Zahl | 50 | Optionale Anzahl der zu lesenden Zeilen |
Glob
Findet Dateien, die einem Glob-Muster entsprechen.
| Feld | Typ | Beispiel | Beschreibung |
|---|
pattern | Zeichenkette | "**/*.ts" | Glob-Muster zum Abgleichen von Dateien |
path | Zeichenkette | "/path/to/dir" | Optionales Verzeichnis zum Durchsuchen. Standardwert ist aktuelles Arbeitsverzeichnis |
Grep
Durchsucht Dateiinhalte mit regulären Ausdrücken.
| Feld | Typ | Beispiel | Beschreibung |
|---|
pattern | Zeichenkette | "TODO.*fix" | Regex-Muster zum Suchen |
path | Zeichenkette | "/path/to/dir" | Optionale Datei oder Verzeichnis zum Durchsuchen |
glob | Zeichenkette | "*.ts" | Optionales Glob-Muster zum Filtern von Dateien |
output_mode | Zeichenkette | "content" | "content", "files_with_matches" oder "count". Standardwert ist "files_with_matches" |
-i | Boolesch | true | Groß-/Kleinschreibung ignorieren |
multiline | Boolesch | false | Mehrzeiliges Matching aktivieren |
WebFetch
Ruft Web-Inhalte ab und verarbeitet sie.
| Feld | Typ | Beispiel | Beschreibung |
|---|
url | Zeichenkette | "https://example.com/api" | URL zum Abrufen von Inhalten |
prompt | Zeichenkette | "Extract the API endpoints" | Prompt zum Ausführen auf dem abgerufenen Inhalt |
WebSearch
Durchsucht das Web.
| Feld | Typ | Beispiel | Beschreibung |
|---|
query | Zeichenkette | "react hooks best practices" | Suchanfrage |
allowed_domains | Array | ["docs.example.com"] | Optional: Nur Ergebnisse von diesen Domains einschließen |
blocked_domains | Array | ["spam.example.com"] | Optional: Ergebnisse von diesen Domains ausschließen |
Agent
Spawnt einen Subagenten.
| Feld | Typ | Beispiel | Beschreibung |
|---|
prompt | Zeichenkette | "Find all API endpoints" | Die Aufgabe für den Agent |
description | Zeichenkette | "Find API endpoints" | Kurze Beschreibung der Aufgabe |
subagent_type | Zeichenkette | "Explore" | Typ des zu verwendenden spezialisierten Agenten |
model | Zeichenkette | "sonnet" | Optionaler Modell-Alias zum Überschreiben des Standards |
PreToolUse-Hooks können steuern, ob ein Tool-Aufruf fortgesetzt wird. Im Gegensatz zu anderen Hooks, die ein Top-Level-decision-Feld verwenden, gibt PreToolUse seine Entscheidung in einem hookSpecificOutput-Objekt zurück. Dies gibt ihm reichere Kontrolle: drei Ergebnisse (zulassen, verweigern oder fragen) plus die Möglichkeit, die Tool-Eingabe vor der Ausführung zu ändern.
| Feld | Beschreibung |
|---|
permissionDecision | "allow" umgeht das Berechtigungssystem, "deny" verhindert den Tool-Aufruf, "ask" fordert den Benutzer zur Bestätigung auf |
permissionDecisionReason | Für "allow" und "ask", dem Benutzer angezeigt, aber nicht Claude. Für "deny", Claude angezeigt |
updatedInput | Ändert die Tool-Eingabeparameter vor der Ausführung. Kombinieren Sie mit "allow", um automatisch zu genehmigen, oder mit "ask", um die geänderte Eingabe dem Benutzer zu zeigen |
additionalContext | Zeichenkette, die zu Claudes Kontext vor der Tool-Ausführung hinzugefügt wird |
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "My reason here",
"updatedInput": {
"field_to_modify": "new value"
},
"additionalContext": "Current environment: production. Proceed with caution."
}
}
PreToolUse verwendete zuvor Top-Level-Felder decision und reason, diese sind jedoch für dieses Ereignis veraltet. Verwenden Sie stattdessen hookSpecificOutput.permissionDecision und hookSpecificOutput.permissionDecisionReason. Die veralteten Werte "approve" und "block" werden auf "allow" und "deny" abgebildet. Andere Ereignisse wie PostToolUse und Stop verwenden weiterhin Top-Level-decision und reason als ihr aktuelles Format.
PermissionRequest
Wird ausgelöst, wenn dem Benutzer ein Berechtigungsdialog angezeigt wird.
Verwenden Sie PermissionRequest-Entscheidungskontrolle, um im Namen des Benutzers zu zulassen oder zu verweigern.
Passt auf Tool-Namen, gleiche Werte wie PreToolUse.
PermissionRequest-Eingabe
PermissionRequest-Hooks erhalten tool_name- und tool_input-Felder wie PreToolUse-Hooks, aber ohne tool_use_id. Ein optionales permission_suggestions-Array enthält die „Immer zulassen”-Optionen, die der Benutzer normalerweise im Berechtigungsdialog sehen würde. Der Unterschied liegt darin, wann der Hook ausgelöst wird: PermissionRequest-Hooks werden ausgelöst, wenn ein Berechtigungsdialog dem Benutzer angezeigt werden soll, während PreToolUse-Hooks vor der Tool-Ausführung unabhängig vom Berechtigungsstatus ausgelöst werden.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{ "type": "toolAlwaysAllow", "tool": "Bash" }
]
}
PermissionRequest-Entscheidungskontrolle
PermissionRequest-Hooks können Berechtigungsanfragen zulassen oder verweigern. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, kann Ihr Hook-Skript ein decision-Objekt mit diesen ereignisspezifischen Feldern zurückgeben:
| Feld | Beschreibung |
|---|
behavior | "allow" gewährt die Berechtigung, "deny" verweigert sie |
updatedInput | Nur für "allow": ändert die Tool-Eingabeparameter vor der Ausführung |
updatedPermissions | Nur für "allow": wendet Berechtigungsregel-Updates an, äquivalent zur Auswahl einer „Immer zulassen”-Option durch den Benutzer |
message | Nur für "deny": teilt Claude mit, warum die Berechtigung verweigert wurde |
interrupt | Nur für "deny": wenn true, stoppt Claude |
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}
PostToolUse
Wird unmittelbar nach erfolgreichem Abschluss eines Tools ausgelöst.
Passt auf Tool-Namen, gleiche Werte wie PreToolUse.
PostToolUse-Eingabe
PostToolUse-Hooks werden ausgelöst, nachdem ein Tool bereits erfolgreich ausgeführt wurde. Die Eingabe enthält sowohl tool_input, die an das Tool gesendeten Argumente, als auch tool_response, das Ergebnis, das es zurückgegeben hat. Das genaue Schema für beide hängt vom Tool ab.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
},
"tool_use_id": "toolu_01ABC123..."
}
PostToolUse-Entscheidungskontrolle
PostToolUse-Hooks können Feedback an Claude nach der Tool-Ausführung geben. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, kann Ihr Hook-Skript diese ereignisspezifischen Felder zurückgeben:
| Feld | Beschreibung |
|---|
decision | "block" fordert Claude mit dem reason auf. Weglassen, um die Aktion fortzusetzen |
reason | Erklärung, die Claude angezeigt wird, wenn decision "block" ist |
additionalContext | Zusätzlicher Kontext für Claude zu berücksichtigen |
updatedMCPToolOutput | Nur für MCP-Tools: ersetzt die Tool-Ausgabe durch den bereitgestellten Wert |
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Claude"
}
}
PostToolUseFailure
Wird ausgelöst, wenn eine Tool-Ausführung fehlschlägt. Dieses Ereignis wird für Tool-Aufrufe ausgelöst, die Fehler werfen oder Fehlerergebnisse zurückgeben. Verwenden Sie dies, um Fehler zu protokollieren, Warnungen zu senden oder korrektes Feedback an Claude zu geben.
Passt auf Tool-Namen, gleiche Werte wie PreToolUse.
PostToolUseFailure-Eingabe
PostToolUseFailure-Hooks erhalten die gleichen tool_name- und tool_input-Felder wie PostToolUse, zusammen mit Fehlerinformationen als Top-Level-Felder:
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": {
"command": "npm test",
"description": "Run test suite"
},
"tool_use_id": "toolu_01ABC123...",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}
| Feld | Beschreibung |
|---|
error | Zeichenkette, die beschreibt, was schief gelaufen ist |
is_interrupt | Optionaler Boolesch, der angibt, ob der Fehler durch Benutzerunterbrechung verursacht wurde |
PostToolUseFailure-Entscheidungskontrolle
PostToolUseFailure-Hooks können Kontext an Claude nach einem Tool-Fehler geben. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, kann Ihr Hook-Skript diese ereignisspezifischen Felder zurückgeben:
| Feld | Beschreibung |
|---|
additionalContext | Zusätzlicher Kontext für Claude neben dem Fehler zu berücksichtigen |
{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Additional information about the failure for Claude"
}
}
Notification
Wird ausgelöst, wenn Claude Code Benachrichtigungen sendet. Passt auf Benachrichtigungstyp: permission_prompt, idle_prompt, auth_success, elicitation_dialog. Matcher weglassen, um Hooks für alle Benachrichtigungstypen auszuführen.
Verwenden Sie separate Matcher, um verschiedene Handler je nach Benachrichtigungstyp auszuführen. Diese Konfiguration löst ein berechtigungsspezifisches Warnungsskript aus, wenn Claude Genehmigung benötigt, und eine andere Benachrichtigung, wenn Claude untätig war:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/permission-alert.sh"
}
]
},
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/idle-notification.sh"
}
]
}
]
}
}
Notification-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten Notification-Hooks message mit dem Benachrichtigungstext, ein optionales title und notification_type, das angibt, welcher Typ ausgelöst wurde.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Notification",
"message": "Claude needs your permission to use Bash",
"title": "Permission needed",
"notification_type": "permission_prompt"
}
Notification-Hooks können Benachrichtigungen nicht blockieren oder ändern. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, können Sie additionalContext zurückgeben, um Kontext zum Gespräch hinzuzufügen:
| Feld | Beschreibung |
|---|
additionalContext | Zeichenkette, die zu Claudes Kontext hinzugefügt wird |
SubagentStart
Wird ausgelöst, wenn ein Claude Code-Subagent über das Agent-Tool spawnt wird. Unterstützt Matcher zum Filtern nach Agent-Typname (integrierte Agents wie Bash, Explore, Plan oder benutzerdefinierte Agent-Namen aus .claude/agents/).
SubagentStart-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten SubagentStart-Hooks agent_id mit der eindeutigen Kennung für den Subagenten und agent_type mit dem Agent-Namen (integrierte Agents wie "Bash", "Explore", "Plan" oder benutzerdefinierte Agent-Namen).
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStart",
"agent_id": "agent-abc123",
"agent_type": "Explore"
}
SubagentStart-Hooks können die Subagenten-Erstellung nicht blockieren, aber sie können Kontext in den Subagenten injizieren. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, können Sie zurückgeben:
| Feld | Beschreibung |
|---|
additionalContext | Zeichenkette, die zum Kontext des Subagenten hinzugefügt wird |
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Follow security guidelines for this task"
}
}
SubagentStop
Wird ausgelöst, wenn ein Claude Code-Subagent seine Antwort beendet hat. Passt auf Agent-Typ, gleiche Werte wie SubagentStart.
SubagentStop-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten SubagentStop-Hooks stop_hook_active, agent_id, agent_type, agent_transcript_path und last_assistant_message. Das Feld agent_type ist der Wert, der zum Filtern von Matchern verwendet wird. Der transcript_path ist das Transkript der Hauptsitzung, während agent_transcript_path das eigene Transkript des Subagenten ist, das in einem verschachtelten subagents/-Ordner gespeichert ist. Das Feld last_assistant_message enthält den Textinhalt der letzten Antwort des Subagenten, daher können Hooks darauf zugreifen, ohne die Transkript-Datei zu analysieren.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../abc123.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStop",
"stop_hook_active": false,
"agent_id": "def456",
"agent_type": "Explore",
"agent_transcript_path": "~/.claude/projects/.../abc123/subagents/agent-def456.jsonl",
"last_assistant_message": "Analysis complete. Found 3 potential issues..."
}
SubagentStop-Hooks verwenden das gleiche Entscheidungskontrollformat wie Stop-Hooks.
Stop
Wird ausgelöst, wenn der Haupt-Claude Code-Agent seine Antwort beendet hat. Wird nicht ausgelöst, wenn der Stopp aufgrund einer Benutzerunterbrechung aufgetreten ist.
Stop-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten Stop-Hooks stop_hook_active und last_assistant_message. Das Feld stop_hook_active ist true, wenn Claude Code bereits als Ergebnis eines Stop-Hooks fortgesetzt wird. Überprüfen Sie diesen Wert oder verarbeiten Sie das Transkript, um zu verhindern, dass Claude Code unbegrenzt läuft. Das Feld last_assistant_message enthält den Textinhalt von Claudes letzter Antwort, daher können Hooks darauf zugreifen, ohne die Transkript-Datei zu analysieren.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true,
"last_assistant_message": "I've completed the refactoring. Here's a summary..."
}
Stop-Entscheidungskontrolle
Stop- und SubagentStop-Hooks können steuern, ob Claude fortgesetzt wird. Zusätzlich zu den JSON-Ausgabefeldern, die allen Hooks zur Verfügung stehen, kann Ihr Hook-Skript diese ereignisspezifischen Felder zurückgeben:
| Feld | Beschreibung |
|---|
decision | "block" verhindert, dass Claude stoppt. Weglassen, um Claude zu stoppen |
reason | Erforderlich, wenn decision "block" ist. Teilt Claude mit, warum es fortgesetzt werden sollte |
{
"decision": "block",
"reason": "Must be provided when Claude is blocked from stopping"
}
TeammateIdle
Wird ausgelöst, wenn ein Agent-Team-Teammate nach Abschluss seiner Runde untätig werden soll. Verwenden Sie dies, um Qualitätsgates vor dem Stoppen eines Teammates durchzusetzen, wie das Erfordern von bestandenen Lint-Checks oder das Überprüfen, dass Ausgabedateien vorhanden sind.
Wenn ein TeammateIdle-Hook mit Code 2 beendet wird, erhält der Teammate die stderr-Nachricht als Feedback und arbeitet weiter, anstatt untätig zu werden. TeammateIdle-Hooks unterstützen keine Matcher und werden bei jedem Auftreten ausgelöst.
TeammateIdle-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten TeammateIdle-Hooks teammate_name und team_name.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "TeammateIdle",
"teammate_name": "researcher",
"team_name": "my-project"
}
| Feld | Beschreibung |
|---|
teammate_name | Name des Teammates, das untätig werden soll |
team_name | Name des Teams |
TeammateIdle-Entscheidungskontrolle
TeammateIdle-Hooks verwenden nur Exit-Codes, keine JSON-Entscheidungskontrolle. Dieses Beispiel prüft, dass ein Build-Artefakt vorhanden ist, bevor ein Teammate untätig werden darf:
#!/bin/bash
if [ ! -f "./dist/output.js" ]; then
echo "Build artifact missing. Run the build before stopping." >&2
exit 2
fi
exit 0
TaskCompleted
Wird ausgelöst, wenn eine Aufgabe als abgeschlossen markiert wird. Dies wird in zwei Situationen ausgelöst: wenn ein Agent eine Aufgabe explizit über das TaskUpdate-Tool als abgeschlossen markiert, oder wenn ein Agent-Team-Teammate seine Runde mit laufenden Aufgaben beendet. Verwenden Sie dies, um Abschluss-Kriterien wie bestandene Tests oder Lint-Checks durchzusetzen, bevor eine Aufgabe geschlossen werden kann.
Wenn ein TaskCompleted-Hook mit Code 2 beendet wird, wird die Aufgabe nicht als abgeschlossen markiert und die stderr-Nachricht wird dem Modell als Feedback zurückgegeben. TaskCompleted-Hooks unterstützen keine Matcher und werden bei jedem Auftreten ausgelöst.
TaskCompleted-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten TaskCompleted-Hooks task_id, task_subject und optional task_description, teammate_name und team_name.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "TaskCompleted",
"task_id": "task-001",
"task_subject": "Implement user authentication",
"task_description": "Add login and signup endpoints",
"teammate_name": "implementer",
"team_name": "my-project"
}
| Feld | Beschreibung |
|---|
task_id | Kennung der abgeschlossenen Aufgabe |
task_subject | Titel der Aufgabe |
task_description | Detaillierte Beschreibung der Aufgabe. Kann fehlen |
teammate_name | Name des Teammates, das die Aufgabe abschließt. Kann fehlen |
team_name | Name des Teams. Kann fehlen |
TaskCompleted-Entscheidungskontrolle
TaskCompleted-Hooks verwenden nur Exit-Codes, keine JSON-Entscheidungskontrolle. Dieses Beispiel führt Tests aus und blockiert die Aufgabenvervollständigung, wenn sie fehlschlagen:
#!/bin/bash
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
# Führen Sie die Test-Suite aus
if ! npm test 2>&1; then
echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
exit 2
fi
exit 0
ConfigChange
Wird ausgelöst, wenn sich eine Konfigurationsdatei während einer Sitzung ändert. Verwenden Sie dies, um Einstellungsänderungen zu überprüfen, Sicherheitsrichtlinien durchzusetzen oder nicht autorisierte Änderungen an Konfigurationsdateien zu blockieren.
ConfigChange-Hooks werden für Änderungen an Einstellungsdateien, verwalteten Richtlinieneinstellungen und Skill-Dateien ausgelöst. Das Feld source in der Eingabe teilt Ihnen mit, welche Art von Konfiguration sich geändert hat, und das optionale Feld file_path gibt den Pfad zur geänderten Datei an.
Der Matcher filtert auf die Konfigurationsquelle:
| Matcher | Wann es ausgelöst wird |
|---|
user_settings | ~/.claude/settings.json ändert sich |
project_settings | .claude/settings.json ändert sich |
local_settings | .claude/settings.local.json ändert sich |
policy_settings | Verwaltete Richtlinieneinstellungen ändern sich |
skills | Eine Skill-Datei in .claude/skills/ ändert sich |
Dieses Beispiel protokolliert alle Konfigurationsänderungen für Sicherheitsaudits:
{
"hooks": {
"ConfigChange": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-config-change.sh"
}
]
}
]
}
}
ConfigChange-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten ConfigChange-Hooks source und optional file_path. Das Feld source gibt an, welche Konfigurationsart sich geändert hat, und file_path gibt den Pfad zur spezifischen Datei an, die geändert wurde.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "ConfigChange",
"source": "project_settings",
"file_path": "/Users/.../my-project/.claude/settings.json"
}
ConfigChange-Entscheidungskontrolle
ConfigChange-Hooks können Konfigurationsänderungen blockieren, damit sie nicht wirksam werden. Verwenden Sie Exit-Code 2 oder ein JSON-decision, um die Änderung zu verhindern. Wenn blockiert, werden die neuen Einstellungen nicht auf die laufende Sitzung angewendet.
| Feld | Beschreibung |
|---|
decision | "block" verhindert, dass die Konfigurationsänderung angewendet wird. Weglassen, um die Änderung zuzulassen |
reason | Erklärung, die dem Benutzer angezeigt wird, wenn decision "block" ist |
{
"decision": "block",
"reason": "Configuration changes to project settings require admin approval"
}
policy_settings-Änderungen können nicht blockiert werden. Hooks werden immer noch für policy_settings-Quellen ausgelöst, daher können Sie sie für Audit-Protokollierung verwenden, aber jede Blockierungsentscheidung wird ignoriert. Dies stellt sicher, dass von Unternehmen verwaltete Einstellungen immer wirksam werden.
WorktreeCreate
Wenn Sie claude --worktree ausführen oder ein Subagent isolation: "worktree" verwendet, erstellt Claude Code eine isolierte Arbeitskopie mit git worktree. Wenn Sie einen WorktreeCreate-Hook konfigurieren, ersetzt er das Standard-Git-Verhalten und lässt Sie ein anderes Versionskontrollsystem wie SVN, Perforce oder Mercurial verwenden.
Der Hook muss den absoluten Pfad zum erstellten Worktree-Verzeichnis auf stdout ausgeben. Claude Code verwendet diesen Pfad als Arbeitsverzeichnis für die isolierte Sitzung.
Dieses Beispiel erstellt eine SVN-Arbeitskopie und gibt den Pfad aus, damit Claude Code ihn verwenden kann. Ersetzen Sie die Repository-URL durch Ihre eigene:
{
"hooks": {
"WorktreeCreate": [
{
"hooks": [
{
"type": "command",
"command": "bash -c 'NAME=$(jq -r .name); DIR=\"$HOME/.claude/worktrees/$NAME\"; svn checkout https://svn.example.com/repo/trunk \"$DIR\" >&2 && echo \"$DIR\"'"
}
]
}
]
}
}
Der Hook liest den Worktree-name aus der JSON-Eingabe auf stdin, checkt eine frische Kopie in ein neues Verzeichnis aus und gibt den Verzeichnispath aus. Das echo in der letzten Zeile ist das, was Claude Code als Worktree-Pfad liest. Leiten Sie jede andere Ausgabe zu stderr um, damit sie nicht mit dem Pfad interferiert.
WorktreeCreate-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten WorktreeCreate-Hooks das Feld name. Dies ist eine Slug-Kennung für den neuen Worktree, entweder vom Benutzer angegeben oder automatisch generiert (zum Beispiel bold-oak-a3f2).
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "WorktreeCreate",
"name": "feature-auth"
}
WorktreeCreate-Ausgabe
Der Hook muss den absoluten Pfad zum erstellten Worktree-Verzeichnis auf stdout ausgeben. Wenn der Hook fehlschlägt oder keine Ausgabe erzeugt, schlägt die Worktree-Erstellung mit einem Fehler fehl.
WorktreeCreate-Hooks verwenden nicht das Standard-Zulassen/Blockieren-Entscheidungsmodell. Stattdessen bestimmt der Erfolg oder Fehler des Hooks das Ergebnis. Nur type: "command"-Hooks werden unterstützt.
WorktreeRemove
Das Cleanup-Gegenstück zu WorktreeCreate. Dieser Hook wird ausgelöst, wenn ein Worktree entfernt wird, entweder wenn Sie eine --worktree-Sitzung beenden und wählen, sie zu entfernen, oder wenn ein Subagent mit isolation: "worktree" beendet wird. Für Git-basierte Worktrees handhabt Claude die Bereinigung automatisch mit git worktree remove. Wenn Sie einen WorktreeCreate-Hook für ein nicht-Git-Versionskontrollsystem konfiguriert haben, koppeln Sie ihn mit einem WorktreeRemove-Hook, um die Bereinigung zu handhaben. Ohne einen wird das Worktree-Verzeichnis auf der Festplatte belassen.
Claude Code übergibt den Pfad, den WorktreeCreate auf stdout ausgegeben hat, als worktree_path in der Hook-Eingabe. Dieses Beispiel liest diesen Pfad und entfernt das Verzeichnis:
{
"hooks": {
"WorktreeRemove": [
{
"hooks": [
{
"type": "command",
"command": "bash -c 'jq -r .worktree_path | xargs rm -rf'"
}
]
}
]
}
}
WorktreeRemove-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten WorktreeRemove-Hooks das Feld worktree_path, das der absolute Pfad zum Worktree ist, das entfernt wird.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "WorktreeRemove",
"worktree_path": "/Users/.../my-project/.claude/worktrees/feature-auth"
}
WorktreeRemove-Hooks haben keine Entscheidungskontrolle. Sie können die Worktree-Entfernung nicht blockieren, können aber Cleanup-Aufgaben wie das Entfernen von Versionskontrollstatus oder das Archivieren von Änderungen durchführen. Hook-Fehler werden nur im Debug-Modus protokolliert. Nur type: "command"-Hooks werden unterstützt.
PreCompact
Wird ausgelöst, bevor Claude Code eine Komprimierungsoperation ausführen soll.
Der Matcher-Wert gibt an, ob die Komprimierung manuell oder automatisch ausgelöst wurde:
| Matcher | Wann es ausgelöst wird |
|---|
manual | /compact |
auto | Auto-Komprimierung, wenn das Kontextfenster voll ist |
PreCompact-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten PreCompact-Hooks trigger und custom_instructions. Für manual enthält custom_instructions das, was der Benutzer in /compact übergibt. Für auto ist custom_instructions leer.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PreCompact",
"trigger": "manual",
"custom_instructions": ""
}
SessionEnd
Wird ausgelöst, wenn eine Claude Code-Sitzung endet. Nützlich für Cleanup-Aufgaben, Protokollierung von Sitzungsstatistiken oder Speicherung des Sitzungsstatus. Unterstützt Matcher zum Filtern nach Ausstiegsgrund.
Das Feld reason in der Hook-Eingabe gibt an, warum die Sitzung endete:
| Grund | Beschreibung |
|---|
clear | Sitzung mit /clear-Befehl gelöscht |
logout | Benutzer hat sich abgemeldet |
prompt_input_exit | Benutzer hat beendet, während die Prompt-Eingabe sichtbar war |
bypass_permissions_disabled | Bypass-Berechtigungsmodus wurde deaktiviert |
other | Andere Ausstiegsgründe |
SessionEnd-Eingabe
Zusätzlich zu den gemeinsamen Eingabefeldern erhalten SessionEnd-Hooks ein Feld reason, das angibt, warum die Sitzung endete. Siehe die Grundtabelle oben für alle Werte.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionEnd",
"reason": "other"
}
SessionEnd-Hooks haben keine Entscheidungskontrolle. Sie können die Sitzungsbeendigung nicht blockieren, können aber Cleanup-Aufgaben durchführen.
Prompt-basierte Hooks
Zusätzlich zu Command- und HTTP-Hooks unterstützt Claude Code Prompt-basierte Hooks (type: "prompt"), die ein LLM zur Evaluierung verwenden, ob eine Aktion zulässig oder blockiert werden soll, und Agent-Hooks (type: "agent"), die einen agentengesteuerten Verifier mit Tool-Zugriff spawnen. Nicht alle Ereignisse unterstützen jeden Hook-Typ.
Ereignisse, die alle vier Hook-Typen unterstützen (command, http, prompt und agent):
PermissionRequest
PostToolUse
PostToolUseFailure
PreToolUse
Stop
SubagentStop
TaskCompleted
UserPromptSubmit
Ereignisse, die nur type: "command"-Hooks unterstützen:
ConfigChange
Notification
PreCompact
SessionEnd
SessionStart
SubagentStart
TeammateIdle
WorktreeCreate
WorktreeRemove
Wie Prompt-basierte Hooks funktionieren
Anstatt einen Bash-Befehl auszuführen, Prompt-basierte Hooks:
- Senden Sie die Hook-Eingabe und Ihren Prompt an ein Claude-Modell, standardmäßig Haiku
- Das LLM antwortet mit strukturiertem JSON, das eine Entscheidung enthält
- Claude Code verarbeitet die Entscheidung automatisch
Prompt-Hook-Konfiguration
Setzen Sie type auf "prompt" und geben Sie eine prompt-Zeichenkette statt eines command an. Verwenden Sie den Platzhalter $ARGUMENTS, um die Hook-JSON-Eingabedaten in Ihren Prompt-Text einzufügen. Claude Code sendet den kombinierten Prompt und die Eingabe an ein schnelles Claude-Modell, das eine JSON-Entscheidung zurückgibt.
Dieser Stop-Hook fragt das LLM, ob Claude stoppen sollte, bevor alle Aufgaben abgeschlossen sind:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}
| Feld | Erforderlich | Beschreibung |
|---|
type | ja | Muss "prompt" sein |
prompt | ja | Der Prompt-Text zum Senden an das LLM. Verwenden Sie $ARGUMENTS als Platzhalter für die Hook-Eingabe JSON. Wenn $ARGUMENTS nicht vorhanden ist, wird die Eingabe JSON an den Prompt angehängt |
model | nein | Modell zur Verwendung für die Evaluierung. Standardwert ist ein schnelles Modell |
timeout | nein | Timeout in Sekunden. Standard: 30 |
Response-Schema
Das LLM muss mit JSON antworten, das Folgendes enthält:
{
"ok": true | false,
"reason": "Explanation for the decision"
}
| Feld | Beschreibung |
|---|
ok | true lässt die Aktion zu, false verhindert sie |
reason | Erforderlich, wenn ok false ist. Erklärung, die Claude angezeigt wird |
Beispiel: Multi-Kriterium-Stop-Hook
Dieser Stop-Hook verwendet einen detaillierten Prompt, um drei Bedingungen zu überprüfen, bevor Claude stoppen darf. Wenn "ok" false ist, setzt Claude die Arbeit mit der bereitgestellten Begründung als nächste Anweisung fort. SubagentStop-Hooks verwenden das gleiche Format, um zu evaluieren, ob ein Subagent stoppen sollte:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
"timeout": 30
}
]
}
]
}
}
Agent-basierte Hooks
Agent-basierte Hooks (type: "agent") sind wie Prompt-basierte Hooks, aber mit Multi-Turn-Tool-Zugriff. Anstatt eines einzelnen LLM-Aufrufs spawnt ein Agent-Hook einen Subagenten, der Dateien lesen, Code durchsuchen und die Codebasis überprüfen kann, um Bedingungen zu überprüfen. Agent-Hooks unterstützen die gleichen Ereignisse wie Prompt-basierte Hooks.
Wie Agent-Hooks funktionieren
Wenn ein Agent-Hook ausgelöst wird:
- Claude Code spawnt einen Subagenten mit Ihrem Prompt und der Hook-JSON-Eingabe
- Der Subagent kann Tools wie Read, Grep und Glob verwenden, um zu untersuchen
- Nach bis zu 50 Turns gibt der Subagent eine strukturierte
{ "ok": true/false }-Entscheidung zurück
- Claude Code verarbeitet die Entscheidung auf die gleiche Weise wie ein Prompt-Hook
Agent-Hooks sind nützlich, wenn die Überprüfung das Überprüfen tatsächlicher Dateien oder Test-Ausgabe erfordert, nicht nur die Evaluierung der Hook-Eingabedaten allein.
Agent-Hook-Konfiguration
Setzen Sie type auf "agent" und geben Sie eine prompt-Zeichenkette an. Die Konfigurationsfelder sind die gleichen wie Prompt-Hooks, mit einem längeren Standard-Timeout:
| Feld | Erforderlich | Beschreibung |
|---|
type | ja | Muss "agent" sein |
prompt | ja | Prompt, der beschreibt, was zu überprüfen ist. Verwenden Sie $ARGUMENTS als Platzhalter für die Hook-Eingabe JSON |
model | nein | Modell zur Verwendung. Standardwert ist ein schnelles Modell |
timeout | nein | Timeout in Sekunden. Standard: 60 |
Das Response-Schema ist das gleiche wie Prompt-Hooks: { "ok": true } zum Zulassen oder { "ok": false, "reason": "..." } zum Blockieren.
Dieser Stop-Hook überprüft, dass alle Unit-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
}
]
}
]
}
}
Hooks im Hintergrund ausführen
Standardmäßig blockieren Hooks die Ausführung von Claude, bis sie abgeschlossen sind. Für lang laufende Aufgaben wie Deployments, Test-Suites oder externe API-Aufrufe setzen Sie "async": true, um den Hook im Hintergrund auszuführen, während Claude weiterarbeitet. Asynchrone Hooks können Claude nicht blockieren oder steuern: Response-Felder wie decision, permissionDecision und continue haben keine Auswirkung, da die Aktion, die sie steuern würden, bereits abgeschlossen ist.
Konfigurieren Sie einen asynchronen Hook
Fügen Sie "async": true zur Konfiguration eines Command-Hooks hinzu, um ihn im Hintergrund ohne Blockierung auszuführen. Dieses Feld ist nur auf type: "command"-Hooks verfügbar.
Dieser Hook führt ein Test-Skript nach jedem Write-Tool-Aufruf aus. Claude arbeitet sofort weiter, während run-tests.sh bis zu 120 Sekunden ausgeführt wird. Wenn das Skript beendet wird, wird seine Ausgabe beim nächsten Gesprächsturn geliefert:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "/path/to/run-tests.sh",
"async": true,
"timeout": 120
}
]
}
]
}
}
Das Feld timeout setzt die maximale Zeit in Sekunden für den Hintergrund-Prozess. Wenn nicht angegeben, verwenden asynchrone Hooks das gleiche 10-Minuten-Standard wie synchrone Hooks.
Wie asynchrone Hooks ausgeführt werden
Wenn ein asynchroner Hook ausgelöst wird, startet Claude Code den Hook-Prozess und setzt sofort fort, ohne auf den Abschluss zu warten. Der Hook erhält die gleiche JSON-Eingabe über stdin wie ein synchroner Hook.
Nachdem der Hintergrund-Prozess beendet wird, wenn der Hook eine JSON-Response mit einem systemMessage- oder additionalContext-Feld erzeugt hat, wird dieser Inhalt Claude beim nächsten Gesprächsturn als Kontext geliefert.
Beispiel: Tests nach Dateiänderungen ausführen
Dieser Hook startet eine Test-Suite im Hintergrund, wenn Claude eine Datei schreibt, und meldet die Ergebnisse Claude, wenn die Tests beendet sind. Speichern Sie dieses Skript unter .claude/hooks/run-tests-async.sh in Ihrem Projekt und machen Sie es mit chmod +x ausführbar:
#!/bin/bash
# run-tests-async.sh
# Hook-Eingabe von stdin lesen
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Tests nur für Quelldateien ausführen
if [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.js ]]; then
exit 0
fi
# Tests ausführen und Ergebnisse über systemMessage melden
RESULT=$(npm test 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "{\"systemMessage\": \"Tests passed after editing $FILE_PATH\"}"
else
echo "{\"systemMessage\": \"Tests failed after editing $FILE_PATH: $RESULT\"}"
fi
Fügen Sie dann diese Konfiguration zu .claude/settings.json im Projekt-Root hinzu. Das Flag async: true lässt Claude weiterarbeiten, während Tests ausgeführt werden:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests-async.sh",
"async": true,
"timeout": 300
}
]
}
]
}
}
Einschränkungen
Asynchrone Hooks haben mehrere Einschränkungen im Vergleich zu synchronen Hooks:
- Nur
type: "command"-Hooks unterstützen async. Prompt-basierte Hooks können nicht asynchron ausgeführt werden.
- Asynchrone Hooks können Claude nicht blockieren oder Entscheidungen zurückgeben. Zum Zeitpunkt des Hook-Abschlusses hat die auslösende Aktion bereits stattgefunden.
- Hook-Ausgabe wird beim nächsten Gesprächsturn geliefert. Wenn die Sitzung untätig ist, wartet die Response bis zur nächsten Benutzerinteraktion.
- Jede Ausführung erstellt einen separaten Hintergrund-Prozess. Es gibt keine Deduplizierung über mehrere Auslösungen des gleichen asynchronen Hooks.
Sicherheitsüberlegungen
Haftungsausschluss
Command-Hooks werden mit den vollständigen Berechtigungen Ihres System-Benutzers ausgeführt.
Command-Hooks führen Shell-Befehle mit Ihren vollständigen Berechtigungen aus. Sie können alle Dateien ändern, löschen oder zugreifen, auf die Ihr Benutzerkonto zugreifen kann. Überprüfen und testen Sie alle Hook-Befehle, bevor Sie sie zu Ihrer Konfiguration hinzufügen.
Best Practices für Sicherheit
Beachten Sie diese Praktiken beim Schreiben von Hooks:
- Validieren und bereinigen Sie Eingaben: Vertrauen Sie niemals blind auf Eingabedaten
- Zitieren Sie immer Shell-Variablen: Verwenden Sie
"$VAR" nicht $VAR
- Blockieren Sie Path-Traversal: Prüfen Sie auf
.. in Dateipfaden
- Verwenden Sie absolute Pfade: Geben Sie vollständige Pfade für Skripte an, verwenden Sie
"$CLAUDE_PROJECT_DIR" für das Projekt-Root
- Überspringen Sie sensible Dateien: Vermeiden Sie
.env, .git/, Schlüssel, etc.
Debug-Hooks
Führen Sie claude --debug aus, um Hook-Ausführungsdetails zu sehen, einschließlich welche Hooks passten, ihre Exit-Codes und Ausgabe. Schalten Sie den ausführlichen Modus mit Ctrl+O um, um Hook-Fortschritt im Transkript zu sehen.
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
Für Troubleshooting häufiger Probleme wie Hooks, die nicht ausgelöst werden, unendliche Stop-Hook-Schleifen oder Konfigurationsfehler, siehe Einschränkungen und Troubleshooting in der Anleitung.