Skip to main content
插件打包(package.json 元数据)、清单(openclaw.plugin.json)、设置入口以及配置 schema 的参考文档。
在找操作流程吗? 操作指南会结合上下文讲解打包: 频道插件提供者插件

包元数据

你的 package.json 需要包含一个 openclaw 字段,用于告诉插件系统你的插件提供了什么:
{
  "name": "@myorg/openclaw-my-channel",
  "version": "1.0.0",
  "type": "module",
  "openclaw": {
    "extensions": ["./index.ts"],
    "setupEntry": "./setup-entry.ts",
    "channel": {
      "id": "my-channel",
      "label": "我的频道",
      "blurb": "频道的简短描述。"
    }
  }
}
如果你将插件作为外部插件发布到 ClawHub,这些 compatbuild 字段是必需的。权威的发布示例位于 docs/snippets/plugin-publish/

openclaw 字段

extensions
string[]
入口点文件(相对于包根目录)。
setupEntry
string
轻量级的仅设置入口(可选)。
channel
object
用于设置、选择器、快速开始和状态界面的频道目录元数据。
providers
string[]
由此插件注册的提供者 id。
install
object
安装提示:npmSpeclocalPathdefaultChoiceminHostVersionexpectedIntegrityallowInvalidConfigRecovery
startup
object
启动行为标志。

openclaw.channel

openclaw.channel 是用于运行时加载之前的频道发现和设置界面的轻量包元数据。
字段类型含义
idstring规范化的频道 id。
labelstring主要频道标签。
selectionLabelstring当需要与 label 不同时,在选择器/设置中显示的标签。
detailLabelstring用于更丰富频道目录和状态界面的次级详细标签。
docsPathstring用于设置和选择链接的文档路径。
docsLabelstring用于文档链接的覆盖标签,当它需要与频道 id 不同时使用。
blurbstring简短的引导/目录描述。
ordernumber频道目录中的排序顺序。
aliasesstring[]频道选择的额外查找别名。
preferOverstring[]此频道应优先于哪些更低优先级的插件/频道 id。
systemImagestring用于频道 UI 目录的可选图标/system-image 名称。
selectionDocsPrefixstring选择界面中文档链接前的前缀文本。
selectionDocsOmitLabelboolean在选择文案中直接显示文档路径,而不是带标签的文档链接。
selectionExtrasstring[]附加在选择文案中的额外短字符串。
markdownCapableboolean将频道标记为支持 markdown,用于外发格式化决策。
exposureobject用于设置、已配置列表和文档界面的频道可见性控制。
quickstartAllowFromboolean将此频道纳入标准快速开始 allowFrom 设置流程。
forceAccountBindingboolean即使只有一个账户存在,也要求显式账户绑定。
preferSessionLookupForAnnounceTargetboolean解析该频道的 announce 目标时优先使用 session 查找。
示例:
{
  "openclaw": {
    "channel": {
      "id": "my-channel",
      "label": "我的频道",
      "selectionLabel": "我的频道(自托管)",
      "detailLabel": "我的频道机器人",
      "docsPath": "/channels/my-channel",
      "docsLabel": "my-channel",
      "blurb": "基于 Webhook 的自托管聊天集成。",
      "order": 80,
      "aliases": ["mc"],
      "preferOver": ["my-channel-legacy"],
      "selectionDocsPrefix": "指南:",
      "selectionExtras": ["Markdown"],
      "markdownCapable": true,
      "exposure": {
        "configured": true,
        "setup": true,
        "docs": true
      },
      "quickstartAllowFrom": true
    }
  }
}
exposure 支持:
  • configured:在已配置/状态类列表界面中包含该频道
  • setup:在交互式设置/配置选择器中包含该频道
  • docs:在文档/导航界面中将该频道标记为面向公众
showConfiguredshowInSetup 仍作为旧别名受支持。优先使用 exposure

openclaw.install

