Appearance
OpenClaw 插件入口辅助函数定义了插件的注册行为。本页给出 definePluginEntry、defineChannelPluginEntry、defineToolPlugin 和 defineSetupPluginEntry 的必填/可选字段、参数类型和注册模式(full、setup-only、setup-runtime、cli-metadata)说明。使用 definePluginEntry 时须在 package.json 中指定 extensions 和 runtimeExtensions,runtime 条目缺失会导致安装/发现失败而不是静默回退到 TypeScript 源文件。所有入口路径必须留在插件包目录内。
OpenClaw 插件入口点完整参考
每个插件默认导出一个入口对象。SDK 提供了四个辅助函数用于创建它们。
对于已安装的插件,package.json 应指向构建后的 JavaScript(存在时):
json
{
"openclaw": {
"extensions": ["./src/index.ts"],
"runtimeExtensions": ["./dist/index.js"],
"setupEntry": "./src/setup-entry.ts",
"runtimeSetupEntry": "./dist/setup-entry.js"
}
}extensions和setupEntry保留作为源代码入口,适用于工作区和 git checkout 开发环境。runtimeExtensions和runtimeSetupEntry在 OpenClaw 加载已安装包时优先使用,避免运行时 TypeScript 编译。必须显式声明:runtimeSetupEntry要求同时声明setupEntry;缺少runtimeExtensions或runtimeSetupEntry产物会导致安装/发现失败,不会静默回退到源代码。- 如果已安装包只声明了 TypeScript 源文件入口,OpenClaw 会尝试找到对应的
dist/*.js文件(如存在),否则回退到 TypeScript 源代码。 - 所有入口路径必须位于插件包目录内。runtime 条目和推断出的构建副本不能使逃逸包目录的
extensions或setupEntry源路径变为合法。
需要完整开发流程?请参考工具插件开发、渠道插件开发或 Provider 插件开发。
defineToolPlugin
导入路径: openclaw/plugin-sdk/tool-plugin
适用于只添加智能体工具的简单插件。defineToolPlugin 保持源代码精简,自动从 TypeBox schema 推断配置和工具参数类型,将普通返回值包装为 OpenClaw 工具结果格式,并暴露静态元数据供 openclaw plugins build 写入 manifest。
typescript
import { Type } from "typebox";
import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin";
export default defineToolPlugin({
id: "stock-quotes",
name: "Stock Quotes",
description: "Fetch stock quotes.",
configSchema: Type.Object({
apiKey: Type.Optional(Type.String({ description: "API key." })),
}),
tools: (tool) => [
tool({
name: "quote",
label: "Quote",
description: "Fetch a quote.",
parameters: Type.Object({
symbol: Type.String({ description: "Ticker symbol." }),
}),
execute: async ({ symbol }, config) => ({ symbol, hasKey: Boolean(config.apiKey) }),
}),
],
});configSchema可选。省略时 OpenClaw 使用严格空对象 schema,生成的 manifest 仍包含configSchema。execute返回纯字符串或 JSON 可序列化值,helper 会包装为带details的文本工具结果。- 工具名称是静态的。
openclaw plugins build根据声明的工具推导出contracts.tools,开发者无需手动重复名称。 - 运行时加载保持严格。已安装插件仍需要
openclaw.plugin.json和package.json中的openclaw.extensions;OpenClaw 不会执行插件代码来推断缺失的 manifest 数据。
definePluginEntry
导入路径: openclaw/plugin-sdk/plugin-entry
适用于 Provider 插件、高级工具插件、hook 插件以及不是消息渠道的所有插件。
typescript
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Short summary",
register(api) {
api.registerProvider({ /* ... */ });
api.registerTool({ /* ... */ });
},
});| 字段 | 类型 | 必填 | 默认值 |
|---|---|---|---|
id | string | 是 | - |
name | string | 是 | - |
description | string | 是 | - |
kind | string | 否 | - |
configSchema | OpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema | 否 | 空对象 schema |
register | (api: OpenClawPluginApi) => void | 是 | - |
id必须与openclaw.plugin.jsonmanifest 中的 id 一致。kind用于独占槽位:"memory"或"context-engine"。configSchema可以是函数用于懒求值。OpenClaw 在首次访问时解析并缓存该 schema,所以昂贵的 schema 构建器只运行一次。
defineChannelPluginEntry
导入路径: openclaw/plugin-sdk/channel-core
在 definePluginEntry 基础上加入渠道特定接线。自动调用 api.registerChannel({ plugin }),暴露可选的根 help CLI 元数据接缝,并通过注册模式控制 registerFull。
typescript
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";
export default defineChannelPluginEntry({
id: "my-channel",
name: "My Channel",
description: "Short summary",
plugin: myChannelPlugin,
setRuntime: setMyRuntime,
registerCliMetadata(api) {
api.registerCli(/* ... */);
},
registerFull(api) {
api.registerGatewayMethod(/* ... */);
},
});| 字段 | 类型 | 必填 | 默认值 |
|---|---|---|---|
id | string | 是 | - |
name | string | 是 | - |
description | string | 是 | - |
plugin | ChannelPlugin | 是 | - |
configSchema | OpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema | 否 | 空对象 schema |
setRuntime | (runtime: PluginRuntime) => void | 否 | - |
registerCliMetadata | (api: OpenClawPluginApi) => void | 否 | - |
registerFull | (api: OpenClawPluginApi) => void | 否 | - |
setRuntime在注册期间被调用,用于存储 runtime 引用(通常通过createPluginRuntimeStore)。CLI 元数据捕获时跳过。registerCliMetadata在api.registrationMode === "cli-metadata"、"discovery"和"full"时都会运行。它是放置渠道自有 CLI 描述符的规范位置,确保根 help 保持非激活、发现快照包含静态命令元数据,且正常 CLI 命令注册与完整插件加载兼容。- 发现注册是非激活的,但并非导入安全。OpenClaw 可能会评估受信任的插件入口和渠道插件模块来构建快照,因此确保顶层导入无副作用,将 socket、客户端、工作线程和服务放在
"full"独有路径后。 registerFull仅在api.registrationMode === "full"时运行,setup-only 加载时跳过。- 与
definePluginEntry一样,configSchema可以是懒工厂,OpenClaw 在首次访问时缓存解析后的 schema。 - 对于插件自有的根 CLI 命令,当你希望命令保持懒加载但不从根 CLI 解析树消失时,优先使用
api.registerCli(..., { descriptors: [...] })。对于配对节点功能命令,优先使用api.registerNodeCliFeature(...)使命令位于openclaw nodes下。对于其他嵌套插件命令,添加parentPath并在传递给注册器的program对象上注册命令。 - 如果
registerFull(...)也注册 gateway RPC 方法,请保持插件特定前缀。保留核心管理员命名空间(config.*、exec.approvals.*、wizard.*、update.*)总是被强制映射到operator.admin。
defineSetupPluginEntry
导入路径: openclaw/plugin-sdk/channel-core
用于轻量的 setup-entry.ts 文件。仅返回 { plugin },无 runtime 或 CLI 接线。
typescript
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
export default defineSetupPluginEntry(myChannelPlugin);当渠道禁用、未配置或启用了延迟加载时,OpenClaw 加载此文件而非完整入口。详见插件打包与配置中的 Setup 入口说明。
实践中,将 defineSetupPluginEntry(...) 与以下窄型 setup helper 配合使用:
openclaw/plugin-sdk/setup-runtime— runtime 安全的 setup helper(翻译、补丁适配器、查找笔记输出、promptResolvedAllowFrom、splitSetupEntries等)openclaw/plugin-sdk/channel-setup— 可选安装的 setup 面openclaw/plugin-sdk/setup-tools— setup/安装 CLI/归档/文档 helper
繁重的 SDK、CLI 注册和长期 runtime 服务应保留在完整入口中。
捆绑工作区渠道若拆分 setup 和 runtime 面,可以使用来自 openclaw/plugin-sdk/channel-entry-contract 的 defineBundledChannelSetupEntry(...) 替代。该合约允许 setup 入口保留 setup 安全的插件/secrets 导出,同时仍暴露一个 runtime setter:
typescript
import { defineBundledChannelSetupEntry } from "openclaw/plugin-sdk/channel-entry-contract";
export default defineBundledChannelSetupEntry({
importMetaUrl: import.meta.url,
plugin: {
specifier: "./channel-plugin-api.js",
exportName: "myChannelPlugin",
},
runtime: {
specifier: "./runtime-api.js",
exportName: "setMyChannelRuntime",
},
});仅在 setup 流程确实需要在完整渠道入口加载前有一个轻量 runtime setter 时使用该捆绑合约。
注册模式
api.registrationMode 告诉插件当前的加载方式:
| 模式 | 触发时机 | 应注册的内容 |
|---|---|---|
"full" | 正常网关启动 | 所有内容 |
"discovery" | 只读能力发现 | 渠道注册 + 静态 CLI 描述符;入口代码可能被加载,但跳过 socket、工作线程、客户端和服务 |
"setup-only" | 禁用/未配置的渠道 | 仅渠道注册 |
"setup-runtime" | 带有 runtime 的 Setup 流程 | 渠道注册 + 完整入口加载前所需的轻量 runtime |
"cli-metadata" | 根 help / CLI 元数据捕获 | 仅 CLI 描述符 |
defineChannelPluginEntry 自动处理这种分离。如果你直接用 definePluginEntry 实现渠道,需要手动检查模式:
typescript
register(api) {
if (
api.registrationMode === "cli-metadata" ||
api.registrationMode === "discovery" ||
api.registrationMode === "full"
) {
api.registerCli(/* ... */);
if (api.registrationMode === "cli-metadata") return;
}
api.registerChannel({ plugin: myPlugin });
if (api.registrationMode !== "full") return;
// 繁重的 runtime 专有注册
api.registerService(/* ... */);
}- 发现模式构建非激活的注册快照。它可能仍然评估插件入口和渠道插件对象,以便 OpenClaw 注册渠道能力和静态 CLI 描述符。应将发现模式中的模块评估视为受信任但轻量:不要在顶层引入网络客户端、子进程、监听器、数据库连接、后台工作线程、凭据读取或其他实时 runtime 副作用。
"setup-runtime"是 setup-only 启动面必须在完整入口加载前存在的窗口期。适合的内容:渠道注册、setup 安全的 HTTP 路由、setup 安全的 gateway 方法和委托 setup helper。繁重的后台服务、CLI 注册器和 Provider/客户端 SDK 初始化仍属于"full"模式。
关于 CLI 注册器的具体建议:
- 当注册器拥有一个或多个根命令且你希望 OpenClaw 在首次调用时懒加载真实 CLI 模块时,使用
descriptors。 - 确保这些 descriptors 覆盖注册器暴露的每个顶层命令根。
- descriptor 命令名称只能包含字母、数字、连字符和下划线,且必须以字母或数字开头。OpenClaw 拒绝不符合此形状的 descriptor 名称,并在渲染帮助前去除描述中的终端控制序列。
- 仅对兼容性旧路径使用
commands纯列表。
插件形态
OpenClaw 按注册行为(非静态元数据)对加载的插件进行分类:
| 形态 | 说明 |
|---|---|
| plain-capability | 恰好注册一种能力类型(例如仅 Provider 的 mistral) |
| hybrid-capability | 注册多种能力类型(例如 openai 同时拥有文本推理、语音、媒体理解和图像生成) |
| hook-only | 只注册 hook,无能力/工具/命令/服务 |
| non-capability | 注册工具、命令、服务或路由,但无能力 |
运行 openclaw plugins inspect <id> 查看插件的形态。
常见问题
registerCliMetadata 和 registerFull 里都能注册 CLI 命令吗?重复注册会怎样?
可以,但推荐仅在 registerCliMetadata 中注册 CLI 描述符,这样根 help 无需激活完整 runtime 即可展示命令。如果在两处注册同一命令,会造成重复注册,导致命令菜单中出现两次。
插件的 id 字段必须与 manifest 一致吗?
是的。definePluginEntry({ id }) 中的 id 必须与 openclaw.plugin.json 的 id 字段完全一致,否则 OpenClaw 加载时会产生错误。
"setup-only" 和 "setup-runtime" 有什么区别?
"setup-only" 用于渠道禁用或未配置时,只需暴露 setup/配置入口,不需要任何运行时能力。"setup-runtime" 是一个过渡窗口:渠道需要在完整入口加载之前就具备部分轻量运行时能力(如 setup 安全的 HTTP 路由或 gateway 方法)时使用,典型场景是延迟加载启动。
相关文档
- SDK 概览 — 注册 API 和子路径参考
- 运行时辅助工具 —
api.runtime和createPluginRuntimeStore - 插件打包与配置 — manifest、setup entry、延迟加载
- 渠道插件开发 — 构建
ChannelPlugin对象 - Provider 插件开发 — Provider 注册与 hook