当前位置: 首页 > news >正文

OpenClaw 源码解析(十三):Plugins 插件系统与能力扩展机制

1. 本期目标

上一期我们分析了 OpenClaw 的 Skills 技能系统。Skill 负责把可复用的任务经验、工具使用流程和行为约束沉淀下来,让 Agent 不只是“有工具”,而是“知道如何使用工具”。

这一期继续分析 OpenClaw 的另一层扩展机制:Plugins 插件系统

前面几期已经反复提到过:

Tool 解决 Agent 能调用什么动作; Skill 解决 Agent 应该如何组织动作; Channel 解决外部消息如何进入 Agent; Provider 解决模型、语音、搜索、媒体能力如何接入; Plugin 则是把这些能力打包扩展到 OpenClaw 的机制。

OpenClaw 官方文档对 Plugin 的定位很明确:插件可以扩展 Channel、模型提供商、Agent harness、Tools、Skills、语音、实时转录、媒体理解、生成、Web fetch、Web search 等运行时能力。(OpenClaw)

本期重点分析:

1. Plugin 在 OpenClaw 架构中解决什么问题? 2. Plugin、Tool、Skill、Channel、Provider 的关系是什么? 3. openclaw.plugin.json 承担什么作用? 4. Plugin 如何安装、启用、加载和验证? 5. definePluginEntry、defineToolPlugin、defineChannelPluginEntry 有什么区别? 6. 插件如何注册工具、技能、Channel、Provider 和 hooks? 7. native plugin 和 compatible bundle 有什么区别? 8. 插件系统的安全边界和排错思路是什么?

2. Plugin 是什么?

可以先给一个直观定义:

Plugin 是 OpenClaw 的能力扩展包。

它不是单纯的工具函数,也不是单纯的提示词文件,而是一个可以被 OpenClaw 发现、验证、加载,并在运行时注册能力的扩展模块。

例如,一个插件可以提供:

一个新的 Telegram-like Channel; 一个新的模型 Provider; 一个新的 Web Search Provider; 一组新的 Agent Tools; 一组配套 Skills; 一组 Gateway HTTP routes; 一组 runtime hooks; 一个本地 CLI backend; 一个媒体生成能力; 一个语音或实时转录能力。

所以 Plugin 的核心作用是:

在不修改 OpenClaw 核心代码的前提下,把新的运行时能力接入系统。

官方构建插件文档也强调,插件可以在不改变 OpenClaw core 的情况下添加消息 Channel、模型 Provider、本地 CLI backend、Agent tool、hook、media provider 等能力。(OpenClaw)


3. 为什么需要 Plugin?

如果没有插件系统,OpenClaw 每增加一个能力都需要改核心代码。

比如要支持一个新的聊天平台:

修改 src/channels; 修改配置 schema; 修改 Gateway 启动逻辑; 修改消息投递逻辑; 修改文档; 重新发布 OpenClaw。

要支持一个新的模型提供商:

修改 provider registry; 修改模型配置; 修改鉴权逻辑; 修改工具调用适配; 重新发布 OpenClaw。

这会导致核心代码越来越臃肿,也会让社区扩展变得困难。

Plugin 系统把这个问题拆开:

OpenClaw core: 提供统一的加载、配置、权限、运行时 API。 Plugin: 按照约定注册自己的能力。 Gateway: 启动时发现插件,并把插件能力纳入统一运行时。

这样,OpenClaw core 只需要维护稳定扩展接口,具体能力可以由插件独立演进。


4. Plugin、Tool、Skill、Channel、Provider 的关系

这几个概念很容易混淆,可以用一句话区分:

Tool 是动作; Skill 是动作说明; Channel 是消息入口; Provider 是能力供应方; Plugin 是把这些能力打包接入 OpenClaw 的扩展机制。

举个例子:

一个 browser plugin: 可以注册 browser tool; 可以附带 browser-automation skill; 可以注册相关 hooks; 可以提供浏览器控制 runtime。 一个 Slack plugin: 可以注册 Slack channel; 可以定义消息收发格式; 可以提供 setup CLI; 可以提供 channel-specific message presentation。 一个 stock plugin: 可以注册 stock_quote tool; 可以提供 API key config schema; 可以附带 stock-analysis skill。

可以画成:

Plugin ├─ Tool ├─ Skill ├─ Channel ├─ Provider ├─ Hook ├─ Gateway method / HTTP route ├─ CLI command └─ Runtime service

所以前几期讲过的 Tool、Skill、Channel,其实都可以通过 Plugin 扩展。


5. Plugin 的两种主要形态

OpenClaw 文档中区分了两类插件格式:

Native OpenClaw plugin Compatible bundle

