AI Coding 多工具协作实战:同一个项目如何无缝切换 Qoder / Claude Code / Codex / Cursor / Trae
关键词:AI Coding、多工具协作、上下文可移植、AGENTS.md、规范驱动开发(SDD)、无缝切换
适用读者:已经用过至少一款 AI 编程工具、正在或打算在同一项目里混用多款工具的中高级开发者
文章目录
- [AI Coding 多工具协作实战:同一个项目如何无缝切换 Qoder / Claude Code / Codex / Cursor / Trae](#AI Coding 多工具协作实战:同一个项目如何无缝切换 Qoder / Claude Code / Codex / Cursor / Trae)
-
- [前言:为什么你会想在同一个项目里用多个 AI 编程工具](#前言:为什么你会想在同一个项目里用多个 AI 编程工具)
- 一、五款工具定位速览(示例,非处方)
-
- [1.1 不止这五款:任意工具都适用](#1.1 不止这五款:任意工具都适用)
- 二、核心难题:为什么"换工具"会让开发断裂
- 三、协作总架构:把"项目真相"放进仓库
- [四、工具无关的共享约定:AGENTS.md 是通用语](#四、工具无关的共享约定:AGENTS.md 是通用语)
- 五、规格驱动:让"为什么做"也留在仓库
- 六、分工协作策略:谁干什么(给依据,不给处方)
-
- [6.1 决策依据(按原则选,不按工具选)](#6.1 决策依据(按原则选,不按工具选))
- [6.2 组合矩阵(例:2 个 / 3 个 / 5 个 / 只有 1 个)](#6.2 组合矩阵(例:2 个 / 3 个 / 5 个 / 只有 1 个))
- [6.3 角色与工具映射(例)](#6.3 角色与工具映射(例))
- 七、实战:同一项目五工具接力(示例)
- 八、主动换工具的"零中断"检查清单
- 九、踩坑与最佳实践
- 十、团队级落地:协作跨越工具、人与时间
- 十一、总结与展望
- 参考资料
前言:为什么你会想在同一个项目里用多个 AI 编程工具
先说一个我自己的真实状态。我手头有一个全栈 SaaS 项目,平时在用五款 AI 编程工具之间来回切:用 Claude Code 在终端里跑长链路的重构和验证,用 Cursor 做多文件编辑和即时补全,用 Codex(OpenAI) 在 CI 里批量跑代码审查,用 Qoder 的 Quest / Expert 模式做需求拆解和架构理解,用 Trae 的 SOLO 模式快速把原型跑起来。
这五款工具只是我当前工具箱里的例子 ,不是一份必须照搬的"配方"。本文真正想讲清楚的是一件事:当你主动换工具时,为什么开发会断裂,以及怎么让它不断裂。 而且这个方法不绑定任何具体工具------Aider、Kiro、Windsurf、GitHub Copilot、Zed、Gemini CLI、CodeBuddy、通义灵码等任意 AI 编程工具,只要让它们读取仓库里同一份"三层契约",结论都成立。下文凡提到具体工具名,一律当作"示例"看待。
说个踩坑现场。上个月有个登录限流的需求,我先用 Cursor 的 Plan 模式理了方案、写了大半实现,临下班前想用 Claude Code 接着跑测试闭环------结果新开会话的 Claude Code 对我项目一无所知:它不知道这项目用 Fastify 而不是 Express,不知道鉴权是 JWT 且 refresh token 必须存 HTTP-only Cookie,更不知道"限流要用 Redis 令牌桶"这个已经在对话里定下的方案。我不得不把背景又讲了一遍,它还按 Express 的套路写了段错误代码。一次普通的"接着干",变成了"从头教"。
把话说透一点:换工具只是"上下文断裂(Context Fracture)"这个更大问题的一个子集。同一个项目的开发状态,还会因为"换会话、换人、换设备"而丢失。很多团队只盯着"工具切换"这一个症状,结果每换一次又从头解释一遍项目背景,比新人入职还累。本文要解决的,是这一类问题的共同根因------项目的"真相"到底存在哪里。
先给结论:只要让项目的真相(约定、规格、进度)以版本化的文件形式住在仓库里,而不是住在某一款工具的对话历史或私有记忆里,换工具就是一次普通的 git pull,开发不会中断。下面所有内容都围绕这句话展开。
一、五款工具定位速览(示例,非处方)
重要声明 :本节列出的 Qoder / Claude Code / Codex / Cursor / Trae 是"多工具协作"这一命题的示例,不是固定结论。你完全可以用 Aider、Kiro、Windsurf、GitHub Copilot、Zed 等替换其中任意一款。选什么工具,取决于你下一节的"决策依据",而不是这一节的排布。
2026 年的 AI 编程工具已经明显分化出两条路线:终端原生的 Agent (Claude Code、Codex CLI)和 AI 原生 IDE(Cursor、Trae、Qoder IDE)。它们对上下文的处理方式差异,直接决定了协作时怎么交接。
| 工具(示例) | 形态 | 自主程度 | 上下文加载机制 | 共享约定文件 | 我最常用的场景 |
|---|---|---|---|---|---|
| Qoder | AI 原生 IDE / CLI / 云端 Agent | 高(Quest + Expert 多智能体) | AGENTS.md + .qoder/rules/** + Repo Wiki |
/AGENTS.md、/.qoder/rules/** |
需求拆解、架构理解、长链路交付 |
| Claude Code | 终端原生 Agent | 高(Agent Loop + Subagents) | CLAUDE.md + rules + skills + hooks |
CLAUDE.md(可 @import AGENTS.md) |
多文件重构、带验证的复杂任务 |
| Codex | 终端原生 Agent(CLI) | 高(exec / TUI) | AGENTS.md 层级加载 |
~/.codex/AGENTS.md、/AGENTS.md |
CI 批量审查、确定性脚本任务 |
| Cursor | AI 原生 IDE(VS Code fork) | 中高(Agent + Background Agent) | .cursorrules / .cursor/rules/*.mdc + RAG 索引 |
读 CLAUDE.md / AGENTS.md 作 fallback |
多文件编辑、补全、Plan 模式 |
| Trae | AI 原生 IDE(VS Code fork) | 中高(Builder / SOLO 多智能体) | MCP 自定义智能体 + 项目上下文 | 规则可指向仓库约定文件 | 快速原型、端到端脚手架 |
注:上表最后一列"我最常用的场景"是个人偏好示例。把"Claude Code 负责重构"写成处方是本文要避免的典型错误------正确问法是"这个任务需要什么能力",而不是"该用哪个工具"。
下面这张图把五款工具的定位放进同一坐标系:横轴是"自主程度",纵轴是"上下文来源"。
#mermaid-svg-sckazDivtdGKFbPI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sckazDivtdGKFbPI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sckazDivtdGKFbPI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sckazDivtdGKFbPI .error-icon{fill:#552222;}#mermaid-svg-sckazDivtdGKFbPI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sckazDivtdGKFbPI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sckazDivtdGKFbPI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sckazDivtdGKFbPI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sckazDivtdGKFbPI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sckazDivtdGKFbPI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sckazDivtdGKFbPI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sckazDivtdGKFbPI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sckazDivtdGKFbPI .marker.cross{stroke:#333333;}#mermaid-svg-sckazDivtdGKFbPI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sckazDivtdGKFbPI p{margin:0;}#mermaid-svg-sckazDivtdGKFbPI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-sckazDivtdGKFbPI .cluster-label text{fill:#333;}#mermaid-svg-sckazDivtdGKFbPI .cluster-label span{color:#333;}#mermaid-svg-sckazDivtdGKFbPI .cluster-label span p{background-color:transparent;}#mermaid-svg-sckazDivtdGKFbPI .label text,#mermaid-svg-sckazDivtdGKFbPI span{fill:#333;color:#333;}#mermaid-svg-sckazDivtdGKFbPI .node rect,#mermaid-svg-sckazDivtdGKFbPI .node circle,#mermaid-svg-sckazDivtdGKFbPI .node ellipse,#mermaid-svg-sckazDivtdGKFbPI .node polygon,#mermaid-svg-sckazDivtdGKFbPI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-sckazDivtdGKFbPI .rough-node .label text,#mermaid-svg-sckazDivtdGKFbPI .node .label text,#mermaid-svg-sckazDivtdGKFbPI .image-shape .label,#mermaid-svg-sckazDivtdGKFbPI .icon-shape .label{text-anchor:middle;}#mermaid-svg-sckazDivtdGKFbPI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-sckazDivtdGKFbPI .rough-node .label,#mermaid-svg-sckazDivtdGKFbPI .node .label,#mermaid-svg-sckazDivtdGKFbPI .image-shape .label,#mermaid-svg-sckazDivtdGKFbPI .icon-shape .label{text-align:center;}#mermaid-svg-sckazDivtdGKFbPI .node.clickable{cursor:pointer;}#mermaid-svg-sckazDivtdGKFbPI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-sckazDivtdGKFbPI .arrowheadPath{fill:#333333;}#mermaid-svg-sckazDivtdGKFbPI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-sckazDivtdGKFbPI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-sckazDivtdGKFbPI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sckazDivtdGKFbPI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-sckazDivtdGKFbPI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sckazDivtdGKFbPI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-sckazDivtdGKFbPI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-sckazDivtdGKFbPI .cluster text{fill:#333;}#mermaid-svg-sckazDivtdGKFbPI .cluster span{color:#333;}#mermaid-svg-sckazDivtdGKFbPI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-sckazDivtdGKFbPI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-sckazDivtdGKFbPI rect.text{fill:none;stroke-width:0;}#mermaid-svg-sckazDivtdGKFbPI .icon-shape,#mermaid-svg-sckazDivtdGKFbPI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-sckazDivtdGKFbPI .icon-shape p,#mermaid-svg-sckazDivtdGKFbPI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-sckazDivtdGKFbPI .icon-shape .label rect,#mermaid-svg-sckazDivtdGKFbPI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-sckazDivtdGKFbPI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-sckazDivtdGKFbPI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-sckazDivtdGKFbPI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 终端原生 Agent 路线
Claude Code
Agent Loop + Subagents
Codex CLI
exec / TUI
AI 原生 IDE 路线
Qoder
Quest + Expert 多智能体
Cursor
Agent + Background Agent
Trae
Builder / SOLO 多智能体
上下文来源
AGENTS.md / CLAUDE.md / rules
Git 仓库 / 代码索引
选型时真正要回答的问题只有三个,按优先级排:
- 这个任务需要多高的"自主闭环"? 需要它自己跑测试、自己修、自己提交,就选 Agent 闭环强的(Claude Code / Codex / Qoder Quest);只需要改几处文件并让我 review,IDE 路线更顺手。
- 上下文从哪来最可靠? 凡是能把约定写进仓库文件的,切换成本都低;凡是只存在私有记忆里的,切换就痛。
- 失败成本谁承担? 钱、用户数据、不可逆操作------只要碰其中任一,先写规格(见第五节),再让工具执行。
1.1 不止这五款:任意工具都适用
上表只列了我常用的五款,但同一套"三层契约"对所有 AI 编程工具都成立。差别仅仅是"它用什么文件名读约定、怎么接规格",本质都是把真相指向仓库里的同一份文件。下面补一张更全的映射,证明方法不挑工具:
| 其他工具(示例) | 原生约定文件 | 接入三层契约的方式 |
|---|---|---|
| Aider | .aider.conf.yml + 会话约定 |
把 AGENTS.md 作为 conventions 文件加入会话(/add 或配置 read 列表) |
| Kiro | 自身 spec 文件(requirements/design/tasks) | 原生即 SDD,直接对应规格层,几乎零改造 |
| Windsurf | .windsurfrules |
规则文件引用仓库 AGENTS.md |
| GitHub Copilot | .github/copilot-instructions.md |
指令文件指向约定层 + 规格层 |
| Zed | 项目 rules / agent 配置 | 指向 AGENTS.md 作共享约定 |
| Gemini CLI | GEMINI.md |
设为 AGENTS.md 的 fallback(Codex 已原生支持) |
| 通义灵码 / CodeBuddy | 各自 Rules / 记忆文件 | 规则引用仓库 AGENTS.md,或靠 @import 复用 |
可以看到一个共性规律:任何工具都有一个"自己的约定文件名",但真正跨工具流通的,是仓库里的 AGENTS.md + 规格目录 。所以正确做法是------各工具的私有文件只做"转发层",详细约定全部写在 AGENTS.md。这样未来你换到第 8 款、第 20 款工具时,只需在它的转发层加一行引用,开发状态照常无缝承接。
推论:本文的"分工协作"与"零中断切换"也因此与具体工具解耦。你手里有几款、分别是哪几款,都不影响下面给出的决策依据和组合矩阵------它们按"能力"排,不按"工具名"排。
二、核心难题:为什么"换工具"会让开发断裂
要治本,得先认清病根。2026 年行业里一个被反复验证的判断是:AI 编码的瓶颈不是模型够不够聪明,而是上下文管理(Context Management)失效。 模型在 1K token 时准确率能到 99%,但上下文扩展到 32K 时可能跌到 70% 以下------这就是"上下文中毒"和"注意力漂移"。
工具切换之所以痛,本质原因是:每款工具重启后,对话历史都不在了,它只能从代码本身重新猜测你的意图。 而代码往往不反映原始意图------为什么这样设计、哪些是被否决的方案、哪些是不可碰的红线,都散落在对话里。
我把"上下文断裂"归为四个来源,换工具只是其中之一:
#mermaid-svg-cboMfDl9TiWHnesG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cboMfDl9TiWHnesG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cboMfDl9TiWHnesG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cboMfDl9TiWHnesG .error-icon{fill:#552222;}#mermaid-svg-cboMfDl9TiWHnesG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cboMfDl9TiWHnesG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cboMfDl9TiWHnesG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cboMfDl9TiWHnesG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cboMfDl9TiWHnesG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cboMfDl9TiWHnesG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cboMfDl9TiWHnesG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cboMfDl9TiWHnesG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cboMfDl9TiWHnesG .marker.cross{stroke:#333333;}#mermaid-svg-cboMfDl9TiWHnesG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cboMfDl9TiWHnesG p{margin:0;}#mermaid-svg-cboMfDl9TiWHnesG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cboMfDl9TiWHnesG .cluster-label text{fill:#333;}#mermaid-svg-cboMfDl9TiWHnesG .cluster-label span{color:#333;}#mermaid-svg-cboMfDl9TiWHnesG .cluster-label span p{background-color:transparent;}#mermaid-svg-cboMfDl9TiWHnesG .label text,#mermaid-svg-cboMfDl9TiWHnesG span{fill:#333;color:#333;}#mermaid-svg-cboMfDl9TiWHnesG .node rect,#mermaid-svg-cboMfDl9TiWHnesG .node circle,#mermaid-svg-cboMfDl9TiWHnesG .node ellipse,#mermaid-svg-cboMfDl9TiWHnesG .node polygon,#mermaid-svg-cboMfDl9TiWHnesG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cboMfDl9TiWHnesG .rough-node .label text,#mermaid-svg-cboMfDl9TiWHnesG .node .label text,#mermaid-svg-cboMfDl9TiWHnesG .image-shape .label,#mermaid-svg-cboMfDl9TiWHnesG .icon-shape .label{text-anchor:middle;}#mermaid-svg-cboMfDl9TiWHnesG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cboMfDl9TiWHnesG .rough-node .label,#mermaid-svg-cboMfDl9TiWHnesG .node .label,#mermaid-svg-cboMfDl9TiWHnesG .image-shape .label,#mermaid-svg-cboMfDl9TiWHnesG .icon-shape .label{text-align:center;}#mermaid-svg-cboMfDl9TiWHnesG .node.clickable{cursor:pointer;}#mermaid-svg-cboMfDl9TiWHnesG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cboMfDl9TiWHnesG .arrowheadPath{fill:#333333;}#mermaid-svg-cboMfDl9TiWHnesG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cboMfDl9TiWHnesG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cboMfDl9TiWHnesG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cboMfDl9TiWHnesG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cboMfDl9TiWHnesG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cboMfDl9TiWHnesG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cboMfDl9TiWHnesG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cboMfDl9TiWHnesG .cluster text{fill:#333;}#mermaid-svg-cboMfDl9TiWHnesG .cluster span{color:#333;}#mermaid-svg-cboMfDl9TiWHnesG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cboMfDl9TiWHnesG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cboMfDl9TiWHnesG rect.text{fill:none;stroke-width:0;}#mermaid-svg-cboMfDl9TiWHnesG .icon-shape,#mermaid-svg-cboMfDl9TiWHnesG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cboMfDl9TiWHnesG .icon-shape p,#mermaid-svg-cboMfDl9TiWHnesG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cboMfDl9TiWHnesG .icon-shape .label rect,#mermaid-svg-cboMfDl9TiWHnesG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cboMfDl9TiWHnesG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cboMfDl9TiWHnesG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cboMfDl9TiWHnesG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 上下文断裂 Context Fracture
换工具
对话/记忆不互通
换会话
同一工具内重新开始
换人
同事/AI 接手同一仓库
换设备
本地记忆未同步
工具各自私有记忆
修复方式:把真相放进仓库
约定层 AGENTS.md
规格层 Spec
进度层 Tasks / Plan
看到这里应该明白:如果你只解决"换工具",却让项目的约定躺在 Claude Code 的 CLAUDE.md 里、规格躺在 Cursor 的 Plan 文件里、进度躺在某次对话里,那你换会话、换人时照样崩。根治办法是让这三样东西都版本化地住在仓库里,与具体工具解耦。
三、协作总架构:把"项目真相"放进仓库
我把"项目真相"拆成三层契约,全部以 Markdown 文件形式进版本库:
| 契约层 | 文件(示例) | 回答的问题 | 生命周期 | 是否进版本库 |
|---|---|---|---|---|
| 约定层 | AGENTS.md + rules/ |
这个项目"永远成立"的规矩 | 长期稳定 | 是(团队共享) |
| 规格层 | openspec/ 或 specs/ |
这次改动"做什么、为什么" | 随变更演进 | 是 |
| 进度层 | tasks.md / PLANS.md / 分支 |
现在做到哪、下一步是什么 | 短期、可丢弃 | 是(或 PR 内) |
这三层加起来的效果:无论你用哪款工具打开仓库,它先读 AGENTS.md 知道规矩,再读规格知道这次要做什么,最后看进度知道从哪接手。工具成了读取这三层文件的"客户端",而不是真相的拥有者。
渲染错误: Mermaid 渲染失败: Parse error on line 11: ... T1Claude Code -->|@import AGENTS.md| -----------------------^ Expecting 'AMP', 'COLON', 'PIPE', 'TESTSTR', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'LINK_ID'
注意图里所有工具都指向同一份 AGENTS.md,差别只是"谁来读、怎么读"。下一节专门讲这件事------它是无缝切换的物理基础。
四、工具无关的共享约定:AGENTS.md 是通用语
好消息是,2026 年这几款工具在"约定文件"上已经出现了事实标准:AGENTS.md 。它不是某一家发明的,而是被 Codex、Qoder 原生采用,又被 Claude Code(@import)、Cursor(fallback)兼容,从而成了跨工具的"通用语"。
各工具的加载机制对照如下:
| 工具(示例) | 约定文件 | 加载方式 | 是否原生读 AGENTS.md | 备注 |
|---|---|---|---|---|
| Codex | ~/.codex/AGENTS.md、/AGENTS.md |
层级拼接,近处覆盖远处 | 是(原生) | 还可配 project_doc_fallback_filenames 读 CLAUDE.md |
| Qoder | ~/.qoder/AGENTS.md、/AGENTS.md、.qoder/rules/** |
向上查找 + 按 frontmatter 按需加载 | 是(原生,CLI 默认名) | 桌面端 Memory/ Rules 亦兼容 |
| Claude Code | CLAUDE.md、.claude/rules/ |
会话启动全量加载 | 否,需显式 @import AGENTS.md |
建议根 CLAUDE.md 只留 @import,详细约定写 AGENTS.md |
| Cursor | .cursorrules / .cursor/rules/*.mdc |
全量 + 按 glob 按需 | 是(作为 fallback 读取) | 把 AGENTS.md 内容同步进 .cursor/rules 或让规则引用它 |
| Trae | 规则 / 自定义 MCP 智能体 | 项目上下文 + 工具装配 | 间接(规则指向) | 在 project rule 里把 AGENTS.md 作为约定入口引用 |
关键实践 :只维护一份 AGENTS.md 作为真相源,各工具的"私有约定文件"只做一件事------指向它。
Claude Code 的根 CLAUDE.md 极简写法:
markdown
# CLAUDE.md(极简转发层,详细约定在 AGENTS.md)
@AGENTS.md
## Claude Code 专属补充
- src/billing/ 下的改动使用 plan mode
- 提交前必须跑 `npm test`
Codex 的全局约定(~/.codex/AGENTS.md):
markdown
## Working agreements
- 修改 JS/TS 文件后始终运行 `npm test`
- 安装依赖优先用 pnpm
- 新增生产依赖前先征求确认
- 所有公共函数写 JSDoc
Qoder 的项目级 AGENTS.md(仓库根,进版本库):
markdown
# Project: 示例 SaaS API
## Architecture
- Node.js + Fastify(不是 Express)
- 数据库:PostgreSQL + Drizzle ORM
- 鉴权:JWT,24h 过期,refresh token 存 HTTP-only Cookie
## Commands
- `pnpm dev` 启动开发服务器
- `pnpm test` 跑 Vitest
- `pnpm lint` ESLint + Prettier
## Conventions
- 新端点必须有对应测试
- 入参校验用 Zod,不用手写
- 生产代码禁止 console.log,用 pino logger
- 所有数据库查询必须参数化
分层拆规则(避免单文件膨胀,对应各工具的 rules/ 目录)。例如 Qoder 的 .qoder/rules/api.mdc 或 Cursor 的 .cursor/rules/api.mdc:
markdown
---
paths:
- "src/api/**/*.ts"
---
# API 开发规则
- 所有端点必须包含输入校验(Zod)
- 缺少鉴权中间件的端点要标记告警
- 错误响应遵循 RFC 7807 Problem Details 格式
为什么不用各自的专属文件各写一遍? 因为那会变成"三个真相源",模型会挑最方便的那段遵守,约定就名存实亡。一份
AGENTS.md+ 各工具转发,是切换零成本的前提。
五、规格驱动:让"为什么做"也留在仓库
约定层解决"永远成立的规矩",但每一次具体改动还有"这次要做什么、为什么"------这部分如果不落地,换工具时对方只能从代码反推意图,必然跑偏。
这就是规范驱动开发(Spec-Driven Development, SDD) 的价值。2026 年主流方案有三类:
- Spec Kit (GitHub):
/constitution→/specify→/plan→/tasks→/implement,带"项目宪法",支持 30+ 种 Agent。 - OpenSpec (Fission AI):
propose→apply→archive,每个变更一个文件夹,归档时更新主规格,跨 25+ 工具且不锁 IDE。 - Kiro (AWS):
requirements → design → tasks,需求用 EARS 句式,开箱即用但闭源付费。
我用 OpenSpec 做跨工具协作,因为它最轻、最不绑工具。初始化:
bash
npm install -g @fission-ai/openspec
openspec init
提一个变更(不写代码,先对齐意图):
bash
# 在任一工具里执行,产物是仓库里的 markdown
openspec propose "为登录接口增加限流与防爆破"
它会在 openspec/changes/ 下生成四份文档:proposal.md(为什么)、specs/(场景与验收)、design.md(技术方案)、tasks.md(原子任务)。人审完再让工具执行:
bash
# 让 Claude Code / Codex / Cursor / Qoder / Trae 的 Agent 读 tasks.md 逐项实现
openspec apply
# 完成后归档,主规格随之更新,下一次任何工具打开都知道现状
openspec archive
规格驱动让"换工具"变成"换一个读同一份规格的客户端"。下面这张闭环图是 SDD 的核心,也是跨工具交接的物理基础:
#mermaid-svg-OjKw3AIrxlyFwci5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OjKw3AIrxlyFwci5 .error-icon{fill:#552222;}#mermaid-svg-OjKw3AIrxlyFwci5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OjKw3AIrxlyFwci5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OjKw3AIrxlyFwci5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OjKw3AIrxlyFwci5 .marker.cross{stroke:#333333;}#mermaid-svg-OjKw3AIrxlyFwci5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OjKw3AIrxlyFwci5 p{margin:0;}#mermaid-svg-OjKw3AIrxlyFwci5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster-label text{fill:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster-label span{color:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster-label span p{background-color:transparent;}#mermaid-svg-OjKw3AIrxlyFwci5 .label text,#mermaid-svg-OjKw3AIrxlyFwci5 span{fill:#333;color:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 .node rect,#mermaid-svg-OjKw3AIrxlyFwci5 .node circle,#mermaid-svg-OjKw3AIrxlyFwci5 .node ellipse,#mermaid-svg-OjKw3AIrxlyFwci5 .node polygon,#mermaid-svg-OjKw3AIrxlyFwci5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OjKw3AIrxlyFwci5 .rough-node .label text,#mermaid-svg-OjKw3AIrxlyFwci5 .node .label text,#mermaid-svg-OjKw3AIrxlyFwci5 .image-shape .label,#mermaid-svg-OjKw3AIrxlyFwci5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-OjKw3AIrxlyFwci5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OjKw3AIrxlyFwci5 .rough-node .label,#mermaid-svg-OjKw3AIrxlyFwci5 .node .label,#mermaid-svg-OjKw3AIrxlyFwci5 .image-shape .label,#mermaid-svg-OjKw3AIrxlyFwci5 .icon-shape .label{text-align:center;}#mermaid-svg-OjKw3AIrxlyFwci5 .node.clickable{cursor:pointer;}#mermaid-svg-OjKw3AIrxlyFwci5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OjKw3AIrxlyFwci5 .arrowheadPath{fill:#333333;}#mermaid-svg-OjKw3AIrxlyFwci5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OjKw3AIrxlyFwci5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OjKw3AIrxlyFwci5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OjKw3AIrxlyFwci5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OjKw3AIrxlyFwci5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OjKw3AIrxlyFwci5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster text{fill:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 .cluster span{color:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OjKw3AIrxlyFwci5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OjKw3AIrxlyFwci5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-OjKw3AIrxlyFwci5 .icon-shape,#mermaid-svg-OjKw3AIrxlyFwci5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OjKw3AIrxlyFwci5 .icon-shape p,#mermaid-svg-OjKw3AIrxlyFwci5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OjKw3AIrxlyFwci5 .icon-shape .label rect,#mermaid-svg-OjKw3AIrxlyFwci5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OjKw3AIrxlyFwci5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OjKw3AIrxlyFwci5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OjKw3AIrxlyFwci5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 不一致回到 Spec
通过
Spec 规格
做什么/为什么
Plan 方案
技术栈/接口
Code 代码
工具执行
Verify 验证
对照验收标准
Archive 归档
更新主规格
提示:规格不是"写完就供着"。它和代码一样会漂移------代码改了规格没改,规格就变成比没有更糟的"谎言文档"。所以归档(archive)那一步不能省,它让规格始终等于当前系统的真实状态。
六、分工协作策略:谁干什么(给依据,不给处方)
回到用户最关心的"分工协作"。这里最容易翻车:把"Claude Code 做 X、Cursor 做 Y"写成固定排班。正确做法是给出决策依据 + 组合矩阵,让你按任务自由排,而不是照抄。
6.1 决策依据(按原则选,不按工具选)
把任务按两个维度分类,就能自然得出分工:
- 维度一:自主闭环需求------任务能否自己跑测试、自己修、自己提交?能 → 终端 Agent 路线;不能/需要密集 review → IDE 路线。
- 维度二:上下文依赖------任务是否需要"项目全局理解 + 长链路"?需要 → 多智能体/Expert 模式;局部小改 → 任意工具。
6.2 组合矩阵(例:2 个 / 3 个 / 5 个 / 只有 1 个)
下面是我自己的示例排法,你可以替换任意工具。原则是"能力互补、避免重复加载同一段上下文":
| 场景(例) | 推荐组合(示例) | 分工逻辑 |
|---|---|---|
| 只有 1 个工具 | 任一支持 AGENTS.md + Plan 的 IDE/Agent |
单体也能跑,关键是约定层 + 规格层进仓库,为将来扩工具铺路 |
| 2 个工具(例) | Claude Code(重任务)+ Cursor(编辑/review) | 前者跑闭环验证,后者做多文件精修与即时补全 |
| 3 个工具(例) | Qoder(拆解/架构)+ Codex(CI 审查)+ Cursor(实现) | 专家理解需求 → 实现 → 独立 Agent 审查,三段互不污染上下文 |
| 5 个工具(例) | Qoder 拆解 → Claude Code 重构 → Cursor 实现 → Codex 审查 → Trae 原型验证 | 每段只接管自己擅长的一段,靠仓库三层契约交接 |
再次强调:上表是示例矩阵,不是配方。两个人、两个任务、两种合规要求,排法都不同。真正不变的是"交接媒介 = 仓库三层契约"。工具数量可自由扩展------你有 N 款工具时,按上表同样的"能力互补、避免重复加载同一段上下文"原则排即可,不必拘泥于五款或某一固定组合。
6.3 角色与工具映射(例)
把"角色"和"工具"分开想:角色是稳定的,工具是可替换的。
| 角色 | 要什么能力 | 可用工具(示例) |
|---|---|---|
| 规格定义者 | 理解业务、写清意图 | 人 + 任意支持 Plan 的工具(Cursor / Claude Code) |
| 架构理解者 | 全局代码认知、长链路 | Qoder Expert / Claude Code Plan subagent |
| 实现者 | 多文件编辑、闭环执行 | Claude Code / Cursor Agent / Codex |
| 审查者 | 独立上下文、找回归 | Codex exec / Claude Code code-reviewer subagent |
| 验证者 | 跑测试、出原型 | 任意能跑 npm test 的 Agent / Trae SOLO |
这张表的价值在于:角色不绑定工具,所以换工具只是换"谁扮演这个角色",交接物不变。
例:Codex(审查) 例:Claude Code(实现) 例:Qoder(拆解) 人(规格定义者) 例:Codex(审查) 例:Claude Code(实现) 例:Qoder(拆解) 人(规格定义者) #mermaid-svg-z9JCGs4mbzDHI8Dx{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-z9JCGs4mbzDHI8Dx .error-icon{fill:#552222;}#mermaid-svg-z9JCGs4mbzDHI8Dx .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-z9JCGs4mbzDHI8Dx .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-z9JCGs4mbzDHI8Dx .marker{fill:#333333;stroke:#333333;}#mermaid-svg-z9JCGs4mbzDHI8Dx .marker.cross{stroke:#333333;}#mermaid-svg-z9JCGs4mbzDHI8Dx svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-z9JCGs4mbzDHI8Dx p{margin:0;}#mermaid-svg-z9JCGs4mbzDHI8Dx .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z9JCGs4mbzDHI8Dx text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-z9JCGs4mbzDHI8Dx .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-z9JCGs4mbzDHI8Dx .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-z9JCGs4mbzDHI8Dx #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-z9JCGs4mbzDHI8Dx .sequenceNumber{fill:white;}#mermaid-svg-z9JCGs4mbzDHI8Dx #sequencenumber{fill:#333;}#mermaid-svg-z9JCGs4mbzDHI8Dx #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-z9JCGs4mbzDHI8Dx .messageText{fill:#333;stroke:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z9JCGs4mbzDHI8Dx .labelText,#mermaid-svg-z9JCGs4mbzDHI8Dx .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .loopText,#mermaid-svg-z9JCGs4mbzDHI8Dx .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-z9JCGs4mbzDHI8Dx .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-z9JCGs4mbzDHI8Dx .noteText,#mermaid-svg-z9JCGs4mbzDHI8Dx .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-z9JCGs4mbzDHI8Dx .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z9JCGs4mbzDHI8Dx .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z9JCGs4mbzDHI8Dx .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-z9JCGs4mbzDHI8Dx .actorPopupMenu{position:absolute;}#mermaid-svg-z9JCGs4mbzDHI8Dx .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-z9JCGs4mbzDHI8Dx .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-z9JCGs4mbzDHI8Dx .actor-man circle,#mermaid-svg-z9JCGs4mbzDHI8Dx line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-z9JCGs4mbzDHI8Dx :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 需求 + AGENTS.md 生成 Spec / Tasks(进仓库) 交接入库(git commit) 读 Spec,按 tasks.md 实现+跑测试 提交 PR 独立上下文审查 审查意见(不污染 C 的上下文)
七、实战:同一项目五工具接力(示例)
光讲架构不够,给一个可复制的最小闭环。假设项目是 example-saas,已经在仓库根放了 AGENTS.md,并初始化了 OpenSpec。
第 1 步:Qoder 做需求拆解(例)
在 Qoder 里用 Quest / Expert 模式,让它读 AGENTS.md 后生成变更提案。产物落到 openspec/changes/add-rate-limit/,人审 specs/ 与 tasks.md。
第 2 步:Claude Code 做实现(例)
切到终端,Claude Code 读根 CLAUDE.md(里面 @import AGENTS.md)和刚生成的 tasks.md:
bash
# 在仓库根启动,自动继承 AGENTS.md 约定
claude
# 会话内:/plan 先出方案 -> 人审 -> 实现
# 实现每段后跑 npm test,绿了再继续
第 3 步:Cursor 做多文件精修(例)
需要改一大片 UI 与 API 时,在 Cursor 里打开同仓库。因为 AGENTS.md 被 fallback 读取,Cursor 自动知道"用 Zod、写测试、参数化查询"。用 Agent 模式跑:add rate limiter 到登录端点,并补一个证明它生效的测试。
第 4 步:Codex 做 CI 审查(例)
提交后,在 CI 里用 Codex 做独立审查,上下文干净、不会被实现者的假设污染:
bash
# .github/workflows/review.yml(片段)
- name: Codex review
run: codex exec "review the diff of this PR against main, flag regressions and missing tests"
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
第 5 步:Trae 做原型验证(例)
用 Trae SOLO 拉一个临时分支,按 tasks.md 跑通 MVP,验证端到端可运行,结果回流到主分支讨论。
贯穿五步的交接物 始终是:仓库里的 AGENTS.md + openspec/ + 分支与 PR。任何一步换人、换会话、换设备,只要 git pull,状态立刻恢复。
反过来说,如果这五步没有三层契约会怎样?Qoder 拆的需求只存在它自己的对话里,Claude Code 实现时只能从代码反推"要限流",却不知道"令牌桶 + 防爆破"的既定方案,于是自作主张用了固定窗口;Cursor 精修时又按自己的习惯写了 console.log;Codex 审查时因为看不到原始验收标准,放过了"限流上限未配置"的缺陷;Trae 验证跑通的还是旧逻辑。五个工具各说各话,最后合出来的是个没人完全理解的模块。差别只在"交接物有没有进仓库"这八个字。
分支与进度管理建议(让进度层也进仓库):
bash
# 每个变更一个分支,名字对应 openspec change id
git checkout -b feat/add-rate-limit
# 任务进度写在仓库 tasks.md,不写在对话里
# 完成后归档规格并合并
openspec archive add-rate-limit
git add openspec && git commit -m "chore: archive add-rate-limit spec"
八、主动换工具的"零中断"检查清单
把上面所有内容收敛成两张可操作的清单。换工具前做完正面清单,换完后跑一遍验证。
换工具前(交接侧)
| 检查项 | 目的 | 没做会怎样 |
|---|---|---|
AGENTS.md 已提交且最新 |
对方知道规矩 | 重头解释约定,风格漂移 |
| 规格/任务已进仓库(openspec/tasks) | 对方知道做什么 | 从代码反推意图,跑偏 |
当前进度写在 tasks.md/分支 |
对方知道从哪接 | 重复劳动或漏做 |
| 关键决策写进规格"为什么" | 对方不推翻既定方案 | 被"优化"掉正确设计 |
红线和禁改项在 AGENTS.md |
对方不碰雷区 | 误删/误改敏感逻辑 |
换工具后(接收侧)
bash
# 1. 拉最新,确认三层契约都在
git pull
ls AGENTS.md openspec 2>/dev/null && echo "契约齐全"
# 2. 让新工具先读约定再动手(以 Codex 为例验证加载)
codex "summarize the instructions you loaded from AGENTS.md"
# 3. 跑回归,确认没破坏既有行为
npm test
# 4. 对照规格验收,而不是对照"我感觉对了"
openspec list # 看有哪些变更待办/进行中
如果新工具没有原生的 AGENTS.md 读取能力 (4.3.2 提到的"方案依赖用户没有的东西"),替代路径是:在它的规则文件里写一行"读取并遵守仓库根
AGENTS.md",或把AGENTS.md内容同步进它的规则目录。区别只是"边写边拦(hooks)"还是"提交后拦(CI)"还是"靠约定软约束"------都能跑,只是反馈时机不同。
硬约束兜底(当某工具缺乏原生 hook 时,用 Git + CI 拦):
yaml
# .github/workflows/guard.yml(任意工具提交都生效)
name: guard
on: [pull_request]
jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run lint && npm test
九、踩坑与最佳实践
踩坑记录
- 把约定写进私有记忆 :只在 Claude Code 的
CLAUDE.md写了规矩,换到 Codex 时对方一无所知。→ 真相只放AGENTS.md,私有文件只转发。 - 规格写完不归档 :
openspec提了一堆变更从不archive,主规格永远过时,下次工具读到的是谎言。→ archive 是闭环不可省的一步。 - AGENTS.md 膨胀到 200 行以上 :信号被稀释,工具遵循度下降。→ 稳定约定留
AGENTS.md,主题规则拆进rules/,流程类做成 Skill。 - 用对话记进度 :"做到第 3 步了"只存在聊天里,换会话即失。→ 进度只写
tasks.md/分支。 - 工具当处方排班:固定"Claude Code 永远做 X",结果某次 X 更适合 Cursor 却没换。→ 按能力维度排,不按工具排。
最佳实践
- 一份真相源:约定、规格、进度全部版本化,工具只是客户端。
- 先对齐再执行:任何非平凡任务,先有 Spec/Plan,再让工具跑。
- 独立上下文审查:审查交给另一个工具的独立 Agent,避免实现者的假设污染。
- 用测试当护栏 :无论哪个工具改的,CI 跑
npm test是最后的真相裁判(Kent Beck 称 TDD 是与 Agent 协作的 superpower)。 - 小步提交 :每完成一个原子任务就提交,切换工具时
git pull即满血恢复。
十、团队级落地:协作跨越工具、人与时间
前面讲的"换工具"其实是三种切换里最轻的一种。真实团队里更常见的是换人 ------同事接手你用 Claude Code 写了一半的模块;以及换时间------三个月后你自己回来改这处代码,早忘了当时的考量。三层契约同样治这两类断裂,而且治得更值钱。
换人 :新人 clone 仓库,先读 AGENTS.md 知道规矩,再读 openspec/ 知道每个模块"为什么这么设计",最后看 tasks.md / 分支知道现状。这比传统的"找原作者问"快一个数量级,且不依赖原作者是否在线。Qoder 的 Repo Wiki 也是同一思路------把代码库自动文档化,新人看 Wiki 即可上手,不必啃源码。
换时间 :规格归档机制(archive)保证 specs/ 始终等于当前系统。三个月后回来,读到的不是过时的设计文档,而是上次归档后的真实状态;AI 代理读到的也是同一份,不会去"修复"一个其实正确的补丁。
企业级分层 :组织级不可变规则(安全、合规)走托管式强制下发------Codex 支持 requirements.toml 约束审批策略与沙箱,Claude Code 支持 managed-settings.json 下发全员指令;团队约定进版本库的 AGENTS.md;个人偏好留本地(AGENTS.local.md、.local.md 进 .gitignore)。三层分离后,组织、团队、个人各管各的,互不污染,也互不绑架。
这样一扩展,文章的适用面从"个人多工具"上升到"团队工程化",普适性明显提升------因为无论个人还是团队,断的根因都是同一句:项目的真相没住在仓库里。
十一、总结与展望
回到开头:多工具开发同一项目,难点从来不是"怎么同时开五个窗口",而是"换工具、换会话、换人、换设备时,开发为什么断了"。答案是项目的真相没住在仓库里,而是住在工具的私有记忆里。
治本的路只有一条------让约定、规格、进度三层契约以版本化文件进仓库 ,把 AGENTS.md 作为跨工具通用语,用 Spec-Driven Development 把"为什么做"也沉淀下来。做到这点,Qoder / Claude Code / Codex / Cursor / Trae(或任何你喜欢的组合)就只是同一个真相源的不同客户端,主动换工具 = 一次 git pull,开发零中断。
2026 年行业正在从"模型崇拜"转向"工程落地",上下文工程取代提示词工程成为核心。谁能把项目意图稳妥地交给仓库、交给团队、交给未来的自己,谁就掌握了 AI Coding 的下一程。
参考资料
- Anthropic. Steering Claude Code: CLAUDE.md, skills, hooks, subagents. https://claude.com/blog/steering-claude-code-skills-hooks-rules-subagents-and-more
- OpenAI. Custom instructions with AGENTS.md -- Codex. https://developers.openai.com/codex/guides/agents-md
- OpenAI. Codex Best Practices. https://developers.openai.com/codex/learn/best-practices
- Qoder. Memory (AGENTS.md & Rules). https://docs.qoder.com/cli/memory
- Cursor. Rules / Customization. https://cursor.com/pt-BR/help/customization/rules
- Trae. Official Site. https://trae.cn/
- Stuzhuk, Y. Spec-Driven Development in 2026. https://stuzhuk.page/blog/spec-driven-development-2026
- Fission AI. OpenSpec. https://github.com/Fission-AI/openspec
- GitHub. Spec Kit. https://github.com/github/spec-kit
- 得物技术. Claude Code + OpenSpec 正在加速 AICoding 落地. https://segmentfault.com/a/1190000047671795
- AgentPatterns. Spec-Driven Development with Spec Kit. https://agentpatterns.ai/workflows/spec-driven-development