Claude Code-Hooks sind Befehle (oder HTTP-Aufrufe, Prompts und ein paar weitere Handler-Typen), die Claude Code an festen Punkten einer Session automatisch ausführt – etwa bevor ein Tool läuft, wenn eine Berechtigung nötig ist oder wenn Claude mit der Antwort fertig ist. Du definierst sie unter einem hooks-Key in einer Settings-Datei wie ~/.claude/settings.json. Jeder Hook bekommt JSON zum Event über stdin und kann über seinen Exit-Code oder ein JSON-Objekt auf stdout antworten. So kann er loggen, benachrichtigen, eine Aktion blockieren oder in deinem Namen antworten.
01So ist ein Hook aufgebaut
Eine Hook-Konfiguration hat drei Ebenen:
- Das Hook-Event, z. B.
PreToolUseoderStop. - Eine Matcher-Gruppe, die filtert, wann er auslöst, z. B. „nur für das Bash-Tool“.
- Ein oder mehrere Hook-Handler – das, was tatsächlich ausgeführt wird.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
Das führt ein Lint-Skript aus, nachdem Claude eine Datei geschrieben oder bearbeitet hat. Für ein zweites Event fügst du einfach einen weiteren Key im selben hooks-Objekt hinzu.
02Wo Hooks liegen
~/.claude/settings.jsonAlle deine ProjekteNein, nur auf deinem Rechner.claude/settings.jsonEin ProjektJa, kann committet werden.claude/settings.local.jsonEin ProjektNeinhooks/hooks.json eines PluginsSolange das Plugin aktiviert istJaHooks aus verschiedenen Dateien werden zusammengeführt, statt sich gegenseitig zu ersetzen. Gib /hooks in Claude Code ein, um alle aktiven Hooks und ihre Herkunft zu sehen.
In einer interaktiven Session hält Claude Code Hooks – auch deine eigenen – zurück, bis du den Workspace-Trust-Dialog für den Ordner bestätigt hast.
03Handler-Typen
Die meisten Hooks sind "type": "command" und führen einen Shell-Befehl aus. Es gibt vier weitere:
http: schickt das Event-JSON per POST an eine URL und liest den Response-Body.mcp_tool: ruft ein Tool auf einem von dir konfigurierten MCP-Server auf.prompt: stellt einem Claude-Modell eine einzelne Frage und liest eine JSON-Entscheidung aus.agent: startet einen Subagent, der vor der Entscheidung Dateien lesen kann (experimentell).
Command-Hooks laufen mit deinen vollen Benutzerrechten, über sh -c auf macOS und Linux bzw. Git Bash (oder PowerShell) auf Windows. Mit "async": true läuft ein Hook im Hintergrund – dann kann er allerdings keine Entscheidungen mehr treffen.
04Matcher
Der matcher legt fest, bei welchen Vorkommen eines Events der Hook läuft. Womit verglichen wird, hängt vom Event ab: bei Tool-Events der Tool-Name, bei Notification der Benachrichtigungstyp, bei SessionStart die Art, wie die Session gestartet wurde, und so weiter.
"*",""oder gar kein Matcher passt auf alles.- Buchstaben, Ziffern,
_,-, Leerzeichen,|und,werden als exakte Namen behandelt.Edit|Writepasst auf beide Tools. - Alles andere ist ein regulärer JavaScript-Ausdruck, d. h.
mcp__memory__.*passt auf alle Tools eines MCP-Servers.
Matcher unterscheiden Groß- und Kleinschreibung. Manche Events, darunter Stop und UserPromptSubmit, ignorieren Matcher. Bei Tool-Events kannst du einen einzelnen Handler mit einem if-Feld und einer Berechtigungsregel wie "Bash(git *)" weiter einschränken.
05Input: was dein Hook bekommt
Jeder Hook bekommt über stdin JSON mit ein paar gemeinsamen Feldern, darunter session_id, transcript_path, cwd und hook_event_name, plus eventspezifische Felder. Ein PreToolUse-Hook für einen Bash-Aufruf bekommt z. B. zusätzlich tool_name und tool_input.command. Lies es mit jq oder einem beliebigen JSON-Parser aus:
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06Output: Exit-Codes und JSON
Ein Hook kann auf zwei Arten antworten.
Exit-Codes. 0 bedeutet Erfolg. 2 ist ein blockierender Fehler: Bei Events, die blockieren können, wird die Aktion gestoppt und dein stderr wird als Begründung verwendet. Jeder andere Code, auch das übliche 1, ist ein nicht blockierender Fehler – die Aktion läuft also weiter und du siehst einen Hinweis auf einen Hook-Fehler. Wenn ein Hook eine Regel durchsetzen soll, beende ihn mit 2, nicht mit 1.
JSON auf stdout. Für feinere Kontrolle beendest du mit 0 und gibst ein einzelnes JSON-Objekt aus. Manche Felder funktionieren überall, etwa continue: false, um Claude komplett zu stoppen. Andere sind eventspezifisch: Stop nutzt decision: "block" mit einem reason, während PreToolUse und PermissionRequest ihre Entscheidung in hookSpecificOutput angeben. Gib sonst nichts auf stdout aus: Schon eine verirrte Zeile aus deinem Shell-Profil verhindert, dass Claude Code das JSON lesen kann.
07Alle Hook-Events
SessionStartEine Session startet oder wird fortgesetztNein (fügt Kontext hinzu)SetupGestartet mit --init-only oder mit --init / --maintenance zusammen mit -pNeinInstructionsLoadedEine CLAUDE.md- oder .claude/rules/*.md-Datei wird geladenNeinUserPromptSubmitDu schickst einen Prompt ab, bevor Claude ihn siehtJaUserPromptExpansionEin eingegebener Befehl wird zu einem Prompt erweitertJaPreToolUseVor jedem Tool-AufrufJaPermissionRequestEin Tool-Aufruf braucht eine BerechtigungsentscheidungErlaubt oder verweigert per JSONPermissionDeniedDer Auto-Modus verweigert einen Tool-AufrufNeinPostToolUseNach einem erfolgreichen Tool-AufrufNein (Tool ist schon gelaufen)PostToolUseFailureNach einem fehlgeschlagenen Tool-AufrufNeinPostToolBatchNach einem Batch paralleler Tool-Aufrufe, vor dem nächsten ModellaufrufJaNotificationClaude Code sendet eine BenachrichtigungNeinMessageDisplayWährend der Antworttext von Claude angezeigt wirdNein (kann ändern, was angezeigt wird)SubagentStart / SubagentStopEin Subagent startet oder ist fertigNur SubagentStopTaskCreated / TaskCompletedEin Task wird erstellt oder als erledigt markiertJaStopClaude ist mit der Antwort fertigJa (lässt Claude weitermachen)StopFailureDer Turn endet mit einem API-FehlerNeinTeammateIdleEin Teammate im Agent-Team wird gleich inaktivJaConfigChangeEine Settings-Datei ändert sich während einer SessionJaCwdChangedDas Arbeitsverzeichnis ändert sichNeinDirectoryAddedEin Verzeichnis wird mit /add-dir hinzugefügtNeinFileChangedEine überwachte Datei ändert sich auf der FestplatteNeinWorktreeCreate / WorktreeRemoveEin Worktree wird erstellt oder entferntJaPreCompact / PostCompactVor und nach der Kontext-KomprimierungNur PreCompactPreModelSwitch / PostModelSwitchVor und nach dem ModellwechselNur PreModelSwitchElicitation / ElicitationResultEin MCP-Server fragt nach einer Eingabe, und nachdem du geantwortet hastJaSessionEndEine Session endetNeinAnthropic fügt hin und wieder neue Events hinzu. Die aktuelle Liste und die Eingabefelder der einzelnen Events findest du in der Hooks-Referenz.
08Welche Events für Benachrichtigungen wichtig sind
Vier Events decken fast alles ab, worüber man informiert werden will:
Stopfür „Claude ist fertig“. Siehe den Guide zum Stop hook.Notificationfür „Claude wartet auf dich“, mit Typen wiepermission_promptundidle_prompt. Siehe den Guide zum Notification hook.PermissionRequest, um sofort informiert zu werden oder zu antworten, sobald eine Berechtigung nötig ist. Siehe den Guide zu PermissionRequest.PreToolUseauf dem ToolAskUserQuestion, um die Multiple-Choice-Fragen von Claude zu sehen oder zu beantworten. Siehe Fragen vom Handy aus beantworten.
Für ein Desktop-Setup zum direkten Einfügen fängst du am besten mit So bekommst du eine Benachrichtigung, wenn Claude Code fertig ist an.
09Wo Claude Code Notifier ins Spiel kommt
Claude Code Notifier baut komplett auf diesen Hooks auf. Das kostenlose Kommandozeilentool ccn läuft auf Mac, Windows und Linux. Bei der Installation fügt es sieben Hook-Einträge in ~/.claude/settings.json ein, die jeweils ccn hook ausführen, und legt einmalig ein Backup der Datei an. ccn läuft pro Event nur ein paar Millisekunden und beendet sich dann – es bleibt also nichts im Hintergrund aktiv.
Allein zeigt es Desktop-Benachrichtigungen an. Mit gekoppelter iPhone- oder Android-App bringen dieselben Hooks deine Antworten zurück: Berechtigungen erlauben oder ablehnen, Fragen beantworten oder die nächste Anweisung schicken, nachdem Claude aufgehört hat. Das Tool ist unabhängig und nicht von Anthropic. Wenn du nur ein Log oder einen Lint-Schritt brauchst, sind ein paar eigene Zeilen einfacher. Details findest du auf der ccn-Seite.
10FAQ
Wie teste ich einen Hook, ohne auf Claude zu warten?
Pipe Beispiel-JSON in das Skript und prüf den Exit-Code: echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Führ dann /hooks in Claude Code aus, um zu prüfen, ob er beim richtigen Event registriert ist.
Warum läuft mein Hook nicht?
Die üblichen Ursachen sind ungültiges JSON in settings.json (abschließende Kommas, Kommentare), ein Matcher, der nicht exakt passt (Groß-/Kleinschreibung zählt), ein Skript ohne Ausführungsrechte oder ein Ordner, dem du noch nicht vertraut hast. Starte Claude Code mit claude --debug und schau im Debug-Log nach, was gelaufen ist. Die vollständige Liste steht in der Troubleshooting-Checkliste.
Wie schalte ich alle Hooks vorübergehend ab?
Setz "disableAllHooks": true in einer Settings-Datei. Um sie nur für einen Lauf zu überspringen, starte Claude Code mit --settings '{"disableAllHooks": true}'. Einen Schalter für einzelne Hooks gibt es nicht; da entfernst du stattdessen den Eintrag. Hooks, die deine Organisation in den Managed Settings festgelegt hat, lassen sich auf keinem der beiden Wege abschalten.
Was ist der Standard-Timeout für Hooks?
Zehn Minuten (600 Sekunden) für Command-, HTTP- und MCP-Tool-Hooks, 30 Sekunden für Prompt-Hooks und 60 für Agent-Hooks. Einige Events haben kürzere Standardwerte, und du kannst bei jedem Handler timeout in Sekunden setzen.