跨 Harness 可移植性模型
跨 Harness 可移植性模型
学习目标
本章要解决什么问题:理解 ECC 如何将一套工作流适配到 Claude Code、Codex、Cursor、OpenCode、Gemini 等多种 AI 编码代理。
读完本章后,你将了解:
- “工作流层 vs 执行表面”的架构分离
- SKILL.md 作为最便携单元的设计原则
- 各 Harness 的适配策略与可移植性差异
- Hermes Operator Shell 的边界定义
前置知识
本章涉及插件系统和可移植性的通用原理,建议先阅读:
- 插件系统架构 — 约定优于配置的组件发现机制
- 跨 Harness 可移植性 — 便携单元设计与适配模式
下文假设你已理解上述概念,直接聚焦 ECC 的具体实现。
项目实践
工作流层与执行表面的分离
ECC 的核心架构决策是将持久的行为逻辑与 Harness 特定的加载和执行机制分离:
ECC 的可移植性矩阵:
| 表面 | 共享源 | Harness 适配 | 可移植性 |
|---|---|---|---|
| Skills | skills/*/SKILL.md | 各 Harness 打包格式 | 高 — 主要是指令文本 |
| Rules | rules/, AGENTS.md | 安装路径、格式 | 中 — 支持但不完全相同 |
| Hooks | hooks/hooks.json | 原生 vs 指令驱动 | 中 — Claude 原生,Codex 指令 |
| MCPs | .mcp.json | 各 Harness MCP 导入 | 高 — MCP 是标准协议 |
| Commands | commands/ | 斜杠命令 vs CLI | 中 — 语义各 Harness 不同 |
| Sessions | 编排脚本 | TUI/daemon/worktree | 低 — Alpha 阶段 |
Harness 适配器合规矩阵
ECC 维护了一个详细的合规矩阵(scripts/lib/harness-adapter-compliance.js),追踪每个表面在各 Harness 中的支持状态:
SKILL.md 的便携性设计
ECC 的 246 个 SKILL.md 文件遵循统一的便携性约定:
---name: tdd-workflowdescription: 测试驱动开发工作流origin: ECC # 来源标记:ECC(官方)或 community---便携性规则:
- 使用 YAML frontmatter 声明
name、description、origin - 描述何时使用该技能(When to Activate)
- 声明所需工具但不嵌入密钥
- 示例保持仓库相对或通用
- Harness 特定命令放在有明确标签的独立区块
适配层的实际目录结构
ECC 为每个 Harness 维护了独立的适配目录:
| 目录 | 目标 Harness | 内容 |
|---|---|---|
.claude-plugin/ | Claude Code | 插件元数据(plugin.json) |
.codex-plugin/ | Codex | 插件配置 + 适配后的 codex.md |
.opencode/ | OpenCode | OpenCode 插件格式的技能/命令 |
.cursor/ | Cursor | 翻译后的规则和设置 |
.gemini/ | Gemini | 指令驱动的兼容性表面 |
.zed/ | Zed | Zed 特定的规则翻译 |
Hermes 边界
Hermes 是 ECC 衍生的 Operator Shell,ECC 明确定义了其与公共仓库的边界:
应该交付:
- 净化的设置文档(
docs/HERMES-SETUP.md) - 仓库相对演示提示
- 通用 Operator 技能
- 不依赖私有凭证的示例
不交付:
- OAuth Token 或 API Key
- 原始的
~/.hermes导出 - 个人工作空间记忆
- 私有数据集
- 未经审查的本地自动化包
问题与规避
Harness 特定假设导致不可移植
问题:技能中使用 Claude 特定的 /compact 命令,在 Codex 中无效。
ECC 的规避:Harness 特定内容放在有明确标签的区块中。主流程使用通用描述。例如在 continuous-learning 技能中:
### If installed as a plugin (recommended):No extra settings.json hook block is required.
### If installed manually:Add this to your settings.json: ...适配层过厚导致不一致
问题:为每个 Harness 维护一份行为逻辑副本,导致不一致。
ECC 的规避:
- 适配层只翻译加载机制,不翻译行为
- 共享行为始终在源位置(
skills/、hooks/) - CI 验证目录计数与 CHANGELOG 声明一致
钩子语义差异
问题:Claude 的 PreToolUse 钩子可以阻塞工具调用,Codex 没有等效机制。
ECC 的规避:
- 在支持原生钩子的 Harness 中使用阻塞钩子
- 在不支持的 Harness 中使用指令描述 + 事后检查
- 文档中明确标注哪些钩子有回退、哪些没有
设计取舍
为什么不做 Harness 无关的运行时?
构建统一的”超级插件”在所有 Harness 上运行:
- 被考虑但放弃的原因:各 Harness 的插件 API 差异太大,维护统一运行时的成本超过收益
- ECC 的选择:薄适配层 + 共享源文件。更简单、更容易调试
为什么共享源码而非分发产物?
ECC 选择共享源码(Markdown 文件)作为分发单位:
- 优势:社区可直接阅读和贡献,适配可透明审计,技能可平滑演进
- 代价:用户看到的是原始 Markdown,而非精美的文档
- 替代方案:构建为静态文档站点或 npm 包。ECC 认为源码即文档更利于社区贡献
为什么 Hooks 在 Codex 中退化为指令?
Codex 没有原生钩子执行能力:
- ECC 的选择:在 AGENTS.md 中以指令描述替代钩子
- 效果:行为从”强制执行”退化为”建议遵守”
- 权衡:不完全等效,但比完全没有好
参考来源
- 源码验证:
docs/architecture/cross-harness.md— 跨 Harness 架构文档 - 源码验证:
.codex-plugin/,.opencode/,.cursor/目录 — 各 Harness 适配 - 源码验证:
scripts/lib/harness-adapter-compliance.js— 合规矩阵 - 跨 Harness 可移植性 — 通用可移植性设计模式