插件(扩展)
快速入门(初次接触插件?)
插件只是一个小代码模块,通过额外功能(命令、工具和 Gateway RPC)扩展 OpenClaw。
大多数情况下,当您需要核心 OpenClaw 尚未内置的功能时(或者您想将可选功能排除在主安装之外),您会使用插件。
快速路径:
- 查看已加载的内容:
openclaw plugins list
- 安装官方插件(示例:Voice Call):
openclaw plugins install @openclaw/voice-call
- 重启 Gateway,然后在 plugins.entries.<id>.config 下配置。
参见 Voice Call 获取具体的插件示例。
可用插件(官方)
- Microsoft Teams 从 2026.1.15 起仅作为插件;如果使用 Teams,请安装 @openclaw/msteams。
- Memory (Core) — 捆绑的内存搜索插件(默认通过 plugins.slots.memory 启用)
- Memory (LanceDB) — 捆绑的长期内存插件(自动回忆/捕获;设置 plugins.slots.memory = "memory-lancedb")
- Voice Call — @openclaw/voice-call
- Zalo Personal — @openclaw/zalouser
- Matrix — @openclaw/matrix
- Nostr — @openclaw/nostr
- Zalo — @openclaw/zalo
- Microsoft Teams — @openclaw/msteams
- Google Antigravity OAuth(provider auth)— 捆绑为 google-antigravity-auth(默认禁用)
- Gemini CLI OAuth(provider auth)— 捆绑为 google-gemini-cli-auth(默认禁用)
- Qwen OAuth(provider auth)— 捆绑为 qwen-portal-auth(默认禁用)
- Copilot Proxy(provider auth)— 本地 VS Code Copilot Proxy 桥接;与内置的 github-copilot 设备登录不同(捆绑,默认禁用)
OpenClaw 插件是通过 jiti 在运行时加载的 TypeScript 模块。配置验证不执行插件代码;它使用插件清单和 JSON Schema 代替。参见 插件清单。
插件可以注册:
- Gateway RPC 方法
- Gateway HTTP 处理程序
- Agent 工具
- CLI 命令
- 后台服务
- 可选的配置验证
- Skills(通过在插件清单中列出 skills 目录)
- 自动回复命令(无需调用 AI agent 即可执行)
插件与 Gateway 在进程内运行,因此将它们视为受信任的代码。 工具编写指南:插件 agent 工具。
运行时助手
插件可以通过 api.runtime 访问选定的核心助手。对于电话 TTS:
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
注意:
- 使用核心 messages.tts 配置(OpenAI 或 ElevenLabs)。
- 返回 PCM 音频缓冲区 + 采样率。插件必须为 provider 重采样/编码。
- Edge TTS 不支持电话。
发现和优先级
OpenClaw 按顺序扫描:
- 配置路径
- plugins.load.paths(文件或目录)
- 工作区扩展
- <workspace>/.openclaw/extensions/*.ts
- <workspace>/.openclaw/extensions/*/index.ts
- 全局扩展
- ~/.openclaw/extensions/*.ts
- ~/.openclaw/extensions/*/index.ts
- 捆绑扩展(随 OpenClaw 一起提供,默认禁用)
- <openclaw>/extensions/*
捆绑插件必须通过 plugins.entries.<id>.enabled 或 openclaw plugins enable <id> 明确启用。已安装的插件默认启用,但可以通过相同方式禁用。
每个插件必须在其根目录包含 openclaw.plugin.json 文件。如果路径指向文件,则插件根是文件的目录,并且必须包含清单。
如果多个插件解析为相同的 id,则上述顺序中的第一个匹配获胜,较低优先级的副本将被忽略。
包集合
插件目录可以包含带有 openclaw.extensions 的 package.json:
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"]
}
}
每个条目成为一个插件。如果包列出多个扩展,则插件 id 变为 name/<fileBase>。
如果您的插件导入 npm 依赖项,请在该目录中安装它们,以便 node_modules 可用(npm install / pnpm install)。
Channel 目录元数据
Channel 插件可以通过 openclaw.channel 宣传入门元数据,并通过 openclaw.install 安装提示。这使核心目录保持无数据。
示例:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk (self-hosted)",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "extensions/nextcloud-talk",
"defaultChoice": "npm"
}
}
}
OpenClaw 还可以合并外部 channel 目录(例如,MPM 注册表导出)。将 JSON 文件放在以下位置之一:
- ~/.openclaw/mpm/plugins.json
- ~/.openclaw/mpm/catalog.json
- ~/.openclaw/plugins/catalog.json
或将 OPENCLAW_PLUGIN_CATALOG_PATHS(或 OPENCLAW_MPM_CATALOG_PATHS)指向一个或多个 JSON 文件(逗号/分号/PATH 分隔)。每个文件应包含 { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }。
插件 ID
默认插件 id:
- 包集合:package.json name
- 独立文件:文件基本名称(~/.../voice-call.ts → voice-call)
如果插件导出 id,OpenClaw 使用它,但当它与配置的 id 不匹配时会发出警告。
配置
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: ["untrusted-plugin"],
load: { paths: ["~/Projects/oss/voice-call-extension"] },
entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } }
}
}
}
字段:
- enabled:主开关(默认:true)
- allow:允许列表(可选)
- deny:拒绝列表(可选;deny 优先)
- load.paths:额外的插件文件/目录
- entries.<id>:每个插件的开关 + 配置
配置更改需要重启 gateway。
验证规则(严格):
- entries、allow、deny 或 slots 中的未知插件 id 是错误。
- 未知的 channels.<id> 键是错误,除非插件清单声明了 channel id。
- 插件配置使用嵌入在 openclaw.plugin.json(configSchema)中的 JSON Schema 进行验证。
- 如果插件被禁用,则保留其配置并发出警告。
插件插槽(独占类别)
某些插件类别是独占的(一次只有一个活动)。使用 plugins.slots 选择哪个插件拥有插槽:
{
plugins: {
slots: {
memory: "memory-core" // 或 "none" 禁用内存插件
}
}
}
如果多个插件声明 kind: "memory",则只加载选定的一个。其他的用诊断信息禁用。
Control UI(schema + labels)
Control UI 使用 config.schema(JSON Schema + uiHints)来呈现更好的表单。
OpenClaw 根据发现的插件在运行时增强 uiHints:
- 为 plugins.entries.<id> / .enabled / .config 添加每个插件的标签
- 在以下位置合并可选的插件提供的配置字段提示: plugins.entries.<id>.config.<field>
如果您希望插件配置字段显示良好的标签/占位符(并将 secrets 标记为敏感),请在插件清单中的 JSON Schema 旁边提供 uiHints。
示例:
{
"id": "my-plugin",
"configSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": { "type": "string" },
"region": { "type": "string" }
}
},
"uiHints": {
"apiKey": { "label": "API Key", "sensitive": true },
"region": { "label": "Region", "placeholder": "us-east-1" }
}
}
CLI
openclaw plugins list
openclaw plugins info <id>
openclaw plugins install <path> # 将本地文件/目录复制到 ~/.openclaw/extensions/<id>
openclaw plugins install ./extensions/voice-call # 相对路径可以
openclaw plugins install ./plugin.tgz # 从本地 tarball 安装
openclaw plugins install ./plugin.zip # 从本地 zip 安装
openclaw plugins install -l ./extensions/voice-call # link(不复制)用于开发
openclaw plugins install @openclaw/voice-call # 从 npm 安装
openclaw plugins update <id>
openclaw plugins update --all
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins doctor
plugins update 仅适用于在 plugins.installs 下跟踪的 npm 安装。
插件还可以注册自己的顶级命令(示例:openclaw voicecall)。
插件 API(概述)
插件导出以下之一:
- 函数:(api) => { ... }
- 对象:{ id, name, configSchema, register(api) { ... } }
插件钩子
插件可以提供钩子并在运行时注册它们。这让插件可以捆绑事件驱动的自动化,而无需单独的钩子包安装。
示例
import { registerPluginHooksFromDir } from "openclaw/plugin-sdk";
export default function register(api) {
registerPluginHooksFromDir(api, "./hooks");
}
注意:
- 钩子目录遵循正常的钩子结构(HOOK.md + handler.ts)。
- 钩子资格规则仍然适用(OS/bins/env/config 要求)。
- 插件管理的钩子在 openclaw hooks list 中显示为 plugin:<id>。
- 您无法通过 openclaw hooks 启用/禁用插件管理的钩子;请改为启用/禁用插件。
Provider 插件(模型 auth)
插件可以注册模型 provider auth 流程,以便用户可以在 OpenClaw 内运行 OAuth 或 API 密钥设置(无需外部脚本)。
通过 api.registerProvider(...) 注册 provider。每个 provider 暴露一个或多个 auth 方法(OAuth、API 密钥、设备代码等)。这些方法支持:
- openclaw models auth login --provider <id> [--method <id>]
示例:
api.registerProvider({
id: "acme",
label: "AcmeAI",
auth: [
{
id: "oauth",
label: "OAuth",
kind: "oauth",
run: async (ctx) => {
// 运行 OAuth 流程并返回 auth 配置文件。
return {
profiles: [
{
profileId: "acme:default",
credential: {
type: "oauth",
provider: "acme",
access: "...",
refresh: "...",
expires: Date.now() + 3600 * 1000,
},
},
],
defaultModel: "acme/opus-1",
};
},
},
],
});
注意:
- run 接收带有 prompter、runtime、openUrl 和 oauth.createVpsAwareHandlers 助手的 ProviderAuthContext。
- 当您需要添加默认模型或 provider 配置时,返回 configPatch。
- 返回 defaultModel,以便 --set-default 可以更新 agent 默认值。
注册消息 channel
插件可以注册channel 插件,其行为类似于内置 channel(WhatsApp、Telegram 等)。Channel 配置位于 channels.<id> 下,并由您的 channel 插件代码验证。
const myChannel = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "demo channel plugin.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
(cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? { accountId }),
},
outbound: {
deliveryMode: "direct",
sendText: async () => ({ ok: true }),
},
};
export default function (api) {
api.registerChannel({ plugin: myChannel });
}
注意:
- 将配置放在 channels.<id> 下(不是 plugins.entries)。
- meta.label 用于 CLI/UI 列表中的标签。
- meta.aliases 为规范化和 CLI 输入添加备用 id。
- meta.preferOver 列出在两者都配置时跳过自动启用的 channel id。
- meta.detailLabel 和 meta.systemImage 让 UI 显示更丰富的 channel 标签/图标。
编写新的消息 channel(分步)
当您想要新的聊天界面("消息 channel")而不是模型 provider 时使用此方法。 模型 provider 文档位于 /providers/* 下。
- 选择 id + 配置形状
- 所有 channel 配置都位于 channels.<id> 下。
- 对于多账户设置,首选 channels.<id>.accounts.<accountId>。
- 定义 channel 元数据
- meta.label、meta.selectionLabel、meta.docsPath、meta.blurb 控制 CLI/UI 列表。
- meta.docsPath 应指向 /channels/<id> 之类的文档页面。
- meta.preferOver 让插件替换另一个 channel(自动启用优先选择它)。
- meta.detailLabel 和 meta.systemImage 由 UI 用于详细文本/图标。
- 实现所需的适配器
- config.listAccountIds + config.resolveAccount
- capabilities(聊天类型、媒体、线程等)
- outbound.deliveryMode + outbound.sendText(用于基本发送)
- 根据需要添加可选适配器
- setup(向导)、security(DM 策略)、status(健康/诊断)
- gateway(启动/停止/登录)、mentions、threading、streaming
- actions(消息操作)、commands(原生命令行为)
- 在插件中注册 channel
- api.registerChannel({ plugin })
最小配置示例:
{
channels: {
acmechat: {
accounts: {
default: { token: "ACME_TOKEN", enabled: true }
}
}
}
}
最小 channel 插件(仅出站):
const plugin = {
id: "acmechat",
meta: {
id: "acmechat",
label: "AcmeChat",
selectionLabel: "AcmeChat (API)",
docsPath: "/channels/acmechat",
blurb: "AcmeChat messaging channel.",
aliases: ["acme"],
},
capabilities: { chatTypes: ["direct"] },
config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) =>
(cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? { accountId }),
},
outbound: {
deliveryMode: "direct",
sendText: async ({ text }) => {
// 在这里将 `text` 传递到您的 channel
return { ok: true };
},
},
};
export default function (api) {
api.registerChannel({ plugin });
}
加载插件(扩展目录或 plugins.load.paths),重启 gateway,然后在配置中配置 channels.<id>。
Agent 工具
参见专门的指南:插件 agent 工具。
注册 gateway RPC 方法
export default function (api) {
api.registerGatewayMethod("myplugin.status", ({ respond }) => {
respond(true, { ok: true });
});
}
注册 CLI 命令
export default function (api) {
api.registerCli(({ program }) => {
program.command("mycmd").action(() => {
console.log("Hello");
});
}, { commands: ["mycmd"] });
}
注册自动回复命令
插件可以注册自定义斜杠命令,这些命令无需调用 AI agent 即可执行。这对于切换命令、状态检查或不需要 LLM 处理的快速操作很有用。
export default function (api) {
api.registerCommand({
name: "mystatus",
description: "Show plugin status",
handler: (ctx) => ({
text: `Plugin is running! Channel: ${ctx.channel}`,
}),
});
}
命令处理程序上下文:
- senderId:发送者的 ID(如果可用)
- channel:发送命令的 channel
- isAuthorizedSender:发送者是否是授权用户
- args:命令后传递的参数(如果 acceptsArgs: true)
- commandBody:完整的命令文本
- config:当前的 OpenClaw 配置
命令选项:
- name:命令名称(不带前导 /)
- description:命令列表中显示的帮助文本
- acceptsArgs:命令是否接受参数(默认:false)。如果为 false 且提供了参数,则命令不会匹配,消息会传递给其他处理程序
- requireAuth:是否需要授权发送者(默认:true)
- handler:返回 { text: string } 的函数(可以是异步)
带授权和参数的示例:
api.registerCommand({
name: "setmode",
description: "Set plugin mode",
acceptsArgs: true,
requireAuth: true,
handler: async (ctx) => {
const mode = ctx.args?.trim() || "default";
await saveMode(mode);
return { text: `Mode set to: ${mode}` };
},
});
注意:
- 插件命令在内置命令和 AI agent 之前处理
- 命令全局注册,适用于所有 channel
- 命令名称不区分大小写(/MyStatus 匹配 /mystatus)
- 命令名称必须以字母开头,仅包含字母、数字、连字符和下划线
- 保留的命令名称(如 help、status、reset 等)不能被插件覆盖
- 跨插件的重复命令注册将失败并显示诊断错误
注册后台服务
export default function (api) {
api.registerService({
id: "my-service",
start: () => api.logger.info("ready"),
stop: () => api.logger.info("bye"),
});
}
命名约定
- Gateway 方法:pluginId.action(示例:voicecall.status)
- 工具:snake_case(示例:voice_call)
- CLI 命令:kebab 或 camel,但避免与核心命令冲突
Skills
插件可以在 repo 中提供 skill(skills/<name>/SKILL.md)。 使用 plugins.entries.<id>.enabled(或其他配置门)启用它,并确保它存在于您的工作区/托管 skills 位置。
分发(npm)
推荐的打包方式:
- 主包:openclaw(此 repo)
- 插件:@openclaw/* 下的单独 npm 包(示例:@openclaw/voice-call)
发布合约:
- 插件 package.json 必须包含带有一个或多个入口文件的 openclaw.extensions。
- 入口文件可以是 .js 或 .ts(jiti 在运行时加载 TS)。
- openclaw plugins install <npm-spec> 使用 npm pack,提取到 ~/.openclaw/extensions/<id>/,并在配置中启用它。
- 配置密钥稳定性:作用域包被规范化为 unscoped id 用于 plugins.entries.*。
示例插件:Voice Call
此 repo 包含一个语音通话插件(Twilio 或日志回退):
- 源代码:extensions/voice-call
- Skill:skills/voice-call
- CLI:openclaw voicecall start|status
- 工具:voice_call
- RPC:voicecall.start、voicecall.status
- 配置(twilio):provider: "twilio" + twilio.accountSid/authToken/from(可选 statusCallbackUrl、twimlUrl)
- 配置(dev):provider: "log"(无网络)
参见 Voice Call 和 extensions/voice-call/README.md 获取设置和使用方法。
安全注意事项
插件与 Gateway 在进程内运行。将它们视为受信任的代码:
- 只安装您信任的插件。
- 首选 plugins.allow 允许列表。
- 更改后重启 Gateway。
测试插件
插件可以(并且应该)提供测试:
- Repo 内插件可以在 src/** 下保留 Vitest 测试(示例:src/plugins/voice-call.plugin.test.ts)。
- 单独发布的插件应运行自己的 CI(lint/build/test)并验证 openclaw.extensions 指向构建的入口点(dist/index.js)。