Research: Codex Plan mode behavior and prompt architecture

Open 💬 1 comment Opened Aug 13, 2026 by microtears
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

调研范围

基于 openai/codex 提交 363427b5e3fe1b6d7499e6bc47651f62a5a3b1d2(2026-08-13)进行源码审阅,聚焦 Plan 模式的状态、提示词、工具约束、流式协议和实施切换流程。

结论

Plan 模式是独立的协作模式,不是 update_plan 待办工具。它主要依赖 developer 提示词约束模型行为,并结合少量运行时硬约束、<proposed_plan> 协议及 TUI 的“批准后实施”交互实现闭环。

运行链路

  1. 用户在 TUI 选择/切换到 Plan。内置预设默认设置 Medium 推理强度,且可由 plan_mode_reasoning_effort 覆盖。
  2. 每轮 world state 将 Plan 提示词包装在 <collaboration_mode> developer 消息中并注入模型上下文,状态随会话持久化。
  3. 模型先进行只读探索、澄清意图、补齐实施决策,然后以独占行的 <proposed_plan>...</proposed_plan> 输出完整计划。
  4. 运行时把该块从普通 assistant 文本中剥离,流式发送 PlanDelta,最终生成 TurnItem::Plan
  5. TUI 收到 PlanItem 后提供三项操作:保留上下文切换 Default 并实施、新开上下文携带计划实施、或继续 Plan 模式。

Plan 提示词要点

完整原文:plan.md

  • 严格分为环境事实探索、意图澄清、实施细节澄清三阶段。
  • 用户的“直接实现”不能结束 Plan 模式,只能理解成“规划如何实施”;仅 developer 指令能切换模式。
  • 允许阅读、搜索、静态分析、无副作用命令和只写缓存的构建/测试。
  • 禁止编辑仓库、应用补丁、迁移、改写型 formatter/codegen,以及所有实际执行计划的副作用操作。
  • 优先使用 request_user_input 询问无法从环境发现、且会实质影响方案的偏好或取舍。
  • 只有当方案“实现者不需要再做决策”时才能生成最终计划;每轮至多一个 <proposed_plan>
  • 最终计划默认应简洁,并包含标题、摘要、公共接口变化、测试和明确的默认假设。

硬约束与软约束

| 行为 | 实现方式 |
|---|---|
| 不因用户命令退出 Plan | developer 提示词 |
| Plan 中不修改仓库 | developer 提示词 |
| update_plan | 运行时明确拒绝 |
| request_user_input | Plan 中可用且阻塞等待;Default 默认不可用,需 feature 开启 |
| 空闲自动唤醒 | Plan 模式下禁止启动 |
| <proposed_plan> | 运行时解析为独立流式事件和 PlanItem |

重要边界:Core 中对 Plan 的通用工具执行没有发现针对 execapply_patch 等变更工具的统一后端拒绝。因此“不得写入”主要是高优先级提示词约束,而非完整的强制沙箱隔离;update_plan 是已确认的特例硬拦截。

关键实现位置

额外注意

实际运行的提示词可能不同于仓库模板:若模型目录返回 collaboration_mode_messages.plan,该内容会优先覆盖本地预设;若 include_collaboration_mode_instructions = false,则不会注入该 developer 提示块。

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 15 days ago

English translation:

Research Scope

A source code review was conducted based on commit 363427b5e3fe1b6d7499e6bc47651f62a5a3b1d2 (2026-08-13) of openai/codex, focusing on Plan mode's state, prompts, tool constraints, streaming protocol, and implementation transition flow.

Conclusions

Plan mode is a distinct collaboration mode, not the update_plan task-list tool. It primarily relies on developer prompts to constrain model behavior, combined with a small number of hard runtime constraints, the <proposed_plan> protocol, and the TUI's “implement after approval” interaction to complete the workflow.

Execution Flow

  1. The user selects/switches to Plan in the TUI. The built-in preset uses Medium reasoning effort by default, which can be overridden by plan_mode_reasoning_effort.
  2. On each turn, the world state wraps the Plan prompt in a <collaboration_mode> developer message and injects it into the model context. The state persists throughout the session.
  3. The model first performs read-only exploration, clarifies intent, and fills in implementation decisions, then outputs a complete plan inside <proposed_plan>...</proposed_plan> on dedicated lines.
  4. The runtime strips this block from ordinary assistant text, streams it as PlanDelta, and ultimately generates a TurnItem::Plan.
  5. After receiving the PlanItem, the TUI provides three options: switch to Default while retaining the context and implement it, start a new context carrying the plan and implement it, or continue in Plan mode.

Key Points of the Plan Prompt

Full original text: plan.md

  • It is strictly divided into three phases: exploring environmental facts, clarifying intent, and clarifying implementation details.
  • A user's request to “implement directly” cannot end Plan mode; it can only be understood as “plan how to implement it.” Only developer instructions can switch modes.
  • Reading, searching, static analysis, side-effect-free commands, and builds/tests that write only to caches are allowed.
  • Editing the repository, applying patches, migrations, rewriting formatters/code generators, and all side-effecting operations that actually execute the plan are prohibited.
  • Prefer using request_user_input to ask about preferences or tradeoffs that cannot be discovered from the environment and would materially affect the approach.
  • A final plan may be generated only when “the implementer does not need to make any further decisions.” Each turn may contain at most one <proposed_plan>.
  • By default, the final plan should be concise and include a title, summary, public interface changes, tests, and explicit default assumptions.

Hard and Soft Constraints

| Behavior | Implementation |
|---|---|
| Do not exit Plan because of a user command | Developer prompt |
| Do not modify the repository in Plan | Developer prompt |
| update_plan | Explicitly rejected at runtime |
| request_user_input | Available in Plan and blocks while awaiting input; unavailable by default in Default unless enabled by a feature |
| Automatic wake-up while idle | Prevented from starting in Plan mode |
| <proposed_plan> | Parsed at runtime into a separate streaming event and PlanItem |

Important boundary: No uniform backend rejection specific to Plan was found in Core for general tool execution involving mutation tools such as exec and apply_patch. Therefore, “must not write” is primarily enforced through high-priority prompt constraints rather than complete mandatory sandbox isolation; update_plan is a confirmed special case with hard blocking.

Key Implementation Locations

Additional Notes

The prompt used at runtime may differ from the repository template: if the model catalog returns collaboration_mode_messages.plan, its content takes precedence over the local preset; if include_collaboration_mode_instructions = false, the developer prompt block is not injected.

<!-- codex-issue-translator -->