# Mailroom — agents 信箱系统 > **版本**: 1.0 草案 (2026-05-31 设计) > **状态**: 试运行;格式稳定后由 CEO 决定是否在 WORKFLOW.md §15 正式纳入流程 > **设计目标**: 让无状态的子代理之间能异步传递消息,把进行中的协调状态从 CEO 的隐式上下文搬到磁盘 ## 1. 设计动机 子代理是 stateless 的——每次 spawn 都是新会话,看不到其他子代理当前在做什么。现行所有协调依赖 CEO 在 prompt 里手动列禁忌、手动转交依赖、手动追踪谁回了什么。一波 6-9 路子代理并行时,CEO 的上下文窗口很快被占满。 信箱让这些消息**显式落盘**: - CEO 派活前可以扫一遍候选执行者的 inbox,看有没有未结的 handoff / blocker - 子代理 spawn 时可以读到自己的待办邮件,了解上下文 - 处理完毕的邮件归档到 `archive/W/`,不丢失追溯,但不打扰当前视图 ## 2. 目录结构 ``` agents/mailroom/ ├── README.md # 本文件 ├── inbox/ │ ├── ceo/ # CEO 的收件箱 │ ├── architect-lin/ # 各 agent 的收件箱(按需创建) │ ├── engineer-zhao/ │ └── ... └── archive/ ├── W17/ # 按 Wave 归档已处理邮件 ├── W18/ └── ... ``` - `inbox//` —— 待处理邮件(status: pending / read / in_progress) - `archive/W/` —— 处理完毕邮件(status: closed),按 Wave 归档保留 - 收件箱目录按需创建,未创建表示该 agent 当前无邮件 ## 3. 权限规则 文件系统不强制权限;权限靠子代理 prompt 中的禁忌条款约束。 | 角色 | 自己的 inbox | 别人的 inbox | archive/ | |------|--------------|--------------|----------| | 接收者本人 | 读 / 改 status / 移到 archive | 只能投递新邮件(write-only) | 只读 | | CEO | 所有权限 | 所有权限(含重投递、强制保留) | 所有权限 | | 其他子代理 | — | 只能投递新邮件 | 只读 | 派子代理时 prompt 必须显式声明可访问的邮箱范围。新增防御性规则 **R-MAIL-SCOPE**:子代理不得读写超出自身 inbox 之外的他人邮箱内容,仅可投递新邮件。 ## 4. 消息文件命名 `---to-.md` - timestamp: `YYYY-MM-DDTHHmm` 本地时间,分钟级即可区分 - kind: 见 §5 - from / to: agent-id(CEO 用 `ceo`,广播用 `all`) 示例:`2026-05-31T1430-task-ceo-to-architect-lin.md` ## 5. 五种邮件类型 | kind | 用途 | 投递方 | 接收方 | |------|------|--------|--------| | task | CEO 派活(prompt 副本,便于事后追溯) | CEO | 执行者 | | report | 子代理回执(done / blocked / aborted) | 执行者 | CEO | | handoff | 子代理之间工作交接(前序产出移交下一棒) | 子代理 A | 子代理 B | | blocker | 阻塞通知(依赖未满足) | 任何 | CEO(必抄送) | | notice | 广播(in-flight 文件锁定 / 流程变更 / 元数据自检失败) | CEO 或系统 | all | ## 6. Frontmatter schema ```yaml --- id: msg-W17.3-001 # 全局唯一,格式 msg--<序号> from: ceo to: architect-lin # 单人用 agent-id;广播用 all wave: W17.3 kind: task # task | report | handoff | blocker | notice status: pending # pending | read | in_progress | closed created: 2026-05-31T14:30 closed: # 处理完毕时填写,YYYY-MM-DDTHHmm related: # 关联消息 id 列表(如本报告对应的 task) - msg-W17.3-000 fixes: # 关联 findings-registry 的 finding id(如有) - F-13.5-1 --- 邮件正文(markdown) ``` - 必填字段:`id` / `from` / `to` / `wave` / `kind` / `status` / `created` - 选填字段:`closed` / `related` / `fixes` - 字符串值不带引号(YAML 1.2 标准) ## 7. 生命周期 ``` [投递] [归档] │ │ ▼ ▼ inbox// pending ──→ read ──→ in_progress ──→ 处理完毕 archive/W/ status: closed ``` 操作动作: | 动作 | 谁执行 | 文件操作 | status 字段 | |------|--------|----------|--------------| | 投递 | 任意 agent | 在 `inbox//` 创建新文件 | pending | | 阅读 | 接收者 | frontmatter 改 status | read | | 开工 | 接收者 | frontmatter 改 status | in_progress | | 完成 | 接收者 | 移动文件到 `archive/W/` + 改 status | closed | | 重投递 | 仅 CEO | 复制 archive 中的文件到 inbox(保留原件) | pending | 接收者**不可物理删除**邮件——只允许移到 archive;如需删除由 CEO 手动操作。这是与 R-NO-FORCE-PUSH 同等级的强约束(新增 **R-MAIL-NO-DELETE**)。 ## 8. 与现有机制的边界 | 机制 | 职责 | 与 mailroom 的区别 | |------|------|---------------------| | `STATUS.md` | 实时编制状态快照 | 由 `scripts/refresh_status.py` 扫 profile.md 生成;mailroom 是消息流 | | `agents//profile.md` performance_log | 永久任务履历 | 任务粒度,事后追加;mailroom 是消息粒度,进行中 | | `agents/audits/findings-registry.md` | 审计发现追踪 | 跨 Wave 持续追踪;mailroom 单条消息生命周期短(一波内闭环) | | `WORKFLOW.md` | 流程规范 | 是规则;mailroom 是规则产生的数据 | **重叠处理原则**:邮件正文 ≠ 履历正文。task 邮件中的 prompt 是 CEO 派活的原始材料,report 邮件中的回执是子代理的原始报告;最终摘要仍按现有流程写到 profile.md 的 performance_log 一条短记录。**邮件保留细节,profile.md 保留摘要,两者互补不重复**。 审计发现的归宿仍是 findings-registry。blocker 邮件如对应某个 finding,frontmatter 的 `fixes` 字段填写 finding id,CEO INSPECT 时按 §14.4 A3 检查关联。 ## 9. CEO 派活前 5 步检查 扩展 [PROMPT_TEMPLATE.md](PROMPT_TEMPLATE.md) 的 CEO 派活前 4 步检查,新增第 5 步: | # | 检查项 | 操作 | 写入模板字段 | |---|--------|------|--------------| | 1 | 列 in-flight 工作区 | 查当前有哪些子代理在跑 | 禁忌 | | 2 | 找前序 Wave 产出 | 从 performance_log 追溯 | 前序成果 | | 3 | 设定任务范围三档 | 必做 / 可做 / 不做 | 任务范围 | | 4 | 统一字数上限 | 固定 250 字 | 字数上限 | | **5** | **扫候选执行者 inbox** | `ls agents/mailroom/inbox/<候选id>/` 看 pending 的 handoff / blocker | 禁忌 / 前序成果 | 若候选执行者 inbox 有未结的 blocker(依赖未满足)→ 优先让其处理 blocker 再派新活,否则新活也会立即变 blocker。 ## 10. 邮件示例 ### 10.1 task 邮件 文件:`inbox/architect-lin/2026-05-31T1500-task-ceo-to-architect-lin.md` ```markdown --- id: msg-W18.1-001 from: ceo to: architect-lin wave: W18.1 kind: task status: pending created: 2026-05-31T15:00 --- # W18.1 任务: 评审 mailroom 设计 请读 agents/mailroom/README.md 并评估: - 是否值得正式纳入 WORKFLOW.md §15 - 权限规则在 prompt 层面如何强约束 - 与 findings-registry 的边界是否清晰 字数上限 250。完成后请发 report 邮件回 ceo。 ``` ### 10.2 report 邮件 文件:`inbox/ceo/2026-05-31T1630-report-architect-lin-to-ceo.md` ```markdown --- id: msg-W18.1-002 from: architect-lin to: ceo wave: W18.1 kind: report status: pending created: 2026-05-31T16:30 related: - msg-W18.1-001 --- # W18.1 评审结论 赞成纳入 §15。建议补充三条边界规则: 1. 接收者不可删除别人邮箱里的邮件 2. CEO 重投递时必须复制而非移动,保留 archive 原件 3. blocker 邮件必须抄送 CEO profile.md 已追加,rating: A-。 ``` ### 10.3 handoff 邮件 文件:`inbox/qa-xu/2026-05-31T1700-handoff-engineer-sun-to-qa-xu.md` ```markdown --- id: msg-W18.2-003 from: engineer-sun to: qa-xu wave: W18.2 kind: handoff status: pending created: 2026-05-31T17:00 related: - msg-W18.2-001 --- # W18.2 LSP 死锁修复完成,请测 修复了 lsp_plugin.cpp:312 的死锁。需要你跑: - `ctest -R lsp_plugin_test` - `ctest -R smoke` 测试通过后请新建一封 report 邮件发给 CEO 并抄送我。 ``` ## 11. 后续路线(v1.0 之外) 格式稳定 + CEO 在 2-3 个 Wave 中实战使用后,再考虑: - 在 WORKFLOW.md §15 加一节正式纳入流程 - 补充 `scripts/mailroom_summary.py` 自动汇总每个 agent 的未读邮件数与最老 pending 邮件年龄 - 在 STATUS.md 增加 邮件待办数 列 - 扩展 `scripts/check_agents_metadata.py` 校验邮件 frontmatter 不在 v1.0 范围。先用 1-2 个 Wave 看实际效果再说。 ## 12. 关联文档 - [WORKFLOW.md](../WORKFLOW.md) — 流程主文档(mailroom 将来可能并入 §15) - [PROMPT_TEMPLATE.md](../PROMPT_TEMPLATE.md) — 派活模板(影响第 5 步检查) - [STATUS.md](../STATUS.md) — 实时编制状态 - [findings-registry.md](../audits/findings-registry.md) — 审计发现追踪 - [POSTMORTEM.md](../POSTMORTEM.md) — 防御性规则(新增 R-MAIL-SCOPE / R-MAIL-NO-DELETE) ## 13. 变更历史 | 日期 | 版本 | 变更 | |------|------|------| | 2026-05-31 | 1.0 草案 | 初始化。CEO 与用户讨论后落地,方案 2(归档保留,不真删) |