Building plugins

建構 Plugin

Plugin 以新功能擴充 OpenClaw:通道、模型提供者、 語音、即時轉錄、即時語音、媒體理解、圖片 生成、影片生成、網頁擷取、網頁搜尋、代理工具,或任何 組合。

你不需要把你的 Plugin 加到 OpenClaw 儲存庫。發布到 ClawHub,使用者即可透過 openclaw plugins install clawhub:<package-name> 安裝。裸套件規格在 啟動切換期間仍會從 npm 安裝。

先決條件

  • Node >= 22 與套件管理器(npm 或 pnpm)
  • 熟悉 TypeScript(ESM)
  • 針對儲存庫內 Plugin:已複製儲存庫並完成 pnpm install。原始碼 checkout Plugin 開發僅支援 pnpm,因為 OpenClaw 會從 extensions/* 工作區套件載入內建 Plugin。

哪一種 Plugin?

若通道 Plugin 無法保證在 onboarding/setup 執行時已安裝,請使用 openclaw/plugin-sdk/channel-setupcreateOptionalChannelSetupSurface(...)。它會產生一組 setup 配接器 + 精靈, 宣告安裝需求,並在 Plugin 安裝前對實際設定寫入 採取封閉失敗。

快速開始:工具 Plugin

本教學會建立一個註冊代理工具的最小 Plugin。通道 與提供者 Plugin 有上方連結的專屬指南。

  • 建立套件與資訊清單

    package.json
    {"name": "@myorg/openclaw-my-plugin","version": "1.0.0","type": "module","openclaw": {  "extensions": ["./index.ts"],  "compat": {    "pluginApi": ">=2026.3.24-beta.2",    "minGatewayVersion": "2026.3.24-beta.2"  },  "build": {    "openclawVersion": "2026.3.24-beta.2",    "pluginSdkVersion": "2026.3.24-beta.2"  }}}
    openclaw.plugin.json
    {"id": "my-plugin","name": "My Plugin","description": "Adds a custom tool to OpenClaw","contracts": {  "tools": ["my_tool"]},"activation": {  "onStartup": true},"configSchema": {  "type": "object",  "additionalProperties": false}}

    每個 Plugin 都需要資訊清單,即使沒有設定也是如此。執行階段註冊的工具 必須列在 contracts.tools 中,讓 OpenClaw 不必載入每個 Plugin 執行階段也能找出擁有它的 Plugin。Plugin 也應明確宣告 activation.onStartup。此範例將它設為 true。完整結構請參閱 資訊清單。標準 ClawHub 發布片段位於 docs/snippets/plugin-publish/

  • 撰寫進入點

    typescript
    // index.tsimport { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";import { Type } from "@sinclair/typebox"; export default definePluginEntry({  id: "my-plugin",  name: "My Plugin",  description: "Adds a custom tool to OpenClaw",  register(api) {    api.registerTool({      name: "my_tool",      description: "Do a thing",      parameters: Type.Object({ input: Type.String() }),      async execute(_id, params) {        return { content: [{ type: "text", text: `Got: ${params.input}` }] };      },    });  },});

    definePluginEntry 用於非通道 Plugin。通道請使用 defineChannelPluginEntry - 請參閱通道 Plugin。 完整進入點選項請參閱進入點

  • 測試與發布

    外部 Plugin: 使用 ClawHub 驗證並發布,然後安裝:

    bash
    clawhub package publish your-org/your-plugin --dry-runclawhub package publish your-org/your-pluginopenclaw plugins install clawhub:@myorg/openclaw-my-plugin

    @myorg/openclaw-my-plugin 這樣的裸套件規格會在 啟動切換期間從 npm 安裝。需要 ClawHub 解析時,請使用 clawhub:

    儲存庫內 Plugin: 放在內建 Plugin 工作區樹下 - 會自動探索。

    bash
    pnpm test -- <bundled-plugin-root>/my-plugin/
  • Plugin 功能

    單一 Plugin 可透過 api 物件註冊任意數量的功能:

    功能 註冊方法 詳細指南
    文字推論(LLM) api.registerProvider(...) 提供者 Plugin
    CLI 推論後端 api.registerCliBackend(...) CLI 後端 Plugin
    通道 / 訊息 api.registerChannel(...) 通道 Plugin
    語音(TTS/STT) api.registerSpeechProvider(...) 提供者 Plugin
    即時轉錄 api.registerRealtimeTranscriptionProvider(...) 提供者 Plugin
    即時語音 api.registerRealtimeVoiceProvider(...) 提供者 Plugin
    媒體理解 api.registerMediaUnderstandingProvider(...) 提供者 Plugin
    圖片生成 api.registerImageGenerationProvider(...) 提供者 Plugin
    音樂生成 api.registerMusicGenerationProvider(...) 提供者 Plugin
    影片生成 api.registerVideoGenerationProvider(...) 提供者 Plugin
    網頁擷取 api.registerWebFetchProvider(...) 提供者 Plugin
    網頁搜尋 api.registerWebSearchProvider(...) 提供者 Plugin
    工具結果 middleware api.registerAgentToolResultMiddleware(...) SDK 總覽
    代理工具 api.registerTool(...) 下方
    自訂命令 api.registerCommand(...) 進入點
    Plugin hook api.on(...) Plugin hook
    內部事件 hook api.registerHook(...) 進入點
    HTTP 路由 api.registerHttpRoute(...) 內部架構
    CLI 子命令 api.registerCli(...) 進入點

    完整註冊 API 請參閱 SDK 總覽

    內建 Plugin 在需要在模型看到輸出前非同步改寫工具結果時, 可以使用 api.registerAgentToolResultMiddleware(...)。請在 contracts.agentToolResultMiddleware 宣告目標執行階段,例如 ["pi", "codex"]。這是受信任的內建 Plugin 介面;外部 Plugin 應優先使用一般 OpenClaw Plugin hook,除非 OpenClaw 之後為此功能 新增明確的信任政策。

    如果你的 Plugin 註冊自訂 Gateway RPC 方法,請把它們放在 Plugin 專屬前綴下。核心管理命名空間(config.*exec.approvals.*wizard.*update.*)會保持保留,且一律解析為 operator.admin,即使 Plugin 要求較窄的範圍也是如此。

    請記住以下 hook guard 語意:

    • before_tool_call{ block: true } 是終止性的,會停止較低優先序的處理器。
    • before_tool_call{ block: false } 會被視為沒有決策。
    • before_tool_call{ requireApproval: true } 會暫停代理執行,並透過 exec 核准覆蓋層、Telegram 按鈕、Discord 互動,或任何通道上的 /approve 命令提示使用者核准。
    • before_install{ block: true } 是終止性的,會停止較低優先序的處理器。
    • before_install{ block: false } 會被視為沒有決策。
    • message_sending{ cancel: true } 是終止性的,會停止較低優先序的處理器。
    • message_sending{ cancel: false } 會被視為沒有決策。
    • message_received:需要傳入 thread/topic 路由時,請優先使用具型別的 threadId 欄位。將 metadata 保留給通道專屬的額外資訊。
    • message_sending:請優先使用具型別的 replyToId / threadId 路由欄位,而不是通道專屬的 metadata key。

    /approve 命令會以有界後援處理 exec 與 Plugin 核准:找不到 exec 核准 id 時,OpenClaw 會用同一個 id 重試 Plugin 核准。Plugin 核准轉送可透過設定中的 approvals.plugin 獨立配置。

    如果自訂核准管線需要偵測同一種有界後援情況, 請優先使用 openclaw/plugin-sdk/error-runtimeisApprovalNotFoundError, 而不是手動比對核准過期字串。

    範例與 hook 參考請參閱 Plugin hook

    註冊代理工具

    工具是 LLM 可以呼叫的具型別函式。它們可以是必需(永遠 可用)或選用(使用者 opt-in):

    typescript
    register(api) {  // Required tool - always available  api.registerTool({    name: "my_tool",    description: "Do a thing",    parameters: Type.Object({ input: Type.String() }),    async execute(_id, params) {      return { content: [{ type: "text", text: params.input }] };    },  });   // Optional tool - user must add to allowlist  api.registerTool(    {      name: "workflow_tool",      description: "Run a workflow",      parameters: Type.Object({ pipeline: Type.String() }),      async execute(_id, params) {        return { content: [{ type: "text", text: params.pipeline }] };      },    },    { optional: true },  );}

    工具工廠會收到由 runtime 提供的內容物件。當工具需要記錄、顯示或配合目前回合的作用中模型進行調整時,請使用 ctx.activeModel。該物件可以包含 providermodelIdmodelRef。請將它視為資訊性的 runtime 中繼資料,而不是防範本機操作者、已安裝 Plugin 程式碼或經修改 OpenClaw runtime 的安全邊界。對於敏感的本機工具,請保留明確的 Plugin 或操作者選擇加入機制,並在作用中模型中繼資料缺失或不合適時採取預設拒絕。

    每個透過 api.registerTool(...) 註冊的工具,也必須在 Plugin manifest 中宣告:

    json
    {  "contracts": {    "tools": ["my_tool", "workflow_tool"]  },  "toolMetadata": {    "workflow_tool": {      "optional": true    }  }}

    OpenClaw 會擷取並快取已註冊工具中通過驗證的描述元,因此 Plugin 不需要在 manifest 中重複 description 或結構描述資料。manifest 合約只宣告擁有權與探索;執行時仍會呼叫即時註冊的工具實作。 對於使用 api.registerTool(..., { optional: true }) 註冊的工具,請設定 toolMetadata.<tool>.optional: true,如此 OpenClaw 就能避免在工具被明確列入允許清單前載入該 Plugin runtime。

    使用者可在設定中啟用選用工具:

    json5
    {  tools: { allow: ["workflow_tool"] },}
    • 工具名稱不得與核心工具衝突(衝突項目會被略過)
    • 註冊物件格式錯誤的工具,包括缺少 parameters,會被略過並在 Plugin 診斷中回報,而不是中斷 agent 執行
    • 對於有副作用或需要額外二進位檔的工具,請使用 optional: true
    • 使用者可以將 Plugin ID 加入 tools.allow,以啟用該 Plugin 的所有工具

    註冊 CLI 指令

    Plugin 可以透過 api.registerCli 加入根層級 openclaw 指令群組。請為每個頂層指令根提供 descriptors,讓 OpenClaw 不需要急切載入每個 Plugin runtime,就能顯示並路由該指令。

    typescript
    register(api) {  api.registerCli(    ({ program }) => {      const demo = program        .command("demo-plugin")        .description("Run demo plugin commands");       demo        .command("ping")        .description("Check that the plugin CLI is executable")        .action(() => {          console.log("demo-plugin:pong");        });    },    {      descriptors: [        {          name: "demo-plugin",          description: "Run demo plugin commands",          hasSubcommands: true,        },      ],    },  );}

    安裝後,驗證 runtime 註冊並執行指令:

    bash
    openclaw plugins inspect demo-plugin --runtime --jsonopenclaw demo-plugin ping

    匯入慣例

    一律從聚焦的 openclaw/plugin-sdk/<subpath> 路徑匯入:

    typescript
      // Wrong: monolithic root (deprecated, will be removed) 

    完整的子路徑參考請參閱 SDK Overview

    在你的 Plugin 內部,請使用本機 barrel 檔案(api.tsruntime-api.ts)進行內部匯入,不要透過其 SDK 路徑匯入自己的 Plugin。

    對於提供者 Plugin,請將提供者專屬 helper 保留在那些套件根層級的 barrel 中,除非該銜接點確實是通用的。目前內建範例包括:

    • Anthropic:Claude stream 包裝器,以及 service_tier / beta helper
    • OpenAI:提供者建構器、預設模型 helper、即時提供者
    • OpenRouter:提供者建構器,以及 onboarding/設定 helper

    如果某個 helper 只在單一內建提供者套件內有用,請將它保留在該套件根層級銜接點,而不是提升到 openclaw/plugin-sdk/*

    部分產生的 openclaw/plugin-sdk/<bundled-id> helper 銜接點仍然存在,用於具有已追蹤擁有者使用情況的內建 Plugin 維護。請將這些視為保留介面,而不是新的第三方 Plugin 的預設模式。

    提交前檢查清單

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s package.json 具有正確的 openclaw 中繼資料 OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s openclaw.plugin.json manifest 存在且有效 OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s 進入點使用 defineChannelPluginEntrydefinePluginEntry OPENCLAW_DOCS_MARKER:calloutClose:

    OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s 所有匯入都使用聚焦的 plugin-sdk/<subpath> 路徑 OPENCLAW_DOCS_MARKER:calloutClose:

    Was this useful?