Zum Hauptinhalt springen
Hooks sind Callback-Funktionen, die Ihren Code als Reaktion auf Agent-Ereignisse ausführen, z. B. wenn ein Tool aufgerufen wird, eine Sitzung startet oder die Ausführung stoppt. Mit Hooks können Sie:
  • Gefährliche Operationen blockieren, bevor sie ausgeführt werden, z. B. destruktive Shell-Befehle oder nicht autorisierter Dateizugriff
  • Alle Tool-Aufrufe protokollieren und überprüfen für Compliance, Debugging oder Analytik
  • Eingaben und Ausgaben transformieren, um Daten zu bereinigen, Anmeldedaten einzufügen oder Dateipfade umzuleiten
  • Menschliche Genehmigung anfordern für sensible Aktionen wie Datenbankschreibvorgänge oder API-Aufrufe
  • Sitzungslebenszyklus verfolgen, um den Status zu verwalten, Ressourcen freizugeben oder Benachrichtigungen zu senden
Dieser Leitfaden behandelt die Funktionsweise von Hooks, deren Konfiguration und bietet Beispiele für häufige Muster wie das Blockieren von Tools, das Ändern von Eingaben und das Weiterleiten von Benachrichtigungen.

Funktionsweise von Hooks

1

Ein Ereignis wird ausgelöst

Während der Agent-Ausführung passiert etwas und das SDK löst ein Ereignis aus: Ein Tool wird aufgerufen (PreToolUse), ein Tool gibt ein Ergebnis zurück (PostToolUse), ein Subagent startet oder stoppt, der Agent ist untätig oder die Ausführung ist beendet. Siehe die vollständige Liste der Ereignisse.
2

Das SDK sammelt registrierte Hooks

Das SDK prüft auf Hooks, die für diesen Ereignistyp registriert sind. Dies umfasst Callback-Hooks, die Sie in options.hooks übergeben, und Shell-Befehls-Hooks aus Einstellungsdateien, wenn der entsprechende settingSources oder setting_sources Eintrag aktiviert ist, was für Standard-query()-Optionen der Fall ist.
3

Matcher filtern, welche Hooks ausgeführt werden

Wenn ein Hook ein matcher Muster hat (z. B. "Write|Edit"), testet das SDK es gegen das Ziel des Ereignisses (z. B. den Tool-Namen). Hooks ohne Matcher werden für jedes Ereignis dieses Typs ausgeführt.
4

Callback-Funktionen werden ausgeführt

Jede übereinstimmende Hook-Callback-Funktion erhält Eingaben über das, was passiert: den Tool-Namen, seine Argumente, die Sitzungs-ID und andere ereignisspezifische Details.
5

Ihr Callback gibt eine Entscheidung zurück

Nach dem Ausführen von Operationen (Protokollierung, API-Aufrufe, Validierung) gibt Ihr Callback ein Ausgabeobjekt zurück, das dem Agent mitteilt, was zu tun ist: die Operation zulassen, blockieren, die Eingabe ändern oder Kontext in das Gespräch einfügen.
Das folgende Beispiel bringt diese Schritte zusammen. Es registriert einen PreToolUse Hook (Schritt 1) mit einem "Write|Edit" Matcher (Schritt 3), sodass der Callback nur für Datei-Schreib-Tools ausgelöst wird. Wenn ausgelöst, erhält der Callback die Eingabe des Tools (Schritt 4), prüft, ob der Dateipfad auf eine .env-Datei abzielt, und gibt permissionDecision: "deny" zurück, um die Operation zu blockieren (Schritt 5):

Verfügbare Hooks

Das SDK bietet Hooks für verschiedene Phasen der Agent-Ausführung. Einige Hooks sind in beiden SDKs verfügbar, während andere nur für TypeScript verfügbar sind.

Hooks konfigurieren

Um einen Hook zu konfigurieren, übergeben Sie ihn im hooks Feld Ihrer Agent-Optionen (ClaudeAgentOptions in Python, das options Objekt in TypeScript):
Die hooks Option ist ein Wörterbuch in Python oder ein Objekt in TypeScript, wobei:

Matcher

