RFC-0002:Plugin / Bundle Artifact 的 apply 合同
状态:Implemented 关联:Epic #5;#2、#3、#6;R5
消费者证据:私有 Preset 组合入口jue-preset-ai-assets(ai-assetspresets/personal)
官方依据(2026-08 核验):
- OpenClaw Plugin bundles · Plugins · Building plugins
- Hermes Plugins · Build a Hermes Plugin
背景
RFC-0001 已规定 Plugin、Bundle 与配置都是 Artifact 形态。Claude / Codex Adapter 的 write() 已支持 artifactKind: "plugin";本 RFC 将 Artifact 选择、Adapter-owned layout detection 与 Core 执行路径统一接线。targets.*.artifact、enabled 与 scope 属于转换环境,不进入 Canonical DSL。
JUE-302 的实测对象是 workspace 项目树(AGENTS.md / skills/ / hooks/)。 OpenClaw 官方文档(2026-08 核验)还定义了独立可安装表面 Compatible bundle:
| OpenClaw 表面 | 是什么 | 与 Jue 的关系 |
|---|---|---|
| Workspace | 项目内 skills/hooks/AGENTS | Adapter 已实现 |
| Compatible bundle | 安装 Claude / Codex / Cursor 布局,映射为 OpenClaw 能力 | 应用 Claude/Codex 已有 plugin 产物,零新布局 |
| Native plugin | openclaw.plugin.json + 进程内 TS 运行时 | 超出 Canonical 能力包;本 RFC 非目标 |
Hermes 的「plugin」是另一套产品语义:
| Hermes 表面 | 是什么 | 与 Jue 的关系 |
|---|---|---|
| Workspace | skills/<cat>/<name>/、config.yaml mcp、MEMORY.md | Adapter 已实现;能力包主路径 |
| General plugin | plugin.yaml + __init__.py(Python tools/hooks/commands) | 运行时扩展;不是 Canonical skill 包的默认载体 |
| Plugin-bundled skills | 同上目录内 skills/<name>/SKILL.md + ctx.register_skill | 可选薄封装;需生成少量 Python |
~/.hermes/plugins / installs.json | 安装注册表 | 不是可分发 Artifact 本身 |
若不按官方表面选型,会误造「第四种 OpenClaw 目录」或「假 Hermes plugin.json」,成本高且无法 plugins install 验收。
目标
- CLI /
targets可选 Artifact 形态(默认不变)。 - 私有 /
npm packPreset 不经公网 publish 即可产出可安装产物。 - 最小代价:能复用 Claude/Codex plugin writer 的绝不重写;不为 OpenClaw 发明新目录树;不为 Hermes 生成完整 Python 工具插件(除非用户显式要 runtime 扩展)。
- Smoke 可对所选形态做原生确认(或诚实
unsupported)。
非目标
- OpenClaw native plugin(
openclaw.plugin.json+definePluginEntry/ 进程内工具)。 - Hermes 完整 Python 工具 / platform / memory / model-provider 插件生成。
- Marketplace / ClawHub / pip 发布流水线。
- 修改 Canonical DSL;强制四端
degraded清零;在 ai-assets 写 Adapter。
官方映射(决定实现形状)
OpenClaw compatible bundle(已支持安装)
openclaw plugins install ./my-bundle
openclaw plugins list # Format: bundle;Bundle format: claude|codex|cursor
openclaw plugins inspect <id>检测标记(官方):
| Bundle format | Marker | OpenClaw 映射(supported) |
|---|---|---|
| Codex | .codex-plugin/plugin.json | skills;hooks(仅 HOOK.md+`handler.ts |
| Claude | .claude-plugin/plugin.json 或无 manifest 默认布局 | skills;commands/→当 skill 根;MCP;settings/LSP;agents / hooks.json 仅 detect |
| Cursor | .cursor-plugin/plugin.json | skills;commands→skills;其余多 detect-only |
安全边界:bundle 不加载任意 in-process 模块;比 native plugin 更窄——这正适合 Jue 从 Canonical 导出的内容包。
Hermes plugin(Python 优先)
~/.hermes/plugins/<name>/
├── plugin.yaml
├── __init__.py # register(ctx)
└── skills/<name>/SKILL.md # 可选;ctx.register_skill- 项目本地:
./.hermes/plugins/(默认关,需HERMES_ENABLE_PROJECT_PLUGINS=true)。 - 能力包(skills/agents/commands 文本)的默认 Hermes 交付仍是 workspace,不是 Python plugin。
- 若需「可
hermes plugins install的 skill 包」,只做 thin skill-plugin(yaml + 自动生成的register_skill循环 + flatskills/),不生成业务 tools。
候选方案
A. 四端各自发明聚合目录
成本高;OpenClaw 官方已提供 Claude/Codex 入口,重复造轮子。否决。
B. 仅 CLI 接线 Claude/Codex;OpenClaw/Hermes 永不做聚合
成本最低短期;但浪费 OpenClaw 已有 plugins install bundle 能力,R5 四端聚合不闭合。作 Phase 0,不作终点。
C. 配置优先 + CLI 覆盖;OpenClaw 委托已有 plugin writer;Hermes 分层(推荐)
见决策。
决策(Accepted)
采用 方案 C,并冻结 kind 名与实现策略:
| Adapter | Kind | 实现策略(最小代价) |
|---|---|---|
claude-code | project, plugin | 已有 write/confirm;只接 CLI/config |
codex | project, plugin | 同上 |
openclaw | workspace, compatible-bundle | compatible-bundle 复用 Claude 或 Codex 的 write(..., { artifactKind: "plugin" }) 产出目录,再以 openclaw plugins install / inspect 确认 Format: bundle |
hermes | workspace, skill-plugin | skill-plugin 生成 plugin.yaml + 最小 __init__.py(仅 register_skill)+ flat skills/<name>/;mcp 继续走 workspace/config.yaml |
OpenClaw compatible-bundle 细节
- 默认 bundle 基底:
claude(ai-assets 以 skills/commands 为主;Claudecommands/→OpenClaw skill 根)。 - 当 Canonical 含 hooks 且需要 OpenClaw 可执行 hooks 时,改用
codex基底(官方:仅 Codex 式HOOK.md+handler 可执行;Claudehooks/hooks.json为 detect-only)。 - 选择来源:
tools.openclaw.bundleFormat: "claude" | "codex" | "cursor" | "auto"(auto= 有 runnable hooks → codex,否则 claude;永不自动选 Cursor)。 - Adapter 代码路径:OpenClaw
write在compatible-bundle分支 委托ai-jue-adapter-claude/ai-jue-adapter-codex的write(或抽共享 helper),禁止复制粘贴第二套目录逻辑。 - Confirm:隔离目录上优先执行
openclaw plugins install <dir>→openclaw plugins inspect <id>,断言Format: bundle与Bundle format: claude|codex;CLI 不可用时保留结构证据并返回unconfirmed。nativeopenclaw.plugin.json不作为 Canonical bundle 的确认证据。 - Workspace 与 bundle 分离:
workspace继续写 AGENTS/skills/hooks 到项目树;bundle 不替代 workspace,除非用户显式选 kind。
Hermes skill-plugin 细节
- 仅打包
canonical.skills;其余 Capability 保持 workspace / degraded 诚实声明。 - 树:
<output>/
├── plugin.yaml # name 取 Preset 引用名(去 jue-preset- 前缀);version 恒 0.1.0;description 有默认值;均可被 tools.hermes.pluginManifest 覆盖
├── __init__.py # 生成:遍历 skills/ 调用 ctx.register_skill
└── skills/<skill-name>/SKILL.md (+ references 等)- Confirm:
plugin.yaml、__init__.py、register_skill与 skill roots 提供结构证据;tirith config validate继续只用于 workspace。 skill-plugin结构已实现;workspace 继续作为 Hermes 能力包主路径。
选择解析(不变)
- CLI
--artifact-kind/--artifact - 否则
targets.<adapter>.artifact auto使用 Adapter 的稳定默认project/workspace
非法 / 未实现 kind:写入前失败,不得静默降级。
详细合同
CLI / ProjectConfig
jue apply --adapter claude-code --artifact-kind plugin
jue apply --adapter openclaw --artifact-kind compatible-bundle
jue apply --adapter hermes --artifact-kind skill-plugin
jue apply --allexport default {
presets: ["ai-assets"],
targets: {
"claude-code": { artifact: "plugin" },
codex: { artifact: "plugin" },
openclaw: { artifact: "compatible-bundle" },
hermes: { artifact: "workspace" } // 或 "skill-plugin"
},
tools: {
openclaw: { bundleFormat: "auto" } // "claude" | "codex" | "cursor" | "auto"
}
};hermes: { artifact: "auto" } 使用稳定默认 workspace;skill-plugin 通过 显式 artifact 或 --artifact 选择。
Core
runCoreAdapter 传入解析后的 kind;禁止硬编码 "project"。
能力诚实矩阵(bundle / skill-plugin)
| Canonical | Claude plugin | Codex plugin | OpenClaw via Claude bundle | OpenClaw via Codex bundle | Hermes skill-plugin |
|---|---|---|---|---|---|
| skills | 支持 | 支持 | 映射为 skills | 映射为 skills | register_skill |
| commands | 支持 | degraded | 当 skill 根 | degraded/不映射 | 不打包 |
| agents | 支持 | 支持(TOML) | detect-only | 视 Codex 映射 | 不打包 |
| hooks | hooks.json | .codex/hooks.json | detect-only | 可执行(OpenClaw 布局) | 不打包(Hermes hooks 另面) |
| mcp | .mcp.json | .mcp.json | 合并到 embedded | 合并到 embedded | 不打包(用 workspace) |
| context.global | project 专用 | project 专用 | 通常不进 bundle | 通常不进 bundle | 不打包 |
导出前必须把上表中的 detect-only / 不打包项以 degraded/unsupported 或 apply 预检警告暴露,禁止静默丢弃而无提示。
安全
- Bundle / skill-plugin 不得含密钥与未脱敏 PII。
- OpenClaw bundle 保持官方窄信任边界(不加载任意 runtime 模块)——故 禁止 为 图省事改写 native
openclaw.plugin.json去「塞」Canonical。 - Hermes
__init__.py仅允许生成固定的register_skill样板,不得嵌入用户 Canonical 正文为可执行代码。 - 安装到 user 插件目录的 confirm 必须用隔离
HOME/ profile,避免污染开发机。
兼容 / 迁移
- 无 flag / 无 targets:默认行为不变(project/workspace)。
packages/docs/agents/openclaw.md区分 workspace vs compatible bundle vs native plugin 三种表面:compatible bundle 是官方可安装表面,没有 Jue 自创 聚合树,workspace 仍是项目主路径。compatible-bundle字符串保留(Guide 已用);语义冻结为「Claude/Codex 兼容包」, 不是第三种目录方言。
验收标准
- #2:Claude/Codex
jue apply --artifact-kind plugin;native 确认能力由--check模式探测(Core 路径不调用 confirm)。 - OpenClaw:
compatible-bundle产物可被openclaw plugins install <dir>识别为Format: bundle;
有 hooks 时bundleFormat=codex(或 auto)且 hooks 可执行面符合官方表。 - Hermes:
skill-plugin生成 thin skill-plugin 结构,并通过plugin.yaml、register_skillinitializer 与 skill roots 提供确认证据;workspace 仍绿。 --all+targets.enabled/artifact/scope分端生效;非法 kind 与未实现 scope 预检失败。smoke:preset-local --entry ai-assets支持 artifact 模式;离线 pack。- 二次 apply 幂等。
已知边界(已实现后遗留)
- OpenClaw CLI 是否在所有 CI 环境提供;当前合同为 CLI 可用时 install+inspect, CLI 缺席时返回结构化
unconfirmed。 - Hermes skill-plugin 是否增加真实
hermes plugins install/listheadless 证据。 - Cursor 仅作为显式
bundleFormat: "cursor"第三基底;auto不选 Cursor。
实施切片
| 顺序 | Issue | 工作 | 代价 |
|---|---|---|---|
| 1 | #2 | CLI/Core/targets 接线 | 小 |
| 2 | #3(OpenClaw) | compatible-bundle 委托 Claude/Codex writer + confirm | 小(无新布局) |
| 3 | #3(Hermes skill-plugin) | thin skill-plugin(skills;mcp 仍 workspace) | 中 |
| 4 | #6 | smoke 矩阵 | 小–中 |
| — | 明确不做 | OpenClaw native plugin、Hermes 业务 Python tools | 避免大代价 |
实现 Issue 必须链接本 RFC。