WWW.YOUINFO.SITE
标签聚合 Chorus

/tag/Chorus

V2EX - 技术 · 2026-05-11 17:57:07+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 15:18:18+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 14:40:24+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 12:49:41+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 10:19:54+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 10:19:54+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 09:47:42+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 09:47:42+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

V2EX - 技术 · 2026-05-11 09:06:03+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 13:31:11+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 12:31:11+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 12:31:11+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 12:31:11+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 12:16:06+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 11:53:57+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 11:46:37+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 11:34:56+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-05-06 11:13:09+08:00 · tech

前阵子给 Chorus 写 CLI 插件,让 coding agent 可以自己 drive 从设计到交付的流程。分别给 Claude Code 和 Codex CLI 上各写了一版,开发体验差距巨大。 基准版本: Claude Code 2.1.126 ,Codex CLI 0.128.0 。两边都在快速迭代,后面版本应该会修掉其中一些问题。 完整对比和踩坑记录我写了一篇长文放在博客了: https://chorus-ai.dev/zh/blog/claude-code-vs-codex-plugin-systems/ V2EX 这里挑几个印象最深的聊聊。 省流 :最后有具体的模块打分对比 一、装完能不能直接跑 Chorus 本体是一个 Web 服务,agent 通过 MCP 工具跟它交互。插件的职责之一是把 MCP server 配进 Agent,让用户不必自己去配置 MCP 。为了达到最佳的使用体验,肯定是用户操作的步骤越少越好。 Claude Code 那边用户输两条 slash command 就完事, .mcp.json 声明在插件里, ${VAR} 运行时展开: /plugin marketplace add Chorus-AIDLC/Chorus /plugin install chorus@chorus-plugins 这样插件自带的 MCP 就能跑在任意一个项目里了,给到 顶级 Codex 这边就困难多了。第一,虽然有命令可以从 marketplace 安装插件,但是启用还需要用户手动在 TUI 里操作没办法复制一条命令直接启用。第二,配置里所有几乎字段都是字面量,不做 ${VAR} 环境变量展开,对于不支持环境变量的字段比如 MCP 的 URL ,需要通过脚本写入到 Codex 配置文件里。 最终我写了个 Bash installer 帮助用户改配置文件硬凑出"一条命令装好"的体感, 但脚本脆得很,Codex 做一些配置层面的重构就得重写。给到 NPC 二、钩子能不能跟着插件走 插件比起纯用 MCP + Skill 来说最大的好处就是 Hooks ,为了保证 Agent 能按照预期跑任务,需要在各种生命周期钩子中埋脚本。Chorus 最基本的功能需要三个钩子: session 启动时调 chorus_checkin 把当前 agent 的身份和待办注入上下文;agent 提交方案以及任务后分别触发独立的 Reviewer Agent 对抗检查。Claude Code 和 Codex 都支持 Hooks ,但这方面的差距也是最大的。 Claude Code 那边就是照着写。插件里放一份 hooks/hooks.json ,用 ${CLAUDE_PLUGIN_ROOT} 指向插件脚本,harness 自动注册。所有的事情都符合预期,你在插件中定义的生命周期钩子会自动在对应的事件发生时触发。 夯爆了 Codex 这边我也是这么做的: 插件里放 hooks.json ,manifest 里 hooks 字段指过去,官方 example 里也是这么写的。装完看 /plugins 面板钩子显示已就位,但 session 启动时钩子根本不跑。 我一开始以为自己哪里写错了,换了好几种写法、改 matcher 、reinstall 、对着 example 逐字比对,大半天就这么过去了。最后去仓库搜 issue 才找到 #16430 : plugin manifest 解析器只认 skills / mcpServers / apps ,不认 hooks ,钩子发现逻辑只扫 config layer 下的 hooks.json ,不扫已安装插件的根目录,这个功能压根就对第三方插件不工作。截至目前版本,Codex 虽然文档里口口声声说插件支持这个功能,但是源码里居然是一个大大的 TODO ,离了大谱。 拉完了 三、钩子事件够不够用 Chorus 想通过插件实现的另一个一个功能是多 agent 并行工作时的可观测性: 用户起 5 个子代理并行写代码,要在看板上看到谁在做哪个任务、做到哪一步、有没有心跳。完全靠 Agent 自己调 MCP 上报不仅费 Token 还不靠谱,用生命周期钩子完成非常合适。 Claude Code 的钩子事件覆盖了子 Agent 整个生命周期: SubagentStart 、 SubagentStop 、 TeammateIdle 、 TaskCompleted 、 SessionEnd ,子代理一起来 harness 就能自动建 session 、发心跳、关 session 。给到 顶级 ,不给夯是因为一些很小的细节,比如无法在 Subagent 关闭后在钩子处注入上下文给主 Agent 等。虽然看起来很小但在多 Agent 协作的时候加工一下 Agent 之间交流的信息对控制行为非常重要。 Codex 这边只有 6 个钩子: SessionStart 、 UserPromptSubmit 、 PreToolUse 、 PostToolUse 、 PermissionRequest 、 Stop 。 整个 agent 生命周期相关的事件都没有 。主 Agent 调 spawn_agent 之后,子代理的存在对插件完全不可见,只能让主代理自己在 prompt 里记得"spawn 前调这个、spawn 后调那个",LLM 大部分时候能遵守,偶尔漏一步就是一个泄漏的 session 挂在那里。大的钩子都有,小钩子缺很多,给到 NPC 吧 四、子代理能不能当一等公民 Chorus 有两个 reviewer agent: proposal 提交后自动跑 proposal-reviewer 审方案,task 提交后自动跑 task-reviewer 审代码。这俩 agent 必须是 只读 的(不能 Edit 、Write 、Bash),不然让它们改了代码就不叫 review 了。权限这事儿最好 harness 在调用层就管住,靠 LLM 自觉不太行。并且最好还能控制最大轮数,防止在独立的 Review Agent 中陷入死循环或者跑偏影响主要任务的推进。 Claude Code 上就是一份 agents/proposal-reviewer.md : --- description: "Review submitted Chorus proposals for quality" model: inherit maxTurns: 20 disallowedTools: [Agent, Edit, Write, NotebookEdit, Bash] --- 可以看到在 Agent 定义的 meta 信息中支持多种配置,允许使用特定模型,支持限制最大轮次,允许屏蔽各种工具的使用等等。 文件正文就是 reviewer 的 system prompt,主代理 Task(subagent_type: "chorus:proposal-reviewer") 一下就起来了,工具权限、模型、轮次上限全都在 harness 层强制。 夯爆了! Codex 的 spawn_agent 工具只认四个内置 role: default / explorer / worker / awaiter , 插件 manifest 里没有注册新 role 的字段 。我一开始还以为 skill 目录下那个 agents/openai.yaml 能注册,实测 spawn_agent(agent_type="chorus-proposal-reviewer") 直接报 unknown agent_type ,翻完 Rust 源码才确认 openai.yaml 只是给 TUI 面板显示用的元数据,纯看看而已。 最后发现了自定义子 Agent 的方式: 把 reviewer 当成 skill ,用内置的 default role spawn,通过 items 数组把 skill 塞进去: spawn_agent( agent_type="default", items=[ { type: "skill", path: "chorus:chorus-proposal-reviewer" }, { type: "text", text: "Review proposal <uuid>. Post VERDICT." } ] ) 能跑,但因为是 default role,子代理什么工具都能用,只能在 SKILL.md 里硬写"严禁修改任何文件、严禁运行 Bash ,最高不要调用 20 次工具",靠 LLM 自觉,太玄乎了。给到 顶级 ,虽然不支持元数据,但是 Skill as Agent 的设计还是挺好玩的 还有个暗雷: Codex 每条根线程最多 6 个并发子代理, completed 状态 不释放槽位 ,必须显式 close_agent(id) ,第 7 次一定爆 agent thread limit reached ,最好在 skill 里提醒一下主 Agent 。 五、文档和调试 这一条写得最有感触,因为前面几节那种"按文档写了但就是不工作"的坑,逼得我必须有办法自己核实真相。 Codex 这边有个意外的好处: 代码完全开源 。文档不齐没关系,翻 codex-rs/ 下的 Rust 源码就能把行为坐实。我后面一堆结论( spawn_agent 只接受四个内置 role 、 config.toml 不展开变量、 completed 子代理不释放线程槽位)都是靠读源码才敢下断言的。文档跟不上进度,但真相至少是可读的。 Claude Code 正好反过来: 文档写得齐整,代码却是黑盒。钩子事件字段、MCP 变量展开规则都交代清楚,但文档没覆盖到的行为就只能靠猜。好在前阵子 Claude Code 有一次"开源"的契机,社区里能找到比较完整的源码,很多之前只能猜的细节现在能验证了。(不过很多新的功能没有,得等下一次开源。。) 开源和文档两件事上两边各赢一半: Claude Code 文档整齐,Codex 源码随时可读,实际做插件的时候这两种资源的价值互补(要不然 Claude Code 你直接开源算了)。 打分 我在原文对九个维度进行了打分,大家也可以参考下 维度 Claude Code Codex 安装 5 2 MCP 集成 5 1 钩子交付 5 0 钩子事件覆盖 5 2 子代理 5 2 Skills 5 4 配置变量 5 1 Marketplace 4 3 文档和调试 4 4 合计 43 19 数字看着悬殊,但不是说 Codex 不能用,只是你要付出额外的很多精力来做 Harness Engineering 来保证你的插件能正确指引 Agent 干活。 结论就是: 如果你想写 纯 skill 集合 ,两边差不多,如果想和 Chorus 一样做一些流程控制等精细的操作,那么 Codex 这边就欠缺太多基础建设了。没有对比就没有伤害,虽然最近 A\ 各种封杀降智不做人,把口碑都败光了,但从 Claude Code 的插件扩展性来看在 Harness Engineering 的理解上确实是断档领先,很多我们习以为常的功能其实是花了大力气去打磨的。也难怪 Claude Code 的生态那么有活力,希望 Codex 赶快抄起来吧。