openclaw.install 是包元数据,不是清单元数据。
字段类型含义
clawhubSpecstring安装/更新和引导按需安装流程的规范化 ClawHub 规格。
npmSpecstring安装/更新回退流程的规范化 npm 规格。
localPathstring本地开发或打包后的安装路径。
defaultChoice"clawhub" | "npm" | "local"当有多个来源可用时的首选安装来源。
minHostVersionstring最低支持的 OpenClaw 版本,格式为 >=x.y.z>=x.y.z-prerelease
expectedIntegritystring预期的 npm dist integrity 字符串,通常为 sha512-...,用于固定安装。
allowInvalidConfigRecoveryboolean允许捆绑插件重装流程从特定的过期配置失败中恢复。
交互式引导也会使用 openclaw.install 来支持按需安装界面。如果你的插件在运行时加载前公开了提供者认证选项或频道设置/目录元数据,引导可以显示该选项,提示选择 ClawHub、npm 或本地安装,安装或启用插件,然后继续所选流程。ClawHub 引导选项使用 clawhubSpec,在存在时会优先使用;npm 选项需要带有注册表 npmSpec 的受信任目录元数据;精确版本和 expectedIntegrity 是可选的 npm 固定项。如果存在 expectedIntegrity,安装/更新流程会对 npm 强制执行它。把“展示什么”的元数据放在 openclaw.plugin.json 中,把“如何安装”的元数据放在 package.json 中。
如果设置了 minHostVersion,安装以及非捆绑的清单注册表加载都会强制执行它。较旧的宿主会跳过外部插件;无效的版本字符串会被拒绝。捆绑源码插件默认视为与宿主检出版本一致。
对于固定的 npm 安装,请在 npmSpec 中保留精确版本,并添加预期的制品完整性:
{
  "openclaw": {
    "install": {
      "npmSpec": "@wecom/[email protected]",
      "expectedIntegrity": "sha512-REPLACE_WITH_NPM_DIST_INTEGRITY",
      "defaultChoice": "npm"
    }
  }
}
allowInvalidConfigRecovery 不是对损坏配置的通用绕过。它仅用于狭义的捆绑插件恢复,因此重装/设置可以修复已知的升级残留,例如缺失的捆绑插件路径,或同一插件的过期 channels.<id> 条目。如果配置因无关原因损坏,安装仍会失败并提示操作员运行 openclaw doctor --fix

延迟完整加载

频道插件可以通过以下方式启用延迟加载:
{
  "openclaw": {
    "extensions": ["./index.ts"],
    "setupEntry": "./setup-entry.ts",
    "startup": {
      "deferConfiguredChannelFullLoadUntilAfterListen": true
    }
  }
}
启用后,OpenClaw 会仅在监听前的启动阶段加载 setupEntry,即使对于已经配置好的频道也是如此。完整入口会在网关开始监听后加载。
只有当你的 setupEntry 在网关开始监听前注册了网关所需的一切内容时,才启用延迟加载(频道注册、HTTP 路由、网关方法)。如果完整入口承担了必需的启动能力,请保持默认行为。
如果你的设置/完整入口注册了网关 RPC 方法,请将它们保留在插件专属前缀下。保留的核心管理命名空间(config.*exec.approvals.*wizard.*update.*)仍由核心拥有,并始终解析到 operator.admin

插件清单

每个原生插件都必须在包根目录中随附一个 openclaw.plugin.json。OpenClaw 使用它在不执行插件代码的情况下验证配置。
{
  "id": "my-plugin",
  "name": "我的插件",
  "description": "为 OpenClaw 添加我的插件功能",
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "webhookSecret": {
        "type": "string",
        "description": "Webhook 验证密钥"
      }
    }
  }
}
对于频道插件,添加 kindchannels
{
  "id": "my-channel",
  "kind": "channel",
  "channels": ["my-channel"],
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {}
  }
}
即使没有配置的插件也必须提供 schema。空 schema 也是有效的:
{
  "id": "my-plugin",
  "configSchema": {
    "type": "object",
    "additionalProperties": false
  }
}
有关完整的 schema 参考,请参阅 插件清单

ClawHub 发布

对于插件包,请使用包专用的 ClawHub 命令:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
旧的仅技能发布别名是给技能使用的。插件包应始终使用 clawhub package publish

Setup 入口

setup-entry.ts 文件是 index.ts 的轻量替代方案,OpenClaw 会在只需要设置相关界面(引导、配置修复、禁用频道检查)时加载它。
// setup-entry.ts
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";
import { myChannelPlugin } from "./src/channel.js";

export default defineSetupPluginEntry(myChannelPlugin);
这可以避免在设置流程中加载较重的运行时代码(加密库、CLI 注册、后台服务)。 将设置安全导出保留在侧车模块中的打包工作区频道,可以使用 openclaw/plugin-sdk/channel-entry-contract 中的 defineBundledChannelSetupEntry(...) 代替 defineSetupPluginEntry(...)。该打包契约还支持可选的 runtime 导出,因此设置阶段的运行时绑定可以保持轻量且明确。
  • 频道已禁用,但仍需要设置/引导界面。
  • 频道已启用但尚未配置。
  • 已启用延迟加载(deferConfiguredChannelFullLoadUntilAfterListen)。
  • 频道插件对象(通过 defineSetupPluginEntry)。
  • 在 gateway listen 之前所需的任何 HTTP 路由。
  • 启动期间需要的任何 gateway 方法。
