策略与访问控制(Policy & Access Control)
概述
OpenClaw 实现了一套分层策略系统,用于管理跨平台的消息频道访问权限,涵盖 Telegram、Discord、Slack、Signal、WhatsApp 等平台。该设计区分了私信(DM)和群组/频道消息,以便应用适当的默认行为和按上下文自定义的配置。
关键策略组件包括:
- DM 策略(DM Policies):指定对未知私信发送者的处理方式,支持 pairing(配对)、allowlist(白名单)、open(开放)或 disabled(禁用)等模式
- 群组策略(Group Policies):规定群组/频道消息的准入条件,支持 @提及要求和白名单过滤
- 白名单(Allowlists)(
allowFrom 和 groupAllowFrom):强制执行显式发送者白名单的配置列表
- 频道级别覆盖(Channel-Specific Overrides):支持按群组、话题/线程或账号进行策略配置
DM 策略模式(DM Policy Modes)
dmPolicy 设置控制网关在一对一对话中对未知发送者的响应方式:
| 模式 | 行为 | 适用场景 |
|---|
pairing | 未知发送者会收到一个配对码,需要在 CLI 手动批准后才能处理消息 | 个人助手的默认推荐模式 |
allowlist | 仅处理 allowFrom 中明确列出的发送者 | 已知联系人的严格访问控制 |
open | 不论发送者是谁,所有传入的私信均被处理 | 公开机器人、演示或测试环境 |
disabled | 忽略/屏蔽所有来自未知发送者的私信 | 仅限群组操作 |
策略解析遵循分层优先级模型,依次考虑从最具体到最通用的范围:话题/线程级别 → 群组级别 → 账号级别配置。
群组与频道策略(Group & Channel Policies)
群组策略规定群组或频道消息是否被处理以及在何种条件下处理:
| 模式 | 行为 | 适用场景 |
|---|
open | 允许群组中任意成员触发机器人;@提及控制激活条件 | 宽松的群组交互 |
allowlist | 消息发送者必须出现在 groupAllowFrom 中,或回退到 allowFrom | 严格的群组交互 |
disabled | 完全屏蔽/忽略所有群组消息 | 在群组中关闭 Agent |
@提及要求(Mention Requirements)
默认情况下,群组模式要求消息 @提及机器人才能触发响应,验证方式包括:
- 使用平台特定语法的显式 @提及(例如 Discord 和 Slack 上的
<@botId>)
- 将消息文本与配置的提及正则表达式模式进行匹配
- 回复或回应机器人之前的消息(线程/回复识别)
白名单与发送者标识符(Allowlists and Sender Identifiers)
白名单通过 allowFrom 和 groupAllowFrom 配置明确控制哪些用户可以与助手交互:
| 平台 | 私信发送者 ID 格式 | 群组/频道 ID 格式 |
|---|
| Telegram | 数字用户 ID(如 8734062810) | 负数 Chat ID(如 -1001234567890) |
| Discord | 字符串用户 ID(如 "123456789") | 字符串 Guild/Channel ID |
| Slack | 字符串用户 ID(如 "U123ABC") | 字符串频道 ID(如 "C123ABC") |
| WhatsApp | E.164 格式电话号码(如 "+15551234567") | 群组 JID |
| Signal | E.164 格式电话号码(如 "+15551234567") | 群组 ID |
| iMessage | Handle(如 "+15551234567"、"email@example.com") | Chat ID、Chat GUID 或 Chat Identifier |
| Mattermost | 用户 ID(如 "userId") | 频道 ID(如 "channelId") |
| Feishu | 用户 ID(如 "ou_xxxxxxxx") | Chat ID(如 "oc_xxxxxxxx") |
| MS Teams | 用户 ID(如 "userId") | 对话 ID(如 "conversationId") |
| LINE | 用户 ID(如 "Uxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") | 群组 ID 或房间 ID |
| Google Chat | 用户 ID(如 "users/123456789") | Space ID(如 "spaces/123456789") |
关键细节
allowFrom 是私信的主要白名单
groupAllowFrom 可选用于群组发送者;若未设置,则回退到 allowFrom
- 白名单中的通配符
"*" 表示该上下文的策略实际上为”开放”
- 白名单条目会经过平台特定的规范化和验证
执行审批策略(Exec Approval Policy)
对于调用可能执行命令的 Agent 工具的敏感操作,OpenClaw 实现了执行审批系统:
- 审批请求被分发到已配置的
target(dm、channel 或 both)
approvers 列表控制谁有权授予批准
- 可选的
agentFilter 和 sessionFilter 可限制需要审批的执行范围
- 审批提示和工作流集成到消息频道中,在执行前要求明确的同意
Telegram
- 支持在启用论坛功能的群组中按**话题(per-topic)**设置精细策略
- 在个人号码模式(自我聊天)下,特殊逻辑会禁用已读回执并强制执行配对以确保安全
- 白名单条目的 ID 通常为数字用户 ID,群组 ID 为较大的负数 Chat ID
- 当
dmPolicy 为 pairing 时,配对过程会通过私信向未知发送者发送审批码
Discord
- 需要特权**消息内容意图(Message Content Intent)**才能查看消息文本并执行策略
- 允许在 Guild 内使用扩展白名单类型按用户和角色 ID 进行过滤
- 支持与 Telegram 和 Slack 类似的自定义群组策略和 @提及控制
- 用户和频道使用字符串 ID
Slack
- 支持 Socket Mode 和传统 HTTP API;在 HTTP 模式下,请求必须在策略执行前验证
signingSecret
- 拥有与其他平台一致的
dmPolicy 和 allowFrom 概念
- 支持由已批准用户控制的交互式回复和按钮
- 白名单由 Slack 用户和频道 ID 组成,规范化时会去除
user: 等前缀
WhatsApp
- 使用全球电话号码(E.164 格式)来标识允许的发送者
- 使用群组 JID 进行群组消息识别
- 支持带回退规则的 DM 策略和白名单
- 拥有提及去除正则表达式和群组介绍提示以辅助 @提及控制
消息流与投递(Message Flow & Delivery)
概述
OpenClaw 的消息投递架构清晰地将消息意图与平台特定的实现细节分离。出站分发遵循一个流水线,从 Agent 消息动作调用经过分层解析,最终到达平台特定的投递。
基本阶段为:
- 动作发起(Action Initiation):Agent 通过
message-tool 或内部自动回复机制调用出站消息动作。
- 目标解析(Target Resolution):将人类可读的标识符或用户/频道 ID 转换为具体的频道-账号-消息目标。
- 会话路由(Session Routing):系统计算或确认适当的会话键(session key),以保持对话连续性和历史关联。
- 投递执行(Delivery Execution):有效负载被分块、净化,并通过消息频道特定的出站适配器进行分发。
出站投递流水线(Outbound Delivery Pipeline)
发送消息的入口函数是 deliverOutboundPayloads。它封装了出站有效负载的组装、针对频道的适当分块、利用投递钩子、加入可靠投递队列,以及调用频道适配器进行最终分发。
出站流水线管理每条消息的异步生命周期,包括重试和错误处理。
消息动作流程(Message Action Flow)
Agent 主要通过 runMessageAction() 调用出站消息动作。流程如下:
message-tool.execute() 是 Agent 发出带参数(如 send、reply、react)消息命令的接口。
runMessageAction() 编排通过 resolveOutboundTarget() 解析目标频道和地址的过程。
resolveOutboundSessionRoute() 确保消息绑定到会话键,用于历史记录和对话追踪。
deliverOutboundPayloads() 管理分块、净化,并通过频道适配器的 sendText 或 sendMedia 方法进行分发。
会话键生成与路由(Session Key Generation & Routing)
会话键唯一标识对话,对于在消息轮次、设备和平台间维护一致的对话状态至关重要。
会话键通常遵循以下模式:
agent:{agentId}:{channel}:{scope}:{peerId}
agentId:处理对话的 Agent
channel:消息平台(telegram、slack 等)
scope:会话范围,如 “main” 或 “thread”
peerId:对话对端的标识符(用户 ID、频道 ID、群组 ID)
会话键将平台细节抽象为代表对话线程的单一引用。
出站会话解析(Outbound Session Resolution)
发送消息时,OpenClaw 解析 OutboundSessionRoute 以将目标与会话关联:
- 它解析并规范化目标字符串。
- 根据已解析的元数据或频道插件能力推断对端类型(
direct、group、channel)。
- 使用
buildAgentSessionKey 构建基础会话键。
- 构建包含
sessionKey、baseSessionKey、peer 和路由地址的完整路由数据。
如果平台特定的解析器不可用,系统支持回退解析。
| 平台 | 目标解析详情 | 会话范围示例 |
|---|
| Telegram | 解析用户或群组 ID;支持各种聊天类型 | direct、group、channel |
| Slack | 处理频道类型(im、mpim、channel) | dm、group、channel |
| WhatsApp | 规范化 JID;支持私聊或群聊 | direct、group |
| Signal | 通过 Signal 协议地址解析收件人 | direct、group |
已解析的会话路由包含 from 和 to 等字段,用于指导出站消息寻址。
消息处理:更新水印与去重(Message Processing: Update Watermarking & Deduplication)
为防止多次处理同一传入更新,OpenClaw 维护更新水印和去重缓存:
- 去重缓存(Deduplication Cache):对于 Telegram 等轮询频道,消息 ID 使用
DirectoryCache 等结构进行缓存,以跳过重复处理。该缓存在 TTL 后淘汰条目,并使用 LRU 策略管理容量。
- 水印持久化(Watermark Persistence):存储当前已处理的最高更新 ID。恢复期间,OpenClaw 计算进行中投递的最小水印,确保即使崩溃后也不会出现消息空缺。
这些机制为入站更新保证了”恰好一次”的处理语义和有序的消息处理。
投递队列(The Delivery Queue)
OpenClaw 实现了一个投递队列目录结构,出站消息被序列化为 JSON 文件,代表等待传输的已入队投递。
- 入队(Enqueue):消息分发时,使用
enqueueDelivery 将其入队,存储为指定投递队列目录中的 JSON 文件。
- 确认/失败(Ack/Fail):投递成功或失败时,调用
ackDelivery 或 failDelivery 来确认或标记失败的投递。
- 重试(Retry):系统支持在网关重启时恢复待处理的投递以进行重试。
这种基于存储的队列设计支持出站消息的可靠性和容错性。
Agent 主要通过 message-tool 与消息交互,该工具:
- 暴露出站消息动作,如
send、reply、react 和 poll。
- 根据活跃频道的插件和当前配置动态构建能力。
- 实现参数验证、回复线程以及反应和交互式投票等高级功能。
| 动作 | 描述 | 参数 |
|---|
send | 发送新消息 | message、mediaUrl、silent |
reply | 对消息进行线程或引用回复 | message、replyTo |
react | 为消息添加表情符号反应 | emoji、messageId |
poll | 创建交互式投票 | question、options |
跨上下文标记(Cross-Context Markers)
系统支持”跨上下文标记(Cross-Context Markers)“,这些标记将跨会话或上下文边界链接消息动作的元数据应用其中。它以关于原始上下文/工具的信息丰富入站或出站消息,便于线程回复和上下文感知处理。
技术数据流:回复投递(Technical Data Flow: Reply Delivery)
以下序列表示从 Agent 生成回复到消息通过频道插件基础设施投递的流程:
该流水线确保每个生成的 Agent 回复都被正确分块、入队,并通过正确的频道适配器发送,同时记录投递元数据用于审计和重试。
总结
OpenClaw 中的消息流与投递涉及 Agent 工具、会话管理、出站路由、更新去重和可靠投递队列之间的复杂协调。关键代码实体包括:
message-tool(面向 Agent 的接口)
runMessageAction()(编排消息投递)
resolveOutboundTarget() 和 resolveOutboundSessionRoute()(目标和会话路由)
deliverOutboundPayloads()(核心投递流水线)
enqueueDelivery()、ackDelivery()(基于文件的投递队列系统)
- 频道出站适配器(Channel Outbound Adapters)(最终平台特定投递)
这个模块化流水线支持跨消息频道的可扩展性、通过会话键实现并发,以及通过持久队列和去重实现高可靠性。
扩展(Extensions)
扩展提供了 OpenClaw 在不修改核心源代码的情况下添加新能力的主要机制。OpenClaw 支持两种主要的扩展类型:
- Plugins(插件) — 注册运行时能力(如模型提供者、工具、钩子和频道)的模块化 TypeScript/JavaScript 包。
- Skills(技能) — 基于 Markdown 的 Agent 能力定义,为 Agent 行为提供指令、示例和引导上下文。
本页提供这些扩展类型、其架构及与系统集成的高级概述。
扩展类型(Extension Types)
| 扩展类型 | 格式 | 用途 | 分发示例 |
|---|
| Plugins | TypeScript/JavaScript 模块或包 | 添加提供者、工具、钩子、频道等 | 捆绑包(extensions/*)、工作区(.openclaw/extensions)或 npm 包 |
| Skills | 名为 SKILL.md 的 Markdown 文件 | 通过指令定义 Agent 能力 | ClawHub(社区集合)、工作区技能文件夹(.openclaw/workspace/skills)或托管安装 |
Plugins 是深度集成到 OpenClaw 运行时系统的代码驱动扩展,而 Skills 则通过自然语言指令和示例增强 Agent 行为。
Plugin 系统架构(Plugin System Architecture)
OpenClaw 按优先级顺序搜索路径来发现 Plugin(先找到者优先):
- 在
plugins.load.paths 中配置的显式路径。
- 当前工作区内的工作区扩展文件夹
.openclaw/extensions/。
- 用户全局扩展文件夹
~/.openclaw/extensions/。
- 随 OpenClaw Gateway 一起发布的捆绑 Plugin。
发现和加载机制会缓存注册表以提高效率。
Plugin SDK 与运行时集成(Plugin SDK and Runtime Integration)
OpenClaw 提供一个类型化的 Plugin SDK,定义了 Plugin 与 Gateway 核心之间的接口,支持:
| 组件 | 角色 |
|---|
| Loader(加载器) | 管理 Plugin 的发现、加载和缓存 |
| Registry(注册表) | 保存活跃的 Plugin 实例及其注册的能力(提供者、工具) |
| Manifest Registry(清单注册表) | 从 Plugin 读取静态元数据(无需加载代码) |
| Runtime(运行时) | 传递给 Plugin 模块的执行上下文,暴露注册能力的 API |
Plugin 在具有特定 API 面的隔离运行时中运行,以注册能力,从而降低风险并提高稳定性。
Plugin 注册流程(Plugin Registration Flow)
Plugin 实现由运行时暴露的 register(api: OpenClawPluginApi) 方法,允许它们注册:
- Providers(提供者):LLM、语音、图像生成、网络搜索和媒体理解提供者。
- Tools(工具):Agent 工具,包括可选和必需的 Agent 代码工具。
- Hooks(钩子):用于提示注入、事件处理和生命周期的系统钩子。
- Channels(频道):处理入站和出站消息的消息平台集成。
Plugin 插槽(Plugin Slots,独占类别)
OpenClaw 将某些 Plugin 角色作为独占”插槽(slots)“管理,即该类别中一次只能有一个 Plugin 处于活跃状态。这在 plugins.slots 配置部分进行设置。
| 插槽 | 用途 | 默认 Plugin |
|---|
memory | 长期记忆实现 | memory-core |
contextEngine | 上下文引擎/提示管理器 | legacy |
插槽通过防止关键扩展类别中的冲突来确保行为一致性。
Skills 系统概述(Skills System Overview)
Skills 是以 Markdown 格式 SKILL.md 文件表达的自然语言驱动的 Agent 能力。这些文件描述新的 Agent 行为、指令、示例和演示。
与基于代码的 Plugin 不同,Skills 纯粹通过受技能元数据和内容控制的提示工程来扩展 Agent。
ClawHub 集成(ClawHub Integration)
ClawHub 是 OpenClaw 的社区技能存储库和分发平台:
- Agent 可以动态地从 ClawHub 发现和建议技能。
- 技能被安装到工作区本地技能文件夹(
.openclaw/workspace/skills/)。
- 在 Agent 运行时,技能被加载并有选择地注入到系统提示中,以增强 Agent 的理解和行为。
该系统通过无需开发工作即可快速共享和部署 Agent 能力来增强可扩展性。
扩展示例(Extension Examples)
OpenClaw 包含几个有代表性的扩展,展示了可扩展性模型:
- Lobster:一个工作流运行时扩展,允许在 Agent 对话中实现可恢复的审批门控和多步骤工具序列。
- Memory Plugins(记忆插件):核心记忆实现,如
@openclaw/memory-core(随 OpenClaw 捆绑)和 memory-lancedb(基于向量的长期记忆),支持可插拔的记忆后端。
- Channel Plugins(频道插件):各种消息平台的集成,如 Discord、Telegram、Matrix、Tlon 和 Google Chat。
- Context Engine Plugins(上下文引擎插件):Plugin 可以注册自定义上下文引擎,如
legacy 引擎或管理 Agent 对话历史如何组装和压缩的自定义实现。
- ACPX Plugin:
@openclaw/acpx Plugin 提供 ACP 运行时后端,演示了 Plugin 如何扩展核心协议实现。
这些示例展示了 OpenClaw 扩展框架的广度和多功能性。
Plugin 架构(Plugin Architecture)
OpenClaw 的 Plugin 系统通过模块化的发现和注册框架,在模型提供者、工具、消息频道和身份验证机制方面实现了可扩展性。
概述
Plugin 架构以 PluginRegistry 为核心,它跨以下扩展点管理 Plugin 生命周期:
- Model Providers(模型提供者):具有身份验证和模型目录的 AI 推理引擎
- OAuth Flows(OAuth 流程):基于 Web 或设备的身份验证机制
- Tools(工具):Agent 的功能能力
- Hooks(钩子):生命周期事件订阅
- Channels(频道):消息平台集成
- Memory Backends(记忆后端):替代存储引擎
Plugin 发现与加载(Plugin Discovery and Loading)
发现顺序和优先级(Discovery Order and Precedence)
OpenClaw 按分层顺序定位 Plugin,先找到者具有优先权:
- 显式配置路径(Explicit Config Paths):如
plugins.load.paths 中声明的
- 工作区扩展(Workspace Extensions):位于
<workspace>/.openclaw/extensions/ 内
- 全局扩展(Global Extensions):位于
~/.openclaw/extensions/
- 捆绑 Plugin(Bundled Plugins):随 OpenClaw 打包的默认 Plugin
加载与运行时隔离(Loading and Runtime Isolation)
PluginLoader 使用 jiti 模块加载器动态加载 Plugin,原生支持 TypeScript/JavaScript。每个 Plugin 执行其 register(api) 入口函数,接收一个 OpenClawPluginApi 实例用于注册能力。
每个 Plugin 获得一个 PluginRuntime 隔离上下文,用于与 Gateway 服务交互,从而实现沙箱化和版本独立性。
Plugin SDK API(Plugin SDK API)
Plugin SDK 通过 openclaw/plugin-sdk 的子路径导出提供类型化模块:
| 子路径 | 用途 |
|---|
openclaw/plugin-sdk/core | 核心类型、基类、辅助函数 |
openclaw/plugin-sdk/plugin-entry | Plugin 注册入口点 |
openclaw/plugin-sdk/provider-setup | AI 提供者和身份验证注册 |
openclaw/plugin-sdk/channel-setup | 消息频道注册 |
openclaw/plugin-sdk/runtime | 运行时接口和状态 |
openclaw/plugin-sdk/sandbox | 沙箱环境交互 |
openclaw/plugin-sdk/webhook-ingress | Webhook 输入处理 |
openclaw/plugin-sdk/testing | 测试工具 |
注册 API(OpenClawPluginApi)
当 Plugin 的 register() 方法执行时,它接收一个暴露扩展方法的 API 对象:
| 方法 | 描述 |
|---|
registerProvider(spec) | 注册带身份验证和模型的 AI 模型提供者 |
registerTool(tool, opts?) | 注册 Agent 工具;对 Agent 可选 |
registerHook(hook) | 附加生命周期或事件钩子 |
registerChannel(channel) | 添加消息频道实现 |
registerService(service) | 启动绑定到 Plugin 生命周期的后台服务 |
registerGatewayRoute(route) | 在 Gateway 服务器上注册 HTTP 路由 |
registerInteractiveHandler(handler) | 注册 CLI 交互处理程序 |
Plugin 导出与提供者(Plugin Exports and Providers)
模型提供者(Model Providers)
模型提供者代表与 AI 后端的连接,暴露身份验证、模型发现和推理流接口。PluginProviderRegistration 类型定义了提供者元数据、身份验证方法、模型和请求钩子。
OAuth 身份验证流程实现 ProviderAuthMethod Plugin,通过上下文对象与用户交互,上下文对象暴露 openUrl() 用于浏览器身份验证,prompter.prompt() 用于用户输入。
工具以工厂(OpenClawPluginToolFactory)的形式实现 Agent 能力,实例化工具时包含以下上下文:
sessionId:当前会话标识符
agentId:调用工具的 Agent
workspaceDir:执行工作区
钩子与事件(Hooks and Events)
钩子允许 Plugin 订阅生命周期时刻,例如:
- Agent 生命周期(Agent Lifecycle):
agent.beforeRun、agent.afterRun
- 系统事件(System Events):配置更改或诊断事件
- 提示注入(Prompt Injection):在 LLM 调用前动态修改提示
Plugin 配置与验证(Plugin Configuration and Validation)
每个 Plugin 可以使用类似 JSON Schema 的定义定义一个 OpenClawPluginConfigSchema,描述预期的配置属性。该 Schema 支持:
- 验证(Validation):
openclaw.json 文件在启动时针对活跃 Plugin Schema 进行验证
- UI 生成(UI Generation):控制 UI 读取 Schema 和
uiHints 以动态生成设置表单
Plugin 插槽(Plugin Slots)
某些 Plugin 归类为独占插槽,每个插槽最多一个 Plugin 处于启用状态:
memory 插槽 — 用于长期记忆后端
contextEngine 插槽 — 用于对话上下文管理
Plugin 发现与优先级总结(Plugin Discovery & Precedence Summary)
| 特性 | 描述 |
|---|
| 清单文件(Manifest File) | Plugin 使用包含元数据和配置 Schema 的 openclaw.plugin.json 来描述 |
| 捆绑目录(Bundled Directory) | 环境变量 OPENCLAW_BUNDLED_PLUGINS_DIR 指向捆绑核心 Plugin 的位置 |
| Plugin 状态(Plugin Status States) | Plugin 可以具有 loaded、disabled 或 error 等状态 |
| 格式支持(Format Support) | 支持 Native(Node.js/TypeScript)和 Bundle(兼容 Codex/Claude)格式 |
结论
OpenClaw 的 Plugin 架构为跨提供者、工具、消息频道和身份验证机制的可扩展性提供了一个强大的模块化系统。其发现流程支持多个覆盖层,确保灵活的 Plugin 管理。Plugin SDK 提供类型化接口用于可信的 Plugin 开发,而运行时隔离和生命周期集成则保证稳定的扩展无缝扩展 OpenClaw 的能力。
Skills 系统(Skills System)
OpenClaw 中的 Skills 系统通过提供打包为目录形式的模块化指令集和工具定义来扩展 Agent 能力。每个 Skill 定义了 Agent 应如何使用特定的二进制文件、API 或本地脚本,并包含用于环境注入和依赖检查的元数据。
一个 Skill 被组织为包含 SKILL.md 文件的目录。该文件将用于配置的 YAML frontmatter 与提供给 Agent 的丰富指令的 Markdown 混合在一起。
技术规范(Technical Specification)
OpenClaw 实现了 AgentSkills.io 规范,其解析器要求 单行(single-line) frontmatter 值,确保与嵌入式 Pi Agent 运行时的兼容性。
YAML frontmatter 定义了基本的 Skill 元数据,而 Markdown 主体包含了塑造 Agent 行为的详细指令。
| 字段 | 类型 | 描述 |
|---|
name | string | Skill 的唯一标识符 |
description | string | 提示构建期间使用的摘要 |
metadata.openclaw | object | OpenClaw 特定扩展(frontmatter 中序列化的 JSON 字符串) |
metadata.openclaw.requires | object | 需求门控规则,例如二进制文件、环境变量和配置路径 |
metadata.openclaw.install | array | 带有方法详情的安装说明(brew、node、uv、go、download) |
系统强制要求所有 frontmatter 值为单行字符串,以确保确定性的解析和提示包含。
需求评估(Requirement Evaluation)
OpenClaw 通过检查以下需求来验证 Skill 的资格:
- OS 匹配(OS Matching):Skills 可以指定支持的操作系统(如
darwin、linux、win32)。
- 二进制可用性(Binary Availability):Skills 可以声明必须在 PATH 上存在的二进制文件(
hasBinary 检测)。
- 环境变量(Environment Variables):必须存在所需的环境变量。
- 配置路径(Configuration Paths):Skills 可能需要启用某些
openclaw.json 配置标志。
此评估决定了 Skill 是否有资格进行提示注入。
Skill 安装与来源(Skill Installation and Sources)
OpenClaw 支持来自多个来源的 Skills,优先级如下。当同名 Skills 存在于不同层级时,优先级更高的来源会覆盖较低的来源。
| 来源类型 | 位置 | 范围 | 优先级 |
|---|
| 工作区 Skills(Workspace Skills) | <workspace>/skills/ | 每个 Agent | 最高 |
| 托管 Skills(Managed Skills) | ~/.openclaw/skills/ | 主机范围 | 中等 |
| 捆绑 Skills(Bundled Skills) | 内置于 OpenClaw 包中 | 主机范围 | 最低 |
| 额外目录(Extra Directories) | 通过 skills.load.extraDirs 配置 | 灵活 | 最低 |
工作区 Skills(Workspace Skills)
位于每个 Agent 的工作区目录中,这些 Skills 提供隔离的、项目特定的功能。工作区 Skills 会覆盖同名的托管和捆绑 Skills。
托管 Skills(Managed Skills)
安装到用户的全局 OpenClaw 配置目录中,托管 Skills 可以在同一主机上的 Agent 之间共享。
捆绑 Skills(Bundled Skills)
这些是随 OpenClaw 本身一起打包的内部内置 Skills。它们作为默认值或回退,可以被工作区或托管 Skills 禁用或覆盖。
管理员可以通过 OpenClaw 配置键 skills.load.extraDirs 指定额外的目录来加载 Skills。
安装程序选择逻辑(Installer Selection Logic)
Skills 可以在 metadata.openclaw.install 下指定多个安装程序,每个安装程序描述不同的安装方法(如 brew 公式、node 包、下载存档)。
OpenClaw 使用 selectPreferredInstallSpec 根据环境能力和用户偏好选择最佳安装方法:
| 优先级 | 安装程序类型 | 条件/偏好 |
|---|
| 1 | brew | 如果 preferBrew 为 true 且 brew 二进制文件在 PATH 上 |
| 2 | uv | 始终优先用于通过 uv 管理的 Python 包 |
| 3 | node | 使用工作区或全局 nodeManager(npm/pnpm/bun) |
| 4 | go | 需要 PATH 中有 go 二进制文件 |
| 5 | download | 没有包管理器的二进制存档的回退安装程序 |
此优先级确保用户获得最原生且集成度最高的可用安装体验。
Skill 执行与提示注入(Skill Execution and Prompt Injection)
从静态 Skill 文件到实时 Agent 执行的桥梁,核心是生成动态提示和注入环境变量。
数据流:从 Skill 文件到 Agent 运行时(Data Flow: From Skill Files to Agent Runtime)
系统编译一个 SkillStatusReport,聚合以下信息:
- 所有发现的 Skills 及其元数据。
- 资格和缺失的需求。
- 适用的安装选项。
此报告被 Agent 运行时使用,以构建技能提示片段并正确配置环境。
环境与 API 密钥注入(Environment & API Key Injection)
Skills 可以通过 metadata.openclaw.requires.env 声明它们所需的环境变量,或定义 primaryEnv,表示持有 API 密钥的特定环境变量。
OpenClaw 按以下顺序解析这些变量:
- Node.js
process.env 中存在的环境变量。
- 在工作区或全局
openclaw.json 的 skills.entries.<skill_key>.env 下配置的自定义环境变量。
- 通过
skills.entries.<skill_key>.apiKey 与 primaryEnv 关联的 API 密钥。
此环境注入便于为访问外部 API 的 Skills 传递凭证和工具配置。
工作区 Skills 与托管 Skills 对比(Workspace Skills vs Managed Skills)
OpenClaw 支持多个 Skill 来源,以适应具有隔离或共享能力的多 Agent 设置。
| 特性 | 工作区 Skills | 托管 Skills |
|---|
| 位置 | <workspace>/skills/(每个 Agent 工作区) | ~/.openclaw/skills/(主机范围共享) |
| 隔离 | 专用于特定 Agent 工作区 | 在主机上的所有 Agent 之间共享 |
| 覆盖行为 | 覆盖同名的托管和捆绑 Skills | 覆盖捆绑 Skills |
| 预期用途 | 项目特定或私有自定义工具 | 常用工具(如 web_search) |
会话快照(Session Snapshotting)
为在交互会话期间保持提示一致性,符合条件的 Skills 在会话开始时被快照。此快照保留:
- Skill 指令提示。
- 资格状态。
- 会话期间固定的 Skill 列表。
这可以防止在编辑 Skill 文件后出现会话中途更改的情况,除非启用了 skills.load.watch。
快照数据驻留在 .openclaw/state/<agent_id>/skills-snapshot.json 中,并支持确定性的提示行为。
总结
Skills 系统是通过将能力模块化为可共享、可配置的 Skill 包来扩展 OpenClaw Agent 的核心机制。它确保了对 Skill 元数据、需求门控、安装策略和无缝集成到 Agent 提示周期的强大处理。工作区隔离与托管托管支持强大的多 Agent 部署场景。
延伸阅读参考(References for Further Reading)
docs/tools/creating-skills.md — Skill 格式定义和开发者指南
src/agents/skills-status.ts — 核心 Skill 扫描、状态评估、安装逻辑和快照
src/agents/skills.resolveskillspromptforrun.test.ts — Skill 提示构建和环境注入
src/agents/skills/workspace.ts — 工作区 Skill 管理
src/agents/skills/source.ts — Skill 来源解析
src/agents/skills-install.download.test.ts — Skill 下载和提取安全性
src/agents/skills.buildworkspaceskillstatus.test.ts — Skill 状态报告和资格
src/cli/skills-cli.formatting.test.ts — Skill 信息的 CLI 格式化
Plugin 示例(Plugin Examples)
概述
本文档通过具体示例展示 OpenClaw Plugin 的实现,重点介绍 OAuth 提供者集成和配置模式。
Plugin 结构(Plugin Structure)
Plugin 遵循标准化的目录布局:
extensions/<plugin-name>/
├── index.ts # 入口点和提供者注册
├── oauth.ts # 身份验证流程(如果基于 OAuth)
├── README.md # 用户文档
└── package.json # 元数据和依赖
每个 Plugin 导出一个带有 register() 钩子的清单,该钩子接收 OpenClawPluginApi,暴露以下方法:
registerProvider() — 注册带身份验证方法的模型提供者
registerTool() — 注册 Agent 可调用的工具
registerHook() — 添加生命周期或消息钩子
OAuth Plugin 示例:Google Gemini CLI
提供者注册(Provider Registration)
Google Plugin 展示了带有交互式登录的完整 OAuth 集成:
关键属性:
- Provider ID:
"google-gemini-cli"
- Auth Kind:
"oauth",用于带浏览器重定向的标准 OAuth
- 环境变量(Environment Variables):可选提示,如
GOOGLE_API_KEY
OAuth 方法实现了一个 run 函数,接收带有 UI 辅助工具(prompter)、环境标志(isRemote)和 openUrl 等工具的 ProviderAuthContext。
流程实现(Flow Implementation)
Gemini CLI OAuth 使用 PKCE 和本地 HTTP 回调服务器:
- 凭证发现(Credential discovery) — 尝试本地环境密钥或从已安装的包中提取客户端 ID
- PKCE 支持(PKCE support) — 生成用于授权安全的验证器/挑战对
- 回调服务器(Callback server) — 在 localhost(默认端口 8085)监听 OAuth 回调
- Remote/WSL2 支持 — 当 localhost 不可达时回退到手动代码输入
设备码 OAuth 示例:Qwen Portal
与标准 OAuth 的比较(Comparison with Standard OAuth)
| 方面 | 标准 OAuth | 设备码(Device Code) |
|---|
| 用户交互 | 浏览器重定向 | 终端代码输入 |
| 回调方法 | HTTP 服务器 | 轮询令牌端点 |
| 网络要求 | 本地 HTTP 服务器 | 无 |
| 适用场景 | 桌面 | 无头/远程 |
轮询详情(Polling Details)
- 初始等待遵循服务器建议的
interval
slow_down 错误触发自适应间隔乘法(如 1.5 倍)
- 循环持续直到成功或过期
配置与密钥运行时(Configuration and Secrets Runtime)
密钥解析(Secrets Resolution)
OpenClaw 提供一个专用的密钥运行时,合并配置文件引用、环境变量和运行时覆盖:
prepareSecretsRuntimeSnapshot() — 初始化组合 env 和配置的密钥快照
getActiveRuntimeWebToolsMetadata() — 检索带凭证的活跃 Web 提供者元数据
resolveSetupSecretInputString() — 在入职期间安全提示输入 API 密钥
这集中了密钥访问,防止 Plugin 直接读取环境变量,同时支持在配置文件或配置文件中无缝存储。
入职集成(Onboarding Integration)
入职向导(openclaw onboard)动态发现已注册的 Plugin 数据,以提示输入凭证并启用 Plugin。
网络搜索提供者示例(Web Search Providers Example)
- 提供者检测(Provider detection) — 调用
resolveSearchProviderOptions() 查询已注册的网络搜索 Plugin(brave、Google Gemini、perplexity 等)
- 用户确认(User confirmation) — 提示确认启用所选提供者/工具
- 凭证输入(Credential entry) — 使用
resolveSetupSecretInputString() 安全提示输入 API 密钥,带有遮罩输入和多种密钥输入模式
实现检查清单(Implementation Checklist)
| 组件 | 用途 | 关键文件 |
|---|
| Plugin 入口(Plugin Entry) | 实现绑定提供者、工具、钩子的 register() | extensions/google/index.ts |
| 清单(Manifest) | 提供带 configSchema 的 openclaw.plugin.json | Plugin 包目录 |
| SDK 用法(SDK Usage) | 使用 openclaw/plugin-sdk/* 的导入 | 跨 Plugin 的 SDK |
| 模型提供者(Model Providers) | 注册带正确 id、auth 方法和模型 | src/plugins/contracts/registry.ts |
| OAuth 方法(OAuth Methods) | 使用 ProviderAuthContext 实现 run 函数 | extensions/google/oauth.ts |
| 轮询流程(Polling Flows) | 实现带错误处理的自适应轮询 | extensions/qwen/oauth.ts |
| 密钥运行时(Secrets Runtime) | 使用密钥运行时进行 API 密钥解析 | src/secrets/runtime.ts |
| 入职向导(Onboarding Wizard) | 集成配置提示和密钥输入模式 | src/commands/configure.wizard.ts |
遵循此模式可确保 Plugin 与 OpenClaw 的模块化运行时、授权系统和用户入职设施的顺畅集成。
原生客户端与节点(Native Clients & Nodes)
本文档介绍 OpenClaw 适用于 iOS、macOS 和 Android 的原生客户端应用程序。这些平台特定的应用程序有双重用途:它们既是通过 WebSocket 连接到 Gateway 服务器的 Gateway 客户端(Gateway clients),也是通过 node.invoke RPC 方法向 Agent 运行时暴露设备特定能力(摄像头、屏幕截图、通知、位置)的 Device Node(设备节点)。
概述
原生客户端与 CLI 和控制 UI 有三个关键区别:
- 平台集成(Platform Integration):它们访问平台特定的 API(Android 上的 CameraX、iOS 上的 AVFoundation、macOS 上的 ScreenCaptureKit),而这些 API 对基于 Node.js 或浏览器的客户端不可用。
- Device Node 协议(Device Node Protocol):它们注册为设备节点,并通过
node.invoke RPC 方法暴露 camera.capture、screen.snapshot、notifications.send 和 location.get 等工具。
- 原生 UI(Native UI):它们提供平台原生体验(iOS/macOS 上的 SwiftUI,Android 上的 Jetpack Compose),以及分享扩展、小组件和后台任务等操作系统级集成。
所有原生客户端共享一个从 Gateway 的 TypeScript 协议定义生成的通用协议层,确保跨平台的类型安全通信。
原生客户端架构
原生客户端生态系统由以下部分组成:
- iOS App:带有分享扩展和活动小组件的主 iPhone/iPad 应用。
- macOS App:带有通过
appcast.xml 进行 Sparkle 自动更新集成的菜单栏应用。
- Android App:带有 Jetpack Compose UI 的主 Android 应用。
所有客户端使用**代码生成的协议模型(code-generated protocol models)**以确保类型安全。流水线运行 scripts/protocol-gen-swift.ts 将协议 Schema 转换为平台特定的 Swift 代码。
Device Node 协议(Device Node Protocol)
当原生客户端连接到 Gateway 时,它可以通过在 ConnectParams 中提供设备能力来注册为设备节点(device node)。Gateway 跟踪可用节点并将 node.invoke RPC 调用路由到适当的设备。
设备节点调用流程(Device Node Invocation Flow)
协议为节点通信定义了标准错误码,如 NOT_PAIRED 和 UNAVAILABLE。设备配对遵循用户扫描二维码的引导流程;最近的更新将 Android 入职切换到 Google Code Scanner 以提高可靠性。iOS 中的 NodeAppModel 处理传入的 BridgeInvokeRequest,并将它们分发到适当的能力服务,例如用于摄像头操作的 CameraController 或用于屏幕操作的 ScreenController。
协议代码生成(Protocol Code Generation)
Gateway 的协议定义以 TypeScript 配合 TypeBox/Zod Schema 的形式存在。这些被转换为 Swift 和 Kotlin 代码:
| 组件 | 职责 | 输出路径 |
|---|
scripts/protocol-gen-swift.ts | 生成 Swift Codable 模型 | apps/macos/Sources/OpenClawProtocol/GatewayModels.swift |
GatewayModels.swift | 定义 ConnectParams、RequestFrame、ResponseFrame | apps/macos/Sources/OpenClawProtocol/GatewayModels.swift |
PresenceEntry | 跟踪设备状态、版本和平台 | apps/macos/Sources/OpenClawProtocol/GatewayModels.swift |
生成的代码包含 GATEWAY_PROTOCOL_VERSION(当前为 3),以确保客户端和服务器之间的兼容性。
iOS 与 macOS 生态系统(iOS & macOS Ecosystem)
iOS 和 macOS 应用通过 OpenClawKit Swift Package 共享代码。
iOS 应用结构(iOS App Structure)
iOS 应用包括主应用程序、分享扩展和活动小组件。最近的入职改进添加了首次运行欢迎分页器和 /pair qr 指令。NodeAppModel 管理应用程序状态,包括 Gateway 连接、Agent 选择和处理深度链接。RootCanvas 是主 SwiftUI 视图,负责展示 UI、管理表单(设置、聊天、快速设置)和处理入职流程。
macOS 应用结构(macOS App Structure)
macOS 应用是一个菜单栏应用(OpenClaw),包含:
- Sparkle 自动更新(Sparkle Auto-Update):使用
appcast.xml 管理发布
- OpenClawIPC:进程间通信库
- OpenClawDiscovery:处理本地网络上的 Gateway 发现
Android 生态系统(Android Ecosystem)
Android 应用使用 Gradle 和 Jetpack Compose 构建。
构建配置(Build Configuration)
构建系统管理签名和依赖。apps/android/app/build.gradle.kts 文件定义了构建过程,包括 namespace、compileSdk、minSdk、targetSdk、versionCode 和 versionName。它还处理发布签名配置,确保发布构建使用适当的 keystore 信息进行签名,该信息从 Gradle 属性加载以将敏感数据保留在仓库之外。最近的更新重新设计了聊天设置表单,并刷新了 Connect 和 Voice 标签页以实现更密集的移动布局。
Android 特定功能(Android-Specific Features)
- Google Code Scanner:用于可靠的入职二维码扫描
- 媒体部分(Media Sections):聊天设置中分组的设备和媒体部分
- Jetpack Compose UI:UI 使用 Jetpack Compose 构建,如
buildFeatures 中的 compose = true 标志和 activity-compose 依赖所示
- Flavor Dimensions(变体维度):应用使用产品变体(
play 和 thirdParty)根据分发渠道启用或禁用 SMS 和通话记录访问等某些功能
总结
原生客户端将 OpenClaw 的 Agent 运行时与平台特定的设备能力连接起来。它们提供:
- 类型安全协议(Type-Safe Protocol):从 Gateway Schema 代码生成的模型。
- 平台集成(Platform Integration):摄像头、屏幕和通知的深度操作系统集成。
- 原生 UX(Native UX):SwiftUI 和 Jetpack Compose 界面。
目的与范围(Purpose and Scope)
本文档详细介绍了 OpenClaw 在 iOS、macOS 和 Android 平台上的原生客户端架构。它解释了多平台构建系统设计、Swift 和 Kotlin 代码库,以及从 Gateway 协议 Schema 自动生成代码的流水线。本页阐明了原生客户端如何通过类型安全、版本化的 WebSocket 协议与 Gateway 服务器进行通信。
OpenClaw 在三个主要平台上提供第一方原生客户端应用程序:
-
iOS/iPadOS/watchOS:使用声明式 SwiftUI 以 Swift 构建,包括分享扩展、Live Activity 小组件和 watchOS 伴侣应用。Xcode 项目定义和目标使用 XcodeGen 管理
-
macOS:基于 Swift 的菜单栏应用,设计为无干扰地运行在菜单栏(LSUIElement),专注于系统集成和自动化
-
Android:使用 Kotlin 构建的应用程序,使用 Jetpack Compose UI,通过 Gradle Kotlin DSL 构建脚本管理
所有这些平台与 Gateway 服务器共享基于带 JSON 帧的 WebSocket RPC 的通用通信协议,称为 Gateway Protocol v3。该协议以 TypeScript 正式定义,并代码生成到 Swift/Kotlin 模型中,以确保类型安全和一致的版本控制。
Gateway 协议代码生成(Gateway Protocol Code Generation)
OpenClaw 的 Gateway 协议被定义为描述 RPC 方法、帧和数据结构的 TypeScript JSON Schema。这些 Schema 驱动为原生平台自动生成强类型数据模型和客户端代码。这种方法保证了协议版本控制的一致性,并减少了手动编码错误。
Swift 代码生成由 scripts/protocol-gen-swift.ts 脚本处理,它将 TypeScript Schema 转换为带有 Codable 一致性的 Swift struct,用于 JSON 序列化/反序列化。类似地,Kotlin 代码生成由 scripts/protocol-gen-kotlin.ts 处理,用于 Android。
代码生成流程(Code Generation Flow)
生成的 Swift 代码包括:
- 核心协议帧的
struct 定义:ConnectParams、HelloOk、RequestFrame、ResponseFrame、EventFrame
- 用于标准化错误报告的
enum ErrorCode
- 符合 Swift 的
Codable 和 Sendable 协议,用于并发和编码
- 用于版本匹配的
GATEWAY_PROTOCOL_VERSION 等常量
生成的 Kotlin 代码包括:
- 核心协议帧的
data class 定义,使用 @Serializable 注解进行 JSON 序列化/反序列化
- 用于标准化错误报告的
enum class ErrorCode
GATEWAY_PROTOCOL_VERSION 等常量
关键协议帧结构(Key Protocol Frame Structures)
| 帧类型 | 用途 | Swift 类型 | Kotlin 类型 |
|---|
ConnectParams | 客户端握手请求参数 | struct ConnectParams | data class ConnectParams |
HelloOk | 服务器握手/确认 | struct HelloOk | data class HelloOk |
RequestFrame | RPC 方法调用请求 | struct RequestFrame | data class RequestFrame |
ResponseFrame | RPC 方法响应帧 | struct ResponseFrame | data class ResponseFrame |
EventFrame | 异步服务器到客户端事件 | struct EventFrame | data class EventFrame |
PresenceEntry | 设备存在元数据 | struct PresenceEntry | data class PresenceEntry |
ErrorCode | 枚举错误常量 | enum ErrorCode | enum class ErrorCode |
原生代码库概述(Native Codebases Overview)
iOS / macOS Swift 代码库(iOS / macOS Swift Codebases)
-
Swift 原生客户端被组织到由 XcodeGen 管理的多个目标中:
- iOS 主应用(iOS Main App):带有 SwiftUI 界面和 Gateway 通信
- 分享扩展(Share Extension):用于 iOS 系统范围分享操作
- Live Activity 小组件(Live Activity Widget)
- **watchOS 应用(watchOS App)**伴侣
- macOS 应用(macOS App):带有菜单栏任务和系统服务集成
-
iOS 和 macOS 应用都利用共享的 Swift 包 OpenClawKit,其中包括生成的 Gateway 协议模型、聊天 UI 组件和工具抽象
-
Swift 并发特性如 @MainActor 和 Sendable 被广泛使用,以提供 UI 响应性和安全的多线程通信
-
客户端通过精心实现的原生服务和 UI 绑定管理 Agent 会话、远程 Gateway 连接、语音唤醒和丰富媒体交互
Android Kotlin 代码库(Android Kotlin Codebase)
-
Android 客户端使用现代 Kotlin 代码库:
- Jetpack Compose 用于 UI
- 基于 Coroutine(协程)的异步和响应式模式
- 通过 Android API 集成的语音识别和 TTS
- 封装在
GatewaySession 类中的 Gateway 会话和聊天管理
-
构建系统利用 Gradle Kotlin DSL,支持发布签名、多 ABI 原生库和 Compose BOM 管理
-
Android TalkModeManager 用于语音交互,以平台特定的适配方式镜像 iOS 功能
原生客户端到 Gateway 的数据流(Native Client to Gateway Data Flow)
连接与消息交换(Connection and Message Exchange)
-
连接设置(Connection Setup)
原生客户端发起到 Gateway 的 WebSocket 连接。发送带有客户端能力、设备身份、身份验证令牌和区域设置信息的 ConnectParams 帧
-
握手响应(Handshake Response)
Gateway 响应 HelloOk,提供服务器元数据、功能、会话状态快照和策略信息
-
RPC 方法使用(RPC Method Usage)
原生客户端发送 RequestFrame 消息调用 Gateway RPC 方法(如 agent.identity.get、chat.send),包括作为 JSON 编码有效负载的参数
-
响应和事件帧(Response and Event Frames)
Gateway 发回 ResponseFrame 消息回复 RPC 调用,或发送异步 EventFrame 用于状态更新、通知或 Agent 事件
总结
OpenClaw 原生客户端通过以下关键功能提供凝聚力强的多平台体验:
-
统一协议(Unified Protocol):单一的 Gateway Protocol v3,使用基于 WebSocket RPC 的 JSON 帧模型,以 TypeScript 描述并自动生成到 Swift 和 Kotlin 模型中,确保强类型安全和协议兼容性
-
Swift iOS/macOS 客户端(Swift iOS/macOS clients):组织在多个目标应用/扩展中,通过 OpenClawKit 包共享核心 Gateway 模型和 UI 组件
-
Kotlin Android 客户端(Kotlin Android client):使用 Coroutine、Jetpack Compose UI 和原生语音基础设施的现代 Android 应用
-
自动化代码生成流水线(Automated Code Generation Pipeline):纯粹由 TypeScript Schema 驱动,以保持跨原生平台的一致性并减少重复/错误
此架构在确保与 Gateway 服务器进行健壮且安全的通信的同时,支持可扩展的客户端开发。
Device Node 协议(Device Node Protocol)
协议概述(Protocol Overview)
Device Node(设备节点)使用带有专用 role 参数的标准 WebSocket 协议(v3)连接到 Gateway。与操作员客户端不同,节点的 RPC 方法访问权限有限,主要响应来自 Gateway 的调用请求。
节点连接流程(Node Connection Flow)
来源:src/gateway/server/ws-connection/message-handler.ts(第 147-180 行)
节点角色与授权(Node Role & Authorization)
节点以 role: "node" 连接,可以访问由 Gateway 根据角色和范围验证的一组受限 RPC 方法。
| 节点角色方法 | 用途 | 方向 |
|---|
node.invoke.result | 返回命令执行结果 | 节点 → Gateway |
node.event | 发送异步事件 | 节点 → Gateway |
node.pending.drain | 获取已排队的命令 | 节点 → Gateway |
node.pending.pull | 轮询新命令 | 节点 → Gateway |
node.pending.ack | 确认已处理的项目 | 节点 → Gateway |
skills.bins | 下载 Skill 二进制文件白名单 | 节点 → Gateway |
skills.bins 方法允许节点主机在启用 autoAllowSkills 时将 Skill 提供的二进制文件作为隐式允许,提高了节点主机调用的安全性。
节点配对系统(Node Pairing System)
节点在接收命令之前必须先完成配对。Gateway 通过持久化的 DevicePairingPendingRequest 和 PairedDevice 状态以及相应的审批流程来管理配对。
配对状态模型(Pairing State Model)
配对状态通过两个 JSON 文件持久化:待处理请求和已批准的已配对设备。
每个 PairedDevice 保存设备身份、角色、范围、用于身份验证的令牌以及创建和批准的时间戳等详细信息。
配对流程步骤(Pairing Flow Steps)
-
请求配对(Request Pairing):节点发送 node.pair.request RPC,创建一个持久化为待批准的 DevicePairingPendingRequest。这由 requestDevicePairing 处理。
-
操作员审批(Operator Approval):操作员通过 CLI 或控制 UI 批准请求,将设备移入已配对列表并生成身份验证令牌。approveDevicePairing 函数执行此操作。
-
验证(Verification):节点通过提交带有其 ID 和令牌的 node.pair.verify 来验证其配对;只有这样才能获得完整的协议访问权限。这由 verifyDeviceToken 处理。
此模型支持灵活的角色和范围分配,用于细粒度的权限控制。
节点调用协议(Node Invocation Protocol,node.invoke)
设备控制的关键方法是 node.invoke,允许 Agent 或 Gateway 向由 nodeId 标识的节点发送命令。
节点主机中的调用处理(Invocation Handling in Node Host)
节点监听 node.invoke.request 事件。收到请求后,有效负载被强制转换并分发给本地处理程序。
handleInvoke 函数在节点主机上处理命令。
系统运行(Exec)命令(System Run (Exec) Commands)
system.run 命令允许在节点主机上执行具有重要安全控制的 shell 命令:
-
安全模式(Security Modes):
deny:不允许任何命令
allowlist:仅允许明确允许的命令
full:不受限制
-
询问策略(Ask Policy):
off:无需审批
on-miss:仅对未知命令提示审批
always:始终需要审批
-
白名单匹配(Allowlist Matching):命令被拆分为段,并进行精确匹配或通过安全的仅 stdin 二进制文件匹配。
-
审批请求(Approval Requests):如果命令不在白名单中且策略要求,则通过伴侣应用请求用户审批。
-
TOCTOU 绑定(Binding for TOCTOU):使用当前状态的快照和文件绑定,防止检查时间到使用时间(time-of-check to time-of-use)的不一致性。
Agent 通过 nodes 工具与设备交互,该工具将设备能力抽象为映射到 node.invoke RPC 命令的高级操作。
| 动作 | 协议命令 | 描述 |
|---|
camera_snap | camera.snap | 拍摄静止照片 |
camera_clip | camera.clip | 录制短视频片段 |
screen_record | screen.record | 录制屏幕活动 |
notifications_list | notifications.list | 列出当前通知 |
notifications_action | notifications.action | 执行通知操作 |
device_status | device.status | 查询设备状态信息 |
device_info | device.info | 检索常规设备信息 |
device_permissions | device.permissions | 检查设备权限状态 |
device_health | device.health | 获取设备健康指标 |
run | system.run | 远程执行 shell 命令 |
invoke | 自定义调用命令 | 调用任意节点命令 |
示例:camera_snap 动作触发带有 camera.snap 命令的 node.invoke。
通过 Gateway 的内部调用(Internal Invocation via Gateway)
工具通过解析目标节点来实现命令调用,然后调用 Gateway 的 node.invoke RPC 方法。
这确保了通过 Gateway 的统一接口和集中的安全执行。
设备命令策略与审批(Device Command Policies & Approvals)
为控制安全性,某些节点命令(尤其是 system.run)需要审批流程和细粒度的白名单。
执行审批与白名单(Exec Approvals and Allowlist)
- 命令被解析为段并与白名单进行匹配。
- 如果缺失且
ask=on-miss,则发送用户审批请求。
- 批准后,系统建立一个包含文件和 CWD 绑定的安全计划。
- 失败或不匹配则拒绝执行。
此拒绝或审批过程在允许操作员控制的同时防止潜在有害命令。
总结
Device Node 协议通过 Gateway 实现了 AI Agent 对用户设备的安全、灵活且可扩展的控制。关键要素包括:
- 严格的节点角色和方法授权。
- 具有操作员审批的强大配对系统,强制执行信任边界。
- 用于转发设备命令的
node.invoke RPC 命令。
- 将摄像头、屏幕录制和通知等设备能力抽象的节点特定工具。
- 针对敏感节点命令(
system.run)的安全策略和审批工作流。
这些组件共同允许 OpenClaw 系统安全有效地利用强大的原生设备能力。
iOS 与 macOS 应用(iOS & macOS Apps)
OpenClaw 为 iOS、watchOS 和 macOS 提供原生 Swift 应用程序,这些应用程序作为通过 WebSocket 连接到 Gateway 的设备节点。这些应用通过 node.invoke 协议暴露设备能力,并为聊天、语音交互和 Agent 管理提供平台原生界面。
iOS 应用结构(iOS App Structure)
iOS 应用包含四个主要目标,均通过 XcodeGen 配置:
| 目标 | 类型 | 用途 |
|---|
| OpenClaw | Application | 带有聊天、语音、画布和设备服务的主 iOS 应用 |
| OpenClawShareExtension | App Extension | 用于文本、URL、图像和视频的系统分享表单 |
| OpenClawActivityWidget | App Extension | 显示 Agent 状态的 Live Activity 小组件 |
| OpenClawWatchApp + OpenClawWatchExtension | watchOS App | 用于快速交互的 Apple Watch 伴侣 |
所有目标使用包 ID 前缀 ai.openclaw.ios.*,版本由 OPENCLAW_MARKETING_VERSION 和 OPENCLAW_BUILD_VERSION 构建设置管理。
分享扩展(Share Extension)
用户可以通过系统分享表单将其他应用的内容直接分享到 OpenClaw。支持的内容类型包括文本、单个 URL、最多 10 张图像和一个视频。ShareViewController 打包此内容并使用标准 GatewayNodeSession 协议将其转发到 Gateway。扩展在其 Info.plist 配置中声明激活能力。
Watch 应用(Watch App)
watchOS 伴侣由两个目标组成:OpenClawWatchApp(容器)和 OpenClawWatchExtension(SwiftUI 界面)。它提供以语音查询、状态显示和通过 watch 与 iOS 应用之间的 WatchConnectivity 消息中继为重点的最小功能。Gateway 命令仅限于语音和聊天能力。
活动小组件利用 ActivityKit 显示 Live Activities,展示长时间运行的 Agent 任务进度和状态。它使用 OpenClawActivityAttributes 在主应用和小组件之间定义共享数据结构。
macOS 应用结构(macOS App Structure)
macOS 应用是一个为无干扰的 Agent 交互和 Gateway 管理而设计的菜单栏工具。
关键组件(Key Components)
| 组件 | 描述 |
|---|
| 菜单栏图标(Menu Bar Icon) | 显示连接状态、Agent 选择和快速操作 |
| 聊天窗口(Chat Window) | 显示消息历史记录和输入的浮动界面 |
| Gateway 设置(Gateway Settings) | 连接/断开 Gateway 和身份验证的 UI |
| 语音唤醒(Voice Wake) | 通过 Swabble 集成实现的始终开启的唤醒词检测 |
| 执行审批(Exec Approvals) | 执行请求审批的原生系统提示 |
应用使用包标识符 ai.openclaw.mac,与 iOS 共享 CalVer 版本控制,并通过 LSUIElement = true 不显示 Dock 图标运行。
执行审批提示(Exec Approval Prompts)
macOS 应用为来自 Agent 的 system.run 执行请求显示原生模态对话框。它遵循 Agent 特定的 tools.exec.approvals.enabled 配置。如果原生 UI 审批不可用,则应用回退白名单策略。
Sparkle 自动更新(Sparkle Auto-Update,macOS)
OpenClaw 使用 Sparkle 框架实现无缝的 macOS 应用更新。appcast.xml 从 GitHub 仓库的主分支提供服务,并使用 Ed25519 密钥签名以确保完整性。发布构建在发布前获得 Developer ID 签名和公证。
iOS 应用架构(iOS App Architecture)
iOS 应用维护与 Gateway 的两个并发 WebSocket 连接:
| 连接 | 角色 | 用途 |
|---|
| nodeGateway | node | 接收入站 node.invoke 命令;注册设备能力 |
| operatorGateway | operator | 发送用于聊天、talk、语音唤醒和配置的出站 RPC 调用 |
两个连接都作为 GatewayNodeSession 实例由 NodeAppModel 管理。
NodeAppModel
NodeAppModel 是协调 iOS 应用状态和通信的主要 @Observable 类。其核心职责包括:
- 管理两个 Gateway WebSocket 会话
- 维护连接生命周期、后台状态抑制和重连逻辑
- 拥有设备/本地服务控制器,如
VoiceWakeManager、TalkModeManager 和 ScreenController
- 构建分发传入
node.invoke 命令的 NodeCapabilityRouter
- 维护 Gateway 服务器信息、Agent 选择、连接状态和分享事件的可观察 UI 状态
nodeGateway 上收到的所有 node.invoke 请求都被转发到 NodeAppModel 中的 handleInvoke(),它在通过能力路由器分发之前强制执行权限和后台化规则。
GatewayConnectionController
GatewayConnectionController 管理到 Gateway 服务器的发现、连接、TLS 信任和自动重连。它使用 GatewayDiscoveryModel 进行 Bonjour/mDNS 本地网络 Gateway 服务发现,并根据应用场景阶段处理暂停/恢复。
控制器使用 SHA-256 指纹实现 TOFU(Trust On First Use,首次使用信任)TLS 证书固定。当连接到启用了 TLS 且没有存储指纹的新 Gateway 时,它会探测 TLS 公钥指纹,显示 TrustPrompt UI 供用户审批,并将指纹存储在 GatewayTLSStore 中用于未来验证。后续连接会根据存储的数据验证证书指纹,防止回退到未加密的连接。
TalkModeManager
TalkModeManager 提供双向语音对话支持,将语音识别和文本转语音与 Gateway 集成。
语音转文本(Speech-to-Text):使用 SFSpeechRecognizer 配合 AVAudioEngine 捕获麦克风音频。音频缓冲区馈送到 SFSpeechAudioBufferRecognitionRequest,生成实时转录。系统包含带有可配置超时的静音检测,并支持多种捕获模式:.idle、.continuous 和 .pushToTalk。
文本转语音(Text-to-Speech):TTS 播放由外部 Gateway 处理,通常使用 ElevenLabs TTS API。流式音频(PCM 或 MP3)通过 PCMStreamingAudioPlayer 和/或 StreamingAudioPlayer 播放。语音配置在连接期间从 Gateway 获取。
VoiceWakeManager 与 Swabble 集成(VoiceWakeManager and Swabble Integration)
VoiceWakeManager 使用 AVAudioEngine tap 在 iOS 上运行始终开启的唤醒词检测,将音频缓冲区馈送到自定义识别流水线。缓冲区入队到 AudioBufferQueue,异步排空到语音识别器。唤醒词检测依赖 SwabbleKit 守护进程集成进行高效音频处理。检测触发通过 Gateway 连接路由的语音唤醒事件。
ScreenController 与 A2UI 画布渲染(ScreenController & A2UI Canvas Rendering)
ScreenController 管理用于 Agent 交互和 UI 展示的 WKWebView 画布界面。画布支持加载默认的脚手架 HTML 或导航到外部 URL。滚动交互仅对外部 URL 启用;默认脚手架禁用滚动并传递原始触摸事件。
应用使用 A2UI 开放标准进行声明式 UI 渲染。A2UI bundle(index.html 和相关 JS/CSS)由 scripts/bundle-a2ui.sh 工具生成,结合来自 vendor/a2ui/renderers/lit 和 apps/shared/OpenClawKit/Tools/CanvasA2UI 的源。
构建系统与 XcodeGen(Build System & XcodeGen)
OpenClaw 使用 XcodeGen 声明式地定义 iOS 应用项目及其目标。apps/ios/project.yml 的项目文件定义了多个目标和依赖的设置。它强制执行 Swift 6.0、并发严格性、bundle 打包、签名配置和部署目标。系统集成了 SwiftLint 和 SwiftFormat 作为预构建脚本用于代码风格执行,并与 OpenClawKit 和 Swabble Swift 包共享包依赖。
Android 和 macOS 应用分别使用独立的 Gradle 和 SwiftPM 构建系统。
总结
OpenClaw 的 iOS 和 macOS 原生应用构成了一个集成的、多目标生态系统,提供:通过安全的首次使用信任 TLS 实现无缝的 Gateway 发现和连接管理;通过持续唤醒词检测和双向语音处理实现语音能力;通过系统级分享扩展和 watch 应用伴侣实现多设备体验;通过高效 WKWebView 托管的 A2UI 画布实现响应式 Agent 驱动 UI;以及通过 XcodeGen(iOS)和 Sparkle 自动更新(macOS)实现的现代构建和分发桥接。此架构使 OpenClaw 能够提供与原生设备能力紧密耦合的强大个人 AI 助手体验。