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 bundleNative 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.extensions,openclaw.plugin.json中声明id、name、description、contracts、activation、configSchema,运行时代码中通过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.enabled、plugins.allow、plugins.deny、plugins.load.paths、plugins.slots和plugins.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 restart24. 插件冲突:谁拥有同一个能力?
插件系统引入了一个新问题:
如果两个插件都声明自己拥有同一个 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.json和package.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 --json27. 一个完整例子:Stock Quotes Tool Plugin
我们可以构造一个简单插件,提供股票价格查询工具。
目录结构:
stock-quotes/ ├─ package.json ├─ openclaw.plugin.json ├─ tsconfig.json └─ src/ └─ index.tspackage.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、能力归属和激活方式;运行时代码则通过definePluginEntry、defineToolPlugin或defineChannelPluginEntry注册真实能力。插件安装后还要经过plugins.allow、plugins.deny、plugins.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 执行链路中。