Verwenden Sie Matcher, um zu filtern, wann Ihre Callbacks ausgelöst werden. Das matcher Feld wird gegen einen anderen Wert abgeglichen, je nach Hook-Ereignistyp. Beispielsweise werden Tool-basierte Hooks gegen den Tool-Namen abgeglichen, während Notification Hooks gegen den Benachrichtigungstyp abgeglichen werden. Siehe die Claude Code Hooks-Referenz für die vollständige Liste der Matcher-Werte für jeden Ereignistyp. SDK-Matcher folgen den gleichen Regeln wie Matcher in Einstellungsdateien. Ein Matcher, der nur Buchstaben, Ziffern, _, -, Leerzeichen, , und | enthält, wird als exakte Zeichenkette verglichen, wobei Alternativen durch | oder , und optionales umgebendes Leerzeichen getrennt werden, also Write|Edit und Write, Edit passen jeweils genau auf diese beiden Tools und code-reviewer passt nur auf diesen Agent-Typ. Ein Matcher von *, eine leere Zeichenkette oder das Weglassen des Matchers ganz passt auf jedes Vorkommen des Ereignisses. Ein Matcher, der ein anderes Zeichen enthält, wird als unverankerte reguläre Ausdrücke ausgewertet, also ^mcp__ passt auf jedes MCP-Tool und Edit.* passt sowohl auf Edit als auch auf NotebookEdit. Umgeben Sie einen regulären Ausdruck mit ^ und $, wenn Sie eine Ganz-String-Übereinstimmung benötigen. Ein Matcher wie mcp__memory oder mcp__brave-search enthält nur Zeichen für exakte Übereinstimmung, wird also als exakte Zeichenkette verglichen und passt auf kein Tool; verwenden Sie mcp__memory__.*, um auf jedes Tool von diesem Server zu passen. Bindestriche in der Menge für exakte Übereinstimmung erfordern eine Claude Code Runtime von v2.1.195 oder später. In früheren Versionen wird ein Name mit Bindestrich wie code-reviewer als unverankerte reguläre Ausdrücke ausgewertet und muss als ^code-reviewer$ verankert werden, um genau zu passen. Verwenden Sie das matcher Muster, um nach Möglichkeit spezifische Tools anzusteuern. Ein Matcher mit 'Bash' wird nur für Bash-Befehle ausgeführt, während das Weglassen des Musters Ihre Callbacks für jedes Vorkommen des Ereignisses ausführt. Für Tool-basierte Hooks filtern Matcher nur nach Tool-Namen, nicht nach Dateipfaden oder anderen Argumenten. Um nach Dateipfad zu filtern, prüfen Sie tool_input.file_path in Ihrem Callback.
Tool-Namen entdecken: Siehe Tool-Eingabetypen für die vollständige Liste der integrierten Tool-Namen, oder fügen Sie einen Hook ohne Matcher hinzu, um alle Tool-Aufrufe Ihrer Sitzung zu protokollieren.MCP-Tool-Benennung: MCP-Tools beginnen immer mit mcp__ gefolgt vom Servernamen und der Aktion: mcp__<server>__<action>. Wenn Sie beispielsweise einen Server namens playwright konfigurieren, werden seine Tools mcp__playwright__browser_screenshot, mcp__playwright__browser_click usw. benannt. Der Servername kommt aus dem Schlüssel, den Sie in der mcpServers Konfiguration verwenden.

Callback-Funktionen

Eingaben

Jeder Hook-Callback erhält drei Argumente:
  • Eingabedaten: ein typisiertes Objekt mit Ereignisdetails. Jeder Hook-Typ hat seine eigene Eingabeform. Beispielsweise enthält PreToolUseHookInput tool_name und tool_input, während NotificationHookInput message enthält. Siehe die vollständigen Typdefinitionen in den TypeScript und Python SDK-Referenzen.
    • Alle Hook-Eingaben teilen session_id, cwd und hook_event_name.
    • agent_id und agent_type werden ausgefüllt, wenn der Hook in einem Subagent ausgelöst wird. In TypeScript befinden sich diese in der Basis-Hook-Eingabe und sind für alle Hook-Typen verfügbar. In Python sind sie optionale Felder auf PreToolUse, PostToolUse, PostToolUseFailure und PermissionRequest, und erforderliche Felder auf SubagentStart und SubagentStop.
  • Tool-Verwendungs-ID (str | None / string | undefined): korreliert PreToolUse und PostToolUse Ereignisse für denselben Tool-Aufruf.
  • Kontext: In TypeScript enthält eine signal Eigenschaft (AbortSignal) für Abbruch. In Python ist dieses Argument für zukünftige Verwendung reserviert.

