Plugins (Extensions)

Schnellstart (neu bei Plugins?)

Ein Plugin ist einfach ein kleines Code-Modul, das OpenClaw um zusätzliche Features erweitert (Commands, Tools und Gateway RPC).

Meistens nutzt du Plugins, wenn du ein Feature brauchst, das noch nicht in OpenClaw eingebaut ist (oder wenn du optional Features aus deiner Hauptinstallation raushalten willst).

Schnelleinstieg:

  1. Schau dir an, was bereits geladen ist:
openclaw plugins list
  1. Installiere ein offizielles Plugin (Beispiel: Voice Call):
openclaw plugins install @openclaw/voice-call
  1. Starte den Gateway neu und konfiguriere dann unter plugins.entries.<id>.config.

Siehe Voice Call für ein konkretes Plugin-Beispiel.

Verfügbare Plugins (offiziell)

  • Microsoft Teams ist seit 2026.1.15 nur als Plugin verfügbar; installiere @openclaw/msteams, wenn du Teams nutzt.
  • Memory (Core) — mitgeliefertes Memory-Search-Plugin (standardmäßig aktiviert über plugins.slots.memory)
  • Memory (LanceDB) — mitgeliefertes 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) — mitgeliefert als google-antigravity-auth (standardmäßig deaktiviert)
  • Gemini CLI OAuth (Provider Auth) — mitgeliefert als google-gemini-cli-auth (standardmäßig deaktiviert)
  • Qwen OAuth (Provider Auth) — mitgeliefert als qwen-portal-auth (standardmäßig deaktiviert)
  • Copilot Proxy (Provider Auth) — lokale VS Code Copilot Proxy Bridge; unterscheidet sich vom eingebauten github-copilot Device Login (mitgeliefert, standardmäßig deaktiviert)

OpenClaw Plugins sind TypeScript-Module, die zur Laufzeit über jiti geladen werden. Config-Validierung führt keinen Plugin-Code aus; sie nutzt stattdessen das Plugin-Manifest und JSON Schema. Siehe Plugin-Manifest.

Plugins können registrieren:

  • Gateway RPC Methods
  • Gateway HTTP Handler
  • Agent Tools
  • CLI Commands
  • Background Services
  • Optionale Config-Validierung
  • Skills (durch Auflistung von skills-Verzeichnissen im Plugin-Manifest)
  • Auto-Reply Commands (werden ohne AI Agent ausgeführt)

Plugins laufen im selben Prozess wie der Gateway, behandle sie also als vertrauenswürdigen Code. Tool-Authoring-Guide: Plugin Agent Tools.

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:

  • Nutzt die Core-Konfiguration messages.tts (OpenAI oder ElevenLabs).
  • Gibt PCM-Audio-Buffer + Sample-Rate zurück. Plugins müssen für Provider selbst resampling/encoding machen.
  • Edge TTS wird für Telefonie nicht unterstützt.

Entdeckung & Priorität

