
最近在折腾 Codex CLI 的 MultiAgentV2 功能,踩了个挺别扭的坑,这篇把问题说清楚。
简单讲:Codex CLI 里 MultiAgentV2 的消息加密机制把 agent 之间的通信记录给"加密"没了——不是被破解,是根本没留明文副本。在 2026 年 6 月 5 日合并的 PR #26210 之后,所有 agent 父子通信的 content 字段被置空,只剩下一串 encrypted_content 密文。这意味着你事后想回溯"父 agent 到底给子 agent 交代了什么任务",只能去别的地方找,rollout 文件里已经看不到了。
这个问题记录在 GitHub 的 issue #28058 里,由用户 ignatremizov 在 2026 年 6 月 13 日提交。考虑到 Codex CLI 仓库已经有超过 98,000 颗星和 14,600 个 fork,受影响的人应该不少。
InterAgentCommunication 的 content 字段被置空,明文内容只存在于 encrypted_content 中spawn_agent、send_message 和 followup_task 这三个工具调用Codex CLI 是 OpenAI 的命令行工具,用来驱动代码代理。它的 MultiAgentV2 功能让一个父 agent 能够协调多个子 agent:比如一个跑测试、一个重构模块、一个调查 bug。这些 agent 之间通过三个工具调用来通信:spawn_agent(创建子 agent 并分配任务)、send_message(发送额外上下文)、followup_task(分配后续任务)。
在 0.137.0 版本之前,这些消息以明文形式存储在本地 rollout 历史里,任何开发者事后都可以翻看"父 agent 到底给子 agent 布置了什么"。PR #26210 有意改变了这个行为,作为加强 agent 间消息传输隐私的一部分。但问题在于,这次改动没有区分"给模型看的加密消息"和"给人类审计的明文记录"——两个需求被混在一起处理了。
这个历史记录不是可有可无的。在团队协作场景下,用 Codex CLI 的开发者依赖 rollout 来事后回答这类问题:谁让谁干了什么、按什么顺序、结果有没有偏离原始任务。一旦这个数据源变得不可读,审计就只能依赖有人在别处保留了原始 prompt,而这不是所有工作流都会默认做的事情。
issue 里的描述很准确。InterAgentCommunication 结构定义在 codex-rs/protocol/src/protocol.rs 的第 735 到 791 行(commit fde21ba),包含两个关键字段:content 是明文字符串,encrypted_content 是可选的加密字段。原来的构造函数 new() 会填充 content 并把 encrypted_content 设为 None。
新的构造函数 new_encrypted() 则反过来:把 content 初始化为空字符串,所有内容只存在 encrypted_content 里。当 MultiAgentV2 加密发送给子 agent 的消息时,用的是 new_encrypted()。结果是:本地 rollout 历史、父进程的 trace 缩减、以及所有调试输出都丢失了任务或消息的可读文本。
issue 作者用三个具体问题总结了影响:spawn_agent 里子 agent 收到了什么任务、send_message 发送了什么消息、以及后来查看历史时为什么存在某个子线程。这三个问题在改动之后已经无法通过检查 rollout 来回答了。
MultiAgentV2 是 Codex CLI 子 agent 系统的第二代方案:第一代用明文消息进行端到端协调。PR #26210 引入的加密机制目的是防止 agent 间消息内容暴露在不该出现的地方——这个动机是合理的,特别是当 Codex CLI 运行在共享环境中,或者 payload 要经过第三方可能监听的通道时。
issue 本身也说得很清楚:并不是要求回退这次加密交付。问题更具体:给模型加密不应该等于同时删除人类审计所需的可读副本。这是两个不同的关注点,PR #26210 用单一机制同时处理了。
值得把这个问题和 issue #26753 区分开来,后者更早提出并与同一改动相关。26753 描述的是模型不支持加密工具时 spawn_agent 的 schema 校验返回 400 错误——调用根本没完成。而 #28058 发生在加密消息已经被接受并成功交付之后:问题出在交付成功后,留下的记录里没有明文。
对比改动前后的消息格式可以更清楚地理解影响范围。改动前,agent 间消息大致是这样的:
{ "author": "orchestrator", "recipient": "agent-refactor-1", "content": "Refactor the auth module and run the test suite", "encrypted_content": null, "trigger_turn": true
} 改动后,当 MultiAgentV2 加密交付消息时,同一条记录在 rollout 里变成了:
{ "author": "orchestrator", "recipient": "agent-refactor-1", "content": "", "encrypted_content": "eyJhbGciOiJBMjU2R0NNIiwi...", "trigger_turn": true
} content 变成空字符串,所有有用文本都在 encrypted_content 这个密文 blob 里,只有接收方能解密。实际的 Rust 结构定义(来自 issue 附带的源码引用)是:
pub struct InterAgentCommunication { pub id: Option, pub author: AgentPath, pub recipient: AgentPath, pub other_recipients: Vec, pub content: String, pub encrypted_content: Option, pub internal_chat_message_metadata_passthrough: Option, pub trigger_turn: bool,
} impl InterAgentCommunication { pub fn new_encrypted( author: AgentPath, recipient: AgentPath, other_recipients: Vec, encrypted_content: String, trigger_turn: bool, ) -> Self { Self { id: None, author, recipient, other_recipients, content: String::new(), encrypted_content: Some(encrypted_content), internal_chat_message_metadata_passthrough: None, trigger_turn, } }
} 对比表格:
| 状态 | content 字段 | encrypted_content 字段 | 本地 rollout 可审计 |
|---|---|---|---|
| PR #26210 之前 (new()) | 消息明文 | None | 是 |
| PR #26210 之后 MultiAgentV2 (new_encrypted()) | 空字符串 | 加密 payload | 否 |
⚠️ 注意:这不是加密漏洞。问题不是消息保护不当,而是加密后没有任何明文副本留给本地审计。
如果你的 Codex CLI 版本在 0.137.0 之后且启用了 MultiAgentV2,可以直接查看 session 的 rollout 文件来确认行为。
# macOS / Linux
grep -o '"encrypted_content":"[^"]*"' ~/.codex/sessions/*/rollout.jsonl | head -5 # Windows (PowerShell)
Select-String -Path "$env:USERPROFILE\.codex\sessions\*\rollout.jsonl" -Pattern '"encrypted_content":"' 如果上述命令有输出,同时同一批记录的 content 字段是空的,那你的安装已经受到 issue #28058 的影响。可以对比未启用 MultiAgentV2 的 session,或者 2026 年 6 月 5 日之前的 session,看两者的 content 明文差异。
issue 本身没有提供禁用加密的配置选项。目前想看明文只能不从 rollout 获取,而是在编排端于 MultiAgentV2 加密之前就自己记录任务——大多数工作流不会默认这么做。
受影响的主要是两类人:审计生产环境 agent 行为的团队,以及调试"子 agent 为什么做了预期之外的事"的开发者。两种情况下,答案以前都存在本地 rollout 里;有了 MultiAgentV2 加密后,除非手动解密 payload,否则答案就消失了。issue 没有把解密描述为人类查看自身历史的正常流程的一部分。
这个问题不是 Codex CLI 独有的:任何端到端加密 payload 的系统都会面临保密性和可审计性之间的张力。区别在于,在由 agent 做决策、执行代码变更的流水线里,"谁让谁干了什么"的可追溯性不是可选项——这是重建"为什么仓库变成了现在这个状态"的唯一途径。
以下序列图展示了任务信息在 spawn_agent 流程中丢失的位置:
sequenceDiagram
participant M as 父 Agent
participant W as Codex CLI
participant S as 子 Agent
M->>W: spawn_agent 携带任务 T
W->>W: 内部加密消息
W->>S: 交付加密消息
Note over M,W: 本地 rollout 已不再保存任务 T 的明文 issue 提出的修复方案很明确:在保持 message 字段加密用于模型交付的同时,添加一个独立的审计字段明文存储到 rollout 元数据、历史记录和 trace 里。这个分离——一个通道给模型、一个通道给审计人类——本质上和企业系统中加密业务 payload 但保留明文审计元数据的做法是同一原理。
💭 关键点:issue 不是要回退加密,而是要求"给模型加密"不再自动等于"没人能事后审计任务"。
写这篇文章时,issue #28058 在 openai/codex 的 issue 追踪器里仍然是打开状态,标记了 CLI、bug 和 subagent 标签,尚未关联修复 PR。issue 明确描述了修复应该长什么样:一个不加密的审计字段,独立于模型看到的 message,存储在 rollout 元数据、历史记录和 trace 里。
对于已经在生产环境中运行 MultiAgentV2 且审计至关重要的团队(合规审查、故障调试、管控 agent 间任务分配),目前的实际建议是:不要把加密后的 rollout 当成唯一的真相来源,在 MultiAgentV2 加密之前就在编排端自己记录任务。
自己测一下:在启用了 MultiAgentV2 的 session 上跑 grep -o "encrypted_content" ~/.codex/sessions/*/rollout.jsonl,确认一下本地历史里任务的明文是否已经没了。
是 Codex CLI 的 agent 协调系统,允许一个父 agent 通过 spawn_agent、send_message 和 followup_task 这些工具调用来协调多个子 agent 分担代码任务。
加密了接收模型看到的消息 payload,同时副作用是清空了原本存储在本地历史里的 content 明文字段。
如果在 0.137.0 之后的版本上启用了 MultiAgentV2,检查 rollout 文件:如果看到 encrypted_content 有内容而 content 是空的,那就是在复现 issue #28058 的行为。
根据 issue 描述,没有。问题不在加密强度,而在于加密后本地审计没有了明文副本。
#26753 是模型不支持加密工具时 schema 校验返回 400,调用根本没完成。#28058 是消息已经成功送达,但送达后没有明文记录。
这篇文章发的时候还没有。issue 仍打开,没有关联的修复 PR,但 issue 本身已经提出了具体方案:一个不加密的审计字段,和加密 payload 分开存储。