Ausgaben

Ihr Callback gibt ein Objekt mit zwei Kategorien von Feldern zurück:
  • Top-Level-Felder funktionieren bei jedem Ereignis gleich: systemMessage zeigt eine Nachricht für den Benutzer an, und continue (continue_ in Python) bestimmt, ob der Agent nach diesem Hook weiterläuft.
  • hookSpecificOutput steuert die aktuelle Operation. Die Felder darin hängen vom Hook-Ereignistyp ab. Für PreToolUse Hooks ist dies der Ort, an dem Sie permissionDecision ("allow", "deny", "ask" oder "defer"), permissionDecisionReason und updatedInput setzen. Wenn Sie "defer" zurückgeben, endet die Abfrage, damit Sie sie später fortsetzen können. Für PostToolUse Hooks können Sie additionalContext setzen, um Informationen zum Tool-Ergebnis anzuhängen. Um die Ausgabe des Tools vor Claude zu ersetzen, setzen Sie updatedToolOutput, das für jedes Tool in beiden SDKs funktioniert. Das ältere updatedMCPToolOutput Feld ersetzt nur MCP-Tool-Ausgabe und ist veraltet.
Geben Sie {} zurück, um die Operation ohne Änderungen zuzulassen. SDK-Callback-Hooks verwenden das gleiche JSON-Ausgabeformat wie Claude Code Shell-Befehls-Hooks, das jedes Feld und ereignisspezifische Option dokumentiert. Für die SDK-Typdefinitionen siehe die TypeScript und Python SDK-Referenzen.
Wenn mehrere Hooks oder Berechtigungsregeln gelten, hat deny Vorrang vor defer, was Vorrang vor ask hat, was Vorrang vor allow hat. Wenn ein Hook deny zurückgibt, wird die Operation blockiert, unabhängig von anderen Hooks.

Asynchrone Ausgabe

Standardmäßig wartet der Agent darauf, dass Ihr Hook zurückkommt, bevor er fortfährt. Wenn Ihr Hook einen Nebeneffekt ausführt, wie Protokollierung oder Webhook-Versand, und das Verhalten des Agenten nicht beeinflussen muss, können Sie stattdessen eine asynchrone Ausgabe zurückgeben. Dies teilt dem Agent mit, dass er sofort fortfahren soll, ohne auf die Fertigstellung des Hooks zu warten:
Asynchrone Ausgaben können nicht blockieren, ändern oder Kontext in die Operation einfügen, da der Agent bereits weitergegangen ist. Verwenden Sie sie nur für Nebeneffekte wie Protokollierung, Metriken oder Benachrichtigungen.

Beispiele

Tool-Eingabe ändern

Dieses Beispiel fängt Write-Tool-Aufrufe ab und schreibt das file_path Argument um, um /sandbox voranzustellen, wodurch alle Datei-Schreibvorgänge in ein Sandbox-Verzeichnis umgeleitet werden. Der Callback gibt updatedInput mit dem geänderten Pfad und permissionDecision: 'allow' zurück, um die umgeschriebene Operation automatisch zu genehmigen:
Wenn Sie updatedInput verwenden, müssen Sie auch permissionDecision: 'allow' einschließen, um die geänderte Eingabe automatisch zu genehmigen, oder permissionDecision: 'ask', um sie dem Benutzer anzuzeigen. Mit 'defer' wird updatedInput ignoriert. Geben Sie immer ein neues Objekt zurück, anstatt das ursprüngliche tool_input zu mutieren.

Kontext hinzufügen und ein Tool blockieren

Dieses Beispiel blockiert Schreibvorgänge in das /etc Verzeichnis und erklärt den Grund sowohl dem Modell als auch dem Benutzer:
  • permissionDecision: 'deny' stoppt den Tool-Aufruf.
  • permissionDecisionReason teilt dem Modell mit, warum, damit es nicht erneut versucht.
  • systemMessage zeigt dem Benutzer, was passiert ist.

Spezifische Tools automatisch genehmigen

Standardmäßig kann der Agent vor der Verwendung bestimmter Tools um Genehmigung bitten. Dieses Beispiel genehmigt schreibgeschützte Dateisystem-Tools (Read, Glob, Grep) automatisch, indem permissionDecision: 'allow' zurückgegeben wird, sodass sie ohne Benutzerbestätigung ausgeführt werden, während alle anderen Tools normalen Berechtigungsprüfungen unterliegen:

