Plugin-Hooks sind prozessinterne Erweiterungspunkte für OpenClaw-Plugins. Verwenden Sie sie, wenn ein Plugin Agentenläufe, Tool-Aufrufe, Nachrichtenfluss, Sitzungslebenszyklus, Subagent-Routing, Installationen oder den Gateway-Start prüfen oder ändern muss. Verwenden Sie stattdessen interne Hooks, wenn Sie ein kleines, vom Operator installiertesDocumentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
HOOK.md-Skript für Befehls- und Gateway-Ereignisse wie
/new, /reset, /stop, agent:bootstrap oder gateway:startup möchten.
Schnellstart
Registrieren Sie typisierte Plugin-Hooks mitapi.on(...) aus Ihrem Plugin-Einstieg:
priority ausgeführt. Hooks
mit gleicher Priorität behalten die Registrierungsreihenfolge bei.
api.on(name, handler, opts?) akzeptiert:
priority- Handler-Reihenfolge (höher wird zuerst ausgeführt).timeoutMs- optionales Budget pro Hook. Wenn gesetzt, bricht der Hook-Runner diesen Handler nach Ablauf des Budgets ab und fährt mit dem nächsten fort, anstatt langsame Setup- oder Recall-Arbeit das vom Aufrufer konfigurierte Modell-Timeout verbrauchen zu lassen. Lassen Sie es weg, um das standardmäßige Beobachtungs-/Entscheidungs-Timeout zu verwenden, das der Hook-Runner generisch anwendet.
hooks.timeouts.<hookName> überschreibt hooks.timeoutMs, das wiederum den vom
Plugin definierten Wert api.on(..., { timeoutMs }) überschreibt. Jeder konfigurierte Wert muss
eine positive Ganzzahl von höchstens 600000 Millisekunden sein. Bevorzugen Sie Überschreibungen pro Hook
für bekanntermaßen langsame Hooks, damit ein Plugin nicht überall ein längeres Budget
erhält.
Jeder Hook erhält event.context.pluginConfig, die aufgelöste Konfiguration für das
Plugin, das diesen Handler registriert hat. Verwenden Sie sie für Hook-Entscheidungen, die
aktuelle Plugin-Optionen benötigen; OpenClaw injiziert sie pro Handler, ohne das
gemeinsam genutzte Ereignisobjekt zu verändern, das andere Plugins sehen.
Hook-Katalog
Hooks sind nach der Oberfläche gruppiert, die sie erweitern. Namen in Fettdruck akzeptieren ein Entscheidungsergebnis (blockieren, abbrechen, überschreiben oder Genehmigung anfordern); alle anderen dienen nur der Beobachtung. Agenten-Turnbefore_model_resolve- Provider oder Modell überschreiben, bevor Sitzungsnachrichten geladen werdenagent_turn_prepare- in die Warteschlange gestellte Plugin-Turn-Injektionen verbrauchen und Kontext für denselben Turn vor Prompt-Hooks hinzufügenbefore_prompt_build- dynamischen Kontext oder System-Prompt-Text vor dem Modellaufruf hinzufügenbefore_agent_start- kombinierte Phase nur für Kompatibilität; bevorzugen Sie die beiden Hooks obenbefore_agent_run- den finalen Prompt und die Sitzungsnachrichten vor der Modellübermittlung prüfen und den Lauf optional blockierenbefore_agent_reply- den Modell-Turn mit einer synthetischen Antwort oder Stille kurzschließenbefore_agent_finalize- die natürliche finale Antwort prüfen und einen weiteren Modelldurchlauf anfordernagent_end- finale Nachrichten, Erfolgsstatus und Laufdauer beobachtenheartbeat_prompt_contribution- Heartbeat-spezifischen Kontext für Hintergrundmonitor- und Lebenszyklus-Plugins hinzufügen
model_call_started/model_call_ended- bereinigte Provider-/Modellaufruf-Metadaten, Timing, Ergebnis und begrenzte Request-ID-Hashes ohne Prompt- oder Antwortinhalt beobachtenllm_input- Provider-Eingabe beobachten (System-Prompt, Prompt, Verlauf)llm_output- Provider-Ausgabe beobachten
before_tool_call- Tool-Parameter umschreiben, Ausführung blockieren oder Genehmigung anfordernafter_tool_call- Tool-Ergebnisse, Fehler und Dauer beobachtentool_result_persist- die aus einem Tool-Ergebnis erzeugte Assistentennachricht umschreibenbefore_message_write- einen laufenden Nachrichtenschreibvorgang prüfen oder blockieren (selten)
inbound_claim- eine eingehende Nachricht vor dem Agenten-Routing beanspruchen (synthetische Antworten)message_received- eingehenden Inhalt, Absender, Thread und Metadaten beobachtenmessage_sending- ausgehenden Inhalt umschreiben oder Zustellung abbrechenmessage_sent- Erfolg oder Fehler der ausgehenden Zustellung beobachtenbefore_dispatch- einen ausgehenden Dispatch vor der Channel-Übergabe prüfen oder umschreibenreply_dispatch- an der finalen Antwort-Dispatch-Pipeline teilnehmen
session_start/session_end- Grenzen des Sitzungslebenszyklus verfolgenbefore_compaction/after_compaction- Compaction-Zyklen beobachten oder annotierenbefore_reset- Sitzungs-Reset-Ereignisse beobachten (/reset, programmatische Resets)
subagent_spawning/subagent_delivery_target/subagent_spawned/subagent_ended- Subagent-Routing und Abschlusszustellung koordinieren
gateway_start/gateway_stop- Plugin-eigene Dienste mit dem Gateway starten oder stoppencron_changed- vom Gateway verwaltete Cron-Lebenszyklusänderungen beobachten (hinzugefügt, aktualisiert, entfernt, gestartet, abgeschlossen, geplant)before_install- Skill- oder Plugin-Installationsscans prüfen und optional blockieren
Richtlinie für Tool-Aufrufe
before_tool_call erhält:
event.toolNameevent.params- optional
event.derivedPaths, das Best-Effort-Hinweise zu vom Host abgeleiteten Zielpfaden für bekannte Tool-Umschläge wieapply_patchenthält; wenn vorhanden, können diese Pfade unvollständig sein oder überschätzen, was das Tool tatsächlich berühren wird (zum Beispiel bei fehlerhaften oder partiellen Eingaben) - optional
event.runId - optional
event.toolCallId - Kontextfelder wie
ctx.agentId,ctx.sessionKey,ctx.sessionId,ctx.runId,ctx.jobId(bei Cron-gesteuerten Läufen gesetzt) und diagnostischesctx.trace
block: trueist terminal und überspringt Handler mit niedrigerer Priorität.block: falsewird so behandelt, als gäbe es keine Entscheidung.paramsschreibt die Tool-Parameter für die Ausführung um.requireApprovalpausiert den Agentenlauf und fragt den Benutzer über Plugin- Genehmigungen. Der Befehl/approvekann sowohl Exec- als auch Plugin-Genehmigungen erteilen.- Ein
block: truemit niedrigerer Priorität kann weiterhin blockieren, nachdem ein Hook mit höherer Priorität eine Genehmigung angefordert hat. onResolutionerhält die aufgelöste Genehmigungsentscheidung -allow-once,allow-always,deny,timeoutodercancelled.
api.registerTrustedToolPolicy(...) registrieren. Diese laufen vor gewöhnlichen
before_tool_call-Hooks und vor Entscheidungen externer Plugins. Verwenden Sie sie nur
für vom Host vertrauenswürdige Gates wie Workspace-Richtlinie, Budgetdurchsetzung oder
reservierte Workflow-Sicherheit. Externe Plugins sollten normale before_tool_call-
Hooks verwenden.
Persistenz von Tool-Ergebnissen
Tool-Ergebnisse können strukturiertedetails für UI-Rendering, Diagnosen,
Medien-Routing oder Plugin-eigene Metadaten enthalten. Behandeln Sie details als Laufzeitmetadaten,
nicht als Prompt-Inhalt:
- OpenClaw entfernt
toolResult.detailsvor Provider-Replay und Compaction- Eingabe, damit Metadaten nicht zu Modellkontext werden. - Persistierte Sitzungseinträge behalten nur begrenzte
details. Überdimensionierte Details werden durch eine kompakte Zusammenfassung undpersistedDetailsTruncated: trueersetzt. tool_result_persistundbefore_message_writelaufen vor der finalen Persistenzbegrenzung. Hooks sollten zurückgegebenedetailsdennoch klein halten und vermeiden, promptrelevanten Text nur indetailsabzulegen; platzieren Sie für das Modell sichtbare Tool-Ausgabe incontent.
Prompt- und Modell-Hooks
Verwenden Sie die phasenspezifischen Hooks für neue Plugins:before_model_resolve: erhält nur den aktuellen Prompt und Anhang- Metadaten. Geben SieproviderOverrideodermodelOverridezurück.agent_turn_prepare: erhält den aktuellen Prompt, vorbereitete Sitzungsnachrichten und alle Exactly-once-Injektionen in der Warteschlange, die für diese Sitzung entnommen wurden. Geben SieprependContextoderappendContextzurück.before_prompt_build: erhält den aktuellen Prompt und Sitzungsnachrichten. Geben SieprependContext,appendContext,systemPrompt,prependSystemContextoderappendSystemContextzurück.heartbeat_prompt_contribution: läuft nur für Heartbeat-Turns und gibtprependContextoderappendContextzurück. Er ist für Hintergrundmonitore vorgesehen, die den aktuellen Zustand zusammenfassen müssen, ohne benutzerinitiierte Turns zu ändern.
before_agent_start bleibt aus Kompatibilitätsgründen bestehen. Bevorzugen Sie die expliziten Hooks oben,
damit Ihr Plugin nicht von einer veralteten kombinierten Phase abhängt.
before_agent_run läuft nach der Prompt-Erstellung und vor jeder Modelleingabe,
einschließlich Prompt-lokalem Laden von Bildern und llm_input-Beobachtung. Er erhält
die aktuelle Benutzereingabe als prompt, plus geladene Sitzungshistorie in messages
und den aktiven System-Prompt. Geben Sie { outcome: "block", reason, message? }
zurück, um den Lauf zu stoppen, bevor das Modell den Prompt lesen kann. reason ist intern;
message ist der benutzersichtbare Ersatz. Die einzigen unterstützten Ergebnisse sind
pass und block; nicht unterstützte Entscheidungsformen schlagen geschlossen fehl.
Wenn ein Lauf blockiert wird, speichert OpenClaw nur den Ersatztext in
message.content plus nicht sensible Blockierungsmetadaten wie die ID des blockierenden Plugins
und den Zeitstempel. Der ursprüngliche Benutzertext wird nicht im Transcript oder zukünftigen
Kontext beibehalten. Interne Blockierungsgründe werden als sensibel behandelt und aus
Transcript-, Verlaufs-, Broadcast-, Log- und Diagnose-Payloads ausgeschlossen. Observability
sollte bereinigte Felder wie Blocker-ID, Ergebnis, Zeitstempel oder eine sichere
Kategorie verwenden.
before_agent_start und agent_end enthalten event.runId, wenn OpenClaw
den aktiven Lauf identifizieren kann. Derselbe Wert ist auch unter ctx.runId verfügbar.
Cron-gesteuerte Läufe stellen außerdem ctx.jobId bereit (die ID des auslösenden Cron-Jobs), damit
Plugin-Hooks Metriken, Seiteneffekte oder Zustand auf einen bestimmten geplanten
Job eingrenzen können.
Für von Channels stammende Läufe ist ctx.messageProvider die Provider-Oberfläche wie
discord oder telegram, während ctx.channelId die Zielkennung der Konversation ist,
wenn OpenClaw sie aus dem Sitzungsschlüssel oder den Zustellungsmetadaten ableiten kann.
agent_end ist ein Beobachtungs-Hook und läuft nach dem Turn fire-and-forget. Der
Hook-Runner wendet ein Timeout von 30 Sekunden an, damit ein blockiertes Plugin oder ein Embedding-
Endpunkt das Hook-Promise nicht dauerhaft offen lassen kann. Ein Timeout wird protokolliert und
OpenClaw fährt fort; Plugin-eigene Netzwerkarbeit wird dadurch nicht abgebrochen, es sei denn, das
Plugin verwendet zusätzlich sein eigenes Abbruchsignal.
Verwenden Sie model_call_started und model_call_ended für Provider-Aufruf-Telemetrie,
die keine rohen Prompts, Verläufe, Antworten, Header, Request-Bodys
oder Provider-Request-IDs erhalten soll. Diese Hooks enthalten stabile Metadaten wie
runId, callId, provider, model, optional api/transport, terminale
durationMs/outcome und upstreamRequestIdHash, wenn OpenClaw einen
begrenzten Provider-Request-ID-Hash ableiten kann.
before_agent_finalize wird nur ausgeführt, wenn ein Harness im Begriff ist, eine natürliche
finale Assistentenantwort zu akzeptieren. Dies ist nicht der Abbruchpfad /stop und wird nicht
ausgeführt, wenn der Benutzer einen Turn abbricht. Geben Sie { action: "revise", reason } zurück, um
beim Harness vor der Finalisierung einen weiteren Modelldurchlauf anzufordern, { action: "finalize", reason? }, um die Finalisierung zu erzwingen, oder lassen Sie ein Ergebnis weg, um fortzufahren.
Native Codex-Stop-Hooks werden in diesen Hook als OpenClaw-
before_agent_finalize-Entscheidungen weitergeleitet.
Wenn action: "revise" zurückgegeben wird, können Plugins retry-Metadaten einfügen, um
den zusätzlichen Modelldurchlauf begrenzt und replay-sicher zu machen:
instruction wird an den Revisionsgrund angehängt, der an den Harness gesendet wird.
idempotencyKey ermöglicht es dem Host, Wiederholungen für dieselbe Plugin-Anfrage über
äquivalente Finalisierungsentscheidungen hinweg zu zählen, und maxAttempts begrenzt, wie viele zusätzliche Durchläufe der
Host zulässt, bevor er mit der natürlichen finalen Antwort fortfährt.
Nicht gebündelte Plugins, die rohe Konversations-Hooks benötigen (before_model_resolve,
before_agent_reply, llm_input, llm_output, before_agent_finalize,
agent_end oder before_agent_run), müssen Folgendes setzen:
plugins.entries.<id>.hooks.allowPromptInjection=false deaktiviert werden.
Sitzungserweiterungen und Injektionen für den nächsten Turn
Workflow-Plugins können kleinen JSON-kompatiblen Sitzungszustand mitapi.registerSessionExtension(...) persistieren und ihn über die Gateway-Methode
sessions.pluginPatch aktualisieren. Sitzungszeilen projizieren registrierten Erweiterungszustand
über pluginExtensions, sodass Control UI und andere Clients Plugin-eigenen Status rendern können,
ohne Plugin-Interna kennen zu müssen.
Verwenden Sie api.enqueueNextTurnInjection(...), wenn ein Plugin dauerhaften Kontext benötigt, der
genau einmal den nächsten Model-Turn erreichen soll. OpenClaw leert eingereihte Injektionen vor
Prompt-Hooks, verwirft abgelaufene Injektionen und dedupliziert pro Plugin nach idempotencyKey.
Dies ist der richtige Ansatzpunkt für Genehmigungsfortsetzungen, Richtlinienzusammenfassungen,
Deltas von Hintergrundmonitoren und Befehlsfortsetzungen, die im nächsten Turn für das Model
sichtbar sein sollen, aber nicht zu dauerhaftem System-Prompt-Text werden sollen.
Bereinigungssemantik ist Teil des Vertrags. Bereinigungs-Callbacks für Sitzungserweiterungen und
Runtime-Lebenszyklus erhalten reset, delete, disable oder
restart. Der Host entfernt den persistenten Sitzungserweiterungszustand und die ausstehenden
Injektionen für den nächsten Turn des besitzenden Plugins bei reset/delete/disable; restart behält
dauerhaften Sitzungszustand bei, während Bereinigungs-Callbacks Plugins ermöglichen,
Scheduler-Jobs, Ausführungskontext und andere Out-of-Band-Ressourcen der alten Runtime-Generation
freizugeben.
Nachrichten-Hooks
Verwenden Sie Nachrichten-Hooks für Routing und Zustellungsrichtlinien auf Kanalebene:message_received: eingehenden Inhalt, Absender,threadId,messageId,senderId, optionale Lauf-/Sitzungskorrelation und Metadaten beobachten.message_sending:contentumschreiben oder{ cancel: true }zurückgeben.message_sent: finalen Erfolg oder Fehler beobachten.
content das verborgene gesprochene Transkript enthalten,
auch wenn die Kanal-Payload keinen sichtbaren Text/keine sichtbare Beschriftung hat. Das Umschreiben dieses
content aktualisiert nur das für Hooks sichtbare Transkript; es wird nicht als
Medienbeschriftung gerendert.
Nachrichten-Hook-Kontexte stellen stabile Korrelationsfelder bereit, wenn verfügbar:
ctx.sessionKey, ctx.runId, ctx.messageId, ctx.senderId, ctx.trace,
ctx.traceId, ctx.spanId, ctx.parentSpanId und ctx.callDepth. Bevorzugen Sie
diese erstklassigen Felder, bevor Sie ältere Metadaten lesen.
Bevorzugen Sie typisierte Felder threadId und replyToId, bevor Sie kanalspezifische
Metadaten verwenden.
Entscheidungsregeln:
message_sendingmitcancel: trueist terminal.message_sendingmitcancel: falsewird als keine Entscheidung behandelt.- Umgeschriebener
contentwird an Hooks mit niedrigerer Priorität weitergegeben, sofern kein späterer Hook die Zustellung abbricht. message_sendingkanncancelReasonund begrenztemetadatazusammen mit einem Abbruch zurückgeben. Neue Nachrichten-Lebenszyklus-APIs stellen dies als unterdrücktes Zustellungsergebnis mit dem Grundcancelled_by_message_sending_hookbereit; ältere direkte Zustellung gibt aus Kompatibilitätsgründen weiterhin ein leeres Ergebnisarray zurück.message_sentdient nur der Beobachtung. Handler-Fehler werden protokolliert und ändern das Zustellungsergebnis nicht.
Installations-Hooks
before_install wird nach dem integrierten Scan für Skill- und Plugin-Installationen ausgeführt.
Geben Sie zusätzliche Befunde oder { block: true, blockReason } zurück, um die
Installation zu stoppen.
block: true ist terminal. block: false wird als keine Entscheidung behandelt.
Gateway-Lebenszyklus
Verwenden Siegateway_start für Plugin-Dienste, die Gateway-eigenen Zustand benötigen. Der
Kontext stellt ctx.config, ctx.workspaceDir und ctx.getCron?.() für
Cron-Inspektion und -Aktualisierungen bereit. Verwenden Sie gateway_stop, um lang laufende
Ressourcen zu bereinigen.
Verlassen Sie sich für Plugin-eigene Runtime-Dienste nicht auf den internen Hook gateway:startup.
cron_changed wird bei Gateway-eigenen Cron-Lebenszyklusereignissen mit einer typisierten
Ereignis-Payload ausgelöst, die die Gründe added, updated, removed, started, finished
und scheduled abdeckt. Das Ereignis enthält einen Snapshot PluginHookGatewayCronJob
(einschließlich state.nextRunAtMs, state.lastRunStatus und
state.lastError, wenn vorhanden) sowie einen PluginHookGatewayCronDeliveryStatus
von not-requested | delivered | not-delivered | unknown. Entfernte
Ereignisse enthalten weiterhin den gelöschten Job-Snapshot, damit externe Scheduler den
Zustand abgleichen können. Verwenden Sie ctx.getCron?.() und ctx.config aus dem Runtime-
Kontext, wenn Sie externe Wake-Scheduler synchronisieren, und behalten Sie OpenClaw als
Quelle der Wahrheit für Fälligkeitsprüfungen und Ausführung bei.
Bevorstehende Veraltungen
Einige Hook-nahe Oberflächen sind veraltet, werden aber weiterhin unterstützt. Migrieren Sie vor dem nächsten Major-Release:- Klartext-Kanalumschläge in
inbound_claim- undmessage_received- Handlern. Lesen Sie stattdessenBodyForAgentund die strukturierten Benutzerkontextblöcke, anstatt flachen Umschlagtext zu parsen. Siehe Klartext-Kanalumschläge → BodyForAgent. before_agent_startbleibt aus Kompatibilitätsgründen erhalten. Neue Plugins solltenbefore_model_resolveundbefore_prompt_buildstatt der kombinierten Phase verwenden.onResolutioninbefore_tool_callverwendet jetzt die typisierte UnionPluginApprovalResolution(allow-once/allow-always/deny/timeout/cancelled) anstelle eines frei formuliertenstring.
command-auth → command-status - finden Sie unter
Plugin SDK-Migration → Aktive Veraltungen.
Verwandt
- Plugin SDK-Migration - aktive Veraltungen und Zeitplan für Entfernungen
- Plugins erstellen
- Plugin SDK-Überblick
- Plugin-Einstiegspunkte
- Interne Hooks
- Interne Plugin-Architektur