Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help


id: ADR-015 title: 统一能力目录是基于规范所有者的只读投影 date: 2026-08-22 status: proposed relates-to:

  • https://github.com/zeroclaw-labs/zeroclaw/issues/9346
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6489
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8908
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8850
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8367
  • docs/book/src/plugins/index.md
  • crates/zeroclaw-plugins/src/config.rs

ADR-015:统一能力目录是规范所有者之上的只读投影

上下文

ZeroClaw 有多个用于描述功能的界面:内置渠道和工具、已安装的插件包、注册表中可用的软件包、已配置的提供商和渠道别名、网关集成条目、CLI 插件命令、Web 仪表盘视图、ZeroCode,以及面向代理的设置指南。这些界面目前回答了不同的问题,并使用了“已安装”“已配置”“已启用”“活跃”和“正常”等含义重叠的词语。

#6489 中提出的产品方向,是为集成、内置组件、可安装软件包、已配置实例和运行时观测结果建立一个真实可信的统一目录。这一方向有时被概括为“一切都是插件”,但可持续的架构范围更窄:一个目录,而不是一种实现机制。内置实现和基于软件包的实现可以无限期共存。

已接受的 RFC #9346 定义了缺失的契约。目录必须将软件包事实、能力事实、实现事实、已配置实例事实和运行时观测结果分开。它必须从每个事实的规范归属方派生事实,而不是创建另一个持久化生命周期注册表。在退役任何路由、执行迁移或承诺稳定的公共 API 之前,它还必须保持与现有软件包投影和 Integration 投影的兼容性。

此记录描述了该目标架构。它并不表示统一目录投影、兼容性桥接或运行时观测模型已经发布。

决策

保持五个身份彼此独立

统一目录会为不同事实使用不同的标识:

  • **包构件:**内置、已安装或注册表中可用的构件;当构件存在时,由包源、命名空间/名称、版本以及不可变内容或准入修订版本标识。
  • **能力:**带类型的行为,例如 channel:discordprovider:ollamatool:web_search、记忆后端、技能、观察器或平台集成。
  • **实现:**提供某项功能的内置实现或软件包提供的实现。
  • **已配置实例:**所属子系统规范配置中由操作员定义的别名。
  • **运行时观测:**运行时所有者针对某个运行时生成所报告的瞬时激活、运行状况或故障证据。

这些标识彼此不可替代。一个包可以公开多个能力。一个能力可以有内置、已安装和注册表中可用的实现。配置的实例可以在没有活动运行时实例的情况下存在。运行时观测结果可能会过时,而不改变安装、配置或启用状态。

标识符不得包含机密、原始配置值、访问令牌、主机名、用户名、绝对路径或可变的显示标签。软件包提供的能力和运行时观测结果始终绑定到确切的工件来源,因此不会合并已安装版本和注册表版本,升级也不会使激活或健康状态证据变得含义不明。

通过所有者声明能力身份

能力标识由能力族所有者通过类型化的内置清单字段或纳入的软件包清单架构声明。目录将构件和实现关联到这些声明。它不得根据可调用工具名称、宽泛的 PluginCapability 类型、显示名称或并行分组表推断逻辑标识。

没有所有者提供的类型化声明的族,在该所有者添加声明之前不具有目录能力标识。这使分组权保留在了解该能力的子系统中,而不是将其转移到目录投影中。

项目权威来源证据,而非生命周期写入

目录面向读取。它会在请求时从规范所有者生成视图,或从携带足够源代际信息、能够自行失效的派生缓存中生成视图。它不接受生命周期写入,也不会持久化另一张启用、准入、配置、激活、就绪或健康表。

每个状态轴只有一个所有者:

事实所有者
注册表可用性已配置的注册表或索引客户端
内置可用性编译后的内置清单
已安装的软件包和准入状态软件包安装和准入清单
能力标识、导出项和实现来源通过类型化资源清单或已接纳的 manifest 声明确定能力族所有者
已配置的实例所属子系统的规范 Config
已启用状态规范配置以及所属子系统的激活策略
活动状态实例化或注册该实例的运行时注册表
健康或失败特定能力的运行时所有者或探针
面向代理的就绪状态一种按需投影,例如 #8367,利用目录身份和证据,而不成为另一个生命周期所有者

缺失的证据是 unknown,而不是 false。状态结果区分已知为真、已知为假、未知和不适用。健康状况是由所有者定义的观测结果,而不是可以同时声明 healthyfailed 的相互独立布尔值。运行时观测包含观测时间、运行时代次、选定实现、软件包支持时的工件来源,以及新鲜度规则。一旦过期,健康状况就会恢复为未知,直到刷新。

投影并不是跨独立所有者的原子事务。公共负载包含 generated_at,并在适用时包含参与所有者的代次信息或来源信息,因此消费者无法推断软件包、配置和运行时事实是在同一时间观测到的。