www.v2ex.com · 2026-04-27 16:23:01+08:00 · tech

之前在 V2EX 发过几次帖子分享我在开发开源项目 Chorus ,一个给 Claude Code 用的 Harness 时的 经验和教训 。简单说就是让 Agent 不只是写代码,而是自己管整个项目:领需求、出方案、拆任务、写代码、提交审查,从 Idea 到交付走完一条流水线。中间有独立的 Reviewer Agent 自动审方案和代码,审不过打回重做,不用你盯着,把我们从无限的 Agent Review 地狱里解救出来。 上次发帖之后老哥们反应挺热烈,Issues 里提了不少实际问题。有说装 Docker 门槛太高的,有说生成的文档导不出来没法给客户看的,有说 Onboarding 走一半卡住了的。我挨个看了,这次 v0.6.6 基本都回应了。 最大的变化现在一行命令就能启动: npx @chorus-aidlc/chorus 跑完打开 http://localhost:8637 配合 Claude Code 插件就能用,不用配数据库,不用写 compose 文件。全栈纯 JS 实现,macOS 和 Linux 都能直接跑。 另外根据 Issue 里的反馈加了文档导出,Markdown 、PDF 、Word 三种格式。有老哥说项目交付要给客户看文档,之前只能在 Chorus 里看确实不方便,现在 Proposal 草稿阶段就能导出预览。 其他比如 Proposal 审批了发现方向不对可以撤回重来,Onboarding 不会再卡死,Agent 上线一次调用拿到所有状态接着干活,就不展开了。 详细的看博客: https://chorus-ai.dev/zh/blog/chorus-v0.6.6-release/ GitHub: https://github.com/Chorus-AIDLC/Chorus 感谢之前提 Issue 和反馈的各位,有问题继续拍砖。我的目标是让 Claude Code 自己推项目给我们省点力。

