edit | blame | history | raw

2026-07-01 PMO 停顿通知

用户目标

用户指出 Mindraw 项目中自己主要和全局 PMO 沟通,PMO 再给其他 coder 派任务;worker 完成、阻塞或停下时,最应该第一时间知道的是 PMO,而不是只用音频通知用户本人。

本轮目标:先针对 Mindraw 建立 PMO worker stop 兜底通知机制。

完成标准:

  • PMO 派工时有 active assignment 记录。
  • worker Stop 时能向 PMO 可读 inbox 写结构化事件。
  • 事件能区分近期是否回写统一台账。
  • 不把所有 Codex Stop 都通知 PMO。
  • 不改变现有 MD-* / M4C-* / PM-* 任务边界。

当前起点

  • Mindraw 统一台账:/Users/ar/Projects/ExcalidrawX/02-P/plan-progress.markdown
  • 主项目入口规则:/Users/ar/Projects/ExcalidrawX/AGENTS.md
  • m4c 子项目入口规则:/Users/ar/Projects/ExcalidrawX/p.mindrawforcodex/AGENTS.md
  • 现有全局 Stop hook:/Users/ar/.codex/hooks.json
  • 原有音频提醒 hook 已优化:匹配 PMO active assignment 的 worker Stop 不再给用户播放 Stop 音频;非 PMO 管理场景和 PermissionRequest 仍保留音频提醒。

已完成事项

  • 新增 PMO inbox:/Users/ar/Projects/ExcalidrawX/02-P/PMO_INBOX.md
  • 新增 active assignment 配置:/Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json
  • 新增 PMO 原始事件日志:/Users/ar/Projects/ExcalidrawX/02-P/pmo-events.jsonl
  • 新增 Stop hook 脚本:/Users/ar/.codex/hooks/pmo_stop_event.py
  • 更新全局 hooks 配置:/Users/ar/.codex/hooks.json
  • 优化音频提醒:/Users/ar/.codex/hooks/audio_alert.py 会在 PMO active assignment Stop 场景静音。
  • 更新项目规则:
  • /Users/ar/Projects/ExcalidrawX/AGENTS.md
  • /Users/ar/Projects/ExcalidrawX/p.mindrawforcodex/AGENTS.md
  • 更新项目索引:/Users/ar/Projects/ExcalidrawX/INDEX.md
  • 更新统一台账,新增 P-20260701-pmo-worker-stop-notification

关键决策

  • Stop hook 只对 Mindraw 项目生效,且必须匹配 pmo-active-assignments.json 中的 active assignment。
  • PMO 派发 MD-* / M4C-* worker 任务时,必须登记真实 task_idplan_idrolecwd_prefixassigned_atstatus=active
  • worker 完成、取消或被替代后,PMO 必须把对应 assignment 改为 done / cancelled / superseded
  • assigned_at 用来避免把 PMO 派工时更新台账的 mtime 误判为 worker 已回写;hook 只把晚于 assigned_atplan-progress.markdown mtime 视为 worker 回写。
  • hook 是 PMO 兜底通知,不替代 worker 对 plan-progress.markdown 的 Progress Log 回写。
  • 匹配 PMO active assignment 的 worker Stop 不再播放用户侧 Stop 音频提醒;PMO inbox 是第一通知入口。

核心事实 / 变更快照

  • 变更对象:Mindraw PMO worker stop 通知机制。
  • 事实来源:
  • /Users/ar/.codex/hooks/pmo_stop_event.py
  • /Users/ar/.codex/hooks/audio_alert.py
  • /Users/ar/.codex/hooks.json
  • /Users/ar/Projects/ExcalidrawX/02-P/PMO_INBOX.md
  • /Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json
  • /Users/ar/Projects/ExcalidrawX/02-P/pmo-events.jsonl
  • /Users/ar/Projects/ExcalidrawX/02-P/plan-progress.markdown
  • 变更前:
  • worker 停下时主要通过 Codex 音频提醒用户本人。
  • PMO 没有独立的 worker stop inbox。
  • 无 active assignment 配置供 hook 判断哪些 Stop 属于 PMO 派工 worker。
  • 变更后:
  • Stop hook 会在 cwd 属于 /Users/ar/Projects/ExcalidrawX 且匹配 active assignment 时写 PMO event。
  • PMO 可从 02-P/PMO_INBOX.md 读取 Markdown 事件。
  • 原始 JSONL 事件写入 02-P/pmo-events.jsonl
  • 没有 active assignment 的普通 Stop 不通知 PMO。
  • 匹配 active assignment 的 worker Stop 不播放用户侧 Stop 音频;普通 Stop 和 PermissionRequest 仍按原音频逻辑提醒用户。
  • 状态分类:
  • worker_stopped_after_progress_write
  • worker_stopped_after_blocker_or_waiting_progress
  • worker_stopped_blocked_without_progress_write
  • worker_stopped_without_progress_write
  • 范围边界:
  • 当前只针对 Mindraw / ExcalidrawX 项目。
  • 未把事件直接推送进 PMO 线程。
  • 未新增 PMO polling automation。
  • 未改业务源码、构建脚本或用户可见行为。
  • 验证证据:
  • /usr/bin/python3 -m py_compile /Users/ar/.codex/hooks/pmo_stop_event.py 通过。
  • /usr/bin/python3 -m json.tool /Users/ar/.codex/hooks.json 通过。
  • /usr/bin/python3 -m json.tool /Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json 通过。
  • dry-run 验证 active assignment 可生成 PMO event。
  • dry-run 验证未来 assigned_at 不会把当前台账 mtime 误判为 worker 回写。
  • 无 active assignment 时 hook 静默跳过。
  • dry-run 验证普通 Stop 仍写 dry_run reason=stopped 音频日志。
  • dry-run 验证 PMO active assignment Stop 写 suppress_pmo_managed_stop,不播放用户侧音频。