保持解析器权限按地址族区分

原生/插件冲突及优先级并非全局目录策略。RFC #8850 为通道和工具提供原生/插件冲突行为。目录会将该结果映射到 channel:*tool:*

对于没有由所有者定义的解析器的提供程序、内存后端、观察器、技能和平台集成,目录会报告每个匹配的实现,并明确标示冲突未解决或未知,且不应用任何隐式排序。之后由所有者定义的解析器可以成为该系列的来源,而不会因此将目录变成解析器。

保持可见性与权限分离

目录可见性可以限制用户、UI、API 或代理所能看到的内容。它无法授予调用权限。

Agent 工具注册表、风险配置文件、每次运行的范围收窄、目标策略、授权授予、审批以及按主体限定的授权仍处于目录之外。诸如 #8367 这样的使用方可以根据目录证据和针对特定主体的策略推导出某一时点的指导,但该指导只是一个投影。它不会授权某项操作、写入生命周期状态,也不会成为已配置实例的事实。

公开投影不包含凭据、机密引用、原始配置值、注册表身份验证、主机身份、无限制的文件系统路径、原始运行时错误和私有清单字段。注册表和清单文本是不可信的元数据,必须作为数据而非指令呈现。

在收敛之前保持兼容性

GET /api/plugins 在包相关工作趋于稳定期间仍作为以包为中心的投影。/api/integrations 仍作为基于共享目录的兼容性投影,直到另行作出的兼容性决策批准将其停用、重定向或对稳定 API 进行破坏性更改。

CLI、Web、ZeroCode、网关和面向代理的就绪功能都使用来自同一契约的版本化投影。可以以兼容方式引入新增字段。标识符变更、路由退役、配置迁移、稳定公共 API 承诺以及市场信任策略都需要单独审查,并制定回滚和兼容性计划。

包标识必须与现有的注册表方向建立映射,而不是另造一套无关的坐标系。实现工作应在第二个使用方依赖这些内容之前,协调包坐标与现有的 MCP 风格包标识,以及单独提出的 OCI 注册表方向。

证据词汇有意遵循既有的分布式状态实践:采用 Kubernetes 风格的条件语义来表示已知、未知和已观测事实,并采用 systemd 对启用意图与运行时活动状态的区分。ZeroClaw 无需整体照搬这些系统,但目录应保留这种区分。

验收关卡

此 ADR 在满足以下所有条件之前仍处于提议状态:

  • 软件包产物、能力、实现、已配置实例、运行时观测结果和状态证据均通过具有代表性的渠道、提供程序、工具、平台和多能力软件包示例进行记录;
  • 每个逻辑能力标识都来自所有者提供的类型化声明,目录无法从可调用名称或宽泛的能力类别中推断出该标识;
  • 每个投影状态字段都标明其事实来源,并正确使用已知、未知和不适用语义;
  • 软件包可用性、安装、准入、配置、启用、激活、健康状态和面向代理的就绪状态仍可在目录中独立表示,且无法通过目录写入;
  • 通道和工具的内置/插件冲突行为与 #8850 一致,而其他能力类别仍明确处于未解决状态,除非其所有者定义了解析器;
  • 软件包提供的能力和运行时观测结果,在已安装版本与可用版本存在差异、升级、重新加载以及运行时世代变更的情况下,始终与确切的制品溯源信息绑定;
  • 公共投影会公开生成元数据或溯源元数据,并不意味着独立所有者之间具有原子一致性;
  • 目录可见性无法授予调用权限,也无法绕过代理、回合、目标、授权、审批或策略检查;
  • /api/plugins/api/integrations 在任何路由合并、退役或稳定 API 承诺之前,都提供了增量兼容桥接;并且
  • 软件包坐标标识会在不止一个软件包使用者依赖它之前,与现有的 MCP 和 OCI 注册表规范进行协调。

后果

积极后果:

  • 贡献者可以判断某条事实属于软件包可用性、安装、配置、启用、激活、运行状况还是就绪状态。
  • CLI、网关、Web、ZeroCode 和面向代理的指南可以使用同一套词汇,而无需复制生命周期状态。
  • 内置实现和插件实现可以共存,而无需假装所有内置实现都已迁移到 WASM。
  • 运行时健康状态和激活声明将以证据为依据,而不是从配置或软件包是否存在中推断。
  • 兼容性工作可以在公开路由或术语变更之前以增量方式推进。

负面后果:

  • 目录契约比单个 status 枚举更复杂。
  • 能力族所有者必须先添加类型化声明,其能力才能顺利参与。
  • 运行时负责人必须先发布按代次限定的观测数据,目录才能报告活动状态或健康状况的证据。
  • API 收敛速度较慢,因为 /api/plugins/api/integrations 必须通过兼容性切片进行桥接。
  • 包坐标协调必须足够早地进行,以避免再引入一套注册表身份系统。

参考文献