on(eventName, handler).
Erstellen Sie Ihren ersten Mod, bevor Sie hier beginnen. Alle Events und ihre genauen Felder finden Sie in der Referenz, oder lesen Sie die Typen für Ihren Build.
Wie ein Hook ein Ereignis verarbeitet
Ein Hook sitzt zwischen einem Ereignis und dem, was Claude Code daraufhin tun würde. Er kann das Ereignis daher beobachten, umschreiben oder selbst beantworten. Er erhält drei Argumente: die Mods-API als$, das Ereignis als e und den nächsten Handler als next. Die Handler für ein Ereignis bilden eine Middleware-Kette. next(e) ruft den nächsten Handler auf, also den Hook eines anderen Mods oder, am Ende der Kette, das eigene Verhalten von Claude Code, und wird zum Ergebnis aufgelöst. Was Ihr Hook mit next macht, bestimmt, welche der drei Möglichkeiten er umsetzt.
Ein Ereignis beobachten
Um ein Ereignis zu beobachten, ohne es zu ändern, erledigen Sie Ihre Arbeit und gebennext(e) zurück. Dieser Hook protokolliert jedes Tool, das Claude gleich verwenden wird:
● my-mod: Claude is about to use Bash, wobei my-mod der Name Ihres Plugins ist. Das Tool wird so ausgeführt, wie es auch ohne den Mod ausgeführt würde.
Um nach dem Ereignis zu handeln, verwenden Sie await next(e), erledigen Ihre Arbeit und geben das Ergebnis zurück. Dieser Hook protokolliert jedes Tool, nachdem es ausgeführt wurde:
next(e) aufgelöst wurde.
Ein Ereignis umschreiben
Um zu ändern, worauf Claude Code reagiert, etwa den Text eines Prompts, rufen Sienext mit einer geänderten Kopie des Ereignisses auf. Das Ereignis selbst ist unveränderlich: Es ist tief eingefroren, und eine Zuweisung an ein Feld löst einen Fehler aus. Dieser Hook entfernt bei jedem Prompt vor dem Senden führende und nachfolgende Leerzeichen:
await next(e) und geben Sie dann eine Kopie des Ergebnisses zurück, in der ein Feld ersetzt ist.
Ein Ereignis beantworten
Um ein Ereignis selbst zu verarbeiten, geben Sie ein Ergebnis zurück, ohnenext aufzurufen. Dadurch wird die Kette abgekürzt, sodass nachfolgende Mods und das eigene Verhalten von Claude Code nicht ausgeführt werden. Dieser Hook lehnt jeden Bash-Befehl ab:
deny-Text als Ergebnis des Tools. Jedes Ereignis hat eine eigene Ergebnisstruktur, die in der Ereignisreferenz aufgeführt ist.
Filtern, welche Ereignisse ein Hook verarbeitet
Um einen Hook nur für bestimmte Ereignisse auszuführen, übergeben Sie einen Filter als zweites Argument anon. Claude Code nennt den Filter einen Matcher. Es handelt sich um ein Objekt, dessen Felder mit denen des Ereignisses verglichen werden, und der Hook wird nur ausgeführt, wenn jedes Feld übereinstimmt. Ein Feld kann ein Wert, ein Array zulässiger Werte oder ein regulärer Ausdruck sein.
Jede Zeile in diesem Beispiel registriert dieselbe Funktion, hook, für eine engere Auswahl von Tool-Aufrufen:
hook wird einmal für einen Bash-, Edit- oder Write-Aufruf ausgeführt und einmal für einen Aufruf eines Tools, dessen Name mit mcp__github__ beginnt. Ein Aufruf eines anderen Tools, etwa Read, stimmt mit keinem der drei überein, sodass hook dafür nicht ausgeführt wird.
Der Ereignisname kann ein Platzhalter sein. 'classic.*' passt auf jedes Einstellungs-Hook-Ereignis. '*' passt auf jedes Ereignis außer den Telemetrie-Ereignissen, die ihren eigenen Namen und einen { to: 'collector' }-Filter verwenden.
Registrieren Sie jedes Ereignis nur einmal pro Matcher. Wenn Sie on zweimal für session.start ohne Matcher aufrufen, kann das Modul nicht geladen werden und meldet on("session.start") is registered twice without a matcher. Fassen Sie alles, was Ihr Mod beim Sitzungsstart tut, in einem Hook zusammen.
Auf das reagieren, was Claude tut
Behandeln Sie diese Events, um einen Tool-Aufruf, einen Prompt oder einen Turn zu sehen oder zu ändern, während er stattfindet. Alle Events und was ein Hook jeweils zurückgeben kann, finden Sie in der Event-Referenz.Einen Tool-Aufruf absichern oder ändern
Eintool.call-Hook sieht jedes Tool, das Claude gleich verwenden wird, und kann den Aufruf daher ablehnen, seine Argumente ändern oder ihn durchlassen. tool.call wird ausgelöst, wenn Claude Code gleich ein Tool ausführt, einschließlich Aufrufen eines Subagenten und Aufrufen von MCP-Tools. e.tool ist der Name des Tools, und die Argumente des Tools sind Felder von e, etwa e.command für Bash. Wenn Sie next(e) aufrufen, führt Claude Code die Berechtigungsprüfung und anschließend das Tool aus.
Dieser Hook lehnt einen Bash-Befehl ab, der einen Force-Push ausführt, und teilt Claude den Grund mit:
git push --force versucht, wird der Befehl nicht ausgeführt und es erscheint keine Berechtigungsabfrage, weil der Hook next nie aufruft. Claude liest den deny-Text als Ergebnis des Tools, formulieren Sie ihn also als Anweisung, nach der Claude handeln kann. Jeder andere Bash-Befehl wird so ausgeführt, wie er es ohne den Mod würde.
Um nach der Ausführung eines Tools zu handeln, verwenden Sie await next(e), erledigen Ihre Arbeit und geben zurück, was next Ihnen geliefert hat. Dieser Hook protokolliert jede .mdx-Datei, die Claude ändert, mit $.ui.log, das dem Transkript eine abgeblendete Zeile hinzufügt, die Claude nicht liest:
.mdx-Datei bearbeitet oder geschrieben hat, nennt eine abgeblendete Zeile im Transkript die Datei. Für andere Dateitypen oder für einen abgelehnten oder fehlgeschlagenen Aufruf wird nichts protokolliert. Claudes Sicht auf den Aufruf ändert sich nicht, weil der Hook das erhaltene Ergebnis zurückgibt.
Ihr Hook kann einen Aufruf auch ändern, erneut versuchen, selbst beantworten oder sein Ergebnis zurückhalten:
- Den Aufruf ändern: Übergeben Sie geänderte Argumente an
next. - Den Aufruf erneut versuchen: Rufen Sie
next(e)noch einmal auf. Ein Hook, der beim ersten ErgebnisisErrorsieht, kann das Tool ein zweites Mal ausführen und dieses Ergebnis zurückgeben. - Den Aufruf selbst beantworten: Geben Sie ein Objekt mit einem
result-Feld zurück, ohnenextaufzurufen, und geben Sieresultbei einem integrierten Tool die Form, die das eigene Ergebnis dieses Tools in den Typen für Ihren Build hat. Es erscheint keine Berechtigungsabfrage und das Tool wird nicht ausgeführt, sodass das von Ihnen zurückgegebene Ergebnis alles ist, was Claude über den Vorgang erfährt. - Das Ergebnis vor Claude zurückhalten: Geben Sie nach
await next(e)den Wert{ deny: reason }zurück. Claude liest Ihren Grund anstelle dessen, wasnextzurückgegeben hat. Wenn das Tool ausgeführt wurde, hält das deny sein Ergebnis vor Claude zurück und macht nichts von dem rückgängig, was das Tool getan hat. Wenn das Tool ausgeführt wurde und erfolgreich war, folgt der Grund auf einen Hinweis wieBash ran, and a plugin withheld its result:.
tool.call-Hook jedes Mods ausgeführt, und eine Blockierung durch einen davon ist endgültig.
Einen Tool-Aufruf zurückhalten, bis der Benutzer entscheidet
Ein Hook kann einen Tool-Aufruf anhalten und den Benutzer fragen, was geschehen soll, bevor er fortgesetzt wird. Eintool.call-Hook kann await verwenden, bevor er next aufruft oder zurückkehrt, und der Tool-Aufruf bleibt bis dahin ausstehend. Um dem Benutzer die Frage zu stellen, rufen Sie $.ui.ask auf. Es zeigt Ihre Frage über einer nummerierten Liste Ihrer Optionen in dem Dialog an, den Claude verwendet, um Sie etwas zu fragen, und wird mit der Bezeichnung aufgelöst, die der Benutzer auswählt. Nach Ihren Optionen fügt der Dialog eine Zeile zum Eingeben einer anderen Antwort und eine Zeile Chat about this hinzu.
Das Muster RISKY in diesem Beispiel erfasst rm -r, rm -rf, git reset --hard und git push mit --force und übersieht andere Schreibweisen wie git push -f. Dieses Modul fragt nach, bevor es einen Bash-Befehl ausführt, der dem Muster entspricht:
rm -rf build versucht, erscheint die Frage mit dem Befehl darin, und der Befehl wartet auf die Antwort:
- Der Benutzer wählt Run it: Der Hook ruft
next(e)auf, und die übliche Berechtigungsprüfung wird danach trotzdem ausgeführt - Der Benutzer wählt Refuse: Der Befehl wird nicht ausgeführt, und Claude liest den
deny-Text - Der Benutzer gibt eine Antwort ein:
$.ui.askwird mit dem eingegebenen Text aufgelöst. Der Hook vergleicht ihn mitRun it, sodass jeder andere Text den Befehl ablehnt. - Niemand antwortet:
$.ui.askwird abgelehnt, wenn der Benutzer die Frage schließt oder Chat about this wählt, sowie in einerclaude -p-Ausführung, sodass dercatch-Block die Antwort aufRefusebelässt
$.ui.ask stattfinden, weil diese Zeit nicht auf das Zeitlimit des Hooks angerechnet wird. Zeit, die Sie mit dem Warten auf ein eigenes Promise verbringen, wird hingegen angerechnet. Claude Code überspringt einen Hook, der das Zeitlimit überschreitet, sodass der zurückgehaltene Befehl ausgeführt würde.
Einen Tool-Aufruf genehmigen oder ablehnen, bevor der Benutzer gefragt wird
Um zu entscheiden, ob ein Tool-Aufruf ausgeführt werden darf, behandeln Sietool.check, das Event, in dem Claude Code diese Entscheidung trifft. Es wird ausgelöst, nachdem die Berechtigungsregeln und die Einstellungs-Hooks entschieden haben, und next(e) wird mit deren Entscheidung aufgelöst: allow, ask oder deny. Ihr Hook gibt diese Entscheidung oder eine andere zurück. e.input enthält die Argumente des Tools, etwa command für Bash.
Für einen festen Befehl oder Pfad verwenden Sie eine Berechtigungsregel wie Bash(npm test), die keinen Code erfordert. Behandeln Sie tool.check, wenn die Entscheidung davon abhängt, was in diesem Moment zutrifft, etwa vom aktuellen Git-Branch oder von einem Wert, den ein anderer Hook festgehalten hat.
Dieser Hook lehnt git push ab, solange der aktuelle Branch main ist:
main gibt der Hook deny zurück, selbst wenn eine Regel git push erlaubt. Auf einem anderen Branch und bei anderen Befehlen erhält der Aufruf die Entscheidung, die er ohne den Mod erhalten würde.
Der Hook prüft den Text des Befehls, betrachten Sie ihn also als Erinnerung für Claude. Um Pushes auf main für alle zu blockieren, schützen Sie den Branch bei Ihrem Git-Host.
Ein Hook kann allow, ask oder deny zurückgeben und daher auch einen Aufruf genehmigen, den ein PreToolUse-Hook außerhalb der verwalteten Einstellungen blockiert hat. Unter Berechtigungen mit Hooks erweitern ist aufgeführt, welche Entscheidungen gegenüber einem Mod Bestand haben.
Einen Prompt umschreiben oder ergänzen
Einprompt.submit-Hook sieht jeden Prompt, bevor der Turn beginnt, und kann den Text daher umschreiben oder ergänzen. e.text ist das, was eingegeben wurde.
Dieser Hook fügt für Claude den Namen des aktuellen Branches hinzu, sobald ein Prompt einen Pull Request erwähnt:
open a PR for this change senden, sieht Ihre Nachricht im Transkript unverändert aus, und Claude liest danach zusätzlich eine Zeile wie Current branch: feature/auth. Ein Prompt, der keinen Pull Request erwähnt, wird unverändert weitergeleitet, und git wird nicht ausgeführt.
Um einen Prompt zu stoppen, geben Sie { drop: 'the reason' } zurück, ohne next aufzurufen. Der Text wandert zurück in das Eingabefeld des Benutzers, und dieser sieht Prompt dropped by a hook: gefolgt von Ihrem Grund, richten Sie den Grund also an ihn. Wenn Ihr Hook ein drop zurückgibt, nachdem sein Aufruf von next(e) den Prompt durchgelassen hat, wird der Turn trotzdem ausgeführt, und der Hook schlägt fehl, mit einer Meldung, die a drop after its next() was answered enthält.
Weitere Events decken den Rest dessen ab, was Claude liest: prompt.section für jeden Abschnitt des System-Prompts, prompt.context für den mit der ersten Nachricht gesendeten Kontext und skill.prompt für den Text eines Skills. Text aus diesen Hooks, der sich zwischen Anfragen ändert, macht den Prompt-Cache ungültig. In einem skill.prompt-Hook können Sie außerdem auslesen, aus welchem Plugin oder welcher Datei der Skill stammt.
Einen Turn verfolgen
Ein Turn umfasst alles, was Claude als Antwort auf einen Prompt tut. Behandeln Sieturn.start, turn.step und turn.complete, um einen Turn zu verfolgen:
Schreiben Sie einen
turn.step-Hook als asynchronen Generator, weil das Event gestreamt wird. yield* next(e) leitet die Antwort beim Streamen weiter und ergibt das fertige Ergebnis. Dieser Hook protokolliert, wie viel von jeder Anfrage die Claude API aus dem Prompt-Cache bedient hat:
result.usage enthält die Token-Zahlen, die die Claude API für eine Anfrage meldet, sowie das model, das geantwortet hat: input_tokens, output_tokens, cache_read_input_tokens und cache_creation_input_tokens. Der Hook wird auch für Anfragen von Subagenten ausgeführt, prüfen Sie also e.agentId, wenn Sie nur die Hauptkonversation erfassen möchten.
Um die Tool-Aufrufe zu sehen, die die API während der Anfrage selbst ausgeführt hat, etwa Aufrufe des Advisor-Tools, lesen Sie result.serverToolUses. Claude Code führt diese Aufrufe nicht aus, daher wird für sie kein tool.call- oder tool.check-Hook ausgelöst. Das Feld fehlt, wenn die Antwort keine solchen Aufrufe enthält, und erfordert Claude Code v2.1.290 oder höher.
Die Events der Einstellungs-Hooks behandeln
Einstellungs-Hooks sind die Befehls-, HTTP-, Prompt- und Agent-Hooks, die Sie in Einstellungsdateien konfigurieren. Jedes Event eines Einstellungs-Hooks, etwaStop, SessionEnd oder PostToolUse, ist auch ein Event, das aus classic. gefolgt vom Namen des Einstellungs-Hook-Events besteht, etwa classic.Stop. e ist das JSON, das ein Einstellungs-Hook über stdin erhält, einschließlich transcript_path.
Dieser Hook verwendet Stop, das ausgelöst wird, wenn Claude mit dem Antworten fertig ist, um zu protokollieren, wo das Transkript der Sitzung gespeichert ist:
next(e) zurück, beobachtet das Event also nur und ändert nichts daran, wie der Turn endet.
Zusammen mit anderen Mods ausführen
Mehrere Mods können dasselbe Ereignis verarbeiten, und jeder von ihnen kann fehlschlagen. Wenn Ihr Mod Tool-Aufrufe blockiert, prüfen Sie seine Position in der Kette und was passiert, wenn sein Hook fehlschlägt.Die Reihenfolge, in der Mods ausgeführt werden
Hooks für dasselbe Ereignis bilden eine Middleware-Kette. Dasnext jedes Mods ruft den Hook des nachfolgenden Mods auf, und das letzte next erreicht das eigene Verhalten von Claude Code. Der erste Mod ist der äußerste: Er sieht das Ereignis vor den anderen und das Ergebnis nach ihnen, und er entscheidet, ob die anderen überhaupt ausgeführt werden. Ein späterer Mod kann nicht verhindern, dass ein früherer ein Ereignis sieht.
Claude Code ordnet die Kette danach, woher jeder Mod stammt:
- Der integrierte Wächter
sec-default@builtin, ein in Claude Code integrierter Mod, den/pluginalscc-plugin-sec-defaultauflistet, sofern er geladen wird, Mods, die Ihre Organisation inprependPluginsauflistet, und anschließend jeder andere Mod, der als Mod Ihrer Organisation gilt und nicht inappendPluginssteht - Mods, die Sie installieren
- Mods, die Ihre Organisation in
appendPluginsauflistet - Andere in Claude Code integrierte Mods
dependencies auflistet. Innerhalb eines Moduls werden Hooks in der Reihenfolge ausgeführt, in der register on aufgerufen hat.
Wo Einstellungs-Hooks in der Reihenfolge ausgeführt werden
Die in Einstellungsdateien konfiguriertenPreToolUse-Hooks werden ebenfalls während eines Tool-Aufrufs ausgeführt, und zwar an festen Stellen in der Kette der Mods:
PreToolUse-Hooks aus verwalteten Einstellungen: werden vor demtool.call-Hook des ersten Mods ausgeführt, und eine Blockierung durch einen von ihnen ist endgültig, sodass kein Mod den Aufruf sieht.PreToolUse-Hooks aus allen anderen Einstellungsdateien und aus derhooks/hooks.jsonvon Plugins: werden ausgeführt, nachdem der letzte Modnextaufgerufen hat, als Teil des eigenen Verhaltens von Claude Code. Ein Mod, dertool.callbeantwortet, ohnenextaufzurufen, verhindert ihre Ausführung, und ein Mod, dernextaufruft, sieht ihre Entscheidung in dem Ergebnis, das er zurückgibt.
tool.check wird ausgelöst, nachdem diese Hooks und die Berechtigungsregeln entschieden haben, sodass ein Hook darauf einen Aufruf genehmigen kann, den ein Hook aus der zweiten Gruppe blockiert hat.
Einen fehlschlagenden Hook behandeln
Ein fehlschlagender Hook unterbricht die Sitzung nicht, und Sie können entscheiden, was stattdessen passiert. Wenn ein Hook ohne.catch-Handler eine Ausnahme auslöst, eine Zeitüberschreitung hat oder ein Ergebnis mit falscher Struktur zurückgibt, hängt das weitere Vorgehen davon ab, ob er next aufgerufen hatte:
- Er ist fehlgeschlagen, bevor er
nextaufgerufen hat: Claude Code überspringt ihn, und der nächste Handler wird an seiner Stelle ausgeführt - Er ist fehlgeschlagen, nachdem
nextaufgelöst wurde: Dieses Ergebnis bleibt bestehen, und nichts wird ein zweites Mal ausgeführt
my-mod: tool.call hook skipped: threw Error: boom. Wo Sie sie lesen, hängt von der Sitzung ab, wie Herausfinden, warum ein Mod nichts tut auflistet. Ein ui.render-Hook, dessen Zeichnung die Validierung nicht besteht, wird anders gemeldet, wie Einen Baum aus Elementen erstellen beschreibt.
Damit ein Hook, der Aufrufe blockiert, im Fehlerfall sicher blockiert (Fail-closed), fügen Sie einen .catch-Fehlerhandler hinzu, der an seiner Stelle antwortet. Hier ist guard Ihre Hook-Funktion, und der Handler prüft next.called, um festzustellen, ob guard next bereits aufgerufen hatte, als es fehlschlug:
guard bei einem Bash-Aufruf eine Ausnahme auslöst oder eine Zeitüberschreitung hat, ruft Claude Code den Handler mit demselben Ereignis auf:
guardist fehlgeschlagen, bevor esnextaufgerufen hat: Der Befehl wird nicht ausgeführt, und Claude liest dendeny-Text mit der Fehlerart am Endeguardist fehlgeschlagen, nachdem esnextaufgerufen hat: Dasnext(e)des Handlers wird zu dem Ergebnis aufgelöst, das der Aufruf vonguarderzeugt hat, ohne den Befehl erneut auszuführen, und Claude liest dieses Ergebnis
guard next nicht aufgerufen, wird der Befehl dann so fortgesetzt, als gäbe es den Mod nicht.
Dieselbe Handler-Struktur eignet sich für einen Wächter auf prompt.submit oder config.set. Wenn next.called false ist, geben Sie die Ablehnung zurück, die die Ereignisreferenz für dieses Ereignis auflistet: { drop: 'the reason' } für prompt.submit, { deny: 'the reason' } für config.set.
Bei tool.check und plugin.register gilt eine Ablehnung, die nach dem Auflösen von next zurückgegeben wird, weiterhin, geben Sie sie also zurück, ohne next.called zu prüfen:
tool.check: Geben Sie{ decision: 'deny', reason: 'the reason' }zurückplugin.register: Geben Sie{ refuse: 'the reason' }zurück, wie Mods ablehnen, wenn Ihre Prüfung fehlschlägt zeigt
tool.call hält ein deny, das nach dem Auflösen von next zurückgegeben wird, das Ergebnis vor Claude zurück.
Nächste Schritte
- Die Mods-API verwenden: Befehle und Tools hinzufügen, ein Modell aufrufen und Aufgaben zeitgesteuert ausführen
- In der Oberfläche zeichnen: anzeigen, was Ihre Hooks in einem Bereich oder oberhalb des Prompts sammeln
- Einen Mod testen: jedes dieser Ereignisse aus einem Test heraus auslösen
- Mods-Referenz: alle Ereignisse, alle Methoden der Mods-API und die Grenzwerte