文件变更

  • 新增:/Users/ar/.codex/hooks/pmo_stop_event.py
  • 修改:/Users/ar/.codex/hooks/audio_alert.py
  • 修改:/Users/ar/.codex/hooks.json
  • 新增:/Users/ar/Projects/ExcalidrawX/02-P/PMO_INBOX.md
  • 新增:/Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json
  • 新增:/Users/ar/Projects/ExcalidrawX/02-P/pmo-events.jsonl
  • 修改:/Users/ar/Projects/ExcalidrawX/AGENTS.md
  • 修改:/Users/ar/Projects/ExcalidrawX/p.mindrawforcodex/AGENTS.md
  • 修改:/Users/ar/Projects/ExcalidrawX/INDEX.md
  • 修改:/Users/ar/Projects/ExcalidrawX/02-P/plan-progress.markdown

可复用命令 / Runbook

用途:验证 PMO Stop hook 的语法、配置和 dry-run 输出。

前置条件:

  • hook 脚本存在:/Users/ar/.codex/hooks/pmo_stop_event.py
  • Mindraw active assignment 配置存在:/Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json
  • dry-run 不会写入真实 PMO inbox。

设置命令:

/usr/bin/python3 -m py_compile /Users/ar/.codex/hooks/pmo_stop_event.py
/usr/bin/python3 -m json.tool /Users/ar/.codex/hooks.json >/dev/null
/usr/bin/python3 -m json.tool /Users/ar/Projects/ExcalidrawX/02-P/pmo-active-assignments.json >/dev/null

验证步骤:

PMO_STOP_EVENT_DRY_RUN=1 /usr/bin/python3 /Users/ar/.codex/hooks/pmo_stop_event.py Stop <<'JSON'
{"last_assistant_message":"任务完成,已回写进度。"}
JSON

说明:在真实配置中没有 active assignment 时,上述命令应静默退出。

验证普通 Stop 音频仍保留:

CODEX_HOME=/private/tmp/audio-alert-test-home-ordinary CODEX_AUDIO_ALERT_DRY_RUN=1 /usr/bin/python3 /Users/ar/.codex/hooks/audio_alert.py Stop <<'JSON'
{"last_assistant_message":"任务完成。"}
JSON

如需验证 active assignment 匹配,用临时测试 config 指向 PMO_STOP_EVENT_CONFIG,并在 m4c cwd 下运行:

PMO_STOP_EVENT_DRY_RUN=1 PMO_STOP_EVENT_CONFIG=/private/tmp/pmo-active-assignments-test.json /usr/bin/python3 /Users/ar/.codex/hooks/pmo_stop_event.py Stop <<'JSON'
{"last_assistant_message":"M4C-TEST-01 已卡住,等待 PMO 确认下一步。"}
JSON

验证 PMO 管理 Stop 静音时,用临时测试 config 指向 AUDIO_ALERT_PMO_CONFIG,并在 m4c cwd 下运行:

CODEX_HOME=/private/tmp/audio-alert-test-home-pmo AUDIO_ALERT_PMO_CONFIG=/private/tmp/audio-alert-pmo-active-test.json CODEX_AUDIO_ALERT_DRY_RUN=1 /usr/bin/python3 /Users/ar/.codex/hooks/audio_alert.py Stop <<'JSON'
{"last_assistant_message":"M4C-AUDIO-TEST 已完成,已回写进度。"}
JSON

清理 / 恢复命令:

rm -f /private/tmp/pmo-active-assignments-test.json /private/tmp/pmo-active-assignments-future-test.json /private/tmp/pmo-inbox-test.md /private/tmp/pmo-events-test.jsonl
rm -rf /private/tmp/audio-alert-test-home-ordinary /private/tmp/audio-alert-test-home-pmo
rm -f /private/tmp/audio-alert-pmo-active-test.json

搜索关键词:

  • PMO_INBOX
  • pmo-active-assignments
  • pmo_stop_event
  • worker_stopped_without_progress_write
  • assigned_at
  • suppress_pmo_managed_stop

未决问题

  • 当前没有把 PMO event 直接推送到某个 PMO Codex 线程;如后续要做,需要 PMO 线程 ID 或专门的 PMO automation。
  • 当前没有伪造 active worker;后续 PMO 派发任务时必须按真实任务登记 active assignment。
  • 新 hook 修改后需要 Codex 重新加载并在 /hooks 中信任。

后续建议

  • 下一次 PMO 派发 MD-* / M4C-* worker 时,先复制 pmo-active-assignments.json 中对应模板,改成真实 active assignment。
  • 观察前几次 PMO inbox 事件,必要时调整 progress_recent_window_seconds
  • 如果 PMO 希望被主动唤醒,而不是读取 inbox,可再加一个 PMO automation 定时扫描 PMO_INBOX.md

三个月后回看检查

只读本存档可以还原:为什么做 PMO worker stop 通知、触发条件、核心文件、active assignment 字段、Stop hook 行为、状态分类和验证证据。合格。