核心结论先说:两个 Agent 之间不应该靠"聊天"通信,而应该靠"共享文件 + 状态机 + 结构化交接物"通信。
Claude Code 和 Codex 是两个独立的 CLI/Agent,没有共享会话记忆。所谓"有机协作",本质上是把协作变成一套外部可见、可审计、可恢复的协议 。下面给出一套可直接落地的方案,也兼容你这个仓库已有的 .superpowers/sdd 体系。
一、总体架构:文件即消息,状态即通信
┌─────────────────────────────────────────────┐
│ 共享仓库 / 共享工作区 │
│ │
│ .superpowers/agents/ │
│ ├── tasks/<task-id>/ │
│ │ ├── brief.md 任务书(双方共读) │
│ │ ├── contract.json 契约/交接物 │
│ │ ├── status.json 状态机 │
│ │ ├── dev/ Claude Code 产物 │
│ │ └── test/ Codex 产物 │
│ └── ledger.md 全局进度台账 │
└─────────────────────────────────────────────┘
▲ ▲
Claude Code 写入 | | Codex 写入
dev/report | | test/report
└──────────────┘
通过 status.json 完成状态流转,互不直接对话
两个 Agent 不直接聊天,而是:
- 读同一个
brief.md - 写各自的
report.md - 通过
status.json判断"现在轮到谁" - 通过
contract.json传递结构化信息
二、状态机:明确"现在该谁干活"
每个任务维护一个状态文件 status.json:
json
{
"taskId": "F1-11",
"title": "通用 flush 发送层",
"status": "DEV_IN_PROGRESS",
"owner": "claude-code",
"next": "codex",
"updatedAt": "2026-08-21T10:00:00+08:00",
"history": [
{
"status": "PLANNED",
"actor": "human",
"at": "2026-08-21T09:00:00+08:00"
},
{
"status": "DEV_IN_PROGRESS",
"actor": "human",
"at": "2026-08-21T09:05:00+08:00"
}
]
}
建议状态流:
PLANNED
→ DEV_IN_PROGRESS Claude Code 开始实现
→ DEV_DONE Claude Code 提交实现 + 自测报告
→ TEST_IN_PROGRESS Codex 开始独立测试/审查
→ TEST_PASSED Codex 给出 APPROVE
→ TEST_FAILED Codex 给出 NEEDS_FIX
→ DEV_FIX Claude Code 修复
→ TEST_IN_PROGRESS Codex 回归
→ HUMAN_REVIEW /人工最终 gate
→ CLOSED
规则:
- 只有当前 owner 可以更新状态,防止两个人同时写。
- 每次状态变更必须写
history,形成审计轨迹。 - 如果某个状态超过超时时间,人工介入,而不是让 Agent 无限循环。
三、交接物:Claude Code 交给 Codex 什么
Claude Code 完成开发后,不能只说"我写完了",而要生成一个结构化交接物 dev/report.md 或 contract.json。
建议 contract.json 结构:
json
{
"taskId": "F1-11",
"from": "claude-code",
"to": "codex",
"status": "DEV_DONE",
"git": {
"branch": "feat/f1-11",
"commit": "a1b2c3d",
"diff": "git diff a1b2c3d^..a1b2c3d"
},
"changedFiles": [
"src/stores/hypergraphStore.ts",
"src/lib/eventFlush.ts",
"src/lib/__tests__/event-flush.test.ts"
],
"interfacesProduced": [
{
"name": "flushPendingEvents",
"signature": "flushPendingEvents(): Promise<FlushResult>",
"contract": "成功条目移出 pendingEvents,失败保留重试"
},
{
"name": "netPendingEvents",
"signature": "netPendingEvents()",
"contract": "undo 已撤销操作的补偿事件与原始事件相抵后返回净事件列表"
}
],
"selfTest": {
"commands": [
"npx vitest run src/lib/__tests__/event-flush.test.ts",
"npm run lint"
],
"summary": "全部通过",
"evidenceFiles": [
".superpowers/agents/tasks/F1-11/dev/test-output.log"
]
},
"claims": [
{
"claim": "flush 成功后 pendingEvents 清空",
"type": "COMPUTED",
"evidence": "event-flush.test.ts:42"
}
],
"risks": [
"netPendingEvents 对跨节点补偿事件可能还需要 Codex 重点验证"
],
"questions": [
"undo 后立即 flush 的边界行为是否符合你的理解?"
]
}
Codex 拿到这个文件后,不需要"猜" Claude Code 做了什么,直接:
- 读取
git branch/commit - 检查
changedFiles - 按
interfacesProduced写契约测试 - 按
claims逐条核验 - 针对
risks做重点攻击
四、交接物:Codex 交回给 Claude Code 什么
Codex 测试/审查完成后,写 test/report.md:
markdown
# F1-11 独立测试报告
## 结论
VERDICT: NEEDS_FIX
## 已执行
- [x] 读 diff:a1b2c3d
- [x] 运行全部相关测试:3 个失败
- [x] 新增契约测试:net-pending-events.edge.test.ts
- [x] 手动复现:undo → flush → 事件重放
## 问题清单
### Critical
- [C1] undo 后 flush 仍重放了已撤销事件
- 复现:...
- 期望:...
- 实际:...
- 证据:`.superpowers/agents/tasks/F1-11/test/repro-C1.log`
### Major
- [M1] `flushPendingEvents` 失败重试无退避,可能无限循环
### Minor
- [m1] 缺少空项目 no-op 的显式测试
## 对 Claude Code 的要求
- 请修复 C1,并补充对应回归测试
- 修复后更新 contract.json 的 status=DEV_FIX
这样 Claude Code 收到的是一个可执行的问题清单,而不是模糊的"感觉不太行"。
五、Prompt 模板:让两个 Agent 知道自己的角色
Claude Code 的开发 Prompt
text
你是开发者 Agent。
任务:读取 .superpowers/agents/tasks/F1-11/brief.md
约束:
- 只实现 brief 中 files-allow 允许的文件
- 禁止修改 files-forbid 文件
- 必须 TDD:先写失败测试,再实现
- 完成后运行相关测试和 lint
- 不要自己宣布"完成"
- 把结果写入 dev/report.md 和 contract.json
- 更新 status.json:status=DEV_DONE, owner=codex
Codex 的测试 Prompt
text
你是独立测试/审查 Agent。
对象:.superpowers/agents/tasks/F1-11
你的职责:
- 不要修改实现代码
- 只允许新增/修改测试文件
- 读取 dev/report.md 和 contract.json
- 对 diff 做独立审查
- 按 brief 的验收标准逐条验证
- 重点攻击 claims 和 risks
- 输出 VERDICT: APPROVE / NEEDS_FIX
- 所有结论必须附可复现命令和证据文件
- 禁止只引用 Claude Code 的自测结果
- 更新 status.json:TEST_PASSED 或 TEST_FAILED
六、分支与 Git 协作方式
最简单可靠的协作方式是串行共享分支:
bash
# 1. Claude Code 开发
git checkout -b feat/f1-11
claude -p "读取 brief,实现,更新 handoff,提交"
# 2. Codex 测试
git checkout feat/f1-11
codex exec "读取 handoff,独立测试,输出报告,提交测试文件"
# 3. 如果有问题,回到 Claude Code
codex exec "..."
claude -p "读取 test/report.md,修复 C1,更新 handoff"
如果两个 Agent 要并行处理不同任务,则需要:
- 不同任务使用不同分支
- 用
files-allow/files-forbid保证不碰同一批文件 - 合入前由脚本检查冲突矩阵
你仓库里的 batch-plan 冲突矩阵机制已经天然适合这件事。
七、如何做到"有机"?五个关键设计
| 设计 | 作用 |
|---|---|
| 1. 单一事实源 | brief.md 是唯一需求来源,双方都读它,避免各自脑补 |
| 2. 显式接口 | 用 contract.json 写清 Produces / Consumes,不靠自然语言猜 |
| 3. 最小交接物 | Claude Code 只交 diff、接口、证据、风险;Codex 只交问题清单、证据、结论 |
| 4. 独立证据 | 双方都必须给"命令 + 输出文件",不能只写"我验证过了" |
| 5. 人工兜底 | 最终合并/收官由人做 gate,Agent 只负责把证据做扎实 |
八、可以直接落地的目录结构
text
.superpowers/agents/
├── ledger.md # 全局进度台账
├── queue/
│ └── ready.txt # 待派发任务队列
└── tasks/
└── F1-11/
├── brief.md # 任务书
├── contract.json # 结构化交接物
├── status.json # 状态机
├── dev/
│ ├── report.md
│ ├── test-output.log
│ └── evidence/
└── test/
├── report.md
├── added-tests.diff
├── test-output.log
└── evidence/
这套方案不需要两个 Agent 实时对话,也不需要它们互相知道对方的存在。它们只需要:
读同一个文件、写同一个文件、遵守同一个状态机。
这就是两个独立智能体之间最"有机"也最可靠的协作方式。