Skip to main content
每个插件都会导出一个默认入口对象。SDK 提供了用于创建它们的辅助函数。 对于已安装的插件,package.json 在可用时应将运行时加载指向构建后的 JavaScript:
{
  "openclaw": {
    "extensions": ["./src/index.ts"],
    "runtimeExtensions": ["./dist/index.js"],
    "setupEntry": "./src/setup-entry.ts",
    "runtimeSetupEntry": "./dist/setup-entry.js"
  }
}
extensionssetupEntry 对于工作区和 git 检出开发仍然有效。runtimeExtensionsruntimeSetupEntry 在 OpenClaw 加载已安装包时更受青睐,并允许 npm 包避免运行时 TypeScript 编译。显式运行时入口是必需的:runtimeSetupEntry 需要 setupEntry,而缺少 runtimeExtensionsruntimeSetupEntry 制品会导致安装/发现失败,而不是静默回退到源代码。如果 已安装包只声明了一个 TypeScript 源入口,OpenClaw 会在存在时使用 匹配的构建后 dist/*.js 同级文件,然后再回退到 TypeScript 源文件。 所有入口路径都必须保持在插件包目录内。运行时入口以及推断出的构建后 JavaScript 同级文件,不能让一个会越界的 extensionssetupEntry 源路径变得有效。
想看一步步的讲解? 请参见 工具插件通道插件提供者插件

defineToolPlugin

导入: openclaw/plugin-sdk/tool-plugin 适用于只添加代理工具的简单插件。defineToolPlugin 会保持作者编写的源代码尽可能精简,从 TypeBox schema 推断配置和工具参数类型,将普通返回值包装为 OpenClaw 工具结果格式,并暴露静态元数据,供 openclaw plugins build 写入插件清单。
import { Type } from "typebox";
import { defineToolPlugin } from "openclaw/plugin-sdk/tool-plugin";

export default defineToolPlugin({
  id: "stock-quotes",
  name: "股票报价",
  description: "获取股票报价。",
  configSchema: Type.Object({
    apiKey: Type.Optional(Type.String({ description: "API 密钥。" })),
  }),
  tools: (tool) => [
    tool({
      name: "quote",
      label: "报价",
      description: "获取报价。",
      parameters: Type.Object({
        symbol: Type.String({ description: "股票代码。" }),
      }),
      execute: async ({ symbol }, config) => ({ symbol, hasKey: Boolean(config.apiKey) }),
    }),
  ],
});
  • configSchema 是可选的。省略时,OpenClaw 会使用严格的空对象 schema,并且生成的清单仍然会包含 configSchema
  • execute 返回普通字符串或可 JSON 序列化的值。该辅助函数会将其包装为带有 details 的文本工具结果。
  • 工具名称是静态的。openclaw plugins build 会根据已声明的工具推导 contracts.tools,因此作者无需手动重复名称。
  • 运行时加载仍然保持严格。已安装插件仍然需要 openclaw.plugin.jsonpackage.json 中的 openclaw.extensions;OpenClaw 不会执行插件代码来推断缺失的清单数据。

definePluginEntry

导入: openclaw/plugin-sdk/plugin-entry 适用于提供者插件、高级工具插件、钩子插件,以及任何不是消息通道的内容。
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";

export default definePluginEntry({
  id: "my-plugin",
  name: "我的插件",
  description: "简短摘要",
  register(api) {
    api.registerProvider({
      /* ... */
    });
    api.registerTool({
      /* ... */
    });
  },
});
字段类型必需默认值
idstring-
namestring-
descriptionstring-
kindstring-
configSchemaOpenClawPluginConfigSchema | () => OpenClawPluginConfigSchema空对象 schema
register(api: OpenClawPluginApi) => void-
  • id 必须与 openclaw.plugin.json 清单匹配。
  • kind 用于独占槽位:"memory""context-engine"
  • configSchema 可以是一个用于延迟求值的函数。
  • OpenClaw 会在首次访问时解析并记忆化该 schema,因此开销较大的 schema 构建器只会运行一次。

defineChannelPluginEntry

导入: openclaw/plugin-sdk/channel-core definePluginEntry 进行通道特定封装。它会自动调用 api.registerChannel({ plugin }),暴露一个可选的根帮助 CLI 元数据接口,并根据注册模式对 registerFull 进行门控。
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";

