Claude Code + Codex 怎么分工?别把“允许结束”当成“可以提交”
假设你让 Claude Code 修改一个列表接口:不传每页条数时默认取 20 条,显式传入 0 时应返回参数错误。实现完成后,Codex 指出代码把这两种输入混在了一起。Claude 随后回复:“已收到审查意见,接下来处理。”这轮只作说明,没有改文件。
如果此时启用了 codex-plugin-cc 的停止审查,看到 ALLOW,能否认为刚才的问题已经解决?
不能。在本文核对的实现中,停止审查的提示词要求:只检查上一轮直接做出的代码改动;上一轮若只是状态、总结或审查结果,就立即允许结束。因此,同一个 ALLOW 既可能表示没有发现阻断问题,也可能表示这一轮根本没有需要审查的代码改动。停止审查提示词
这正是两个 Agent 分工时容易漏掉的部分:审查者指出问题、实现者修好问题、允许当前一轮结束,是三件不同的事。判断修改是否完成,要看具体问题是否得到处理,以及修复后的代码是否经过验证。
下面的列表接口是作者构造的教学情境,不是真实故障记录。官方事实固定到 openai/codex-plugin-cc 提交 db52e28f4d9ded852ab3942cea316258ae4ef346;2026-09-20 查询官方 main,仍指向这一提交。这里讨论该插件的命令和停止审查,不把结论套到所有 Codex 客户端。
同一个 ALLOW,可能来自两种不同的情况
停止审查通过 Claude Code 的 Stop hook 触发。启用后,hook 把上一条 Claude 回复交给 Codex 检查,再解释返回结果。提示词明确把范围限制为上一轮直接产生的代码改动,并排除单纯的状态输出、setup、总结和审查结果。hook 实现
这样的范围有其用途:返回一份审查意见,本身不应再次被当成一次代码实现,否则“审查的结果”还会不断触发“对结果的审查”。但相应地,一轮回复能够结束,并不代表更早的代码问题都被重新检查过。
我从固定源码中原样提取了纯函数 parseStopReviewOutput,给它传入人工构造的回复,观察解析结果。没有启动 Claude Code、Codex 模型或真正的 Stop hook。
| 人工输入 | 官方解析函数返回的 ok | 这一结果能说明什么 |
|---|---|---|
ALLOW: No direct code edits in this turn. | true | 解析器接受了“这一轮没有直接改代码”的允许结束回复 |
ALLOW: No blocking issue found. | true | 解析器接受了“没有发现阻断问题”的允许结束回复 |
BLOCK: The regression remains. | false | 解析器将这条问题回复解释为阻止结束 |
| 空输出或不符合约定的首行 | false | 输出不能按约定解释,需要另外处理 |
这五项离线断言都通过了。实验说明的是解析规则如何处理这些输入,不是模型真的对某个项目得出了上述结论,更不是对插件审查准确率的测量。
源码只检查首行的 ALLOW: 或 BLOCK: 前缀;它不会在这里再次运行业务测试,确认“问题已经修好”。提示词限定审查范围,解析器决定是否阻止当前停止,两者都不能代替对具体修改的验收。
回到开头:如果上一轮只有“接下来处理”的汇报,按提示词得到允许结束是可能的。此时仍应保留“0 被当成默认值”这个未处理问题,而不是从 ALLOW 倒推出文件已经修复。
审查命令的工作,到返回意见为止
/codex:review 的命令文件直接规定它只做审查,不修复问题、不应用补丁,并原样返回 Codex 输出。运行时的原生 review 路径还显式以 read-only 创建审查线程。命令约束;运行时实现
所以,收到发现后不能默认等待“审查者顺便修好”。如果主线改动由 Claude Code 完成,可以把确认成立的问题交回 Claude Code,让它修改并运行相关验证;Codex 再检查修复是否遗漏了问题。这是基于该插件职责的工作安排,不是“Claude 天生只能实现、Codex 天生只能审查”的能力排名。
需要让 Codex 接手实现时,也应把角色变化说清楚:谁现在可以写文件,原实现者是否停止修改,最后由谁整合。两个 Agent 并行处理互不重叠的工作是另一种安排,但同一个修复若同时有两个写入者,就难以判断最后接受的是哪一种修改。
在这一篇里,分工的最小单位是一条需要处理的发现。读完意见的人应当能回答:它是否成立;由谁接手;接手者要改变什么;拿什么结果回来。如果只能回答“已经问过第二个模型”,工作还没有交到可执行的下一步。
把“请修复”写成实现者能够验证的任务
开头的发现不能只转述为“把参数处理得更健壮”。实现者需要知道原来的约定:省略参数允许使用默认值,而显式传入 0 是无效输入。这两个条件不同,修复不能简单地把所有无效输入都改成默认值,也不能把默认值一并取消。
下面是我会交回实现者的任务文本。它是作者建议的写法,不是插件自动生成的记录:
待处理问题:pageSize=0 被当成未传参数,返回默认页大小。
预期约定:未传时默认20;传入时必须是1至100的整数。
实现责任:由当前实现者修改;审查者继续保持只读。
修改范围:参数解析及其直接调用路径,不改排序和分页协议。
先核实:定位0进入默认值分支的原因,检查现有验证是否会提前拒绝。
验证输入:未传、0、-1、1、100、101,以及非整数输入。
返回证据:改动位置、实际运行的检查、实际结果与仍未覆盖的情况。
若发现不成立:给出阻断该路径的代码或测试证据,不为满足意见而改代码。
这段任务文本把实现和验证联系起来:若约定确实如此,未传参数应继续使用默认值,0 和越界值应按接口既有错误约定拒绝,边界值应被接受。它没有预填“测试通过”,也没有替项目决定响应格式。
实现者返回后,先检查他到底做了什么。如果只是把 0 改成一个特例,却没有查看同一个解析分支如何处理负数或非整数输入,就还没有回答任务中已经明确的问题。如果本地检查没有运行成功,应保留失败原因;不能因为补丁看起来合理,就把验证结果写成通过。
反过来,审查者也可能漏看了调用前的验证。若上游已经拒绝 0,应当撤销这条发现,或把它缩小到确实存在的路径。这里复核的是代码与输入之间的关系,不是谁给出的语气更肯定。
每次修复后,审查对象都是修复后的代码。旧意见可以帮助定位,但不能因为第一次审查已结束,就把新增修改视为已经看过。测试负责检查约定下的行为,后续审查负责检查修复是否引入其他遗漏;两者回答的问题不同。
可选的停止审查,适合补遗漏而不是代替交付判断
官方提供 /codex:setup --enable-review-gate 和对应的关闭命令,并提醒它可能形成长时间运行的 Claude/Codex 循环、较快消耗使用限额,建议仅在有人主动关注会话时开启。官方 README
是否开启,应看当前工作是否需要这一层停止前反馈。一次明确的小修复,人工发起审查并处理发现通常已经能形成闭环;不必为了使用两个 Agent,把每次状态回复都变成新的审查任务。若开启后不断出现新的意见,应回到具体问题和变更范围判断,而不是把持续运行本身当成质量在提高。
另一个容易混淆的地方是输出名称。Stop hook 使用 ALLOW / BLOCK;插件对抗式审查的结构化结果使用 approve / needs-attention。它们属于不同路径,不能统一解释成“整个项目可以交付”,也不能给这些结果另造一套所谓官方的 Hold / Redesign 等级。对抗式结果 schema
命令入口也应分清:插件的 /codex:review 不接受额外 focus 文本;需要指定要挑战的设计或风险面,应使用支持 focus 的 /codex:adversarial-review。不要把其他客户端 /review 的用法直接复制到这个插件命令后面。对抗式命令
这些限制并不意味着停止审查没有价值。它能把部分问题在会话停止前反馈给实现者,但团队仍要决定如何处理尚未成立、尚未修复或尚未验证的发现;合并与发布的权限也不会因为返回了某个前缀就自动转移给模型。
结束这次修改时,保留问题的去向
回到列表接口,合理的结束情况可以是:问题成立,已经修复并留下相关验证结果;也可以是上游确实阻断了它,发现被有证据地撤销。如果还缺少环境或调用链证据,就明确保留这个缺口,由负责交付的人决定后续动作。
“两个模型都说可以”不提供这些信息。“哪条发现由谁处理,改了哪里,验证了什么,还缺什么”才让接手的人知道工作进行到哪一步。
在 Claude Code 作为主工作台的安排下,我会让它持续负责实现和修复,让 Codex 保持一个明确的审查视角。需要切换职责时再显式交接。真正让协作收敛的,不是固定哪个模型更擅长什么,而是每一条意见都有人处理,处理结果可以回到当前代码上检查。
本文的运行证据仅限于提取的官方纯解析函数与人工回复:5项离线断言通过。停止审查范围、只读配置和命令约束来自固定源码静态核对;没有真实运行模型审查或自动修复循环,列表接口示例也未实现或实测,因此不声明双 Agent 提高了准确率、速度或生产质量。