这些启动阶段的 gateway 方法仍应避免使用保留的核心管理命名空间,例如 config.*update.*
  • CLI 注册。
  • 后台服务。
  • 重型运行时导入(crypto、SDK 等)。
  • 仅在启动后才需要的 gateway 方法。

细粒度 setup 辅助导入

对于热路径的仅设置场景,当你只需要设置面的部分能力时,优先使用更细粒度的 setup 辅助接口,而不是更宽泛的 plugin-sdk/setup 总入口:
导入路径适用场景关键导出
plugin-sdk/setup-runtimesetupEntry / 延迟频道启动中仍然可用的设置期运行时辅助工具createSetupTranslatorcreatePatchedAccountSetupAdaptercreateEnvPatchedAccountSetupAdaptercreateSetupInputPresenceValidatornoteChannelLookupFailurenoteChannelLookupSummarypromptResolvedAllowFromsplitSetupEntriescreateAllowlistSetupWizardProxycreateDelegatedSetupWizardProxy
plugin-sdk/setup-adapter-runtime已弃用的兼容别名;请使用 plugin-sdk/setup-runtimecreateEnvPatchedAccountSetupAdapter
plugin-sdk/setup-tools设置/安装 CLI/归档/文档辅助工具formatCliCommanddetectBinaryextractArchiveresolveBrewExecutableformatDocsLinkCONFIG_DIR
当你想要完整的共享设置工具箱时,请使用更宽泛的 plugin-sdk/setup 接口,包括诸如 moveSingleAccountChannelSectionToDefaultAccount(...) 之类的配置补丁辅助工具。 对于固定的设置向导文案,请使用 createSetupTranslator(...)。它会遵循 CLI 向导的语言环境(先读取 OPENCLAW_LOCALE,再读取系统语言环境变量),并回退到英文。插件专有的设置文案应保留在插件自有代码中,仅将通用的设置标签、状态文本以及官方打包插件的设置文案放入共享目录键。 setup 补丁适配器在导入时对热路径是安全的。其打包后的单账户提升契约面查找是懒加载的,因此导入 plugin-sdk/setup-runtime 不会在适配器真正被使用之前就急切地加载打包契约面的发现逻辑。

频道拥有的单账户提升

当某个频道从单账户顶层配置升级到 channels.<id>.accounts.* 时,默认共享行为是将被提升的账户范围值移动到 accounts.default 打包频道可以通过其 setup 契约面来收窄或覆盖该提升行为:
  • singleAccountKeysToMove:应移动到被提升账户中的额外顶层键
  • namedAccountPromotionKeys:当已存在命名账户时,仅这些键会移动到被提升账户;共享的策略/投递键保留在频道根部
  • resolveSingleAccountPromotionTarget(...):选择哪个现有账户接收被提升的值
Matrix 是当前的打包示例。如果已经恰好存在一个命名的 Matrix 账户,或者 defaultAccount 指向一个现有的非规范键,例如 Ops,那么提升会保留该账户,而不是创建一个新的 accounts.default 条目。

Configuration Schema

Plugin configuration is validated against the JSON Schema in the manifest. Users configure plugins in the following way:
{
  plugins: {
    entries: {
      "my-plugin": {
        config: {
          webhookSecret: "abc123",
        },
      },
    },
  },
}
During registration, your plugin receives this configuration as api.pluginConfig. For channel-specific configuration, use the channel configuration section instead:
{
  channels: {
    "my-channel": {
      token: "bot-token",
      allowFrom: ["user1", "user2"],
    },
  },
}

Build Channel Config Schema

Use buildChannelConfigSchema to convert a Zod schema into the ChannelConfigSchema wrapper used by plugin-owned configuration artifacts:
import { z } from "zod";
import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";

const accountSchema = z.object({
  token: z.string().optional(),
  allowFrom: z.array(z.string()).optional(),
  accounts: z.object({}).catchall(z.any()).optional(),
  defaultAccount: z.string().optional(),
});