export default defineChannelPluginEntry({
  id: "my-channel",
  name: "我的通道",
  description: "简短摘要",
  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 会在注册期间调用,因此你可以存储运行时引用 (通常通过 createPluginRuntimeStore)。在 CLI 元数据 捕获期间会跳过它。
  • registerCliMetadata 会在 api.registrationMode === "cli-metadata"api.registrationMode === "discovery" 以及 api.registrationMode === "full" 时运行。 这是放置通道拥有的 CLI 描述符的规范位置,这样根帮助可以保持非激活、发现快照可以包含静态命令元数据,并且常规 CLI 命令注册仍然与完整插件加载兼容。
  • 发现注册是非激活的,但不是免导入的。OpenClaw 可能会 评估受信任的插件入口和通道插件模块来构建 快照,因此请保持顶层导入无副作用,并将 sockets、 clients、workers 和 services 放在仅 "full" 的路径之后。
  • registerFull 仅在 api.registrationMode === "full" 时运行。它会在 仅 setup 加载期间被跳过。
  • definePluginEntry 类似,configSchema 可以是延迟工厂,OpenClaw 会在首次访问时对解析后的 schema 进行记忆化。
  • 对于插件拥有的根 CLI 命令,当你希望命令保持懒加载但又不从 根 CLI 解析树中消失时,请优先使用 api.registerCli(..., { descriptors: [...] })。 对于成对节点功能命令,请优先使用 api.registerNodeCliFeature(...),这样命令会落在 openclaw nodes 下。 对于其他嵌套插件命令,请添加 parentPath 并在传给注册器的 program 对象上注册命令;OpenClaw 会在调用插件前将其解析为 父命令。对于通道插件,请优先从 registerCliMetadata(...) 注册这些描述符,并让 registerFull(...) 专注于仅运行时工作。
  • 如果 registerFull(...) 还注册 gateway RPC 方法,请将它们保留在 插件专用前缀下。保留的核心管理员命名空间(config.*exec.approvals.*wizard.*update.*)始终会被强制归类为 operator.admin

defineSetupPluginEntry

导入: openclaw/plugin-sdk/channel-core 用于轻量级的 setup-entry.ts 文件。只返回 { plugin },不包含运行时或 CLI 接线。
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";

export default defineSetupPluginEntry(myChannelPlugin);
当通道被禁用、未配置,或者启用了延迟加载时,OpenClaw 会加载这个入口而不是完整入口。有关这在何时重要,请参见 Setup and Config 实践中,将 defineSetupPluginEntry(...) 与以下窄范围 setup 辅助族配对使用:
  • openclaw/plugin-sdk/setup-runtime 用于运行时安全的 setup 辅助工具,例如 createSetupTranslator、导入安全的 setup patch 适配器、lookup-note 输出、 promptResolvedAllowFromsplitSetupEntries 和委托式 setup 代理
  • openclaw/plugin-sdk/channel-setup 用于可选安装的 setup 表面
  • openclaw/plugin-sdk/setup-tools 用于 setup/安装 CLI/归档/文档辅助工具
将重型 SDK、CLI 注册以及长生命周期的运行时服务保留在完整入口中。 分离 setup 和 runtime 表面的打包工作区通道可以改用 openclaw/plugin-sdk/channel-entry-contract 中的 defineBundledChannelSetupEntry(...)。 该契约允许 setup 入口保留 setup 安全的 plugin/secrets 导出,同时仍然暴露一个运行时 setter:
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",
  },
  registerSetupRuntime(api) {
    api.registerHttpRoute({
      path: "/my-channel/events",
      auth: "plugin",
      handler: async (req, res) => {
        /* 仅限 setup 的安全路由 */
      },
    });
  },
});
仅在 setup 流程确实需要一个轻量级运行时 setter 或在完整通道入口加载之前需要 setup 安全的 gateway 表面时,才使用这个 bundled contract。 registerSetupRuntime 仅在 "setup-runtime" 加载时运行;请将其限制为 仅配置路由或在延迟的完整激活之前必须存在的方法。

注册模式

api.registrationMode 会告诉你的插件它是如何被加载的:
模式何时需要注册的内容
"full"正常 gateway 启动全部内容
"discovery"只读能力发现通道注册加静态 CLI 描述符;入口代码可能会加载,但要跳过 sockets、workers、clients 和 services
"setup-only"被禁用/未配置的通道仅通道注册
"setup-runtime"带有可用运行时的 setup 流程通道注册加上在完整入口加载之前所需的轻量级运行时
"cli-metadata"根帮助 / CLI 元数据捕获仅 CLI 描述符
defineChannelPluginEntry 会自动处理这种拆分。如果你直接为通道使用 definePluginEntry,则需要自己检查模式:
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;

  // 仅运行时的重型注册
  api.registerService(/* ... */);
}
发现模式会构建一个非激活的注册表快照。它仍可能计算插件入口和通道插件对象,以便 OpenClaw 可以注册通道能力和静态 CLI 描述符。将发现过程中的模块求值视为受信任但轻量:不要在顶层引入网络客户端、子进程、监听器、数据库连接、后台 worker、凭据读取或其他实时运行时副作用。 "setup-runtime" 视为 setup-only 启动表面必须存在、但不能重新进入完整打包通道运行时的窗口。适合的内容包括通道注册、setup 安全的 HTTP 路由、setup 安全的 gateway 方法,以及委托式 setup 辅助。重型后台服务、CLI 注册器和 provider/client SDK 启动仍然属于 "full" 针对 CLI 注册器而言:
  • 当注册器拥有一个或多个根命令,并且你希望 OpenClaw 在首次调用时懒加载真实的 CLI 模块时,请使用 descriptors
  • 确保这些描述符覆盖注册器暴露的每一个顶层命令根
  • 将描述符命令名限制为字母、数字、连字符和下划线,并且以字母或数字开头;OpenClaw 会拒绝不符合该形状的描述符名称,并在渲染帮助之前剥离描述中的终端控制序列
  • 仅在急切兼容路径中单独使用 commands

插件形态

OpenClaw 根据已加载插件的注册行为对其进行分类:
形态描述
plain-capability一种能力类型(例如,仅 provider)
hybrid-capability多种能力类型(例如,provider + speech)
hook-only仅有 hooks,没有 capabilities
non-capability工具/命令/服务,但没有 capabilities
使用 openclaw plugins inspect <id> 查看插件的形态。

相关