OpenClaw scannt in dieser Reihenfolge:

  1. Config-Pfade
  • plugins.load.paths (Datei oder Verzeichnis)
  1. Workspace Extensions
  • <workspace>/.openclaw/extensions/*.ts
  • <workspace>/.openclaw/extensions/*/index.ts
  1. Globale Extensions
  • ~/.openclaw/extensions/*.ts
  • ~/.openclaw/extensions/*/index.ts
  1. Mitgelieferte Extensions (mit OpenClaw ausgeliefert, standardmäßig deaktiviert)
  • <openclaw>/extensions/*

Mitgelieferte Plugins müssen explizit über plugins.entries.<id>.enabled oder openclaw plugins enable <id> aktiviert werden. Installierte Plugins sind standardmäßig aktiviert, können aber auf die gleiche Weise deaktiviert werden.

Jedes Plugin muss eine openclaw.plugin.json-Datei in seinem Root-Verzeichnis 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 auflösen, gewinnt der erste Treffer in der obigen Reihenfolge und Kopien mit niedrigerer Priorität werden ignoriert.

Package Packs

Ein Plugin-Verzeichnis kann eine package.json mit openclaw.extensions enthalten:

{
  "name": "my-pack",
  "openclaw": {
    "extensions": ["./src/safety.ts", "./src/tools.ts"]
  }
}

Jeder Eintrag wird zu einem Plugin. Wenn das Pack mehrere Extensions auflistet, wird die Plugin-ID zu name/<fileBase>.

Wenn dein Plugin npm-Abhängigkeiten importiert, installiere sie in diesem Verzeichnis, damit node_modules verfügbar ist (npm install / pnpm install).

Channel Catalog Metadata

Channel-Plugins können Onboarding-Metadaten über openclaw.channel und Installations-Hinweise über openclaw.install bereitstellen. So bleibt der 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 Channel-Kataloge zusammenführen (z. B. einen MPM-Registry-Export). Lege eine JSON-Datei an einem dieser Orte ab:

  • ~/.openclaw/mpm/plugins.json
  • ~/.openclaw/mpm/catalog.json
  • ~/.openclaw/plugins/catalog.json

Oder zeige mit 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:

  • Package Packs: package.json name
  • Standalone-Datei: Datei-Basisname (~/.../voice-call.tsvoice-call)

Wenn ein Plugin id exportiert, nutzt OpenClaw diese, warnt aber, wenn sie nicht mit der konfigurierten ID übereinstimmt.

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: zusätzliche Plugin-Dateien/-Verzeichnisse
  • entries.<id>: Plugin-spezifische Toggles + Config

Config-Änderungen erfordern einen Gateway-Neustart.

Validierungsregeln (strikt):

  • Unbekannte Plugin-IDs in entries, allow, deny oder slots sind Fehler.
  • Unbekannte channels.<id>-Keys sind Fehler, außer ein Plugin-Manifest deklariert die Channel-ID.
  • Plugin-Config wird mit dem JSON Schema validiert, das in openclaw.plugin.json (configSchema) eingebettet ist.
  • Wenn ein Plugin deaktiviert ist, wird seine Config beibehalten und eine Warnung ausgegeben.

Plugin Slots (exklusive Kategorien)

Manche Plugin-Kategorien sind exklusiv (nur eines aktiv zur gleichen Zeit). Nutze plugins.slots, um auszuwählen, welches Plugin den Slot besitzt:

{
  plugins: {
    slots: {
      memory: "memory-core", // oder "none" um Memory-Plugins zu deaktivieren
    },
  },
}

Wenn mehrere Plugins kind: "memory" deklarieren, wird nur das ausgewählte geladen. Andere werden mit Diagnostics deaktiviert.

Control UI (Schema + Labels)

Die Control UI nutzt config.schema (JSON Schema + uiHints), um bessere Formulare zu rendern.

OpenClaw erweitert uiHints zur Laufzeit basierend auf entdeckten Plugins:

  • Fügt Plugin-spezifische Labels für plugins.entries.<id> / .enabled / .config hinzu
  • Führt optionale Plugin-bereitgestellte Config-Field-Hints zusammen unter: plugins.entries.<id>.config.<field>

Wenn du möchtest, dass deine Plugin-Config-Felder gute Labels/Platzhalter zeigen (und Secrets als sensibel 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>                 # kopiert eine lokale Datei/Verzeichnis nach ~/.openclaw/extensions/<id>
openclaw plugins install ./extensions/voice-call # relativer Pfad ok
openclaw plugins install ./plugin.tgz           # installiert aus lokalem Tarball
openclaw plugins install ./plugin.zip           # installiert aus lokalem Zip
openclaw plugins install -l ./extensions/voice-call # Link (keine Kopie) für Dev
openclaw plugins install @openclaw/voice-call # installiert von npm
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.

Plugins können auch eigene Top-Level-Commands registrieren (Beispiel: openclaw voicecall).

Plugin API (Überblick)

Plugins exportieren entweder:

  • Eine Funktion: (api) => { ... }
  • Ein Objekt: { id, name, configSchema, register(api) { ... } }

Plugin Hooks

Plugins können Hooks mitliefern und zur Laufzeit registrieren. So kann ein Plugin event-gesteuerte Automatisierung bündeln, ohne eine separate Hook-Pack-Installation.

Beispiel

import { registerPluginHooksFromDir } from "openclaw/plugin-sdk";

export default function register(api) {
  registerPluginHooksFromDir(api, "./hooks");
}

Hinweise:

  • Hook-Verzeichnisse folgen der normalen Hook-Struktur (HOOK.md + handler.ts).
  • Hook-Eligibility-Regeln gelten weiterhin (OS/Bins/Env/Config-Anforderungen).
  • Plugin-verwaltete Hooks erscheinen in openclaw hooks list mit plugin:<id>.
  • Du kannst Plugin-verwaltete Hooks nicht über openclaw hooks aktivieren/deaktivieren; aktiviere/deaktiviere stattdessen das Plugin.

Provider Plugins (Model Auth)

Plugins können Model Provider Auth-Flows registrieren, damit Nutzer OAuth oder API-Key-Setup innerhalb von OpenClaw ausführen können (keine externen Skripte nötig).

Registriere einen Provider über api.registerProvider(...). Jeder Provider stellt eine oder mehrere Auth-Methoden bereit (OAuth, API Key, Device Code, etc.). Diese Methoden ermöglichen:

  • openclaw models auth login --provider <id> [--method <id>]

Beispiel:

api.registerProvider({
  id: "acme",
  label: "AcmeAI",
  auth: [
    {
      id: "oauth",
      label: "OAuth",
      kind: "oauth",
      run: async (ctx) => {
        // Führe OAuth-Flow aus und gib Auth-Profile zurück.
        return {
          profiles: [
            {
              profileId: "acme:default",
              credential: {
                type: "oauth",
                provider: "acme",
                access: "...",
                refresh: "...",
                expires: Date.now() + 3600 * 1000,
              },
            },
          ],
          defaultModel: "acme/opus-1",
        };
      },
    },
  ],
});

Hinweise:

  • run erhält einen ProviderAuthContext mit prompter, runtime, openUrl und oauth.createVpsAwareHandlers-Helpers.
  • Gib configPatch zurück, wenn du Standard-Models oder Provider-Config hinzufügen musst.
  • Gib defaultModel zurück, damit --set-default Agent-Defaults aktualisieren kann.

Messaging Channel registrieren

Plugins können Channel-Plugins registrieren, die sich wie eingebaute Channels verhalten (WhatsApp, Telegram, etc.). Channel-Config liegt unter channels.<id> und wird von deinem Channel-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:

  • Lege Config unter channels.<id> ab (nicht plugins.entries).
  • meta.label wird für Labels in CLI/UI-Listen genutzt.
  • meta.aliases fügt alternative IDs für Normalisierung und CLI-Eingaben hinzu.
  • meta.preferOver listet Channel-IDs auf, die beim Auto-Enable übersprungen werden, wenn beide konfiguriert sind.
  • meta.detailLabel und meta.systemImage ermöglichen UIs, reichhaltigere Channel-Labels/Icons anzuzeigen.

Neuen Messaging Channel schreiben (Schritt für Schritt)

Nutze dies, wenn du eine neue Chat-Oberfläche (einen “Messaging Channel”) willst, keinen Model Provider. Model-Provider-Docs liegen unter /providers/*.

  1. Wähle eine ID + Config-Form
  • Alle Channel-Config liegt unter channels.<id>.
  • Bevorzuge channels.<id>.accounts.<accountId> für Multi-Account-Setups.
  1. Definiere die Channel-Metadaten
  • meta.label, meta.selectionLabel, meta.docsPath, meta.blurb steuern CLI/UI-Listen.
  • meta.docsPath sollte auf eine Docs-Seite wie /channels/<id> zeigen.
  • meta.preferOver lässt ein Plugin einen anderen Channel ersetzen (Auto-Enable bevorzugt es).
  • meta.detailLabel und meta.systemImage werden von UIs für Detail-Text/Icons genutzt.
  1. Implementiere die erforderlichen Adapter
  • config.listAccountIds + config.resolveAccount
  • capabilities (Chat-Typen, Media, Threads, etc.)
  • outbound.deliveryMode + outbound.sendText (für einfaches Senden)
  1. Füge optionale Adapter nach Bedarf hinzu
  • setup (Wizard), security (DM-Policy), status (Health/Diagnostics)
  • gateway (Start/Stop/Login), mentions, threading, streaming
  • actions (Message Actions), commands (Native Command Behavior)
  1. Registriere den Channel in deinem Plugin
  • api.registerChannel({ plugin })

Minimales Config-Beispiel:

{
  channels: {
    acmechat: {
      accounts: {
        default: { token: "ACME_TOKEN", enabled: true },
      },
    },
  },
}

Minimales Channel-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 }) => {
      // liefere `text` an deinen Channel hier
      return { ok: true };
    },
  },
};

export default function (api) {
  api.registerChannel({ plugin });
}

Lade das Plugin (Extensions-Verzeichnis oder plugins.load.paths), starte den Gateway neu und konfiguriere dann channels.<id> in deiner Config.

Agent Tools

Siehe den dedizierten Guide: Plugin Agent Tools.

Gateway RPC Method registrieren

export default function (api) {
  api.registerGatewayMethod("myplugin.status", ({ respond }) => {
    respond(true, { ok: true });
  });
}

CLI Commands registrieren

export default function (api) {
  api.registerCli(
    ({ program }) => {
      program.command("mycmd").action(() => {
        console.log("Hello");
      });
    },
    { commands: ["mycmd"] },
  );
}

Auto-Reply Commands registrieren

Plugins können eigene Slash-Commands registrieren, die ohne AI Agent ausgeführt werden. Das ist nützlich für Toggle-Commands, 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-Context:

  • senderId: Die ID des Senders (falls verfügbar)
  • channel: Der Channel, in dem der Command gesendet wurde
  • isAuthorizedSender: Ob der Sender ein autorisierter Nutzer ist
  • args: Argumente, die nach dem Command übergeben wurden (wenn acceptsArgs: true)
  • commandBody: Der vollständige Command-Text
  • config: Die aktuelle OpenClaw-Config

Command-Optionen:

  • name: Command-Name (ohne führendes /)
  • description: Hilfetext, der in Command-Listen angezeigt wird
  • acceptsArgs: Ob der Command Argumente akzeptiert (Standard: false). Wenn false und Argumente übergeben werden, matcht der Command nicht und die Nachricht fällt durch zu anderen Handlern
  • requireAuth: 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-Commands werden vor eingebauten Commands und dem AI Agent verarbeitet
  • Commands sind global registriert und funktionieren über alle Channels
  • Command-Namen sind case-insensitive (/MyStatus matcht /mystatus)
  • Command-Namen müssen mit einem Buchstaben beginnen und dürfen nur Buchstaben, Zahlen, Bindestriche und Unterstriche enthalten
  • Reservierte Command-Namen (wie help, status, reset, etc.) können nicht von Plugins überschrieben werden
  • Doppelte Command-Registrierung über Plugins schlägt mit einem Diagnostic-Fehler fehl

Background Services registrieren

export default function (api) {
  api.registerService({
    id: "my-service",
    start: () => api.logger.info("ready"),
    stop: () => api.logger.info("bye"),
  });
}

Namenskonventionen

  • Gateway Methods: pluginId.action (Beispiel: voicecall.status)
  • Tools: snake_case (Beispiel: voice_call)
  • CLI Commands: kebab oder camel, aber vermeide Konflikte mit Core-Commands

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/Managed-Skills-Locations vorhanden ist.

Distribution (npm)

Empfohlenes Packaging:

  • Haupt-Package: openclaw (dieses Repo)
  • Plugins: separate npm-Packages unter @openclaw/* (Beispiel: @openclaw/voice-call)

Publishing-Vertrag:

  • Plugin-package.json muss openclaw.extensions mit einer oder mehreren Entry-Dateien enthalten.
  • Entry-Dateien können .js oder .ts sein (jiti lädt TS zur Laufzeit).
  • openclaw plugins install <npm-spec> nutzt npm pack, extrahiert nach ~/.openclaw/extensions/<id>/ und aktiviert es in der Config.
  • Config-Key-Stabilität: Scoped Packages 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 (optional statusCallbackUrl, twimlUrl)
  • Config (Dev): provider: "log" (kein Netzwerk)

Siehe Voice Call und extensions/voice-call/README.md für Setup und Nutzung.

Sicherheitshinweise

Plugins laufen im selben Prozess wie der Gateway. Behandle sie als vertrauenswürdigen Code:

  • Installiere nur Plugins, denen du vertraust.
  • Bevorzuge plugins.allow-Allowlists.
  • Starte den Gateway nach Änderungen neu.

Plugins testen

Plugins können (und sollten) Tests mitliefern:

  • In-Repo-Plugins können Vitest-Tests unter src/** ablegen (Beispiel: src/plugins/voice-call.plugin.test.ts).
  • Separat veröffentlichte Plugins sollten ihre eigene CI ausführen (Lint/Build/Test) und validieren, dass openclaw.extensions auf den gebauten Entrypoint zeigt (dist/index.js).