Plugins (Extensions)
Schnellstart (neu bei Plugins?)
Ein Plugin ist einfach ein kleines Code-Modul, das OpenClaw um zusätzliche Funktionen erweitert (Befehle, Tools und Gateway-RPC).
Meistens wirst du Plugins verwenden, wenn du ein Feature willst, das noch nicht in Core-OpenClaw eingebaut ist (oder wenn du optionale Features aus deiner Hauptinstallation heraushalten willst).
Schneller Einstieg:
- Sieh dir an, was bereits geladen ist:
openclaw plugins list
- Installiere ein offizielles Plugin (Beispiel: Voice Call):
openclaw plugins install @openclaw/voice-call
Npm-Specs sind registry-only (Paketname + optionale exakte Version oder dist-tag). Git/URL/Datei-Specs und Semver-Ranges werden abgelehnt.
Bare-Specs und @latest bleiben auf dem stabilen Track. Wenn npm eines davon
zu einer Prerelease auflöst, stoppt OpenClaw und fordert dich auf, explizit mit einem
Prerelease-Tag wie @beta/@rc oder einer exakten Prerelease-Version zu bestätigen.
- Starte das Gateway neu, dann konfiguriere unter
plugins.entries.<id>.config.
Siehe Voice Call für ein konkretes Beispiel-Plugin. Suchst du Drittanbieter-Listings? Siehe Community-Plugins.
Architektur
OpenClaws Plugin-System hat vier Ebenen:
- Manifest + Discovery
OpenClaw findet Plugin-Kandidaten aus konfigurierten Pfaden, Workspace-Roots,
globalen Extension-Roots und gebündelten Extensions. Discovery liest zuerst
openclaw.plugin.jsonplus Paket-Metadaten. - Aktivierung + Validierung Core entscheidet, ob ein entdecktes Plugin aktiviert, deaktiviert, blockiert oder für einen exklusiven Slot wie Memory ausgewählt wird.
- Runtime-Laden Aktivierte Plugins werden in-process via jiti geladen und registrieren Fähigkeiten in einer zentralen Registry.
- Oberflächen-Konsum Der Rest von OpenClaw liest die Registry, um Tools, Kanäle, Provider-Setup, Hooks, HTTP-Routen, CLI-Befehle und Services zu exponieren.
Die wichtige Design-Grenze:
- Discovery + Config-Validierung sollte aus Manifest/Schema-Metadaten funktionieren, ohne Plugin-Code auszuführen
- Runtime-Verhalten kommt vom
register(api)-Pfad des Plugin-Moduls
Diese Trennung erlaubt OpenClaw, Config zu validieren, fehlende/deaktivierte Plugins zu erklären und UI/Schema-Hinweise zu erstellen, bevor die vollständige Runtime aktiv ist.
Ausführungsmodell
Plugins laufen in-process mit dem Gateway. Sie sind nicht gesandboxt. Ein geladenes Plugin hat die gleiche Prozess-Vertrauensgrenze wie Core-Code.
Auswirkungen:
- ein Plugin kann Tools, Netzwerk-Handler, Hooks und Services registrieren
- ein Plugin-Bug kann das Gateway zum Absturz bringen oder destabilisieren
- ein bösartiges Plugin entspricht beliebiger Codeausführung innerhalb des OpenClaw-Prozesses
Verwende Allowlists und explizite Install/Load-Pfade für nicht gebündelte Plugins. Behandle Workspace-Plugins als Entwicklungscode, nicht als Produktions-Defaults.
Wichtiger Vertrauenshinweis:
plugins.allowvertraut Plugin-IDs, nicht der Quell-Provenienz.- Ein Workspace-Plugin mit derselben ID wie ein gebündeltes Plugin überschattet absichtlich die gebündelte Kopie, wenn dieses Workspace-Plugin aktiviert/in der Allowlist ist.
- Das ist normal und nützlich für lokale Entwicklung, Patch-Tests und Hotfixes.
Verfügbare Plugins (offiziell)
- Microsoft Teams ist seit 2026.1.15 nur als Plugin verfügbar; installiere
@openclaw/msteams, wenn du Teams verwendest. - Memory (Core) — gebündeltes Memory-Search-Plugin (standardmäßig aktiviert über
plugins.slots.memory) - Memory (LanceDB) — gebündeltes Langzeit-Memory-Plugin (Auto-Recall/Capture; setze
plugins.slots.memory = "memory-lancedb") - Voice Call —
@openclaw/voice-call - Zalo Personal —
@openclaw/zalouser - Matrix —
@openclaw/matrix - Nostr —
@openclaw/nostr - Zalo —
@openclaw/zalo - Microsoft Teams —
@openclaw/msteams - Google Antigravity OAuth (Provider-Auth) — gebündelt als
google-antigravity-auth(standardmäßig deaktiviert) - Gemini CLI OAuth (Provider-Auth) — gebündelt als
google-gemini-cli-auth(standardmäßig deaktiviert) - Qwen OAuth (Provider-Auth) — gebündelt als
qwen-portal-auth(standardmäßig deaktiviert) - Copilot Proxy (Provider-Auth) — lokale VS Code Copilot Proxy-Brücke; verschieden vom eingebauten
github-copilotDevice Login (gebündelt, standardmäßig deaktiviert)
OpenClaw-Plugins sind TypeScript-Module, die zur Runtime via jiti geladen werden. Config-Validierung führt keinen Plugin-Code aus; sie verwendet stattdessen das Plugin-Manifest und JSON Schema. Siehe Plugin-Manifest.
Plugins können registrieren:
- Gateway-RPC-Methoden
- Gateway-HTTP-Routen
- Agent-Tools
- CLI-Befehle
- Hintergrund-Services
- Kontext-Engines
- Optionale Config-Validierung
- Skills (durch Auflistung von
skills-Verzeichnissen im Plugin-Manifest) - Auto-Reply-Befehle (ausführen ohne KI-Agent-Aufruf)
Plugins laufen in-process mit dem Gateway, behandle sie also als vertrauenswürdigen Code. Tool-Entwicklungsanleitung: Plugin Agent-Tools.
Lade-Pipeline
Beim Start führt OpenClaw grob Folgendes durch:
- Plugin-Root-Kandidaten entdecken
openclaw.plugin.jsonund Paket-Metadaten lesen- Unsichere Kandidaten ablehnen
- Plugin-Config normalisieren (
plugins.enabled,allow,deny,entries,slots,load.paths) - Aktivierung für jeden Kandidaten entscheiden
- Aktivierte Module via jiti laden
register(api)aufrufen und Registrierungen in der Plugin-Registry sammeln- Registry für Befehle/Runtime-Oberflächen exponieren
Die Sicherheits-Gates greifen vor der Runtime-Ausführung. Kandidaten werden blockiert, wenn der Entry das Plugin-Root verlässt, der Pfad world-writable ist oder die Pfad-Ownership für nicht gebündelte Plugins verdächtig aussieht.
Manifest-First-Verhalten
Das Manifest ist die Control-Plane-Wahrheitsquelle. OpenClaw verwendet es um:
- das Plugin zu identifizieren
- deklarierte Kanäle/Skills/Config-Schema zu entdecken
plugins.entries.<id>.configzu validieren- Control-UI-Labels/Platzhalter zu ergänzen
- Install/Katalog-Metadaten anzuzeigen
Das Runtime-Modul ist der Data-Plane-Teil. Es registriert tatsächliches Verhalten wie Hooks, Tools, Befehle oder Provider-Flows.
Was der Loader cached
OpenClaw hält kurze In-Process-Caches für:
- Discovery-Ergebnisse
- Manifest-Registry-Daten
- Geladene Plugin-Registries
Diese Caches reduzieren stoßweisen Start- und wiederholten Befehls-Overhead. Sie sind als kurzlebige Performance-Caches zu betrachten, nicht als Persistenz.
Runtime-Helpers
Plugins können über api.runtime auf ausgewählte Core-Helpers zugreifen. Für Telefonie-TTS:
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
Hinweise:
- Verwendet die Core-
messages.tts-Konfiguration (OpenAI oder ElevenLabs). - Gibt PCM-Audio-Buffer + Sample-Rate zurück. Plugins müssen für Provider resamplen/enkodieren.
- Edge TTS wird für Telefonie nicht unterstützt.
Für STT/Transkription können Plugins aufrufen:
const { text } = await api.runtime.stt.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// Optional wenn MIME nicht zuverlässig abgeleitet werden kann:
mime: "audio/ogg",
});
Hinweise:
- Verwendet die Core-Media-Understanding-Audio-Konfiguration (
tools.media.audio) und Provider-Fallback-Reihenfolge. - Gibt
{ text: undefined }zurück, wenn keine Transkriptionsausgabe erzeugt wird (z.B. übersprungene/nicht unterstützte Eingabe).
Gateway-HTTP-Routen
Plugins können HTTP-Endpoints mit api.registerHttpRoute(...) exponieren.
api.registerHttpRoute({
path: "/acme/webhook",
auth: "plugin",
match: "exact",
handler: async (_req, res) => {
res.statusCode = 200;
res.end("ok");
return true;
},
});
Routen-Felder:
path: Routenpfad unter dem Gateway-HTTP-Server.auth: erforderlich. Verwende"gateway"für normale Gateway-Auth oder"plugin"für plugin-verwaltete Auth/Webhook-Verifikation.match: optional."exact"(Standard) oder"prefix".replaceExisting: optional. Erlaubt demselben Plugin, seine eigene bestehende Routen-Registrierung zu ersetzen.handler: gibttruezurück, wenn die Route die Anfrage bearbeitet hat.
Hinweise:
api.registerHttpHandler(...)ist veraltet. Verwendeapi.registerHttpRoute(...).- Plugin-Routen müssen
authexplizit deklarieren. - Exakte
path + match-Konflikte werden abgelehnt, es sei dennreplaceExisting: true, und ein Plugin kann nicht die Route eines anderen Plugins ersetzen. - Überlappende Routen mit unterschiedlichen
auth-Levels werden abgelehnt. Halteexact/prefix-Fallthrough-Ketten auf demselben Auth-Level.
Plugin-SDK-Import-Pfade
Verwende SDK-Subpaths statt des monolithischen openclaw/plugin-sdk-Imports beim
Entwickeln von Plugins:
openclaw/plugin-sdk/corefür generische Plugin-APIs, Provider-Auth-Typen und gemeinsame Helpers.openclaw/plugin-sdk/compatfür gebündelten/internen Plugin-Code, der breitere gemeinsame Runtime-Helpers alscorebraucht.openclaw/plugin-sdk/telegramfür Telegram-Kanal-Plugins.openclaw/plugin-sdk/discordfür Discord-Kanal-Plugins.openclaw/plugin-sdk/slackfür Slack-Kanal-Plugins.openclaw/plugin-sdk/signalfür Signal-Kanal-Plugins.openclaw/plugin-sdk/imessagefür iMessage-Kanal-Plugins.openclaw/plugin-sdk/whatsappfür WhatsApp-Kanal-Plugins.openclaw/plugin-sdk/linefür LINE-Kanal-Plugins.openclaw/plugin-sdk/msteamsfür die gebündelte Microsoft Teams-Plugin-Oberfläche.- Gebündelte extension-spezifische Subpaths sind ebenfalls verfügbar:
openclaw/plugin-sdk/acpx,openclaw/plugin-sdk/bluebubbles,openclaw/plugin-sdk/copilot-proxy,openclaw/plugin-sdk/device-pair,openclaw/plugin-sdk/diagnostics-otel,openclaw/plugin-sdk/diffs,openclaw/plugin-sdk/feishu,openclaw/plugin-sdk/google-gemini-cli-auth,openclaw/plugin-sdk/googlechat,openclaw/plugin-sdk/irc,openclaw/plugin-sdk/llm-task,openclaw/plugin-sdk/lobster,openclaw/plugin-sdk/matrix,openclaw/plugin-sdk/mattermost,openclaw/plugin-sdk/memory-core,openclaw/plugin-sdk/memory-lancedb,openclaw/plugin-sdk/minimax-portal-auth,openclaw/plugin-sdk/nextcloud-talk,openclaw/plugin-sdk/nostr,openclaw/plugin-sdk/open-prose,openclaw/plugin-sdk/phone-control,openclaw/plugin-sdk/qwen-portal-auth,openclaw/plugin-sdk/synology-chat,openclaw/plugin-sdk/talk-voice,openclaw/plugin-sdk/test-utils,openclaw/plugin-sdk/thread-ownership,openclaw/plugin-sdk/tlon,openclaw/plugin-sdk/twitch,openclaw/plugin-sdk/voice-call,openclaw/plugin-sdk/zaloundopenclaw/plugin-sdk/zalouser.
Kompatibilitätshinweis:
openclaw/plugin-sdkwird für bestehende externe Plugins weiterhin unterstützt.- Neue und migrierte gebündelte Plugins sollten kanal- oder extension-spezifische
Subpaths verwenden; verwende
corefür generische Oberflächen undcompatnur, wenn breitere gemeinsame Helpers benötigt werden.
Read-only-Kanal-Inspektion
Wenn dein Plugin einen Kanal registriert, implementiere bevorzugt
plugin.config.inspectAccount(cfg, accountId) neben resolveAccount(...).
Warum:
resolveAccount(...)ist der Runtime-Pfad. Es darf davon ausgehen, dass Credentials vollständig materialisiert sind, und kann bei fehlenden Secrets sofort abbrechen.- Read-only-Befehlspfade wie
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolveund Doctor/Config-Reparatur-Flows sollten keine Runtime-Credentials materialisieren müssen, nur um die Konfiguration zu beschreiben.
Empfohlenes inspectAccount(...)-Verhalten:
- Nur beschreibenden Account-Status zurückgeben.
enabledundconfiguredbewahren.- Credential-Source/Status-Felder einschließen, wenn relevant, wie:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Du musst keine rohen Token-Werte zurückgeben, nur um Read-only-Verfügbarkeit zu melden.
tokenStatus: "available"(und das passende Source-Feld) zurückzugeben reicht für Status-Befehle. - Verwende
configured_unavailable, wenn ein Credential via SecretRef konfiguriert ist, aber im aktuellen Befehlspfad nicht verfügbar.
Damit können Read-only-Befehle “konfiguriert aber in diesem Befehlspfad nicht verfügbar” melden, statt abzustürzen oder den Account falsch als nicht konfiguriert zu melden.
Performance-Hinweis:
- Plugin-Discovery und Manifest-Metadaten verwenden kurze In-Process-Caches, um stoßweise Start-/Reload-Arbeit zu reduzieren.
- Setze
OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1oderOPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1, um diese Caches zu deaktivieren. - Cache-Fenster über
OPENCLAW_PLUGIN_DISCOVERY_CACHE_MSundOPENCLAW_PLUGIN_MANIFEST_CACHE_MSanpassen.
Discovery & Rangfolge
OpenClaw scannt in dieser Reihenfolge:
- Config-Pfade
plugins.load.paths(Datei oder Verzeichnis)
- Workspace-Extensions
<workspace>/.openclaw/extensions/*.ts<workspace>/.openclaw/extensions/*/index.ts
- Globale Extensions
~/.openclaw/extensions/*.ts~/.openclaw/extensions/*/index.ts
- Gebündelte Extensions (mit OpenClaw ausgeliefert, meist standardmäßig deaktiviert)
<openclaw>/extensions/*
Die meisten gebündelten Plugins müssen explizit über
plugins.entries.<id>.enabled oder openclaw plugins enable <id> aktiviert werden.
Standardmäßig aktivierte gebündelte Plugin-Ausnahmen:
device-pairphone-controltalk-voice- aktives Memory-Slot-Plugin (Standard-Slot:
memory-core)
Installierte Plugins sind standardmäßig aktiviert, können aber auf die gleiche Weise deaktiviert werden.
Workspace-Plugins sind standardmäßig deaktiviert, es sei denn, du aktivierst sie explizit oder setzt sie auf die Allowlist. Das ist beabsichtigt: Ein ausgechecktes Repo sollte nicht stillschweigend zu Produktions-Gateway-Code werden.
Härtungs-Hinweise:
- Wenn
plugins.allowleer ist und nicht gebündelte Plugins auffindbar sind, loggt OpenClaw eine Startup-Warnung mit Plugin-IDs und Quellen. - Kandidatenpfade werden vor der Discovery-Aufnahme sicherheitsgeprüft. OpenClaw blockiert Kandidaten wenn:
- der Extension-Entry das Plugin-Root verlässt (einschließlich Symlink/Pfad-Traversal-Escapes),
- Plugin-Root/Quellpfad world-writable ist,
- Pfad-Ownership für nicht gebündelte Plugins verdächtig ist (POSIX-Owner ist weder aktuelle UID noch Root).
- Geladene nicht gebündelte Plugins ohne Install/Load-Path-Provenienz geben eine Warnung aus, damit du Vertrauen pinnen (
plugins.allow) oder Install-Tracking (plugins.installs) einrichten kannst.
Jedes Plugin muss eine openclaw.plugin.json-Datei in seinem Root enthalten. Wenn ein Pfad
auf eine Datei zeigt, ist das Plugin-Root das Verzeichnis der Datei und muss das
Manifest enthalten.
Wenn mehrere Plugins zur gleichen ID aufgelöst werden, gewinnt der erste Treffer in der obigen Reihenfolge und Kopien mit niedrigerer Priorität werden ignoriert.
Das bedeutet:
- Workspace-Plugins überschatten absichtlich gebündelte Plugins mit derselben ID
plugins.allow: ["foo"]autorisiert das aktivefoo-Plugin nach ID, auch wenn die aktive Kopie aus dem Workspace statt dem gebündelten Extension-Root kommt- wenn du striktere Provenienz-Kontrolle brauchst, verwende explizite Install/Load-Pfade und inspiziere die aufgelöste Plugin-Quelle vor dem Aktivieren
Aktivierungsregeln
Aktivierung wird nach der Discovery aufgelöst:
plugins.enabled: falsedeaktiviert alle Pluginsplugins.denygewinnt immerplugins.entries.<id>.enabled: falsedeaktiviert dieses Plugin- Workspace-Origin-Plugins sind standardmäßig deaktiviert
- Allowlists schränken das aktive Set ein, wenn
plugins.allownicht leer ist - Allowlists sind ID-basiert, nicht quell-basiert
- Gebündelte Plugins sind standardmäßig deaktiviert, es sei denn:
- die gebündelte ID ist im eingebauten Standard-An-Set, oder
- du aktivierst es explizit, oder
- Kanal-Config aktiviert das gebündelte Kanal-Plugin implizit
- Exklusive Slots können das ausgewählte Plugin für diesen Slot erzwingen
In aktuellem Core gehören zu den gebündelten Standard-An-IDs lokale/Provider-Helpers wie
ollama, sglang, vllm, plus device-pair, phone-control und
talk-voice.
Paket-Packs
Ein Plugin-Verzeichnis kann ein package.json mit openclaw.extensions enthalten:
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"]
}
}
Jeder Eintrag wird ein Plugin. Wenn das Pack mehrere Extensions listet, wird die Plugin-ID
zu name/<fileBase>.
Wenn dein Plugin npm-Deps importiert, installiere sie in diesem Verzeichnis, damit
node_modules verfügbar ist (npm install / pnpm install).
Sicherheitsschutz: Jeder openclaw.extensions-Eintrag muss nach Symlink-Auflösung innerhalb des Plugin-Verzeichnisses bleiben. Einträge, die das Paketverzeichnis verlassen, werden abgelehnt.
Sicherheitshinweis: openclaw plugins install installiert Plugin-Dependencies mit
npm install --ignore-scripts (keine Lifecycle-Scripts). Halte Plugin-Dependency-Trees
“reines JS/TS” und vermeide Pakete, die postinstall-Builds erfordern.
Kanal-Katalog-Metadaten
Kanal-Plugins können Onboarding-Metadaten über openclaw.channel und
Install-Hinweise über openclaw.install bewerben. Das hält den Core-Katalog datenfrei.
Beispiel:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk (self-hosted)",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "extensions/nextcloud-talk",
"defaultChoice": "npm"
}
}
}
OpenClaw kann auch externe Kanal-Kataloge zusammenführen (zum Beispiel einen MPM-Registry-Export). Lege eine JSON-Datei an einem der folgenden Orte ab:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
Oder zeige OPENCLAW_PLUGIN_CATALOG_PATHS (oder OPENCLAW_MPM_CATALOG_PATHS) auf
eine oder mehrere JSON-Dateien (Komma/Semikolon/PATH-getrennt). Jede Datei sollte
{ "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] } enthalten.
Plugin-IDs
Standard-Plugin-IDs:
- Paket-Packs:
package.jsonname - Standalone-Datei: Datei-Basisname (
~/.../voice-call.ts→voice-call)
Wenn ein Plugin id exportiert, verwendet OpenClaw es, warnt aber, wenn es nicht mit der
konfigurierten ID übereinstimmt.
Registry-Modell
Geladene Plugins mutieren nicht direkt zufällige Core-Globals. Sie registrieren sich in einer zentralen Plugin-Registry.
Die Registry verfolgt:
- Plugin-Records (Identität, Quelle, Herkunft, Status, Diagnosen)
- Tools
- Legacy-Hooks und typisierte Hooks
- Kanäle
- Provider
- Gateway-RPC-Handler
- HTTP-Routen
- CLI-Registrars
- Hintergrund-Services
- Plugin-eigene Befehle
Core-Features lesen dann aus dieser Registry, statt direkt mit Plugin-Modulen zu sprechen. Das hält das Laden einseitig:
- Plugin-Modul -> Registry-Registrierung
- Core-Runtime -> Registry-Konsum
Diese Trennung ist wichtig für die Wartbarkeit. Sie bedeutet, dass die meisten Core-Oberflächen nur einen Integrationspunkt brauchen: “Registry lesen”, nicht “jeden Plugin-Modul speziell behandeln”.
Konfiguration
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-extension"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } },
},
},
}
Felder:
enabled: Master-Toggle (Standard: true)allow: Allowlist (optional)deny: Denylist (optional; Deny gewinnt)load.paths: extra Plugin-Dateien/Verzeichnisseslots: exklusive Slot-Selektoren wiememoryundcontextEngineentries.<id>: pro-Plugin-Toggles + Config
Config-Änderungen erfordern einen Gateway-Neustart.
Validierungsregeln (strikt):
- Unbekannte Plugin-IDs in
entries,allow,denyoderslotssind Fehler. - Unbekannte
channels.<id>-Keys sind Fehler, es sei denn, ein Plugin-Manifest deklariert die Kanal-ID. - Plugin-Config wird gegen das in
openclaw.plugin.json(configSchema) eingebettete JSON Schema validiert. - Wenn ein Plugin deaktiviert ist, wird seine Config bewahrt und eine Warnung ausgegeben.
Deaktiviert vs. fehlend vs. ungültig
Diese Zustände sind absichtlich unterschiedlich:
- deaktiviert: Plugin existiert, aber Aktivierungsregeln haben es ausgeschaltet
- fehlend: Config referenziert eine Plugin-ID, die Discovery nicht gefunden hat
- ungültig: Plugin existiert, aber seine Config passt nicht zum deklarierten Schema
OpenClaw bewahrt Config für deaktivierte Plugins, damit ein erneutes Einschalten nicht destruktiv ist.
Plugin-Slots (exklusive Kategorien)
Einige Plugin-Kategorien sind exklusiv (nur eins gleichzeitig aktiv). Verwende
plugins.slots, um auszuwählen, welches Plugin den Slot besitzt:
{
plugins: {
slots: {
memory: "memory-core", // oder "none" um Memory-Plugins zu deaktivieren
contextEngine: "legacy", // oder eine Plugin-ID wie "lossless-claw"
},
},
}
Unterstützte exklusive Slots:
memory: aktives Memory-Plugin ("none"deaktiviert Memory-Plugins)contextEngine: aktive Kontext-Engine-Plugin ("legacy"ist der eingebaute Standard)
Wenn mehrere Plugins kind: "memory" oder kind: "context-engine" deklarieren, wird nur
das ausgewählte Plugin für diesen Slot geladen. Andere werden mit Diagnosen deaktiviert.
Kontext-Engine-Plugins
Kontext-Engine-Plugins besitzen die Session-Kontext-Orchestrierung für Ingestion, Assembly
und Compaction. Registriere sie in deinem Plugin mit
api.registerContextEngine(id, factory), dann wähle die aktive Engine mit
plugins.slots.contextEngine.
Verwende das, wenn dein Plugin die Standard-Kontextpipeline ersetzen oder erweitern muss, statt nur Memory-Suche oder Hooks hinzuzufügen.
Control-UI (Schema + Labels)
Die Control-UI verwendet config.schema (JSON Schema + uiHints), um bessere Formulare zu rendern.
OpenClaw ergänzt uiHints zur Runtime basierend auf entdeckten Plugins:
- Fügt pro-Plugin-Labels für
plugins.entries.<id>/.enabled/.confighinzu - Mergt optionale plugin-bereitgestellte Config-Feld-Hinweise unter:
plugins.entries.<id>.config.<field>
Wenn du möchtest, dass deine Plugin-Config-Felder gute Labels/Platzhalter anzeigen (und Secrets als sensitiv markieren),
stelle uiHints neben deinem JSON Schema im Plugin-Manifest bereit.
Beispiel:
{
"id": "my-plugin",
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": { "type": "string" },
"region": { "type": "string" }
}
},
"uiHints": {
"apiKey": { "label": "API Key", "sensitive": true },
"region": { "label": "Region", "placeholder": "us-east-1" }
}
}
CLI
openclaw plugins list
openclaw plugins info <id>
openclaw plugins install <path> # eine lokale Datei/Verzeichnis nach ~/.openclaw/extensions/<id> kopieren
openclaw plugins install ./extensions/voice-call # relativer Pfad ok
openclaw plugins install ./plugin.tgz # aus lokalem Tarball installieren
openclaw plugins install ./plugin.zip # aus lokalem Zip installieren
openclaw plugins install -l ./extensions/voice-call # linken (keine Kopie) für Entwicklung
openclaw plugins install @openclaw/voice-call # von npm installieren
openclaw plugins install @openclaw/voice-call --pin # exakten aufgelösten name@version speichern
openclaw plugins update <id>
openclaw plugins update --all
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins doctor
plugins update funktioniert nur für npm-Installationen, die unter plugins.installs getrackt werden.
Wenn sich gespeicherte Integritäts-Metadaten zwischen Updates ändern, warnt OpenClaw und bittet um Bestätigung (verwende globales --yes zum Umgehen von Prompts).
Plugins können auch eigene Top-Level-Befehle registrieren (Beispiel: openclaw voicecall).
Plugin-API (Überblick)
Plugins exportieren entweder:
- Eine Funktion:
(api) => { ... } - Ein Objekt:
{ id, name, configSchema, register(api) { ... } }
register(api) ist, wo Plugins Verhalten anhängen. Häufige Registrierungen umfassen:
registerToolregisterHookon(...)für typisierte Lifecycle-HooksregisterChannelregisterProviderregisterHttpRouteregisterCommandregisterCliregisterContextEngineregisterService
Kontext-Engine-Plugins können auch einen Runtime-eigenen Kontext-Manager registrieren:
export default function (api) {
api.registerContextEngine("lossless-claw", () => ({
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
async ingest() {
return { ingested: true };
},
async assemble({ messages }) {
return { messages, estimatedTokens: 0 };
},
async compact() {
return { ok: true, compacted: false };
},
}));
}
Dann in der Config aktivieren:
{
plugins: {
slots: {
contextEngine: "lossless-claw",
},
},
}
Plugin-Hooks
Plugins können Hooks zur Runtime registrieren. Das erlaubt einem Plugin, event-getriebene Automatisierung zu bündeln, ohne ein separates Hook-Pack zu installieren.
Beispiel
export default function register(api) {
api.registerHook(
"command:new",
async () => {
// Hook-Logik hier.
},
{
name: "my-plugin.command-new",
description: "Runs when /new is invoked",
},
);
}
Hinweise:
- Hooks explizit über
api.registerHook(...)registrieren. - Hook-Berechtigungsregeln gelten weiterhin (OS/Bins/Env/Config-Anforderungen).
- Plugin-verwaltete Hooks erscheinen in
openclaw hooks listmitplugin:<id>. - Du kannst Plugin-verwaltete Hooks nicht über
openclaw hooksaktivieren/deaktivieren; aktiviere/deaktiviere stattdessen das Plugin.
Agent-Lifecycle-Hooks (api.on)
Für typisierte Runtime-Lifecycle-Hooks verwende api.on(...):
export default function register(api) {
api.on(
"before_prompt_build",
(event, ctx) => {
return {
prependSystemContext: "Follow company style guide.",
};
},
{ priority: 10 },
);
}
Wichtige Hooks für Prompt-Konstruktion:
before_model_resolve: läuft vor dem Session-Laden (messagessind nicht verfügbar). Verwende dies, um deterministischmodelOverrideoderproviderOverridezu überschreiben.before_prompt_build: läuft nach dem Session-Laden (messagessind verfügbar). Verwende dies, um Prompt-Input zu formen.before_agent_start: Legacy-Kompatibilitäts-Hook. Bevorzuge die zwei expliziten Hooks oben.
Core-erzwungene Hook-Policy:
- Operatoren können Prompt-Mutations-Hooks pro Plugin über
plugins.entries.<id>.hooks.allowPromptInjection: falsedeaktivieren. - Wenn deaktiviert, blockiert OpenClaw
before_prompt_buildund ignoriert prompt-mutierende Felder, die vom Legacy-before_agent_startzurückgegeben werden, bewahrt aber Legacy-modelOverrideundproviderOverride.
before_prompt_build-Ergebnisfelder:
prependContext: Text dem User-Prompt für diesen Run voranstellen. Am besten für turn-spezifischen oder dynamischen Content.systemPrompt: vollständiger System-Prompt-Override.prependSystemContext: Text dem aktuellen System-Prompt voranstellen.appendSystemContext: Text an den aktuellen System-Prompt anhängen.
Prompt-Build-Reihenfolge in der eingebetteten Runtime:
prependContextauf den User-Prompt anwenden.systemPrompt-Override anwenden, wenn vorhanden.prependSystemContext + aktueller System-Prompt + appendSystemContextanwenden.
Merge- und Rangfolge-Hinweise:
- Hook-Handler laufen nach Priorität (höher zuerst).
- Für gemergte Kontext-Felder werden Werte in Ausführungsreihenfolge konkateniert.
before_prompt_build-Werte werden vor Legacy-before_agent_start-Fallback-Werten angewendet.
Migrations-Anleitung:
- Verschiebe statische Anleitung von
prependContextnachprependSystemContext(oderappendSystemContext), damit Provider stabilen System-Prefix-Content cachen können. - Behalte
prependContextfür pro-Turn dynamischen Kontext, der an die Benutzernachricht gebunden bleiben soll.
Provider-Plugins (Model-Auth)
Plugins können Model-Provider registrieren, damit Benutzer OAuth- oder API-Key-Setup innerhalb von OpenClaw durchführen, Provider-Setup im Onboarding/Model-Picker darstellen und zur impliziten Provider-Discovery beitragen können.
Provider-Plugins sind die modulare Extensions-Naht für Model-Provider-Setup. Sie sind nicht nur “OAuth-Helpers” mehr.
Provider-Plugin-Lebenszyklus
Ein Provider-Plugin kann an fünf verschiedenen Phasen teilnehmen:
- Auth
auth[].run(ctx)führt OAuth, API-Key-Erfassung, Device-Code oder benutzerdefiniertes Setup durch und gibt Auth-Profile plus optionale Config-Patches zurück. - Nicht-interaktives Setup
auth[].runNonInteractive(ctx)behandeltopenclaw onboard --non-interactiveohne Prompts. Verwende dies, wenn der Provider benutzerdefiniertes headless Setup jenseits der eingebauten einfachen API-Key-Pfade braucht. - Wizard-Integration
wizard.onboardingfügt einen Eintrag zuopenclaw onboardhinzu.wizard.modelPickerfügt einen Setup-Eintrag zum Model-Picker hinzu. - Implizite Discovery
discovery.run(ctx)kann Provider-Config automatisch während der Model-Auflösung/Auflistung beitragen. - Post-Selection-Follow-Up
onModelSelected(ctx)läuft, nachdem ein Modell gewählt wurde. Verwende dies für provider-spezifische Arbeit wie das Herunterladen eines lokalen Modells.
Das ist die empfohlene Aufteilung, weil diese Phasen unterschiedliche Lifecycle-Anforderungen haben:
- Auth ist interaktiv und schreibt Credentials/Config
- nicht-interaktives Setup ist flag/env-getrieben und darf nicht prompten
- Wizard-Metadaten sind statisch und UI-gerichtet
- Discovery sollte sicher, schnell und fehlertolerant sein
- Post-Select-Hooks sind Seiteneffekte, die an das gewählte Modell gebunden sind
Provider-Auth-Vertrag
auth[].run(ctx) gibt zurück:
profiles: Auth-Profile zum SchreibenconfigPatch: optionaleopenclaw.json-ÄnderungendefaultModel: optionaleprovider/model-Referenznotes: optionale benutzerseitige Hinweise
Core dann:
- schreibt die zurückgegebenen Auth-Profile
- wendet Auth-Profil-Config-Verdrahtung an
- mergt den Config-Patch
- wendet optional das Standardmodell an
- führt den
onModelSelected-Hook des Providers aus, wenn angemessen
Das bedeutet, ein Provider-Plugin besitzt die provider-spezifische Setup-Logik, während Core den generischen Persistenz- und Config-Merge-Pfad besitzt.
Provider-nicht-interaktiver Vertrag
auth[].runNonInteractive(ctx) ist optional. Implementiere es, wenn der Provider
headless Setup braucht, das nicht durch die eingebauten generischen
API-Key-Flows ausgedrückt werden kann.
Der nicht-interaktive Kontext enthält:
- die aktuelle und Basis-Config
- geparste Onboarding-CLI-Optionen
- Runtime-Logging/Fehler-Helpers
- Agent/Workspace-Verzeichnisse
resolveApiKey(...)zum Lesen von Provider-Keys aus Flags, Env oder bestehenden Auth- Profilen unter Berücksichtigung von--secret-input-modetoApiKeyCredential(...)zum Konvertieren eines aufgelösten Keys in ein Auth-Profil- Credential mit der richtigen Plaintext- vs. Secret-Ref-Speicherung
Verwende diese Oberfläche für Provider wie:
- selbst gehostete OpenAI-kompatible Runtimes, die
--custom-base-url+--custom-model-idbrauchen - provider-spezifische nicht-interaktive Verifikation oder Config-Synthese
Prompte nicht aus runNonInteractive. Lehne fehlende Eingaben mit umsetzbaren
Fehlern ab.
Provider-Wizard-Metadaten
wizard.onboarding steuert, wie der Provider im gruppierten Onboarding erscheint:
choiceId: Auth-Choice-WertchoiceLabel: Options-LabelchoiceHint: kurzer HinweisgroupId: Gruppen-Bucket-IDgroupLabel: Gruppen-LabelgroupHint: Gruppen-HinweismethodId: auszuführende Auth-Methode
wizard.modelPicker steuert, wie ein Provider als “jetzt einrichten”-Eintrag
in der Modellauswahl erscheint:
labelhintmethodId
Wenn ein Provider mehrere Auth-Methoden hat, kann der Wizard entweder auf eine explizite Methode zeigen oder OpenClaw pro-Methode-Auswahlmöglichkeiten synthetisieren lassen.
OpenClaw validiert Provider-Wizard-Metadaten, wenn das Plugin sich registriert:
- doppelte oder leere Auth-Methoden-IDs werden abgelehnt
- Wizard-Metadaten werden ignoriert, wenn der Provider keine Auth-Methoden hat
- ungültige
methodId-Bindungen werden zu Warnungen herabgestuft und fallen auf die verbleibenden Auth-Methoden des Providers zurück
Provider-Discovery-Vertrag
discovery.run(ctx) gibt eines von folgenden zurück:
{ provider }{ providers }null
Verwende { provider } für den häufigen Fall, dass das Plugin eine Provider-ID besitzt.
Verwende { providers }, wenn ein Plugin mehrere Provider-Einträge entdeckt.
Der Discovery-Kontext enthält:
- die aktuelle Config
- Agent/Workspace-Verzeichnisse
- Prozess-Env
- einen Helper zum Auflösen des Provider-API-Keys und eines discovery-sicheren API-Key-Werts
Discovery sollte:
- schnell sein
- best-effort sein
- bei Fehler sicher zu überspringen sein
- vorsichtig mit Seiteneffekten sein
Es sollte nicht von Prompts oder lang laufendem Setup abhängen.
Discovery-Reihenfolge
Provider-Discovery läuft in geordneten Phasen:
simpleprofilepairedlate
Verwende:
simplefür günstige umgebungs-only Discoveryprofilewenn Discovery von Auth-Profilen abhängtpairedfür Provider, die sich mit einem anderen Discovery-Schritt koordinieren müssenlatefür teure oder lokale Netzwerk-Probing
Die meisten selbst gehosteten Provider sollten late verwenden.
Gute Provider-Plugin-Grenzen
Gut geeignet für Provider-Plugins:
- lokale/selbst gehostete Provider mit benutzerdefinierten Setup-Flows
- provider-spezifisches OAuth/Device-Code-Login
- implizite Discovery lokaler Model-Server
- Post-Selection-Seiteneffekte wie Model-Pulls
Weniger überzeugend:
- triviale API-Key-only Provider, die sich nur durch Env-Variable, Base-URL und ein Standardmodell unterscheiden
Diese können trotzdem Plugins werden, aber der Hauptvorteil der Modularität kommt vom Extrahieren verhaltensreicher Provider zuerst.
Registriere einen Provider über api.registerProvider(...). Jeder Provider exponiert eine
oder mehrere Auth-Methoden (OAuth, API-Key, Device-Code, etc.). Diese Methoden können
antreiben:
openclaw models auth login --provider <id> [--method <id>]openclaw onboard- Model-Picker “Custom Provider”-Setup-Einträge
- implizite Provider-Discovery während Model-Auflösung/Auflistung
Beispiel:
api.registerProvider({
id: "acme",
label: "AcmeAI",
auth: [
{
id: "oauth",
label: "OAuth",
kind: "oauth",
run: async (ctx) => {
// OAuth-Flow ausführen und Auth-Profile zurückgeben.
return {
profiles: [
{
profileId: "acme:default",
credential: {
type: "oauth",
provider: "acme",
access: "...",
refresh: "...",
expires: Date.now() + 3600 * 1000,
},
},
],
defaultModel: "acme/opus-1",
};
},
},
],
wizard: {
onboarding: {
choiceId: "acme",
choiceLabel: "AcmeAI",
groupId: "acme",
groupLabel: "AcmeAI",
methodId: "oauth",
},
modelPicker: {
label: "AcmeAI (custom)",
hint: "Connect a self-hosted AcmeAI endpoint",
methodId: "oauth",
},
},
discovery: {
order: "late",
run: async () => ({
provider: {
baseUrl: "https://acme.example/v1",
api: "openai-completions",
apiKey: "${ACME_API_KEY}",
models: [],
},
}),
},
});
Hinweise:
runempfängt einenProviderAuthContextmitprompter,runtime,openUrlundoauth.createVpsAwareHandlers-Helpers.runNonInteractiveempfängt einenProviderAuthMethodNonInteractiveContextmitopts,resolveApiKeyundtoApiKeyCredential-Helpers für headless Onboarding.- Gib
configPatchzurück, wenn du Standard-Modelle oder Provider-Config hinzufügen musst. - Gib
defaultModelzurück, damit--set-defaultAgent-Defaults aktualisieren kann. wizard.onboardingfügt eine Provider-Auswahl zuopenclaw onboardhinzu.wizard.modelPickerfügt einen “diesen Provider einrichten”-Eintrag zum Model-Picker hinzu.discovery.rungibt entweder{ provider }für die eigene Provider-ID des Plugins zurück oder{ providers }für Multi-Provider-Discovery.discovery.ordersteuert, wann der Provider relativ zu eingebauten Discovery-Phasen läuft:simple,profile,pairedoderlate.onModelSelectedist der Post-Selection-Hook für provider-spezifische Follow-Up-Arbeit wie das Pullen eines lokalen Modells.
Einen Messaging-Kanal registrieren
Plugins können Kanal-Plugins registrieren, die sich wie eingebaute Kanäle verhalten
(WhatsApp, Telegram, etc.). Kanal-Config liegt unter channels.<id> und wird
von deinem Kanal-Plugin-Code validiert.
const myChannel = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "demo channel plugin.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async () => ({ ok: true }),
},
};
export default function (api) {
api.registerChannel({ plugin: myChannel });
}
Hinweise:
- Config unter
channels.<id>ablegen (nichtplugins.entries). meta.labelwird für Labels in CLI/UI-Listen verwendet.meta.aliasesfügt alternative IDs für Normalisierung und CLI-Eingaben hinzu.meta.preferOverlistet Kanal-IDs auf, die bei Auto-Enable übersprungen werden, wenn beide konfiguriert sind.meta.detailLabelundmeta.systemImagelassen UIs reichere Kanal-Labels/Icons anzeigen.
Kanal-Onboarding-Hooks
Kanal-Plugins können optionale Onboarding-Hooks auf plugin.onboarding definieren:
configure(ctx)ist der Basis-Setup-Flow.configureInteractive(ctx)kann das interaktive Setup für sowohl konfigurierte als auch nicht konfigurierte Zustände vollständig übernehmen.configureWhenConfigured(ctx)kann das Verhalten nur für bereits konfigurierte Kanäle überschreiben.
Hook-Rangfolge im Wizard:
configureInteractive(wenn vorhanden)configureWhenConfigured(nur wenn Kanalstatus bereits konfiguriert)- Fallback auf
configure
Kontext-Details:
configureInteractiveundconfigureWhenConfigurederhalten:configured(trueoderfalse)label(benutzerseitiger Kanalname für Prompts)- plus die gemeinsamen Config/Runtime/Prompter/Options-Felder
- Die Rückgabe von
"skip"lässt Auswahl und Account-Tracking unverändert. - Die Rückgabe von
{ cfg, accountId? }wendet Config-Updates an und zeichnet die Account-Auswahl auf.
Einen neuen Messaging-Kanal schreiben (Schritt für Schritt)
Verwende dies, wenn du eine neue Chat-Oberfläche (einen “Messaging-Kanal”) willst, nicht einen Model-Provider.
Model-Provider-Docs befinden sich unter /providers/*.
- ID + Config-Form wählen
- Alle Kanal-Config liegt unter
channels.<id>. - Bevorzuge
channels.<id>.accounts.<accountId>für Multi-Account-Setups.
- Kanal-Metadaten definieren
meta.label,meta.selectionLabel,meta.docsPath,meta.blurbsteuern CLI/UI-Listen.meta.docsPathsollte auf eine Docs-Seite wie/channels/<id>zeigen.meta.preferOverlässt ein Plugin einen anderen Kanal ersetzen (Auto-Enable bevorzugt es).meta.detailLabelundmeta.systemImagewerden von UIs für Detailtext/Icons verwendet.
- Die erforderlichen Adapter implementieren
config.listAccountIds+config.resolveAccountcapabilities(Chat-Typen, Medien, Threads, etc.)outbound.deliveryMode+outbound.sendText(für einfaches Senden)
- Optionale Adapter nach Bedarf hinzufügen
setup(Wizard),security(DM-Policy),status(Health/Diagnose)gateway(Start/Stop/Login),mentions,threading,streamingactions(Nachrichtenaktionen),commands(natives Befehlsverhalten)
- Den Kanal in deinem Plugin registrieren
api.registerChannel({ plugin })
Minimales Config-Beispiel:
{
channels: {
acmechat: {
accounts: {
default: { token: "ACME_TOKEN", enabled: true },
},
},
},
}
Minimales Kanal-Plugin (nur Outbound):
const plugin = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "AcmeChat messaging channel.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? {
accountId,
},
},
outbound: {
deliveryMode: "direct",
sendText: async ({ text }) => {
// `text` an deinen Kanal zustellen
return { ok: true };
},
},
};
export default function (api) {
api.registerChannel({ plugin });
}
Lade das Plugin (Extensions-Verzeichnis oder plugins.load.paths), starte das Gateway neu,
dann konfiguriere channels.<id> in deiner Config.
Agent-Tools
Siehe die dedizierte Anleitung: Plugin Agent-Tools.
Eine Gateway-RPC-Methode registrieren
export default function (api) {
api.registerGatewayMethod("myplugin.status", ({ respond }) => {
respond(true, { ok: true });
});
}
CLI-Befehle registrieren
export default function (api) {
api.registerCli(
({ program }) => {
program.command("mycmd").action(() => {
console.log("Hello");
});
},
{ commands: ["mycmd"] },
);
}
Auto-Reply-Befehle registrieren
Plugins können benutzerdefinierte Slash-Befehle registrieren, die ohne Aufruf des KI-Agents ausgeführt werden. Das ist nützlich für Toggle-Befehle, Status-Checks oder schnelle Aktionen, die keine LLM-Verarbeitung brauchen.
export default function (api) {
api.registerCommand({
name: "mystatus",
description: "Show plugin status",
handler: (ctx) => ({
text: `Plugin is running! Channel: ${ctx.channel}`,
}),
});
}
Command-Handler-Kontext:
senderId: Die Sender-ID (wenn verfügbar)channel: Der Kanal, auf dem der Befehl gesendet wurdeisAuthorizedSender: Ob der Sender ein autorisierter Benutzer istargs: Argumente nach dem Befehl (wennacceptsArgs: true)commandBody: Der vollständige Befehlstextconfig: Die aktuelle OpenClaw-Config
Command-Optionen:
name: Befehlsname (ohne führendes/)nativeNames: Optionale Native-Command-Aliase für Slash/Menü-Oberflächen. Verwendedefaultfür alle nativen Provider oder provider-spezifische Keys wiediscorddescription: Hilfetext in BefehlslistenacceptsArgs: Ob der Befehl Argumente akzeptiert (Standard: false). Wenn false und Argumente angegeben werden, matcht der Befehl nicht und die Nachricht fällt durch zu anderen HandlernrequireAuth: Ob autorisierter Sender erforderlich ist (Standard: true)handler: Funktion, die{ text: string }zurückgibt (kann async sein)
Beispiel mit Autorisierung und Argumenten:
api.registerCommand({
name: "setmode",
description: "Set plugin mode",
acceptsArgs: true,
requireAuth: true,
handler: async (ctx) => {
const mode = ctx.args?.trim() || "default";
await saveMode(mode);
return { text: `Mode set to: ${mode}` };
},
});
Hinweise:
- Plugin-Befehle werden vor eingebauten Befehlen und dem KI-Agent verarbeitet
- Befehle werden global registriert und funktionieren über alle Kanäle
- Befehlsnamen sind case-insensitive (
/MyStatusmatcht/mystatus) - Befehlsnamen müssen mit einem Buchstaben beginnen und dürfen nur Buchstaben, Zahlen, Bindestriche und Unterstriche enthalten
- Reservierte Befehlsnamen (wie
help,status,reset, etc.) können von Plugins nicht überschrieben werden - Doppelte Befehlsregistrierung über Plugins hinweg scheitert mit einem Diagnosefehler
Hintergrund-Services registrieren
export default function (api) {
api.registerService({
id: "my-service",
start: () => api.logger.info("ready"),
stop: () => api.logger.info("bye"),
});
}
Namenskonventionen
- Gateway-Methoden:
pluginId.action(Beispiel:voicecall.status) - Tools:
snake_case(Beispiel:voice_call) - CLI-Befehle: kebab oder camel, aber Konflikte mit Core-Befehlen vermeiden
Skills
Plugins können einen Skill im Repo mitliefern (skills/<name>/SKILL.md).
Aktiviere ihn mit plugins.entries.<id>.enabled (oder anderen Config-Gates) und stelle sicher,
dass er in deinen Workspace/verwalteten Skills-Locations vorhanden ist.
Distribution (npm)
Empfohlenes Packaging:
- Hauptpaket:
openclaw(dieses Repo) - Plugins: separate npm-Pakete unter
@openclaw/*(Beispiel:@openclaw/voice-call)
Veröffentlichungsvertrag:
- Plugin
package.jsonmussopenclaw.extensionsmit einer oder mehreren Entry-Dateien enthalten. - Entry-Dateien können
.jsoder.tssein (jiti lädt TS zur Runtime). openclaw plugins install <npm-spec>verwendetnpm pack, extrahiert nach~/.openclaw/extensions/<id>/und aktiviert es in der Config.- Config-Key-Stabilität: Scoped-Pakete werden zur unscoped ID für
plugins.entries.*normalisiert.
Beispiel-Plugin: Voice Call
Dieses Repo enthält ein Voice-Call-Plugin (Twilio oder Log-Fallback):
- Source:
extensions/voice-call - Skill:
skills/voice-call - CLI:
openclaw voicecall start|status - Tool:
voice_call - RPC:
voicecall.start,voicecall.status - Config (Twilio):
provider: "twilio"+twilio.accountSid/authToken/from(optionalstatusCallbackUrl,twimlUrl) - Config (Dev):
provider: "log"(kein Netzwerk)
Siehe Voice Call und extensions/voice-call/README.md für Setup und Nutzung.
Sicherheitshinweise
Plugins laufen in-process mit dem Gateway. Behandle sie als vertrauenswürdigen Code:
- Installiere nur Plugins, denen du vertraust.
- Bevorzuge
plugins.allow-Allowlists. - Denke daran, dass
plugins.allowID-basiert ist, also kann ein aktiviertes Workspace-Plugin absichtlich ein gebündeltes Plugin mit derselben ID überschatten. - Starte das Gateway nach Änderungen neu.
Plugins testen
Plugins können (und sollten) Tests mitliefern:
- In-Repo-Plugins können Vitest-Tests unter
src/**halten (Beispiel:src/plugins/voice-call.plugin.test.ts). - Separat veröffentlichte Plugins sollten ihre eigene CI (Lint/Build/Test) betreiben und validieren, dass
openclaw.extensionsauf den gebauten Entrypoint (dist/index.js) zeigt.