www.v2ex.com · 2026-04-27 16:23:01+08:00 · tech

之前在 V2EX 发过几次帖子分享我在开发开源项目 Chorus ,一个给 Claude Code 用的 Harness 时的 经验和教训 。简单说就是让 Agent 不只是写代码,而是自己管整个项目:领需求、出方案、拆任务、写代码、提交审查,从 Idea 到交付走完一条流水线。中间有独立的 Reviewer Agent 自动审方案和代码,审不过打回重做,不用你盯着,把我们从无限的 Agent Review 地狱里解救出来。 上次发帖之后老哥们反应挺热烈,Issues 里提了不少实际问题。有说装 Docker 门槛太高的,有说生成的文档导不出来没法给客户看的,有说 Onboarding 走一半卡住了的。我挨个看了,这次 v0.6.6 基本都回应了。 最大的变化现在一行命令就能启动: npx @chorus-aidlc/chorus 跑完打开 http://localhost:8637 配合 Claude Code 插件就能用,不用配数据库,不用写 compose 文件。全栈纯 JS 实现,macOS 和 Linux 都能直接跑。 另外根据 Issue 里的反馈加了文档导出,Markdown 、PDF 、Word 三种格式。有老哥说项目交付要给客户看文档,之前只能在 Chorus 里看确实不方便,现在 Proposal 草稿阶段就能导出预览。 其他比如 Proposal 审批了发现方向不对可以撤回重来,Onboarding 不会再卡死,Agent 上线一次调用拿到所有状态接着干活,就不展开了。 详细的看博客: https://chorus-ai.dev/zh/blog/chorus-v0.6.6-release/ GitHub: https://github.com/Chorus-AIDLC/Chorus 感谢之前提 Issue 和反馈的各位,有问题继续拍砖。我的目标是让 Claude Code 自己推项目给我们省点力。