Building plugins
工具外掛
defineToolPlugin 會建立一個僅新增可供代理程式呼叫之工具的外掛:不含
頻道、模型提供者、鉤子、服務或設定後端。它會產生 OpenClaw 所需的
資訊清單中繼資料,讓 OpenClaw 無須載入外掛執行階段程式碼即可探索工具。
若要建立提供者、頻道、鉤子、服務或混合功能外掛,請改從 建立外掛、頻道外掛 或提供者外掛開始。
需求
- Node 22.22.3+、Node 24.15+ 或 Node 25.9+。
- TypeScript ESM 套件輸出。
typebox位於dependencies中(不能只位於devDependencies,因為產生的 外掛會在執行階段匯入它)。openclaw >=2026.5.17,即第一個匯出openclaw/plugin-sdk/tool-plugin的版本。- 套件根目錄須提供
dist/、openclaw.plugin.json和package.json。
快速入門
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm testplugins init 會建立下列架構:
| 檔案 | 用途 |
|---|---|
src/index.ts |
含一個 echo 工具的 defineToolPlugin 進入點 |
src/index.test.ts |
斷言工具清單的中繼資料測試 |
tsconfig.json |
輸出至 dist/ 的 NodeNext TypeScript |
vitest.config.ts |
src/**/*.test.ts 的 Vitest 設定 |
package.json |
指令碼、執行階段相依套件、openclaw.extensions: ["./dist/index.js"] |
openclaw.plugin.json |
初始工具所產生的資訊清單中繼資料 |
npm run plugin:build 會先執行 npm run build(tsc),再執行
openclaw plugins build --entry ./dist/index.js。npm run plugin:validate
會重新建置並執行 openclaw plugins validate --entry ./dist/index.js。
驗證成功時會輸出:
外掛 stock-quotes 有效。openclaw plugins init <id> 選項:
| 旗標 | 預設值 | 效果 |
|---|---|---|
--directory <path> |
<id> |
輸出目錄 |
--name <name> |
使用標題大小寫的 <id> |
顯示名稱 |
--type <type> |
tool |
架構類型:tool 或 provider |
--force |
關閉 | 覆寫現有的輸出目錄 |
撰寫工具
defineToolPlugin 接受外掛識別資訊、選用的設定結構描述,以及
靜態工具清單。參數與設定型別會從 TypeBox 結構描述推斷。
export default defineToolPlugin({ id: "stock-quotes", name: "Stock Quotes", description: "擷取股票報價快照。", configSchema: Type.Object({ apiKey: Type.Optional(Type.String({ description: "報價 API 金鑰。" })), baseUrl: Type.Optional(Type.String({ description: "報價 API 基礎 URL。" })), }), tools: (tool) => [ tool({ name: "stock_quote", label: "股票報價", description: "擷取股票報價快照。", parameters: Type.Object({ symbol: Type.String({ description: "股票代碼,例如 OPEN。" }), }), outputSchema: Type.Object( { symbol: Type.String(), configured: Type.Boolean(), baseUrl: Type.String(), }, { additionalProperties: false }, ), async execute({ symbol }, config, context) { context.signal?.throwIfAborted(); return { symbol: symbol.toUpperCase(), configured: Boolean(config.apiKey), baseUrl: config.baseUrl ?? "https://api.example.com", }; }, }), ],});工具名稱是穩定的 API。請選擇唯一、全小寫且足夠具體的名稱, 以避免與核心工具或其他外掛衝突。
選用工具與工廠工具
當使用者應明確將工具加入允許清單,工具才會傳送給模型時,請設定 optional: true。
openclaw plugins build 會寫入相符的
toolMetadata.<tool>.optional 資訊清單項目,讓 OpenClaw 無須載入外掛執行階段程式碼,
即可得知該工具為選用工具。
tool({ name: "workflow_run", description: "執行外部工作流程。", parameters: Type.Object({ goal: Type.String() }), optional: true, execute: ({ goal }) => ({ queued: true, goal }),});若工具必須先取得執行階段工具情境才能建立,請使用 factory,例如針對特定執行選擇退出、
檢查沙箱狀態,或繫結執行階段輔助函式。即使具體工具是在
執行階段建立,中繼資料仍維持靜態。
tool({ name: "local_workflow", description: "在沙箱工作階段之外執行本機工作流程。", parameters: Type.Object({ goal: Type.String() }), optional: true, factory({ api, toolContext }) { if (toolContext.sandboxed) { return null; } return createLocalWorkflowTool(api); },});工廠仍須預先宣告固定的工具名稱。若外掛會動態計算工具名稱,或將工具
與鉤子、服務、提供者或命令結合,請直接使用 definePluginEntry。
傳回值
defineToolPlugin 會將一般傳回值包裝成 OpenClaw 工具結果
格式:
- 當模型應看到完全相同的文字時,傳回字串。
- 當你希望模型看到格式化的 JSON,且 OpenClaw 將原始值保留在
details中時, 傳回與 JSON 相容的值。
tool({ name: "echo_text", description: "回傳輸入文字。", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => input,});tool({ name: "echo_json", description: "以結構化 JSON 回傳輸入。", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => ({ input, length: input.length }),});當你需要自訂 AgentToolResult,或想重複使用現有的
api.registerTool 實作時,請使用工廠工具。
輸出契約
當工具傳回穩定且與 JSON 相容的資料時,請新增 outputSchema。它描述的是
儲存在 AgentToolResult.details 中的原始值,而不是
content 中的格式化文字:
tool({ name: "shipment_list", description: "列出貨運項目。", parameters: Type.Object({ buyer: Type.Optional(Type.String()), }), outputSchema: Type.Array( Type.Object( { id: Type.String(), buyer: Type.String(), paid: Type.Boolean(), tons: Type.Number(), }, { additionalProperties: false }, ), ), execute: ({ buyer }) => listShipments(buyer),});程式碼模式和工具搜尋會將此 結構描述轉換成有界限的 TypeScript 風格輸出提示。這讓模型能在一個程式中呼叫 並轉換已知結果,而不必再花一輪模型回合 觀察其形狀。
OpenClaw 會在執行目錄呼叫前編譯結構描述,然後在工具鉤子執行後驗證
最終的 details 值,再透過橋接器傳回。無效的結構描述無法執行工具;
結果不相符則會使已完成的呼叫失敗。請納入所有不會擲出例外的結果變體,
包括結構化錯誤變體;若結果不穩定,則省略結構描述。請勿在結構描述說明中放入
祕密或敏感值,因為受信任的輸出中繼資料可能會對模型可見。
若你希望取得完整且精簡的輸出提示,請在物件層級使用 { additionalProperties: false };
開放或截斷的結構描述仍可透過 tools.describe(...) 使用,
但不會被宣告為完整的快速索引契約。
工廠工具會在其傳回的具體 AnyAgentTool 上宣告 outputSchema。
靜態 tool({ factory }) 宣告不接受個別的輸出結構描述,
因為它可能與執行階段工具產生偏差。
設定
configSchema 為選用。省略時,OpenClaw 會套用嚴格的空物件
結構描述;產生的資訊清單仍會包含 configSchema。
export default defineToolPlugin({ id: "no-config-tools", name: "No Config Tools", description: "新增不需要設定的工具。", tools: () => [],});使用 configSchema 時,第二個 execute 引數的型別會從中推斷:
const configSchema = Type.Object({ apiKey: Type.String(),}); export default defineToolPlugin({ id: "configured-tools", name: "Configured Tools", description: "新增已設定的工具。", configSchema, tools: (tool) => [ tool({ name: "configured_ping", description: "檢查設定是否可用。", parameters: Type.Object({}), execute: (_params, config) => ({ hasKey: config.apiKey.length > 0 }), }), ],});OpenClaw 會從閘道設定中的外掛項目讀取外掛設定。請勿在原始碼或文件範例中 寫死祕密;請依據外掛的安全模型,使用設定、環境變數或 SecretRefs。
產生的中繼資料
OpenClaw 必須先讀取外掛資訊清單,才能匯入外掛執行階段程式碼。
defineToolPlugin 會為此公開靜態中繼資料,而
openclaw plugins build 會將其寫入套件。變更外掛 ID、名稱、說明、設定結構描述、
啟用條件或工具名稱後,請重新執行產生器:
npm run buildopenclaw plugins build --entry ./dist/index.js單一工具外掛所產生的資訊清單:
{ "id": "stock-quotes", "name": "Stock Quotes", "description": "Fetch stock quote snapshots.", "version": "0.1.0", "configSchema": { "type": "object", "additionalProperties": false, "properties": {} }, "activation": { "onStartup": true }, "contracts": { "tools": ["stock_quote"] }}contracts.tools 是重要的探索契約:它會告訴 OpenClaw 每個工具由哪個
外掛擁有,而無須載入每個已安裝外掛的執行階段。過時的資訊清單可能導致
工具無法被探索,或將註冊錯誤歸咎於錯誤的外掛。
套件中繼資料
openclaw plugins build 也會將 package.json 對齊所選的執行階段
進入點:
{ "type": "module", "files": ["dist", "openclaw.plugin.json", "README.md"], "dependencies": { "typebox": "^1.1.38" }, "peerDependencies": { "openclaw": ">=2026.5.17" }, "openclaw": { "extensions": ["./dist/index.js"] }}請發布建置後的 JavaScript(./dist/index.js),而不是 TypeScript 原始碼進入點。
原始碼進入點僅適用於工作區本機開發。
在 CI 中驗證
當產生的中繼資料過時時,plugins build --check 會在不重寫檔案的情況下失敗:
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm testOpenClaw SDK 相容性欄位帶有 TypeScript @deprecated 註解,
編輯器會將其顯示為遷移警告。若要在 CI 中強制執行,請啟用具備型別感知能力的規則,例如
@typescript-eslint/no-deprecated。
Oxlint 不具備型別感知能力,因此無法強制執行這些註解。所以產生的
plugins init 架構不會新增棄用項目的 lint 設定。
plugins validate 會檢查:
openclaw.plugin.json存在,且可通過一般資訊清單載入器。- 目前的進入點會匯出
defineToolPlugin中繼資料。 - 產生的資訊清單欄位與進入點中繼資料相符。
contracts.tools與宣告的工具名稱相符。package.json會將openclaw.extensions指向所選的執行階段進入點。
在本機安裝並檢查
從另一個 OpenClaw 簽出目錄或已安裝的命令列介面安裝此套件路徑:
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtime若要執行封裝後的冒煙測試,請先封裝,再安裝壓縮套件:
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --json安裝後,請重新啟動或重新載入閘道,並要求代理程式使用該 工具。如果看不到該工具,請先檢查外掛執行階段及實際生效的 工具目錄,再變更程式碼(請參閱疑難排解)。
發布
套件準備就緒後,透過 ClawHub 發布。clawhub package publish
接受一個來源:本機資料夾、GitHub 儲存庫(owner/repo[@ref])或
壓縮套件 URL。
clawhub package publish ./stock-quotes --dry-runclawhub package publish ./stock-quotes使用明確的 ClawHub 定位器安裝:
openclaw plugins install clawhub:your-org/stock-quotes在啟動切換期間,單獨的 npm 套件規格仍會從 npm 安裝,但 ClawHub 是 OpenClaw 外掛的首選探索與發布介面。關於擁有者範圍及 版本審查,請參閱 ClawHub 發布。
疑難排解
plugin entry not found: ./dist/index.js
所選的進入點檔案不存在。請執行 npm run build,然後重新執行
openclaw plugins build --entry ./dist/index.js 或
openclaw plugins validate --entry ./dist/index.js。
plugin entry does not expose defineToolPlugin metadata
該進入點未匯出由 defineToolPlugin 建立的值。請確認
模組的預設匯出是 defineToolPlugin(...) 的結果,或使用
--entry 傳入正確的進入點。
openclaw.plugin.json generated metadata is stale
資訊清單已不再與進入點中繼資料相符。請執行:
npm run buildopenclaw plugins build --entry ./dist/index.js請同時提交 openclaw.plugin.json 和 package.json 的變更。
package.json openclaw.extensions must include ./dist/index.js
套件中繼資料指向不同的執行階段進入點。請執行
openclaw plugins build --entry ./dist/index.js,讓產生器將
套件中繼資料與你預計發布的進入點對齊。
Cannot find package 'typebox'
建置後的外掛會在執行階段匯入 typebox。請將它保留在 dependencies 中,
重新安裝、重新建置,然後再次執行驗證。
安裝後未顯示工具
請依序檢查下列項目:
openclaw plugins inspect <plugin-id> --runtimeopenclaw plugins validate --root <plugin-root> --entry ./dist/index.jsopenclaw.plugin.json具有contracts.tools,且包含預期的工具名稱。package.json具有openclaw.extensions: ["./dist/index.js"]。- 安裝外掛後,閘道已重新啟動或重新載入。