Hooks sind benutzerdefinierte Shell-Kommandos, HTTP-Endpunkte, LLM-Prompts oder Agents, die automatisch an bestimmten Stellen im Claude Code Lebenszyklus ausgeführt werden.
Hook-Typen
1. Command Hooks (type: "command")
Shell-Kommandos mit JSON-Input via stdin und Exit-Codes für Ergebnisse.
{
"type": "command",
"command": ".claude/hooks/validator.sh",
"timeout": 30,
"async": false,
"once": false,
"statusMessage": "Running validation..."
}
Parameter:
command(string): Pfad zum Skript. Unterstützt$CLAUDE_PROJECT_DIR,${CLAUDE_PLUGIN_ROOT}.timeout(number): Max. Laufzeit in Sekunden (Standard: 600s).async(boolean): Asynchrone Ausführung (Standard: false).once(boolean): Einmal pro Session (Standard: false).statusMessage(string): Benutzerdefinierte Statusmeldung.
2. HTTP Hooks (type: "http")
POST-Anfragen an URLs mit JSON-Payload.
{
"type": "http",
"url": "http://localhost:8080/hooks/validate",
"headers": {
"Authorization": "Bearer $MY_TOKEN"
},
"allowedEnvVars": ["MY_TOKEN"],
"timeout": 30
}
Parameter:
url(string): HTTP-Endpunkt mit Umgebungsvariablen-Interpolation.headers(object): HTTP-Header (Variablen werden interpoliert).allowedEnvVars(array): Whitelist für Header-Interpolation.timeout(number): Max. Laufzeit (Standard: 30s).
3. Prompt Hooks (type: "prompt")
Single-Turn-Evaluation durch Claude mit Ja/Nein-Antwort.
{
"type": "prompt",
"prompt": "Should this command be allowed? $ARGUMENTS",
"model": "claude-opus",
"timeout": 30
}
Parameter:
prompt(string): Der Prompt.$ARGUMENTSwird durch Hook-Input ersetzt.model(string):claude-opus,claude-sonnet,claude-haiku.timeout(number): Max. Laufzeit (Standard: 30s).
4. Agent Hooks (type: "agent")
Spawnen Subagents für komplexe Verifizierungen mit Tool-Zugriff.
{
"type": "agent",
"prompt": "Verify that tests pass",
"context": "fork",
"agent": "Plan"
}
Parameter:
prompt(string): Anleitung für den Subagent.context(string):forkfür isolierten Context.agent(string):Explore,Plan,general-purpose.
Hook-Events — Vollständige Liste
Session-Events
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
SessionStart |
startup|resume|clear|compact | Nein | Neue/fortgesetzte Session. Umgebungsvariable: CLAUDE_ENV_FILE |
SessionEnd |
clear|logout|other | Ja (Exit 2) | Session-Beendigung. Timeout: 1,5s (hart). |
InstructionsLoaded |
— | Nein | CLAUDE.md/Rules geladen. |
Tool-Execution-Events
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
PreToolUse |
Tool-Name (Bash, Edit|Write, mcp__.*) | Ja (Exit 2) | Vor Tool-Ausführung. Umgebungsvariablen: CLAUDE_TOOL_NAME, CLAUDE_TOOL_INPUT. |
PostToolUse |
Tool-Name | Nein | Nach erfolgreicher Ausführung. |
PostToolUseFailure |
Tool-Name | Nein | Nach fehlgeschlagener Ausführung. |
PermissionRequest |
Tool-Name | Ja (Exit 2) | Bestätigungsdialog wird angezeigt. |
Agent-Events
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
SubagentStart |
Agent-Typ (Explore, Plan, ...) | Nein | Subagent wird gespawnt. |
SubagentStop |
Agent-Typ | Ja (Exit 2) | Subagent beendet. |
Stop |
— | Ja (Exit 2) | Hauptagent beendet Antwort. |
StopFailure |
Fehlertyp (rate_limit, auth_failed, server_error, other) | Nein | Turn beendet sich aufgrund API-Fehler. |
Konfiguration & Kontext
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
ConfigChange |
user_settings|project_settings|policy_settings | Ja (Exit 2) | Konfigurationsdatei wird geändert. |
Notification |
permission_prompt|idle_prompt|other | Nein | Benachrichtigung wird angezeigt. |
PreCompact |
— | Nein | Context-Kompression beginnt. |
PostCompact |
— | Nein | Context-Kompression abgeschlossen. |
Qualitäts-Gates
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
TeammateIdle |
— | Nein | Team-Mitglied wird inaktiv. |
TaskCompleted |
— | Nein | Task wird als abgeschlossen markiert. |
Git-Worktree-Events
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
WorktreeCreate |
— | Ja (Exit 2) | Git-Worktree wird erstellt. Ausgabe: Pfad auf stdout. |
WorktreeRemove |
— | Nein | Worktree wird gelöscht. |
Benutzer-Input & MCP
| Event | Matcher | Blockierbar | Beschreibung |
|---|---|---|---|
UserPromptSubmit |
— | Ja (Exit 2) | Bevor Benutzer-Prompt verarbeitet wird. |
Elicitation |
MCP-Server-Name | Ja (Exit 2) | MCP-Server fordert Input an. |
ElicitationResult |
MCP-Server-Name | Nein | Benutzer antwortet auf Elicitation. |
Matcher-Syntax
Matcher verwenden reguläre Ausdrücke zum Filtern von Hook-Events.
Matcher-Unterstützung nach Event:
| Event | Matcher-Ziel | Beispiele |
|---|---|---|
| PreToolUse, PostToolUse, PermissionRequest | Tool-Name | Bash, Edit|Write, Read, mcp__.* |
| SessionStart | Session-Quelle | startup, resume, clear, compact |
| SessionEnd | Exit-Grund | clear, logout, other |
| SubagentStart, SubagentStop | Agent-Typ | Explore, Plan, oder benutzerdefinierte Namen |
| ConfigChange | Config-Quelle | user_settings, project_settings, policy_settings |
| StopFailure | Fehlertyp | rate_limit, authentication_failed, server_error |
| Elicitation, ElicitationResult | MCP-Server-Name | Konfigurierte Server-Namen |
Regex-Beispiele:
"matcher": "Bash" // Exakt: nur Bash
"matcher": "Edit|Write" // Alternation: Edit oder Write
"matcher": "mcp__.*" // Alle MCP-Tools
"matcher": "mcp__memory__.*" // Nur memory MCP-Tools
"matcher": "^(Read|Grep|Glob)$" // Read-Only-Tools
Events OHNE Matcher-Unterstützung:
- UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, InstructionsLoaded
Umgebungsvariablen
Immer verfügbar:
CLAUDE_PROJECT_DIR # Absoluter Projekt-Pfad
CLAUDE_SESSION_ID # Eindeutige Session-ID
CLAUDE_CODE_REMOTE="true" # Gesetzt in Remote-Umgebungen
SessionStart-exklusiv:
CLAUDE_ENV_FILE # Pfad zu Datei für Umgebungsvariablen
# Beispiel: echo "export NODE_ENV=production" >> "$CLAUDE_ENV_FILE"
PreToolUse-exklusiv:
CLAUDE_TOOL_NAME # Name des aufzurufenden Tools
CLAUDE_TOOL_INPUT # JSON-Input des Tools (als String)
HTTP-Hooks:
Alle Umgebungsvariablen in allowedEnvVars werden in Header interpoliert.
Exit-Codes
| Code | Bedeutung | Blockierung |
|---|---|---|
| 0 | Erfolg | JSON wird geparst oder Aktion erlaubt |
| 2 | Blockierender Fehler | stderr als Meldung, Aktion blockiert |
| 1, 3, ... | Nicht-blockierend | stderr im verbose-Modus |
Exit-Code 2 Blockierungsverhalten nach Event:
| Event | Ergebnis |
|---|---|
| PreToolUse | Tool-Ausführung blockiert |
| PermissionRequest | Permission verweigert |
| UserPromptSubmit | Prompt-Verarbeitung blockiert |
| Stop, SubagentStop | Stopp verhindert |
| ConfigChange | Konfigurationsänderung blockiert |
| WorktreeCreate | Worktree-Erstellung blockiert |
| Elicitation | Elicitation verweigert |
| PostToolUse, PostToolUseFailure | Nicht-blockierend |
Konfigurationsformat
Hooks werden in settings.json (Projekt oder Benutzer) konfiguriert:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/validate.sh",
"timeout": 30
}
]
}
],
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/setup.sh",
"once": true
}
]
}
]
},
"disableAllHooks": false
}
Konfigurationsquellen (Priorität, von niedrig zu hoch):
~/.claude/settings.json(Benutzer).claude/settings.json(Projekt, shareable).claude/settings.local.json(Projekt, lokal)- Verwaltete Richtlinien (Organisation)
- Plugin
hooks/hooks.json - Skill/Agent-Frontmatter
Höhere Priorität überschreibt niedrigere.
Hooks deaktivieren:
{
"disableAllHooks": true
}
Einzelne Hooks können nicht deaktiviert werden — müssen aus Konfiguration entfernt werden.
JSON Output-Schema
Erfolgreiche Antwort (Exit 0):
{
"continue": true,
"suppressOutput": false,
"systemMessage": "Hook executed",
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow"
}
}
Blockierende Antwort (Exit 2):
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Blocked by policy"
}
}
Allgemeines Schema:
{
"continue": true|false,
"stopReason": "string (wenn continue=false)",
"suppressOutput": false,
"systemMessage": "string (an Benutzer)",
"hookSpecificOutput": {
"hookEventName": "EventName",
"permissionDecision": "allow|deny|ask",
"permissionDecisionReason": "string",
"updatedInput": {},
"updatedMCPToolOutput": {},
"additionalContext": "string"
}
}
HTTP Hook Fehlerbehandlung
| Response | Verhalten |
|---|---|
| 2xx + leerer Body | Erfolg, Aktion erlaubt |
| 2xx + JSON | JSON wird geparst |
| 2xx + Text | Text als Kontext hinzugefügt |
| Non-2xx | Nicht-blockierender Fehler |
| Timeout | Nicht-blockierender Fehler |
Um zu blockieren: 2xx mit {"hookSpecificOutput": {"permissionDecision": "deny"}} zurückgeben.
Timeouts
| Hook-Typ | Standard |
|---|---|
| Command | 600 Sekunden |
| Prompt | 30 Sekunden |
| Agent | 60 Sekunden |
| HTTP | 30 Sekunden |
| SessionEnd | 1,5 Sekunden (hart) |
SessionEnd-Timeout überschreiben:
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
Pfad-Substitution
Platzhalter in command:
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/script.sh"
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/tool.sh"
"command": "${CLAUDE_PLUGIN_DATA}/dependencies/lib"
Mit Leerzeichen immer quoten:
"command": "\"$CLAUDE_PROJECT_DIR/.claude/hooks/my script.sh\""
Asynchrone & Einmalausführung
Asynchrone Hooks (blockieren nicht):
{
"type": "command",
"command": ".claude/hooks/background-task.sh",
"async": true
}
Einmal pro Session:
{
"type": "command",
"command": ".claude/hooks/setup.sh",
"once": true
}
Hook-Verwaltung
Tippe /hooks in Claude Code für Read-Only-Browser:
- Alle Hook-Events mit Zählern
- Quellenort (User, Project, Local, Plugin)
- Vollständige Handler-Details
Praktische Beispiele
Destruktive Befehle blockieren
#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qE '(rm -rf|dd if=)'; then
jq -n '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny"}}'
exit 2
else
exit 0
fi
Umgebungsvariablen beim Start
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo "export NODE_ENV=production" >> "$CLAUDE_ENV_FILE"
exit 0
fi
Linter nach Datei-Änderungen
#!/bin/bash
FILE=$(jq -r '.tool_input.file_path')
if [[ "$FILE" == *.py ]]; then
python -m pylint "$FILE"
fi
Prompt-Validierung
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Edit",
"hooks": [{
"type": "prompt",
"prompt": "Is this change safe? $ARGUMENTS",
"model": "claude-opus"
}]
}
]
}
}
Secrets filtern
#!/bin/bash
jq -r '.tool_output // ""' | \
sed -E 's/password[=:]\s*[^ ]+/password=***REDACTED***/gi'
Force-Push verhindern
#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qE 'git push.*(--force|-f)'; then
jq -n '{hookSpecificOutput: {hookEventName: "PreToolUse", permissionDecision: "deny"}}'
exit 2
fi
MCP-Tools whitelist
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__.*",
"hooks": [{
"type": "prompt",
"prompt": "Allow MCP tool? $ARGUMENTS",
"model": "claude-sonnet"
}]
}
]
}
}
Sicherheitshinweise
- Verwaltete Richtlinien-Hooks können nicht deaktiviert werden.
- Unternehmen können
allowManagedHooksOnlynutzen. - MCP-Elicitation-Hooks können Schemas nicht überschreiben.
policy_settingsConfigChange-Blockierungen werden ignoriert.
Dokumentation: 2026-03-21
