on(eventName, handler).
Erstellen Sie Ihren ersten Mod, bevor Sie hier beginnen. Für jedes Ereignis und seine genauen Felder siehe die Referenz oder lesen Sie die Typen für Ihren Build.
Wie ein Hook ein Ereignis behandelt
Ein Hook sitzt zwischen einem Ereignis und dem, was Claude Code daran tun würde, sodass er das Ereignis beobachten, umschreiben oder selbst beantworten kann. Er empfängt 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, der ein Hook eines anderen Mods oder am Ende der Kette Claude Codes eigenes Verhalten ist, und wird zum Ergebnis aufgelöst. Was Ihr Hook mit next tut, entscheidet, welches der drei er tut.
Ein Ereignis beobachten
Um ein Ereignis zu beobachten, ohne es zu ändern, führen Sie Ihre Arbeit aus und geben Sienext(e) zurück. Dieser Hook protokolliert jedes Tool, das Claude verwenden wird:
● my-mod: Claude is about to use Bash im Transkript, wobei my-mod der Name Ihres Plugins ist. Das Tool wird so ausgeführt, wie es ohne den Mod wäre.
Um nach dem Ereignis zu handeln, await next(e), führen Sie Ihre Arbeit aus und geben Sie 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 handelt, z. B. den Text einer Eingabeaufforderung, rufen Sienext mit einer geänderten Kopie des Ereignisses auf. Das Ereignis selbst ist unveränderlich: es ist in jeder Tiefe eingefroren, und das Zuweisen zu einem Feld wirft einen Fehler. Dieser Hook schneidet jede Eingabeaufforderung ab, bevor sie gesendet wird:
await next(e), dann geben Sie eine Kopie des Ergebnisses mit einem ersetzten Feld zurück.
Ein Ereignis beantworten
Um ein Ereignis selbst zu behandeln, geben Sie ein Ergebnis zurück, ohnenext aufzurufen. Das unterbricht die Kette, sodass spätere Mods und Claude Codes eigenes Verhalten nicht ausgeführt werden. Dieser Hook lehnt jeden Bash-Befehl ab:
deny-Text als Ergebnis des Tools. Jedes Ereignis hat seine eigene Ergebnisform, die die Ereignisreferenz auflistet.
Filtern Sie, welche Ereignisse ein Hook behandelt
Um einen Hook nur für einige Ereignisse auszuführen, übergeben Sie einen Filter als zweites Argument anon. Claude Code nennt den Filter einen Matcher. Es ist 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 die gleiche Funktion, hook, für einen engeren Satz von Tool-Aufrufen:
hook wird einmal für einen Bash-, Edit- oder Write-Aufruf ausgeführt und einmal für einen Aufruf zu einem Tool, dessen Name mit mcp__github__ beginnt. Ein Aufruf zu jedem anderen Tool, z. B. Read, passt zu keinem der drei, daher wird hook nicht dafür ausgeführt.
Der Ereignisname kann ein Platzhalter sein. 'classic.*' passt zu jedem Settings-Hook-Ereignis. '*' passt zu jedem Ereignis außer den Telemetrie-Ereignissen, die Sie nach Name oder als 'telemetry.*' hooken.
Registrieren Sie jedes Ereignis einmal pro Matcher. Wenn Sie on zweimal für session.start ohne Matcher aufrufen, schlägt das Modul mit on("session.start") is registered twice without a matcher fehl. Fügen Sie alles, was Ihr Mod beim Sitzungsstart tut, in einen Hook ein.
Hook, was Claude tut
Hooken Sie diese Ereignisse, um einen Tool-Aufruf, eine Eingabeaufforderung oder einen Turn zu sehen oder zu ändern, während er stattfindet. Für jedes Ereignis und was ein Hook zurückgeben kann, siehe die Ereignisreferenz.Schützen oder ändern Sie einen Tool-Aufruf
Eintool.call-Hook sieht jedes Tool, das Claude verwenden wird, sodass er den Aufruf ablehnen, seine Argumente ändern oder ihn durchlassen kann. tool.call wird ausgelöst, wenn Claude Code ein Tool ausführen wird, einschließlich Aufrufe, die ein Subagent tätigt, und Aufrufe zu MCP-Tools. e.tool ist der Name des Tools und die Argumente des Tools sind Felder von e, z. B. e.command für Bash. Wenn Sie next(e) aufrufen, führt Claude Code die Berechtigungsprüfung und dann das Tool aus.
Dieser Hook lehnt einen Bash-Befehl ab, der Force-Push durchführt, und teilt Claude mit, warum:
git push --force versucht, wird der Befehl nicht ausgeführt und es erscheint keine Berechtigungsaufforderung, da der Hook next nie aufruft. Claude liest den deny-Text als Ergebnis des Tools, daher schreiben Sie ihn als Anweisung, auf die Claude reagieren kann. Jeder andere Bash-Befehl wird so ausgeführt, wie er ohne den Mod wäre.
Um nach Ausführung eines Tools zu handeln, await next(e), führen Sie Ihre Arbeit aus und geben Sie das zurück, was next Ihnen gab. Dieser Hook protokolliert jede .mdx-Datei, die Claude ändert, mit $.ui.log, das eine schwache Zeile zum Transkript hinzufügt, die Claude nicht liest:
.mdx-Datei bearbeitet oder geschrieben hat, benennt eine schwache Zeile im Transkript die Datei. Nichts wird für eine andere Art von Datei protokolliert oder für einen Aufruf, der abgelehnt oder fehlgeschlagen ist. Claude’s Ansicht des Aufrufs ändert sich nicht, da der Hook das Ergebnis zurückgibt, das er erhalten hat.
Um einen Aufruf zu ändern, übergeben Sie geänderte Argumente an next. Um einen Aufruf zu wiederholen, rufen Sie next(e) erneut auf: Ein Hook, der isError beim ersten Ergebnis sieht, kann das Tool ein zweites Mal ausführen und dieses Ergebnis zurückgeben. Um einen Aufruf selbst zu beantworten, geben Sie ein Objekt mit einem result-Feld zurück, z. B. { result: 'Skipped by my-mod' }, ohne next aufzurufen. Wenn Sie das tun, erscheint keine Berechtigungsaufforderung und das Tool wird nicht ausgeführt, daher ist das Ergebnis, das Sie zurückgeben, alles, was Claude über das Geschehene erfährt.
Hooks in den verwalteten Einstellungen Ihrer Organisation werden vor jedem tool.call-Hook eines Mods ausgeführt, und ein Block von einem von ihnen ist endgültig.
Halten Sie einen Tool-Aufruf an, bis der Benutzer entscheidet
Ein Hook kann einen Tool-Aufruf anhalten und den Benutzer fragen, was zu tun ist, bevor er fortfährt. Eintool.call-Hook kann await durchführen, bevor er next aufruft oder zurückgibt, und der Tool-Aufruf bleibt ausstehend, bis dann. Um die Frage dem Benutzer 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 zur 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 RISKY-Muster in diesem Beispiel passt zu rm -r, rm -rf, git reset --hard und git push mit --force und verfehlt andere Schreibweisen wie git push -f. Dieses Modul fragt, 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 immer noch 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 zur eingegebenen Antwort aufgelöst. Der Hook vergleicht sie mitRun it, daher lehnt jeder andere Text den Befehl ab. - Niemand antwortet:
$.ui.askwird abgelehnt, wenn der Benutzer die Frage verwirft oder Chat about this auswählt, und in einemclaude -p-Lauf, daher lässt dercatch-Block die Antwort beiRefuse
$.ui.ask, da diese Zeit nicht gegen das 10-Sekunden-Zeitlimit des Hooks zählt. Zeit, die mit dem Warten auf ein eigenes Promise verbracht wird, zählt. Claude Code überspringt einen Hook, der das Zeitlimit überschreitet, daher würde der gehaltene Befehl ausgeführt.
Schreiben Sie eine Eingabeaufforderung um oder fügen Sie sie hinzu
Einprompt.submit-Hook sieht jede Eingabeaufforderung, bevor der Turn beginnt, sodass er den Text umschreiben oder hinzufügen kann. e.text ist das, was eingegeben wurde.
Dieser Hook fügt den aktuellen Branch-Namen für Claude hinzu, wenn eine Eingabeaufforderung einen Pull Request erwähnt:
open a PR for this change senden, sieht Ihre Nachricht im Transkript gleich aus, und Claude liest auch eine Zeile wie Current branch: feature/auth danach. Eine Eingabeaufforderung, die keinen Pull Request erwähnt, wird unverändert weitergeleitet, und git wird nicht ausgeführt.
Andere Ereignisse behandeln den Rest dessen, was Claude liest: prompt.section für jeden Abschnitt der Systemaufforderung, prompt.context für den Kontext, der mit der ersten Nachricht gesendet wird, und skill.prompt für den Text einer Fähigkeit. Text aus diesen Hooks, der sich zwischen Anfragen ändert, invalidiert den Prompt-Cache.
Folgen Sie einem Turn
Ein Turn ist alles, was Claude als Antwort auf eine Eingabeaufforderung tut. Hooken Sieturn.start, turn.step und turn.complete, um einen zu folgen:
Schreiben Sie einen
turn.step-Hook als asynchronen Generator, da das Ereignis streamt. yield* next(e) leitet die Antwort weiter, während sie streamt, und wird zum fertigen Ergebnis ausgewertet. Dieser Hook protokolliert, wie viel von jeder Anfrage die Claude-API aus dem Prompt-Cache bedient hat:
result.usage enthält die vier Token-Zählungen, die die Claude-API für eine Anfrage meldet, plus 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, daher überprüfen Sie e.agentId, wenn Sie nur die Hauptkonversation möchten.
Hooken Sie die Settings-Hook-Ereignisse
Settings-Hooks sind die Befehls-, HTTP-, Eingabeaufforderungs- und Agent-Hooks, die Sie in Einstellungsdateien konfigurieren. Jedes Settings-Hook-Ereignis, z. B.Stop, SessionEnd oder PostToolUse, ist auch ein Ereignis mit dem Namen classic. gefolgt vom Namen des Settings-Hook-Ereignisses, z. B. classic.Stop. e ist das JSON, das ein Settings-Hook auf stdin empfängt, einschließlich transcript_path.
Dieser Hook verwendet Stop, das ausgelöst wird, wenn Claude die Antwort beendet, um zu protokollieren, wo das Transkript der Sitzung gespeichert ist:
next(e) zurück, daher beobachtet er das Ereignis und ändert nichts daran, wie der Turn endet.
Führen Sie neben anderen Mods aus
Mehrere Mods können das gleiche Ereignis hooken, und jeder von ihnen kann fehlschlagen. Wenn Ihr Mod Tool-Aufrufe blockiert, überprüfen Sie seine Position in der Kette und was passiert, wenn sein Hook fehlschlägt.Die Reihenfolge, in der Mods ausgeführt werden
Hooks auf dem gleichen Ereignis bilden eine Middleware-Kette. Jedernext eines Mods ruft den Hook des folgenden Mods auf, und der letzte next erreicht Claude Codes eigenes Verhalten. Der erste Mod ist am weitesten außen: 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 einen früheren nicht daran hindern, ein Ereignis zu sehen.
Claude Code ordnet die Kette danach, woher jeder Mod kommt:
- Der eingebaute Guard
sec-default@builtin, ein in Claude Code eingebauter Mod, den/pluginalscc-plugin-sec-defaultauflistet, wo er lädt, Mods, die Ihre Organisation inprependPluginsauflistet, und dann jeden anderen Mod, der als Mod Ihrer Organisation zählt und nicht inappendPluginsist - Mods, die Sie installieren
- Mods, die Ihre Organisation in
appendPluginsauflistet - Andere in Claude Code eingebaute Mods
dependencies in seinem Manifest auflistet. Innerhalb eines Moduls werden Hooks in der Reihenfolge ausgeführt, in der register on aufgerufen hat.
Wo Settings-Hooks in der Reihenfolge ausgeführt werden
DiePreToolUse-Hooks, die in Einstellungsdateien konfiguriert sind, werden auch während eines Tool-Aufrufs an festen Punkten in der Kette von Mods ausgeführt:
PreToolUse-Hooks aus verwalteten Einstellungen: werden vor dem Hooktool.calldes ersten Mods ausgeführt, und ein Block von einem von ihnen ist endgültig, daher sieht kein Mod den Aufruf.PreToolUse-Hooks aus jeder anderen Einstellungsdatei und aushooks/hooks.jsonvon Plugins: werden nach dem letzten Aufruf vonnexteines Mods ausgeführt, als Teil von Claude Codes eigenem Verhalten. Ein Mod, dertool.callbeantwortet, ohnenextaufzurufen, hindert sie daran, ausgeführt zu werden, und ein Mod, dernextaufruft, sieht ihre Entscheidung im Ergebnis, das er zurückgibt.
tool.check ist das Ereignis, bei dem Claude Code entscheidet, ob ein Tool-Aufruf ausgeführt werden darf. Es wird nach diesen Hooks und den Berechtigungsregeln ausgelöst, und next(e) wird zu ihrer Entscheidung aufgelöst. Ein Hook auf tool.check kann eine andere Entscheidung zurückgeben, z. B. { decision: 'allow' }, daher kann er einen Aufruf genehmigen, den ein Hook in der zweiten Gruppe blockiert hat. Erweitern Sie Berechtigungen mit Hooks listet auf, welche Entscheidungen einen Mod überlagern.
Behandeln Sie einen Hook, der fehlschlägt
Ein Hook, der fehlschlägt, bricht die Sitzung nicht, und Sie können entscheiden, was stattdessen passiert. Wenn ein Hook ohne.catch-Handler wirft, das Zeitlimit überschreitet oder ein Ergebnis der falschen Form zurückgibt, hängt das, was als nächstes passiert, davon ab, ob er next aufgerufen hatte:
- Es ist fehlgeschlagen, bevor
nextaufgerufen wurde: Claude Code überspringt es, und der nächste Handler wird an seiner Stelle ausgeführt - Es 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 es lesen, hängt von der Sitzung ab, wie Finden Sie heraus, warum ein Mod nichts tut auflistet. Ein ui.render-Hook, dessen Zeichnung nicht validiert, wird anders gemeldet, wie Erstellen Sie einen Baum aus Elementen beschreibt.
Um einen Hook, der Aufrufe blockiert, fehlgeschlagen zu schließen, fügen Sie einen .catch-Fehlerhandler hinzu, der stattdessen antwortet. Hier ist guard Ihre Hook-Funktion:
guard funktioniert, wird der Handler nie ausgeführt. Wenn guard bei einem Bash-Aufruf wirft oder das Zeitlimit überschreitet, ruft Claude Code den Handler mit dem gleichen Ereignis auf. Der Handler gibt { deny } zurück, daher wird der Befehl nicht ausgeführt, und Claude liest den Text mit throw oder timeout am Ende. Ohne den Handler würde Claude Code guard überspringen und den Befehl ausführen. Der Handler hat eine Sekunde Zeit zum Antworten.
Nächste Schritte
- Verwenden Sie die Mods-API: Fügen Sie Befehle und Tools hinzu, rufen Sie ein Modell auf und führen Sie Arbeit auf einem Timer aus
- Zeichnen Sie in der Schnittstelle: Zeigen Sie, was Ihre Hooks in einem Bereich oder über der Eingabeaufforderung sammeln
- Testen Sie einen Mod: Lösen Sie eines dieser Ereignisse aus einem Test aus
- Mods-Referenz: Jedes Ereignis, jede Mods-API-Methode und die Limits