Skip to content

OpenClaw 插件入口辅助函数定义了插件的注册行为。本页给出 definePluginEntrydefineChannelPluginEntrydefineToolPlugindefineSetupPluginEntry 的必填/可选字段、参数类型和注册模式(full、setup-only、setup-runtime、cli-metadata)说明。使用 definePluginEntry 时须在 package.json 中指定 extensionsruntimeExtensions,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"
  }
}
  • extensionssetupEntry 保留作为源代码入口,适用于工作区和 git checkout 开发环境。
  • runtimeExtensionsruntimeSetupEntry 在 OpenClaw 加载已安装包时优先使用,避免运行时 TypeScript 编译。必须显式声明:runtimeSetupEntry 要求同时声明 setupEntry;缺少 runtimeExtensionsruntimeSetupEntry 产物会导致安装/发现失败,不会静默回退到源代码。
  • 如果已安装包只声明了 TypeScript 源文件入口,OpenClaw 会尝试找到对应的 dist/*.js 文件(如存在),否则回退到 TypeScript 源代码。
  • 所有入口路径必须位于插件包目录内。runtime 条目和推断出的构建副本不能使逃逸包目录的 extensionssetupEntry 源路径变为合法。

需要完整开发流程?请参考工具插件开发渠道插件开发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.jsonpackage.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({ /* ... */ });
  },
});
字段类型必填默认值
idstring-
namestring-
descriptionstring-
kindstring-
configSchemaOpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema空对象 schema
register(api: OpenClawPluginApi) => void-
  • id 必须与 openclaw.plugin.json manifest 中的 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(/* ... */);
  },
});
字段类型必填默认值
idstring-
namestring-
descriptionstring-
pluginChannelPlugin-
configSchemaOpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema空对象 schema
setRuntime(runtime: PluginRuntime) => void-
registerCliMetadata(api: OpenClawPluginApi) => void-
registerFull(api: OpenClawPluginApi) => void-
  • setRuntime 在注册期间被调用,用于存储 runtime 引用(通常通过 createPluginRuntimeStore)。CLI 元数据捕获时跳过。
  • registerCliMetadataapi.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(翻译、补丁适配器、查找笔记输出、promptResolvedAllowFromsplitSetupEntries 等)
  • openclaw/plugin-sdk/channel-setup — 可选安装的 setup 面
  • openclaw/plugin-sdk/setup-tools — setup/安装 CLI/归档/文档 helper

繁重的 SDK、CLI 注册和长期 runtime 服务应保留在完整入口中。

捆绑工作区渠道若拆分 setup 和 runtime 面,可以使用来自 openclaw/plugin-sdk/channel-entry-contractdefineBundledChannelSetupEntry(...) 替代。该合约允许 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> 查看插件的形态。

常见问题

registerCliMetadataregisterFull 里都能注册 CLI 命令吗?重复注册会怎样?

可以,但推荐仅在 registerCliMetadata 中注册 CLI 描述符,这样根 help 无需激活完整 runtime 即可展示命令。如果在两处注册同一命令,会造成重复注册,导致命令菜单中出现两次。

插件的 id 字段必须与 manifest 一致吗?

是的。definePluginEntry({ id }) 中的 id 必须与 openclaw.plugin.jsonid 字段完全一致,否则 OpenClaw 加载时会产生错误。

"setup-only""setup-runtime" 有什么区别?

"setup-only" 用于渠道禁用或未配置时,只需暴露 setup/配置入口,不需要任何运行时能力。"setup-runtime" 是一个过渡窗口:渠道需要在完整入口加载之前就具备部分轻量运行时能力(如 setup 安全的 HTTP 路由或 gateway 方法)时使用,典型场景是延迟加载启动。

相关文档