const configSchema = buildChannelConfigSchema(accountSchema);
If you have already authored the contract as JSON Schema or TypeBox, use the direct helper so OpenClaw can skip the Zod-to-JSON-Schema conversion on metadata paths:
import { Type } from "typebox";
import { buildJsonChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";

const configSchema = buildJsonChannelConfigSchema(
  Type.Object({
    token: Type.Optional(Type.String()),
    allowFrom: Type.Optional(Type.Array(Type.String())),
  }),
);
For third-party plugins, the cold-path contract remains the plugin manifest: mirror the generated JSON Schema into openclaw.plugin.json#channelConfigs so config schema, setup, and UI surfaces can inspect channels.<id> without loading runtime code.

Installation Wizard

Channel plugins can provide an interactive installation wizard for openclaw onboard. The wizard is a ChannelSetupWizard object on ChannelPlugin:
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/channel-setup";

const setupWizard: ChannelSetupWizard = {
  channel: "my-channel",
  status: {
    configuredLabel: "Connected",
    unconfiguredLabel: "Not configured",
    resolveConfigured: ({ cfg }) => Boolean((cfg.channels as any)?.["my-channel"]?.token),
  },
  credentials: [
    {
      inputKey: "token",
      providerHint: "my-channel",
      credentialLabel: "Bot token",
      preferredEnvVar: "MY_CHANNEL_BOT_TOKEN",
      envPrompt: "Use MY_CHANNEL_BOT_TOKEN from the environment?",
      keepPrompt: "Keep the current token?",
      inputPrompt: "Enter your bot token:",
      inspect: ({ cfg, accountId }) => {
        const token = (cfg.channels as any)?.["my-channel"]?.token;
        return {
          accountConfigured: Boolean(token),
          hasConfiguredValue: Boolean(token),
        };
      },
    },
  ],
};
The ChannelSetupWizard type supports more, including credentials, textInputs, dmPolicy, allowFrom, groupAccess, prepare, and finalize. See the packaged plugin package for a complete example (for example, the Discord plugin’s src/channel.setup.ts).
For DM allowlist prompts that only need the standard note -> prompt -> parse -> merge -> patch flow, prefer the shared setup helpers in openclaw/plugin-sdk/setup: createPromptParsedAllowFromForAccount(...), createTopLevelChannelParsedAllowFromPrompt(...), and createNestedChannelParsedAllowFromPrompt(...).
For channel setup status blocks that differ only in label, score, and optional extra lines, prefer createStandardChannelSetupStatus(...) in openclaw/plugin-sdk/setup instead of hand-writing the same status object in every plugin.
For optional setup surfaces that should only appear in certain contexts, use createOptionalChannelSetupSurface from openclaw/plugin-sdk/channel-setup:
import { createOptionalChannelSetupSurface } from "openclaw/plugin-sdk/channel-setup";

const setupSurface = createOptionalChannelSetupSurface({
  channel: "my-channel",
  label: "My Channel",
  npmSpec: "@myorg/openclaw-my-channel",
  docsPath: "/channels/my-channel",
});
// Returns { setupAdapter, setupWizard }
When you only need one half of this optional installation surface, plugin-sdk/channel-setup also exposes lower-level createOptionalChannelSetupAdapter(...) and createOptionalChannelSetupWizard(...) builders.Generated optional adapters/wizards fail closed when writing real configuration. They reuse the same “installation required” message in validateInput, applyAccountConfig, and finalize, and append a docs link when docsPath is set.
For binary-driven setup UIs, prefer shared delegation helpers instead of duplicating the same binary/state glue in every channel:
  • createDetectedBinaryStatus(...): for status blocks that differ only in label, hint, score, and binary detection
  • createCliPathTextInput(...): for path-based text inputs
  • createDelegatedSetupWizardStatusResolvers(...), createDelegatedPrepare(...), createDelegatedFinalize(...), and createDelegatedResolveConfigured(...): when setupEntry needs to lazily forward to a heavier full wizard
  • createDelegatedTextInputShouldPrompt(...): when setupEntry only needs to delegate textInputs[*].shouldPrompt

Release and Installation

External plugins: Publish to ClawHub, then install:
openclaw plugins install @myorg/openclaw-my-plugin
Bare package specs are installed from npm during startup switching.
In-repo plugins: Place them under the packaged plugin workspace tree, and they are discovered automatically during builds. User-installable:
openclaw plugins install <package-name>
For npm-sourced installs, openclaw plugins install installs the package into a per-plugin project under ~/.openclaw/npm/projects with lifecycle scripts disabled. Keep plugin dependency trees pure JS/TS and avoid packages that require postinstall builds.
Gateway startup does not install plugin dependencies. The npm/git/ClawHub install flows handle dependency resolution; local plugins must already have their dependencies installed.
Packaged package metadata is explicit and is not inferred from built JavaScript at gateway startup. Runtime dependencies should live in the plugin package that owns them; the packaged OpenClaw startup flow does not repair or mirror plugin dependencies.