Skip to main content

Codex 双 harness — AGENTS.md、代理双重发布、钩子适配器 NEW

让 codex-cli 与 Claude Code 并行使用 MoAI-ADK 的共用表面与各 harness 个人指令。

更新 2026-09-28 6 分钟阅读 在 GitHub 上编辑 ↗

MoAI-ADK 的第一 harness(实际驱动代理的运行环境)是 Claude Code,但从 v3.1.3 起它带上了一层 codex-cli 也能读的二元表面。共用规则与代理定义会按 Codex 寻找的位置和形式一并发布,个人指令则按 harness 分开。本文说明这些表面各自解决什么问题。

根 AGENTS.md —— harness 通用的 standing contract

仓库根目录的 AGENTS.md 不是 Claude 专属文件,而是无论哪个代理 harness 驱动一回合都适用的 standing contract(常时契约)。它以单一文件存在,原因在 codex 的读取方式: codex 在字节上限内读项目指示,超出的尾部会被静默丢弃 —— 没有警告,退出码还是 0。装不进上限的契约会以"完整"的姿态汇报。所以"装得进上限"本身就是需求,由 build guard(构建时检查该文件是否在上限之内的机制)把守。

为了腾出空间,11 份常驻加载文档降级成了指向 8 份惰性伴随文档(lazy companion,按需才读的详述文档)的存根(简短摘要)。搬走的是解释义务的文字,从来不是义务本身 —— AGENTS.md 是各 harness 共用契约的基准,.claude/rules/moai/** 和 CLAUDE.md 补充 Claude 专用机制。

信息
个人的 ~/.codex/AGENTS.md 会加入同一条合并链,并在本文件之前被消费,压缩项目契约能承载的宽度。溢出从尾部开始静默丢弃 —— 这正是本文件的条款按最重要在前排序的原因。

代理双重发布 —— 十二份 TOML

保留的 12 个 MoAI 自定义代理以两种形式发布: Claude Code 用的 .claude/agents/moai/*.md(原件),和 codex 读的 .codex/agents/moai/*.toml(派生)。TOML 不是手写的 —— internal/template/agentemit 从 markdown 原件确定性地(同样输入永远同样输出)生成,生成文件的开头钉着一句 “regenerate, do not edit”(重新生成,别直接改)。

原件与派生之间的漂移由三层护栏挡住: golden 文件比对(与期望输出对照)、嵌入校验(与编进二进制的模板对照)、部署校验(与落到用户仓库的结果对照)。改 markdown,TOML 跟着来;只改 TOML,护栏会抓住。

.agents/skills —— 技能镜像

codex-cli 不读 Claude Code 的 .claude/skills/,所以技能以镜像(复写副本)形式部署到 .agents/skills 下。镜像清单不是手工维护的,而是在部署执行时从实际的技能集合导出 —— 技能增减,清单不会过期。这个目录是面向用户仓库之外的部署产物,不进 git;优先符号链接,无法创建链接的环境退回复制部署(moai init、moai update 的完成摘要会说明这一点 —— 详见 moai update 文档)。

各 harness 的个人指令

AGENTS.local.md 是两个 harness 共同读取的个人指令文件,CLAUDE.local.md 是它的旧名称,仅作为回退输入保留。本地 moai codex 的所有启动路径——无参数、cli、app、--spawn 以及 -w——都会按此顺序读取项目根目录中非空的常规文件,在每段正文前加入 <!-- source: <filename> --> 来源标头,再把合并后的内容作为一个 developer_instructions 覆盖项传入。使用 -w 时,Codex 虽在工作树中运行,输入来源仍是原项目根目录。共享的 AGENTS.md 和 CLAUDE.md 都不会导入或链接这两个本地文件。启动器拒绝链接和非常规文件,并从完成检查的同一个文件描述符读取;如果操作者另行提供了 developer_instructions,或 direct/spawn 参数过大,启动会提前失败。其他 harness 的本地设置与记忆仍归各自 harness 所有。Codex Web 不经过本地启动器,因此不会收到这些注入内容。

CLAUDE.local.md 回退与迁移提示

项目里只有 CLAUDE.local.md、没有 AGENTS.local.md 时,moai codex 仍会把该文件作为回退读取,放进 developer_instructions。来源标头写的是实际读取的文件名——此处为 <!-- source: CLAUDE.local.md -->。

走回退路径时,启动器会在标准错误输出一行迁移提示:

text
Advisory: CLAUDE.local.md is a legacy local instruction file; run `moai migrate local-instructions` to move it to AGENTS.local.md.

这条提示是写给操作者的,因此不会进入会成为模型上下文的 developer_instructions。两个文件同时存在时两者都会被读取,提示改为要求手动合并。在三文件结构中——通用契约在 AGENTS.md,Claude 专属层在 CLAUDE.md,个人指令在 AGENTS.local.md——CLAUDE.local.md 只是一个待迁移的旧名称。

internal/codexadapter —— 钩子适配器库

两个 harness 的钩子表面几乎相同,但不完全相同。实测(以 codex-cli 0.153.4 为准)发现分歧有三处: harness 传入的事件名、codex 声明了却不会响应的三个输出键(systemMessage、continue、stopReason),以及 PreToolUse 决定契约 — codex 解析器会拒绝没有 updatedInput 的 permissionDecision:allow,并全面拒绝 permissionDecision:ask。internal/codexadapter 是坐在分发器前面的薄翻译层(internal/hook 不被触碰);被拒绝的决定形态(allow、ask、defer)降级为无意见 {},交给 codex 自己的审批流程,每次降级都通过 discard sink 通报,无理由的 deny 会补上默认理由。

12 事件表

Codex 事件MoAI 分发器参数本里程碑适配?
PreToolUsepre-tool是
PostToolUsepost-tool是
SessionStartsession-start是
SessionEndsession-end是
Stopstop是
UserPromptSubmituser-prompt-submit是
PreCompactcompact否 —— 非交互运行中压缩从未触发
PostCompactpost-compact否 —— 非交互运行中压缩从未触发
PermissionRequestpermission-request否 —— 非交互运行中审批请求从未出现
SubagentStartsubagent-start是
SubagentStopsubagent-stop是
Interrupt—— (无对应物)否 —— 在 SIGINT 时触发;适配需要新的分发器子命令(后续卡片)

共覆盖 12 个事件: 11 个有分发器对应物,官方文档中的第 12 个事件 Interrupt 在对应物出现之前,会以一条明确的"无对应物"消息被识别后拒绝。在 codex-cli 0.153.4 实测中,SubagentStart 与 SubagentStop 确认触发(推翻了此前 0.147.0 下 SubagentStop 不触发的观测),现已适配 —— RenderHooks 会把 moai hook subagent-start --harness codex 和 moai hook subagent-stop --harness codex 两行写入用户的 .codex/hooks.json。compact、permission 系列是基于诚实证据而非假设的保留: 非交互的 codex exec 运行从未达到压缩条件(实测输入上限 1,048,576 字符,最好成绩 264,808 输入 token),也从未引发审批请求 —— 记录为触发未达成,绝不记作"不触发"。

未适配事件不会被静默无视,而是被拒绝。未知事件(拼错)和被识别但不处理的事件(范围决定,或像 Interrupt 那样缺少对应物)返回不同的错误,运营者能把失误和决定区分开。配置校验器不停在第一个,而是收齐所有未知键违规后一次展示。

现在的调用方

RenderHooks 会把 8 个已适配事件的命令写入用户的 .codex/hooks.json。moai init --llm codex|both 创建这套配线;已有项目可用 moai tool enable codex 添加或刷新。

桌面应用与 v3.1.3 发布条件

在 Codex 应用的本地会话中,打开包含已生成的 .codex/hooks.json 和 .codex/config.toml 的项目。Codex 只有在项目信任后才会加载项目钩子和配置。在 Codex CLI 中使用 /hooks 检查钩子;定义发生变化后,需要重新信任。在同一项目中运行 moai doctor 可以检查 MoAI 配线状态。应用的运行环境还必须能找到 moai 命令。项目信任规则见 Codex 钩子文档。

Claude Code 桌面应用的 Local Code 会话与 CLI 共用项目中的 CLAUDE.md、.mcp.json、钩子、技能和设置。在 Code 标签页打开已初始化的项目,并确认该会话能运行 moai。SSH 会话在远程机器上运行,因此远程机器也需要项目和 moai。详见 Claude Code Desktop 配置说明。

以上只是配置步骤,不代表 v3.1.3 的桌面应用发布验证已经完成。在运营者亲自完成 MoAI、Codex 和两款桌面应用的测试并宣布结果之前,发布仍然暂停。

下一步