Mehrere Hooks registrieren

Wenn ein Ereignis ausgelöst wird, werden alle übereinstimmenden Hooks parallel ausgeführt. Bei Berechtigungsentscheidungen gewinnt das restriktivste Ergebnis: Ein einzelnes deny blockiert den Tool-Aufruf, unabhängig davon, was die anderen Hooks zurückgeben. Da die Abschlussreihenfolge nicht deterministisch ist, schreiben Sie jeden Hook so, dass er unabhängig agiert, anstatt sich darauf zu verlassen, dass ein anderer Hook zuerst ausgeführt wurde. Das folgende Beispiel registriert drei unabhängige Prüfungen für jeden Tool-Aufruf:

Mit Multi-Tool-Matchern filtern

Verwenden Sie Multi-Tool-Matcher, um einen Callback über verwandte Tools hinweg zu teilen. Dieses Beispiel registriert drei Matcher mit unterschiedlichen Bereichen:
  • Eine durch Pipe getrennte exakte Liste (Write|Edit|Delete) löst file_security_hook nur für Datei-Änderungs-Tools aus.
  • Ein Regex (^mcp__) löst mcp_audit_hook für alle MCP-Tools aus, deren Namen mit mcp__ beginnen.
  • Ein weggelassener Matcher löst global_logger für jeden Tool-Aufruf unabhängig vom Namen aus.

Subagent-Aktivität verfolgen

Verwenden Sie SubagentStop Hooks, um zu überwachen, wenn Subagents ihre Arbeit beenden. Siehe den vollständigen Eingabetyp in den TypeScript und Python SDK-Referenzen. Dieses Beispiel protokolliert eine Zusammenfassung jedes Mal, wenn ein Subagent abgeschlossen wird:

HTTP-Anfragen von Hooks aus stellen

Hooks können asynchrone Operationen wie HTTP-Anfragen ausführen. Fangen Sie Fehler in Ihrem Hook ab, anstatt sie zu propagieren, da eine nicht behandelte Ausnahme den Agent unterbrechen kann. Dieses Beispiel sendet einen Webhook nach jeder Tool-Fertigstellung und protokolliert, welches Tool ausgeführt wurde und wann. Der Hook fängt Fehler ab, sodass ein fehlgeschlagener Webhook den Agent nicht unterbricht:

Benachrichtigungen an Slack weiterleiten

Verwenden Sie Notification Hooks, um Systembenachrichtigungen vom Agent zu empfangen und sie an externe Dienste weiterzuleiten. Benachrichtigungen werden für Ereignistypen wie folgt ausgelöst:
  • permission_prompt wenn Claude Genehmigung benötigt
  • idle_prompt wenn Claude auf Eingabe wartet
  • auth_success wenn Authentifizierung abgeschlossen ist
  • elicitation_dialog, elicitation_complete und elicitation_response für Benutzer-Abfrage-Flows
Jede Benachrichtigung enthält ein message Feld mit einer für Menschen lesbaren Beschreibung und optional einen title. Dieses Beispiel leitet jede Benachrichtigung an einen Slack-Kanal weiter. Es erfordert eine Slack Incoming Webhook URL, die Sie erstellen, indem Sie eine App zu Ihrem Slack-Workspace hinzufügen und Incoming Webhooks aktivieren:

Häufige Probleme beheben

Hook wird nicht ausgelöst

  • Überprüfen Sie, ob der Hook-Ereignisname korrekt und case-sensitiv ist (PreToolUse, nicht preToolUse)
  • Überprüfen Sie, ob Ihr Matcher-Muster den Tool-Namen genau abgleicht
  • Stellen Sie sicher, dass der Hook unter dem richtigen Ereignistyp in options.hooks ist
  • Für Nicht-Tool-Hooks, die Matcher unterstützen, wie Notification und SubagentStop, gleichen Matcher gegen verschiedene Felder ab, und Stop ignoriert Matcher vollständig (siehe Matcher-Muster)
  • Hooks werden möglicherweise nicht ausgelöst, wenn der Agent das max_turns Limit erreicht, da die Sitzung endet, bevor Hooks ausgeführt werden können

Matcher filtert nicht wie erwartet

Matcher gleichen nur Tool-Namen ab, nicht Dateipfade oder andere Argumente. Um nach Dateipfad zu filtern, prüfen Sie tool_input.file_path in Ihrem Hook:

Hook-Timeout

  • Erhöhen Sie den timeout Wert in der HookMatcher Konfiguration
  • Verwenden Sie das AbortSignal aus dem dritten Callback-Argument, um Abbruch elegant in TypeScript zu behandeln
Ein UserPromptSubmit oder UserPromptExpansion Callback, das sein Timeout überschreitet, blockiert diese Aufforderung mit einer Timeout-Nachricht und die Sitzung wird fortgesetzt. Das Unterbrechen der Abfrage während ein Callback ausstehend ist, bricht den ausstehenden Tool-Aufruf ab. Vor v2.1.208 endete ein Callback-Timeout bei diesen Ereignissen die Abfrage mit error_during_execution, und ein Unterbrechen während eines ausstehenden PreToolUse Callbacks konnte den Tool-Aufruf fortfahren lassen.

Tool wird unerwartet blockiert

  • Überprüfen Sie alle PreToolUse Hooks auf permissionDecision: 'deny' Rückgaben
  • Fügen Sie Protokollierung zu Ihren Hooks hinzu, um zu sehen, welche permissionDecisionReason sie zurückgeben
  • Überprüfen Sie, ob Matcher-Muster nicht zu breit sind: ein leerer Matcher gleicht alle Tools ab

Geänderte Eingabe wird nicht angewendet

  • Stellen Sie sicher, dass updatedInput in hookSpecificOutput ist, nicht auf der obersten Ebene:
  • Geben Sie permissionDecision: 'allow' zurück, um die geänderte Eingabe automatisch zu genehmigen, oder 'ask', um sie dem Benutzer zur Genehmigung anzuzeigen
  • Schließen Sie hookEventName in hookSpecificOutput ein, um zu identifizieren, für welchen Hook-Typ die Ausgabe bestimmt ist

Sitzungs-Hooks nicht in Python verfügbar

SessionStart und SessionEnd können als SDK-Callback-Hooks in TypeScript registriert werden, sind aber im Python SDK nicht verfügbar, da sein HookEvent Typ sie auslässt. In Python sind sie nur als Shell-Befehls-Hooks verfügbar, die in Einstellungsdateien wie .claude/settings.json definiert sind. Um Shell-Befehls-Hooks aus Ihrer SDK-Anwendung zu laden, schließen Sie die entsprechende Einstellungsquelle mit setting_sources oder settingSources ein:
Um stattdessen Initialisierungslogik als Python SDK-Callback auszuführen, verwenden Sie die erste Nachricht von client.receive_response() als Auslöser.

Subagent-Berechtigungsaufforderungen vervielfachen sich

Beim Spawnen mehrerer Subagents kann jeder einzelne Berechtigungen separat anfordern. Subagents erben nicht automatisch Berechtigungen des übergeordneten Agenten. Um wiederholte Aufforderungen zu vermeiden, verwenden Sie PreToolUse Hooks, um spezifische Tools automatisch zu genehmigen, oder konfigurieren Sie Berechtigungsregeln, die für Subagent-Sitzungen gelten.

Rekursive Hook-Schleifen mit Subagents

Ein UserPromptSubmit Hook, der Subagents spawnt, kann unendliche Schleifen erzeugen, wenn diese Subagents denselben Hook auslösen. Um dies zu verhindern:
  • Überprüfen Sie auf einen Subagent-Indikator in der Hook-Eingabe, bevor Sie spawnen
  • Verwenden Sie eine gemeinsame Variable oder Sitzungsstatus, um zu verfolgen, ob Sie bereits in einem Subagent sind
  • Beschränken Sie Hooks so, dass sie nur für die Top-Level-Agent-Sitzung ausgeführt werden

systemMessage wird nicht in der Ausgabe angezeigt

Das systemMessage Feld zeigt eine Nachricht für den Benutzer an, nicht für das Modell. Standardmäßig gibt das SDK Hook-Ausgaben im Nachrichtenstrom nur für SessionStart und Setup Hooks aus, daher wird eine Nachricht von einem anderen Hook-Ereignis nicht angezeigt, es sei denn, Sie setzen includeHookEvents (include_hook_events in Python). Um stattdessen Kontext an das Modell zu übergeben, geben Sie additionalContext zurück. Wenn Sie Hook-Entscheidungen für Ihre Anwendung zuverlässig sichtbar machen müssen, protokollieren Sie sie separat oder verwenden Sie einen dedizierten Ausgabekanal.