Native OpenClaw plugin 使用openclaw.plugin.json加运行时模块,由 OpenClaw 进程内加载,适合开发 OpenClaw 专用的运行时能力;Compatible bundle 则是 Codex、Claude、Cursor 等外部插件布局,被 OpenClaw 映射进自己的插件清单和能力体系。(OpenClaw)

可以这样理解:

Native plugin: OpenClaw 原生插件,可以注册运行时能力。 Compatible bundle: 外部生态内容包,OpenClaw 尽量把其中的 skills、commands、hooks、MCP tools 等映射成原生能力。

Native plugin 更像“代码型插件”,Bundle 更像“内容和元数据包”。


6. Native Plugin 的基本组成

一个最小 Native Plugin 通常包含:

package.json openclaw.plugin.json src/index.ts 或 dist/index.js

其中:

package.json: 告诉 Node / npm 这个包是什么,以及 OpenClaw runtime entry 在哪里。 openclaw.plugin.json: 告诉 OpenClaw 这个插件声明了哪些能力、如何配置、何时激活。 index.ts / index.js: 真正的插件运行时代码,用来 register tool、provider、channel、hook 等。

官方 quickstart 中的示例也包含这三类核心内容:package.json中声明openclaw.extensionsopenclaw.plugin.json中声明idnamedescriptioncontractsactivationconfigSchema,运行时代码中通过definePluginEntry注册工具。(OpenClaw)


7. openclaw.plugin.json 的作用

openclaw.plugin.json是插件系统的核心文件。

它不是给模型看的,也不是给用户看的,而是给 OpenClaw 插件加载器看的。

它解决几个问题:

这个插件是谁? 这个插件声明了哪些能力? 它拥有哪些 tool / channel / provider? 它是否需要启动时加载? 它的配置 schema 是什么? OpenClaw 能否在不执行插件代码的情况下检查它?

官方插件构建文档明确说明:每个插件都需要 manifest,即使没有配置也需要;运行时工具必须出现在contracts.tools中,这样 OpenClaw 才能在不急切加载每个插件 runtime 的情况下发现工具归属。(OpenClaw)

一个简化的 manifest 如下:

{ "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 } }

可以把它理解成:

openclaw.plugin.json 是插件的冷启动身份证。

OpenClaw 可以先读这个文件,判断插件是否存在、配置是否合法、能力是否冲突,而不需要一开始就执行插件代码。


8. 冷元数据和运行时代码的分离

OpenClaw 插件系统有一个很重要的设计思想:

先读冷元数据,再决定是否加载运行时代码。

也就是说,OpenClaw 不会为了知道“这个插件有什么工具”就立即执行它的 JavaScript 代码,而是先读取 manifest。

这有几个好处:

第一,启动更安全: 可以先验证插件身份、配置 schema、工具归属和冲突。 第二,启动更快: 不用无条件加载所有插件 runtime。 第三,排错更清楚: plain inspect 可以做冷检查,runtime inspect 再验证实际注册。 第四,权限边界更明确: 插件声明能力和实际注册能力可以相互校验。

这也是为什么 manifest 里的contracts.tools很重要。

如果插件运行时代码注册了一个工具,但 manifest 里没有声明,那么 OpenClaw 很难在冷启动阶段识别这个工具的归属。


9. Plugin 安装来源

OpenClaw 支持多种插件安装来源:

ClawHub npm git local path marketplace archive

官方插件文档给出的安装示例包括 ClawHub、npm、git 和本地开发目录,例如openclaw plugins install clawhub:<package>npm:<package>git:github.com/<owner>/<repo>@<ref>./my-plugin--link ./my-plugin。(OpenClaw)

可以这样区分:

ClawHub: OpenClaw 原生发现和分发渠道。 npm: 适合 JavaScript / TypeScript 插件包。 git: 适合从仓库分支、tag、commit 安装。 local path: 适合本地开发调试。 marketplace: 适合兼容 Claude 等外部生态的插件包。

如果追求可复现,建议使用带版本、tag 或 commit 的安装方式,而不是总是安装 latest。


10. Plugin 启用与配置

插件安装后,不一定等于立即可用。它还会受到插件配置策略影响。

OpenClaw 的插件配置通常位于:

plugins.entries.<plugin-id>.config plugins.entries.<plugin-id>.enabled plugins.allow plugins.deny plugins.load.paths plugins.slots

官方文档给出的配置形态包括plugins.enabledplugins.allowplugins.denyplugins.load.pathsplugins.slotsplugins.entries;其中plugins.deny优先于 allow 和 per-plugin enablement,plugins.allow是独占白名单,plugins.entries.<id>.enabled: false可以禁用单个插件并保留配置。(OpenClaw)

示例:

{ "plugins": { "enabled": true, "allow": ["stock-quotes"], "deny": ["untrusted-plugin"], "load": { "paths": ["~/Projects/openclaw-stock-plugin"] }, "entries": { "stock-quotes": { "enabled": true, "config": { "apiKey": "YOUR_API_KEY" } } } } }

可以理解为:

安装: 插件文件进入 OpenClaw 可发现范围。 启用: 插件被策略允许加载。 配置: 插件获得运行时所需参数。 重启或 reload: Gateway 真正加载插件 runtime。

11. Plugin policy 和 Tool policy 的区别

这里要特别区分两层策略:

Plugin policy: 决定插件能不能被加载。 Tool policy: 决定插件里的某个工具能不能暴露给模型。

举例:

{ "plugins": { "allow": ["stock-quotes"] }, "tools": { "allow": ["stock_quote"] } }

这表示:

stock-quotes 插件可以加载; stock_quote 工具可以暴露给模型。

如果只允许 tool,但插件被 deny 了:

插件加载失败; 工具自然不会出现。

如果插件加载了,但 tool 没有通过 Tool policy:

插件 runtime 可以存在; 模型当前 session 仍然看不到该工具。

所以二者是上下游关系:

Plugin policy ↓ 插件能否加载 ↓ Tool policy ↓ 工具能否暴露给模型

官方文档也说明,如果插件不在plugins.allow中,则插件拥有的工具不可用,即使tools.allow包含"*"也不行。(OpenClaw)


12. Plugin 加载和 Gateway 重启

安装或更新插件代码后,Gateway 需要重新加载插件。

官方文档说明,安装、更新或卸载插件代码需要 Gateway restart;如果 managed Gateway 已运行并启用 config reload,OpenClaw 可以检测插件安装记录变化并自动重启,否则需要手动执行openclaw gateway restart。(OpenClaw)

这点很关键。

很多初学者会以为:

openclaw plugins install xxx

之后插件马上在正在运行的聊天会话中生效。

但更准确的是:

插件安装改变了磁盘状态; Gateway runtime 还需要重新加载; session 也可能需要下一轮或新 session 才能看到相关能力。

所以调试插件时要形成习惯:

openclaw plugins inspect <plugin-id> --runtime --json openclaw gateway status --deep --require-rpc openclaw gateway restart

官方文档也强调,plaininspect是冷 manifest 和 registry 检查,--runtime才用于证明 registered tools、hooks、services、Gateway methods 或插件自有 CLI commands 是否真正加载。(OpenClaw)


13. definePluginEntry:通用插件入口

definePluginEntry是非 Channel 插件的通用入口。

官方 SDK entrypoint 文档说明,definePluginEntry适用于 provider plugin、高级 tool plugin、hook plugin,以及任何不是 messaging channel 的插件;它通过register(api)注册 provider、tool 等能力。(OpenClaw)

示意:

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

可以理解为:

definePluginEntry 是插件运行时代码的总入口。

它让插件在被 Gateway 加载时,有机会向 OpenClaw 注册自己的能力。


14. defineToolPlugin:轻量工具插件入口

如果一个插件只想注册固定工具列表,可以使用defineToolPlugin

官方 Tool plugins 文档说明,Tool plugin 用来添加 Agent 可调用工具,不添加 channel、model provider、hook、service 或 setup backend;推荐流程是 init、写工具、build、生成 manifest 和 package metadata、validate。(OpenClaw)

示意:

import { Type } from "typebox"; import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin"; export default defineToolPlugin({ id: "stock-quotes", name: "Stock Quotes", description: "Fetch stock quote snapshots.", configSchema: Type.Object({ apiKey: Type.Optional(Type.String()), baseUrl: Type.Optional(Type.String()) }), tools: (tool) => [ tool({ name: "stock_quote", label: "Stock Quote", description: "Fetch a stock quote snapshot.", parameters: Type.Object({ symbol: Type.String() }), async execute({ symbol }, config, context) { context.signal?.throwIfAborted(); return { symbol: symbol.toUpperCase(), configured: Boolean(config.apiKey), baseUrl: config.baseUrl ?? "https://api.example.com" }; } }) ] });

这里有几个重点:

configSchema: 定义插件配置结构。 tools: 定义工具列表。 parameters: 定义工具参数 schema。 execute: 执行工具逻辑。 context.signal: 支持中断和取消。

官方文档也强调,工具名是稳定 API,应选择唯一、小写、足够具体的名称,避免和 core tools 或其他插件冲突。(OpenClaw)


15. required tool、optional tool 和 factory tool

插件工具并不都是同一种暴露方式。

官方文档区分了 required tool、optional tool 和 factory tool。

required tool: 插件启用后默认可用。 optional tool: 需要用户通过 tools.allow 明确 opt-in 后,才暴露给模型。 factory tool: 工具名称固定,但具体工具对象需要根据运行时上下文动态生成。

官方文档说明,required tools 在插件启用时可用;optional tools 需要用户 opt-in;如果工具需要 runtime tool context 才能创建,可以使用 factory,让工具根据 sandbox 状态、runtime helpers 等决定是否返回。(OpenClaw)

例如:

tool({ name: "local_workflow", description: "Run a local workflow outside sandboxed sessions.", parameters: Type.Object({ goal: Type.String() }), optional: true, factory({ api, toolContext }) { if (toolContext.sandboxed) { return null; } return createLocalWorkflowTool(api); } });

这表示:

如果当前 session 是 sandboxed,就不创建这个工具; 如果不是 sandboxed,才返回真正的工具定义。

这个设计可以让插件工具跟随当前 Agent、Session、Sandbox、Channel 上下文变化。


16. defineChannelPluginEntry:Channel 插件入口

如果插件要接入一个新的消息平台,就不能只注册普通工具,而要注册 Channel。

官方 SDK entrypoint 文档说明,defineChannelPluginEntry会包装 channel-specific wiring,自动调用api.registerChannel({ plugin }),并支持 channel 相关 setup / runtime 约定。(OpenClaw)

可以理解为:

defineToolPlugin: 适合只添加工具。 definePluginEntry: 适合添加 provider、hook、高级工具、service 等非 channel 能力。 defineChannelPluginEntry: 适合添加消息平台接入。

Channel 插件通常要处理:

外部平台鉴权; Webhook 或 Gateway 连接; 入站消息标准化; DM / group 访问控制; pairing; reply threading; outbound messaging; 平台限流和重试; setup CLI 或 setup wizard。

所以 Channel 插件的复杂度通常高于普通 Tool 插件。


17. Setup entry:为什么 Channel 插件可能需要轻量入口?

Channel 插件有时还会拆出 setup entry。

原因是:某些配置、安装、setup wizard 或 webhook 验证逻辑,需要在 Channel 完整 runtime 尚未启用时也能运行。

官方 SDK entrypoint 文档提到,defineSetupPluginEntry用于轻量setup-entry.ts,OpenClaw 可以在 channel disabled、unconfigured 或 deferred loading 时加载它,而不是加载完整 entry;heavy SDK、CLI registration 和 long-lived runtime services 应放在 full entry 中。(OpenClaw)

可以这样理解:

setup entry: 轻量、安全、配置相关。 full entry: 完整运行时、真实消息收发、长期服务。

这有助于避免一个尚未配置好的 Channel 插件在 Gateway 启动时就加载大量外部 SDK 或启动长连接。


18. 插件注册 Tool 的完整链路

以一个工具插件为例,完整链路可以这样画:

安装插件包 ↓ 读取 package.json ↓ 读取 openclaw.plugin.json ↓ 验证 manifest / configSchema / contracts.tools ↓ 检查 plugins.allow / plugins.deny / entries.enabled ↓ Gateway 启动或重启 ↓ 加载插件 entry ↓ register(api) 执行 ↓ api.registerTool(...) ↓ 工具进入 plugin tool registry ↓ 当前 session 构造 effective tools ↓ 经过 Tool policy / Sandbox / Sender policy ↓ 模型看到允许的工具 schema ↓ 模型发起 tool call ↓ 插件 execute 执行 ↓ tool result 写回 Agent 上下文

这条链路说明:

插件工具不是注册后无条件暴露给模型; 它还要经过插件策略、工具策略、运行时上下文和会话策略过滤。

19. 插件如何携带 Skill?

上一期我们讲过,Skill 是SKILL.md目录。插件也可以携带自己的 Skill。

OpenClaw Skills 文档说明,插件可以在openclaw.plugin.json中列出 skills directories,路径相对于插件根目录;当插件启用时,这些 plugin skills 会加载,适合放置那些太长、不适合写进 tool description,但又应该随插件可用的工具操作指南。(OpenClaw)

比如一个浏览器插件可能包含:

skills/browser-automation/SKILL.md

这个 Skill 告诉 Agent:

如何打开页面; 如何等待元素; 如何点击按钮; 如何处理登录; 如何截图; 如何在失败时回退。

这样 Tool 和 Skill 就形成配套:

Plugin 注册 browser tool; Plugin 携带 browser-automation skill; Agent 既有工具,又有使用工具的流程说明。

20. 插件 Hooks:扩展运行时行为

插件不仅能注册工具,也能注册 hooks。

OpenClaw 文档区分了两类 hook API:一种是通过api.on(...)注册 typed hooks,适合 middleware、policy、message rewriting、prompt shaping、tool control 等;另一种是api.registerHook(...),主要用于内部 hook 系统中的粗粒度 command / lifecycle side effects。(OpenClaw)

可以理解为:

api.on(...): 更偏运行时中间件,可以参与更细粒度控制。 api.registerHook(...): 更偏已有 HOOK-style 自动化兼容,处理粗粒度事件。

可能的 hook 场景包括:

消息进入前改写; 模型调用前调整 prompt; 工具调用前做审批; 工具调用后记录日志; 发送消息后做审计; session reset 后做清理; 命令触发后执行副作用。

这使 Plugin 不只是“增加能力”,还可以“改变能力运行过程”。


21. Plugin Bundle:兼容外部生态

OpenClaw 还支持 compatible bundle,把 Codex、Claude、Cursor 等外部生态的内容映射到 OpenClaw。

官方 Plugin bundles 文档说明,OpenClaw 可以安装来自 Codex、Claude、Cursor 三类外部生态的插件,这些 bundle 是内容和元数据包,会被映射成 OpenClaw 原生的 skills、hooks、MCP tools 等能力;bundle 不是 native plugin,它们不会像 Native plugin 那样在进程内注册任意能力。(OpenClaw)

支持映射的能力包括:

Skill content; Commands; Hook packs; MCP tools; LSP servers。

文档中明确提到,bundle skill roots 会作为普通 OpenClaw skill roots 加载,Claude commands roots 和 Cursor.cursor/commandsroots 也会被作为额外 skill roots 处理。(OpenClaw)

所以 Bundle 的意义是:

不用要求所有外部生态插件都重写成 OpenClaw Native Plugin; OpenClaw 尽量把可兼容的内容接进自己的能力系统。

22. Native Plugin 和 Bundle 的区别

可以从四个角度区分:

1. 是否运行代码 Native Plugin: 可以运行 OpenClaw 插件代码,注册 runtime capabilities。 Bundle: 更多是内容和元数据映射,能力边界更窄。 2. 是否使用 openclaw.plugin.json Native Plugin: 使用 openclaw.plugin.json。 Bundle: 使用 Codex / Claude / Cursor 自己的布局。 3. 能力范围 Native Plugin: 可以注册 tools、channels、providers、hooks、routes、services 等。 Bundle: 主要映射 skills、commands、hooks、MCP tools、LSP defaults 等。 4. 使用场景 Native Plugin: 适合 OpenClaw 专用能力开发。 Bundle: 适合复用外部 Agent 生态已有内容。

一句话概括:

Native Plugin 是 OpenClaw 的原生运行时扩展;Bundle 是外部生态内容到 OpenClaw 的兼容映射。

23. Plugin inspect:冷检查和运行时检查

排查插件时,inspect很重要。

但要区分:

openclaw plugins inspect <id> openclaw plugins inspect <id> --runtime

前者偏冷检查:

插件是否安装; manifest 是否存在; registry 状态如何; 配置是否可识别; 声明能力是什么。

后者会加载 runtime,用来检查:

实际注册了哪些 tools; 实际注册了哪些 hooks; 实际注册了哪些 services; 是否有 plugin-owned CLI commands; runtime import 是否失败。

官方 CLI 文档也说明,plain inspect 会显示 identity、load status、source、manifest capabilities、policy flags、diagnostics、install metadata 等,但默认不导入插件 runtime;加--runtime后才会加载插件模块并展示已注册 hooks、tools、commands、services、Gateway methods 和 HTTP routes。(GitHub)

所以如果遇到:

插件列表里有,但 Agent 看不到工具; 插件启用了,但 hook 没运行; 配置写了,但 Channel 没启动。

优先执行:

openclaw plugins inspect <plugin-id> --runtime --json openclaw gateway status --deep --require-rpc openclaw gateway restart

24. 插件冲突:谁拥有同一个能力?

插件系统引入了一个新问题:

如果两个插件都声明自己拥有同一个 tool 或 channel,怎么办?

例如:

plugin-a 声明 tools: ["stock_quote"] plugin-b 也声明 tools: ["stock_quote"] plugin-x 声明 channel: "telegram" plugin-y 也声明 channel: "telegram"

这会造成能力归属冲突。

OpenClaw 文档的 troubleshooting 中提到,如果出现 duplicate channel 或 tool ownership diagnostics,可以运行openclaw plugins list --enabled --verbose,再用inspect --runtime --json对比每个插件的 channel/tool ownership;如果是有意替换,可以通过 manifestpreferOver表达替换意图。(OpenClaw)

这说明 OpenClaw 并不会默默让后加载的插件覆盖前面的插件,而是尽量把冲突暴露出来。


25. 插件安全风险

Plugin 比 Skill 风险更高。

Skill 通常是 Markdown 行为说明,而 Plugin 可以执行代码、注册工具、开 HTTP route、连接外部服务、读配置、调用本地资源。

所以安装插件要像安装 npm 包或浏览器扩展一样谨慎。

主要风险包括:

第一,代码执行风险: 插件 runtime 是代码,可以在加载或执行时做危险操作。 第二,凭据泄露风险: 插件可能读取 config、env、apiKey 或 workspace 文件。 第三,工具扩大风险: 插件可能注册高权限工具,诱导模型调用。 第四,消息入口风险: Channel 插件可能把外部未授权消息接入 Gateway。 第五,Hook 篡改风险: 插件 hook 可能改写消息、prompt、tool call 或输出。 第六,依赖链风险: npm / git 插件可能携带复杂依赖。

因此建议:

优先安装可信来源插件; 生产环境使用 pinned version; 限制 plugins.allow; 对高风险工具使用 tools.allow / tools.deny; 不可信插件先在测试环境试运行; 查看 openclaw.plugin.json 和 runtime entry; 使用 inspect --runtime 验证实际注册能力; 启用必要的 sandbox 和 approval。

官方插件文档也提醒,应把插件安装视为运行代码,在需要可复现生产安装时优先使用 pinned versions。(OpenClaw)


26. 插件开发的最小流程

如果自己写一个最小工具插件,可以按下面流程:

1. 创建插件包 2. 编写 package.json 3. 编写 openclaw.plugin.json 4. 编写 src/index.ts 5. 注册工具 6. build 成 JavaScript 7. validate 插件 8. 本地 install 或 link 9. restart Gateway 10. inspect --runtime 验证 11. 在 Agent session 中测试工具是否进入 effective tools

官方 Tool plugin 文档推荐流程也类似:使用openclaw plugins init脚手架,编写defineToolPlugin,构建 JavaScript,生成openclaw.plugin.jsonpackage.jsonmetadata,发布或安装前先 validate。(OpenClaw)

示例命令:

openclaw plugins init stock-quotes --name "Stock Quotes" cd stock-quotes npm install npm run plugin:build npm run plugin:validate npm test openclaw plugins install --link . openclaw gateway restart openclaw plugins inspect stock-quotes --runtime --json

27. 一个完整例子:Stock Quotes Tool Plugin

我们可以构造一个简单插件,提供股票价格查询工具。

目录结构:

stock-quotes/ ├─ package.json ├─ openclaw.plugin.json ├─ tsconfig.json └─ src/ └─ index.ts

package.json

{ "name": "@myorg/openclaw-stock-quotes", "version": "0.1.0", "type": "module", "openclaw": { "extensions": ["./dist/index.js"] }, "dependencies": { "typebox": "^1.0.0" }, "devDependencies": { "typescript": "^5.0.0" } }

openclaw.plugin.json

{ "id": "stock-quotes", "name": "Stock Quotes", "description": "Fetch stock quote snapshots.", "activation": { "onStartup": true }, "contracts": { "tools": ["stock_quote"] }, "configSchema": { "type": "object", "additionalProperties": false, "properties": { "apiKey": { "type": "string", "description": "Quote API key." }, "baseUrl": { "type": "string", "description": "Quote API base URL." } } } }

src/index.ts

import { Type } from "typebox"; import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin"; export default defineToolPlugin({ id: "stock-quotes", name: "Stock Quotes", description: "Fetch stock quote snapshots.", configSchema: Type.Object({ apiKey: Type.Optional(Type.String()), baseUrl: Type.Optional(Type.String()) }), tools: (tool) => [ tool({ name: "stock_quote", label: "Stock Quote", description: "Fetch a stock quote snapshot for a ticker symbol.", parameters: Type.Object({ symbol: Type.String({ description: "Ticker symbol, for example AAPL or MSFT." }) }), async execute({ symbol }, config, context) { context.signal?.throwIfAborted(); return { symbol: symbol.toUpperCase(), providerConfigured: Boolean(config.apiKey), baseUrl: config.baseUrl ?? "https://api.example.com", note: "This is a demo response. Replace it with a real quote API call." }; } }) ] });

配置:

{ "plugins": { "entries": { "stock-quotes": { "enabled": true, "config": { "apiKey": "YOUR_API_KEY", "baseUrl": "https://api.example.com" } } } }, "tools": { "allow": ["stock_quote"] } }

这个例子体现了插件系统的核心链路:

manifest 声明工具归属; entry 注册工具运行逻辑; configSchema 定义配置; plugins.entries 注入配置; tools.allow 决定模型是否能看到工具。

28. 插件和 Gateway 的关系

Plugin 最终是由 Gateway 加载的。

因为 Gateway 是 OpenClaw 的控制平面,它负责:

加载配置; 发现插件; 验证插件; 启动 Channel; 注册 Provider; 构造工具目录; 处理会话和消息; 执行 Agent run; 暴露 RPC / HTTP 方法。

所以 Plugin 不是直接被 Agent 单独加载,而是进入 Gateway 的能力注册体系。

可以画成:

openclaw.json ↓ Plugin registry / manifest ↓ Gateway startup ↓ Plugin runtime load ↓ api.registerTool / Channel / Provider / Hook ↓ Gateway capability registry ↓ Agent / Channel / Session / Tool pipeline 使用这些能力

这也是为什么插件修改后通常要重启 Gateway。


29. 插件相关源码阅读路线

这一期建议从这些方向读源码:

第一组:插件入口和 SDK src/plugins/ src/plugin-sdk/ packages 或 extensions 中的插件示例 第二组:插件 manifest 和 registry openclaw.plugin.json plugin registry plugin manifest validation plugin inventory 第三组:插件加载 plugin loader runtime entry loading cold registry runtime inspect 第四组:插件工具 plugin tools tool factory optional tools tools.catalog tools.effective 第五组:插件配置 plugins.entries plugins.allow plugins.deny plugins.load.paths plugins.slots configSchema validation 第六组:插件 hooks typed plugin hooks api.on(...) api.registerHook(...) 第七组:Channel / Provider 插件 channel plugin entry provider plugin entry setup entry deferred loading 第八组:CLI 文档对照 docs/tools/plugin.md docs/plugins/building-plugins.md docs/plugins/tool-plugins.md docs/plugins/manifest.md docs/cli/plugins.md docs/plugins/bundles.md

阅读时可以带着这些问题:

1. OpenClaw 如何发现已安装插件? 2. openclaw.plugin.json 在什么时候被读取? 3. configSchema 在什么时候校验? 4. plugins.allow 和 plugins.deny 在哪里生效? 5. 插件 runtime entry 是如何加载的? 6. api.registerTool 注册后的工具进入了哪个 registry? 7. optional tool 如何等待 tools.allow opt-in? 8. factory tool 如何根据 sandbox/session context 动态返回 null? 9. plain inspect 和 --runtime inspect 差别在哪里? 10. Channel plugin 为什么需要 setup entry?

30. 初学者容易混淆的几个点

30.1 安装插件不等于启用插件

install: 插件文件存在。 enable: 插件被配置策略允许。 runtime loaded: Gateway 真正加载了插件代码。

30.2 Plugin allow 不等于 Tool allow

plugins.allow: 决定插件能不能加载。 tools.allow: 决定工具能不能暴露给模型。

30.3 manifest 不等于 runtime

manifest: 插件声明的冷元数据。 runtime: 插件实际注册的工具、hooks、routes、services。

30.4 Native plugin 不等于 Bundle

Native plugin: OpenClaw 原生运行时扩展。 Bundle: 外部生态内容映射。

30.5 Plugin 不是 Skill

Skill 是行为说明; Plugin 是能力扩展包; Plugin 可以携带 Skill,但二者不是一回事。

31. 我的理解

我认为 OpenClaw 的 Plugin 系统最值得学习的地方,是它把“扩展能力”拆成了两层:

第一层:冷元数据 用 openclaw.plugin.json 描述插件身份、配置 schema 和能力归属。 第二层:运行时代码 用 definePluginEntry / defineToolPlugin / defineChannelPluginEntry 注册真实能力。

这种设计比“加载插件代码后再问它有什么能力”更稳健。

因为 OpenClaw 可以在执行插件代码之前,就完成很多检查:

配置是否合法; 插件是否被 allow / deny; 工具归属是否冲突; Channel 是否重复; 是否需要 onStartup; 是否有 stale plugin config; 是否需要 doctor 修复。

同时,Plugin 又没有被限制成单一形态。它既可以是一个很小的工具插件,也可以是完整 Channel 插件、Provider 插件、Hook 插件、Media 插件,甚至通过 bundle 复用其他 Agent 生态的内容。

所以 Plugin 是 OpenClaw 从“一个本地 Agent 工具”演进为“可扩展 AI 助手平台”的关键机制。


32. 本期重点理解

这一期可以总结为五点:

第一,Plugin 是 OpenClaw 的能力扩展包,可以注册 tools、skills、channels、providers、hooks、services、routes 和 CLI commands。 第二,Native Plugin 通过 openclaw.plugin.json 声明冷元数据,通过 runtime entry 注册真实能力。 第三,Plugin policy 决定插件能否加载,Tool policy 决定插件工具能否暴露给模型。 第四,defineToolPlugin 适合固定工具列表,definePluginEntry 适合通用插件能力,defineChannelPluginEntry 适合消息平台接入。 第五,Compatible Bundle 用来把 Codex、Claude、Cursor 等外部生态内容映射为 OpenClaw skills、commands、hooks、MCP tools 等能力。

一句话概括:

OpenClaw 的 Plugin 系统,本质上是一个 manifest-first 的能力扩展机制:先用冷元数据声明插件身份和能力归属,再由运行时代码把工具、技能、频道、模型和 hooks 接入 Gateway。

33. 本期小结

本期主要分析了 OpenClaw 的 Plugins 插件系统。Plugin 是 OpenClaw 的能力扩展机制,可以在不修改核心代码的前提下接入 Tool、Skill、Channel、Provider、Hook、Gateway route、CLI command 等能力。Native Plugin 依赖openclaw.plugin.json作为冷元数据入口,用于声明插件身份、配置 schema、能力归属和激活方式;运行时代码则通过definePluginEntrydefineToolPlugindefineChannelPluginEntry注册真实能力。插件安装后还要经过plugins.allowplugins.denyplugins.entries、Gateway restart 和 runtime inspect 等步骤,最终能力才会进入 OpenClaw 的运行时体系。对于外部生态,OpenClaw 还支持 Compatible Bundle,把 Codex、Claude、Cursor 等格式中的 skills、commands、hooks、MCP tools 等映射到原生能力体系中。

这一期可以用一句话总结:

Plugin 让 OpenClaw 的能力不再固定在 core 里,而是可以通过可验证、可配置、可安装、可审计的方式持续扩展。

下一期可以继续分析:

OpenClaw 源码解析(十四):Provider 系统与模型能力接入机制

下一期重点看模型 Provider 如何接入 OpenClaw,Provider、Model、Agent runtime、tool calling、media generation、web search provider 之间的关系,以及 OpenClaw 如何把不同模型后端统一到 Agent 执行链路中。

http://www.rkmt.cn/news/1420594.html

相关文章:

  • ChatGPT时代如何避免技术依赖:从Facebook历史看AI生态风险与架构策略
  • 越南语NLP突破:vi-mrc-large模型85.847% EM值背后的训练策略与数据集优化
  • 从PyWxDump项目移除看开源项目合规运营的7个关键教训
  • 当Figma遇上中文:一个浏览器插件的设计语言本土化之旅
  • MiMo-VL-7B-SFT核心技术解析:原生分辨率ViT编码器与跨模态对齐
  • 从零开始微调wuhaicc/xlnet_base_cased:自定义数据集的完整流程
  • OpenClaw 源码解析(十四):Provider 系统与模型能力接入机制
  • Nemotron-3-Nano-Omni-30B-A3B-Reasoning-FP8视频处理深度解析:帧采样与内存优化策略
  • 2026年最硬核的LangChain从入门到精通:全网最细核心组件全景剖析
  • AI Agent驱动B2B销售线索自动化:从零构建低成本自主SDR系统
  • 快速上手FinBERT-FLS:基于3500条标注数据的金融NLP模型实践指南
  • 成都消防操作证报名费多少钱(内行拆解不被割韭菜) - 消防设施操作员考证
  • 抖音一键去水印免费方法与工具推荐
  • 2026广深靠谱全屋定制评测:欧雅尊领衔 - 服务品牌热点
  • 小米招聘 Agent 上线:依托大模型,为求职者提供政策解答、精准岗位推荐等服务
  • 2026年轻触开关/拨动开关/微动开关/自锁开关厂家精选榜单:高品质电子元器件开关与专业元器件开关公司实力推荐! - 企业推荐官【官方】
  • |微信投票怎么发起?云帆投票超实用完整操作教程 - 投票小程序
  • 邢台黄金回收机构评分排行榜:福昌夏领衔,多维度打分助你变现 - 黄金上门回收
  • Windows安装革命:MediaCreationTool.bat如何让系统部署变得轻松自如
  • 网上超市系统|基于Springboot+vue的网上超市系统设计与实现(源码+数据库+文档)
  • LogoS-7Bx2-MoE-13B-v0.2未来展望:MoE技术发展趋势与模型升级路线图
  • 台车式退火炉哪家好?2026年国产实力厂家与源头工厂深度测评 - 品牌推荐大师
  • 5分钟搞定多显示器DPI优化:终极鼠标平滑过渡方案
  • 如何用KeymouseGo实现鼠标键盘自动化:告别重复工作的终极指南
  • 忻州黄金回收门店精选,长悦引领品质服务新标杆 - 专业黄金回收
  • 为什么选择verysmol_llama-v11-KIx2-openmind?轻量级AI模型的5大核心优势
  • FreeRTOS互斥锁的‘坑’你踩过几个?从创建到释放的完整避坑指南与性能调优
  • 鸿蒙数学:AI 底层革命白皮书(根治全人类AI弊病)(一二三阶定世界)
  • 过滤减压阀(非常推荐)
  • 如何让《空洞骑士》模组管理变得轻松愉快:Scarab模组管理器深度解析