Plugins
Plugin-Hooks
Plugin-Hooks sind In-Process-Erweiterungspunkte für OpenClaw-Plugins. Verwenden Sie sie, wenn ein Plugin Agent-Ausführungen, 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 installiertes HOOK.md-Skript für Befehls- und Gateway-Ereignisse wie /new, /reset, /stop, agent:bootstrap oder gateway:startup benötigen.
Schnellstart
Registrieren Sie typisierte Plugin-Hooks mit api.on(...) aus Ihrem Plugin-Einstieg:
export default definePluginEntry({
id: "tool-preflight",
name: "Tool Preflight",
register(api) {
api.on(
"before_tool_call",
async (event) => {
if (event.toolName !== "web_search") {
return;
}
return {
requireApproval: {
title: "Run web search",
description: `Allow search query: ${String(event.params.query ?? "")}`,
severity: "info",
timeoutMs: 60_000,
timeoutBehavior: "deny",
},
};
},
{ priority: 50 },
);
},
});
Hook-Handler werden nacheinander in absteigender priority ausgeführt. Hooks mit gleicher Priorität behalten die Registrierungsreihenfolge bei.
api.on(name, handler, opts?) akzeptiert:
priority- Reihenfolge der Handler (höhere Werte werden 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, statt zuzulassen, dass langsame Einrichtung oder Recall-Arbeit das vom Aufrufer konfigurierte Modell-Timeout verbraucht. Lassen Sie es weg, um das Standard-Timeout für Beobachtung/Entscheidung zu verwenden, das der Hook-Runner allgemein anwendet.
Operatoren können Hook-Budgets auch festlegen, ohne Plugin-Code zu patchen:
{
"plugins": {
"entries": {
"my-plugin": {
"hooks": {
"timeoutMs": 30000,
"timeouts": {
"before_prompt_build": 90000,
"agent_end": 60000
}
}
}
}
}
}
hooks.timeouts.<hookName> überschreibt hooks.timeoutMs, was den vom Plugin angegebenen Wert api.on(..., { timeoutMs }) überschreibt. Jeder konfigurierte Wert muss eine positive ganze Zahl von höchstens 600000 Millisekunden sein. Bevorzugen Sie Überschreibungen pro Hook für bekannte 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 Fettschrift akzeptieren ein Entscheidungsergebnis (blockieren, abbrechen, überschreiben oder Genehmigung anfordern); alle anderen dienen nur der Beobachtung.
Agent-Durchlauf
before_model_resolve- Provider oder Modell überschreiben, bevor Sitzungsnachrichten geladen werdenagent_turn_prepare- in die Warteschlange gestellte Plugin-Durchlauf-Injektionen konsumieren und Kontext für denselben Durchlauf vor Prompt-Hooks hinzufügenbefore_prompt_build- dynamischen Kontext oder System-Prompt-Text vor dem Modellaufruf hinzufügenbefore_agent_start- kombinierte Phase nur aus Kompatibilitätsgründen; bevorzugen Sie die beiden Hooks obenbefore_agent_run- den finalen Prompt und die Sitzungsnachrichten vor der Modellübermittlung prüfen und die Ausführung optional blockierenbefore_agent_reply- den Modelldurchlauf 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 Ausführungsdauer beobachtenheartbeat_prompt_contribution- Heartbeat-spezifischen Kontext für Hintergrundmonitor- und Lebenszyklus-Plugins hinzufügen
Konversationsbeobachtung
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
Tools
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 Assistant-Nachricht umschreibenbefore_message_write- einen laufenden Schreibvorgang einer Nachricht prüfen oder blockieren (selten)
Nachrichten und Zustellung
inbound_claim- eine eingehende Nachricht vor dem Agent-Routing beanspruchen (synthetische Antworten)message_received- eingehenden Inhalt, Absender, Thread und Metadaten beobachtenmessage_sending- ausgehenden Inhalt umschreiben oder Zustellung abbrechenmessage_sent- erfolgreiche oder fehlgeschlagene ausgehende Zustellung beobachtenbefore_dispatch- einen ausgehenden Dispatch vor der Channel-Übergabe prüfen oder umschreibenreply_dispatch- an der finalen Antwort-Dispatch-Pipeline teilnehmen
Sitzungen und Compaction
session_start/session_end- Sitzungslebenszyklus-Grenzen verfolgenbefore_compaction/after_compaction- Compaction-Zyklen beobachten oder annotierenbefore_reset- Sitzungs-Reset-Ereignisse beobachten (/reset, programmgesteuerte Resets)
Subagents
subagent_spawning/subagent_delivery_target/subagent_spawned/subagent_ended- Subagent-Routing und Abschlusszustellung koordinieren
Lebenszyklus
gateway_start/gateway_stop- Plugin-eigene Dienste mit dem Gateway starten oder stoppencron_changed- Gateway-eigene Cron-Lebenszyklusänderungen beobachten (hinzugefügt, aktualisiert, entfernt, gestartet, abgeschlossen, geplant)before_install- Skills- oder Plugin-Installationsscans prüfen und optional blockieren
Richtlinie für Tool-Aufrufe
before_tool_call erhält:
event.toolNameevent.params- optional
event.runId - optional
event.toolCallId - Kontextfelder wie
ctx.agentId,ctx.sessionKey,ctx.sessionId,ctx.runId,ctx.jobId(bei Cron-gesteuerten Ausführungen gesetzt) und diagnostischesctx.trace
Es kann Folgendes zurückgeben:
type BeforeToolCallResult = {
params?: Record<string, unknown>;
block?: boolean;
blockReason?: string;
requireApproval?: {
title: string;
description: string;
severity?: "info" | "warning" | "critical";
timeoutMs?: number;
timeoutBehavior?: "allow" | "deny";
pluginId?: string;
onResolution?: (
decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled",
) => Promise<void> | void;
};
};
Regeln:
block: trueist terminal und überspringt Handler mit niedrigerer Priorität.block: falsewird als keine Entscheidung behandelt.paramsschreibt die Tool-Parameter für die Ausführung um.requireApprovalpausiert die Agent-Ausführung 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 Genehmigung angefordert hat. onResolutionerhält die aufgelöste Genehmigungsentscheidung -allow-once,allow-always,deny,timeoutodercancelled.
Gebündelte Plugins, die Policy auf Host-Ebene benötigen, können vertrauenswürdige Tool-Policies mit api.registerTrustedToolPolicy(...) registrieren. Diese werden vor gewöhnlichen before_tool_call-Hooks und vor Entscheidungen externer Plugins ausgeführt. Verwenden Sie sie nur für vom Host vertrauenswürdige Gates wie Workspace-Policy, Budgetdurchsetzung oder Sicherheit reservierter Workflows. Externe Plugins sollten normale before_tool_call-Hooks verwenden.
Tool-Ergebnis-Persistierung
Tool-Ergebnisse können strukturierte details für UI-Rendering, Diagnose, Medienrouting 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. Zu große Details werden durch eine kompakte Zusammenfassung undpersistedDetailsTruncated: trueersetzt. tool_result_persistundbefore_message_writelaufen vor der finalen Persistenzobergrenze. Hooks sollten zurückgegebenedetailsdennoch klein halten und vermeiden, promptrelevanten Text nur indetailsabzulegen; legen Sie für das Modell sichtbare Tool-Ausgaben incontentab.
Prompt- und Modell-Hooks
Verwenden Sie die phasenspezifischen Hooks für neue Plugins:
before_model_resolve: erhält nur den aktuellen Prompt und Anhangsmetadaten. Geben SieproviderOverrideodermodelOverridezurück.agent_turn_prepare: erhält den aktuellen Prompt, vorbereitete Sitzungsnachrichten und alle genau einmal in die Warteschlange gestellten Injektionen, die für diese Sitzung geleert 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-Durchläufe und gibtprependContextoderappendContextzurück. Er ist für Hintergrundmonitore gedacht, die den aktuellen Zustand zusammenfassen müssen, ohne benutzerinitiierte Durchläufe zu verändern.
before_agent_start bleibt aus Kompatibilitätsgründen erhalten. Bevorzugen Sie die expliziten Hooks oben, damit Ihr Plugin nicht von einer älteren kombinierten Phase abhängt.
before_agent_run läuft nach der Prompt-Erstellung und vor jeder Modelleingabe, einschließlich promptlokalem Laden von Bildern und llm_input-Beobachtung. Es erhält die aktuelle Benutzereingabe als prompt, außerdem den geladenen Sitzungsverlauf in messages und den aktiven System-Prompt. Geben Sie { outcome: "block", reason, message? } zurück, um die Ausführung zu stoppen, bevor das Modell den Prompt lesen kann. reason ist intern; message ist der benutzerseitige Ersatz. Die einzigen unterstützten Ergebnisse sind pass und block; nicht unterstützte Entscheidungsformen schlagen geschlossen fehl.
Wenn eine Ausführung 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 weder im Transkript noch in künftigem Kontext beibehalten. Interne Blockierungsgründe werden als sensibel behandelt und aus Transkript-, Verlaufs-, Broadcast-, Log- und Diagnose-Payloads ausgeschlossen. Beobachtbarkeit sollte bereinigte Felder wie Blocker-ID, Ergebnis, Zeitstempel oder eine sichere Kategorie verwenden.
before_agent_start und agent_end enthalten event.runId, wenn OpenClaw die aktive Ausführung identifizieren kann. Derselbe Wert ist auch auf ctx.runId verfügbar. Cron-gesteuerte Ausführungen 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 beschränken können.
Bei channel-originierenden Ausführungen ist ctx.messageProvider die Provider-Oberfläche wie discord oder telegram, während ctx.channelId der Zielbezeichner der Konversation ist, wenn OpenClaw ihn aus dem Sitzungsschlüssel oder Zustellmetadaten ableiten kann.
agent_end ist ein Beobachtungs-Hook und läuft nach dem Durchlauf nach dem Fire-and-forget-Prinzip. Der Hook-Runner wendet ein Timeout von 30 Sekunden an, damit ein blockiertes Plugin oder ein Embedding-Endpunkt das Hook-Promise nicht dauerhaft ausstehend lässt. 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 Abort-Signal.
Verwenden Sie model_call_started und model_call_ended für Provider-Aufruf-Telemetrie, die keine rohen Prompts, Verläufe, Antworten, Header, Request-Bodies 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 läuft nur, wenn ein Harness im Begriff ist, eine natürliche finale Assistant-Antwort zu akzeptieren. Es ist nicht der /stop-Abbruchpfad und läuft nicht, wenn der Benutzer einen Durchlauf abbricht. Geben Sie { action: "revise", reason } zurück, um vom 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.
Bei der Rückgabe von action: "revise" können Plugins retry-Metadaten einschließen, um den zusätzlichen Modelldurchlauf begrenzt und replay-sicher zu machen:
type BeforeAgentFinalizeRetry = {
instruction: string;
idempotencyKey?: string;
maxAttempts?: number;
};
instruction wird an den Revisionsgrund angehängt, der an das Harness gesendet wird.
idempotencyKey lässt den Host Wiederholungen für dieselbe Plugin-Anfrage über
äquivalente Finalisierungsentscheidungen hinweg zählen, und maxAttempts begrenzt, wie viele zusätzliche Durchläufe der
Host zulässt, bevor er mit der natürlichen endgültigen 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": {
"my-plugin": {
"hooks": {
"allowConversationAccess": true
}
}
}
}
}
Prompt-verändernde Hooks und dauerhafte Einspeisungen für die nächste Runde können pro Plugin
mit plugins.entries.<id>.hooks.allowPromptInjection=false deaktiviert werden.
Sitzungserweiterungen und Einspeisungen für die nächste Runde
Workflow-Plugins können kleinen JSON-kompatiblen Sitzungszustand mit
api.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 darstellen können, ohne Plugin-Interna zu kennen.
Verwenden Sie api.enqueueNextTurnInjection(...), wenn ein Plugin dauerhaften Kontext
genau einmal bis zur nächsten Modellrunde bringen muss. OpenClaw leert eingereihte Einspeisungen vor
Prompt-Hooks, verwirft abgelaufene Einspeisungen und dedupliziert pro Plugin nach idempotencyKey.
Dies ist die richtige Schnittstelle für Genehmigungsfortsetzungen, Richtlinienzusammenfassungen,
Deltas von Hintergrundmonitoren und Befehlsfortsetzungen, die für das Modell in der nächsten Runde
sichtbar sein sollen, aber nicht zu dauerhaftem System-Prompt-Text werden sollen.
Bereinigungssemantik ist Teil des Vertrags. Bereinigung von Sitzungserweiterungen und
Bereinigungs-Callbacks des Laufzeit-Lebenszyklus erhalten reset, delete, disable oder
restart. Der Host entfernt den persistenten Sitzungserweiterungszustand des besitzenden Plugins
und ausstehende Einspeisungen für die nächste Runde bei Zurücksetzen/Löschen/Deaktivieren; Neustart behält
dauerhaften Sitzungszustand bei, während Bereinigungs-Callbacks Plugins Scheduler-Jobs,
Ausführungskontext und andere Out-of-band-Ressourcen für die alte Laufzeitgeneration
freigeben lassen.
Nachrichten-Hooks
Verwenden Sie Nachrichten-Hooks für Routing auf Kanalebene und Zustellrichtlinien:
message_received: eingehenden Inhalt, Absender,threadId,messageId,senderId, optionale Ausführungs-/Sitzungskorrelation und Metadaten beobachten.message_sending:contentumschreiben oder{ cancel: true }zurückgeben.message_sent: endgültigen Erfolg oder Fehler beobachten.
Für reine Audio-TTS-Antworten kann content das verborgene gesprochene Transkript enthalten,
auch wenn die Kanal-Nutzlast 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 veraltete 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.
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 Sie gateway_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 langlaufende
Ressourcen zu bereinigen.
Verlassen Sie sich für Plugin-eigene Laufzeitdienste nicht auf den internen Hook
gateway:startup.
cron_changed wird für Gateway-eigene Cron-Lebenszyklusereignisse mit einer typisierten
Ereignis-Nutzlast 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 Snapshot des gelöschten Jobs, damit externe Scheduler den
Zustand abgleichen können. Verwenden Sie ctx.getCron?.() und ctx.config aus dem Laufzeitkontext,
wenn Sie externe Weck-Scheduler synchronisieren, und behalten Sie OpenClaw als
maßgebliche Quelle für Fälligkeitsprüfungen und Ausführung bei.
Bevorstehende Abkündigungen
Einige hook-nahe Oberflächen sind abgekündigt, werden aber weiterhin unterstützt. Migrieren Sie vor dem nächsten Major-Release:
- Klartext-Kanalumschläge in Handlern für
inbound_claimundmessage_received. Lesen Sie stattdessenBodyForAgentund die strukturierten Benutzerkontextblöcke, statt flachen Umschlagtext zu parsen. Siehe Klartext-Kanalumschläge → BodyForAgent. before_agent_startbleibt aus Kompatibilitätsgründen erhalten. Neue Plugins sollten stattdessenbefore_model_resolveundbefore_prompt_buildanstelle der kombinierten Phase verwenden.onResolutioninbefore_tool_callverwendet jetzt die typisierte UnionPluginApprovalResolution(allow-once/allow-always/deny/timeout/cancelled) anstelle eines frei formuliertenstring.
Die vollständige Liste - Registrierung von Speicherfähigkeiten, Provider-Denkprofil,
externe Authentifizierungs-Provider, Provider-Erkennungstypen, Task-Laufzeit-Accessors
und die Umbenennung von command-auth zu command-status - finden Sie unter
Plugin-SDK-Migration → Aktive Abkündigungen.
Verwandt
- Plugin-SDK-Migration - aktive Abkündigungen und Zeitplan für die Entfernung
- Plugins erstellen
- Plugin-SDK-Übersicht
- Plugin-Einstiegspunkte
- Interne Hooks
- Plugin-Architektur-Interna