# Plan mode · 先出计划，批准了再动手

> 让 agent 先谋后动——plan mode 里它只能读、不能改，把计划写进 plan.md，你批准后才开工。这一章看它的状态机、如何在工具层硬拦编辑、以及 exit_plan_mode 的批准往返。

- 作者：David（道雾轩）
- 专栏：Grok Build 源码解读（https://daiw.org/manual/grok-build.md）
- 最后更新：2026-09-13
- 原文：https://daiw.org/manual/grok-build/plan-mode
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# Plan mode · 先出计划，批准了再动手

有时候你不想让 agent 上来就改代码，而是**先出个计划**给你看。plan mode 就是这个：它只读不改，把计划写进 `plan.md`，你批准了才动手。核心在 `session/plan_mode.rs`(纯状态机)。

## 状态机

`PlanModeState` 四态：`Inactive → Pending → Active → ExitPending`。进入有两条路：你按 <kbd>Shift+Tab</kbd> / 敲 `/plan`(`Pending→Active`)，或模型自己调 `enter_plan_mode` 工具(`Inactive→Active`)。计划写在会话目录的 `plan.md`——**plan mode 里唯一能改的文件**。

## 工具层硬拦编辑

关键是 plan mode **不靠 prompt 叮嘱，靠工具层硬拦**。工具执行前过一道 `plan_mode_edit_gate`：是编辑操作、且目标不是 `plan.md` → **拒绝、工具根本不执行**(返回一条「只能改计划文件」的结果)。而 `plan.md` 的写入**自动放行**(免权限确认)。

<Callout type="info">
  这道闸**在任何权限模式下都成立，包括 yolo**。也就是说，哪怕你开了「全部放行」，plan mode 里它还是改不了代码——yolo 只是在底下待命。**「先谋后动」是通过硬性剥夺编辑能力实现的，不是靠模型自觉**。这比[权限确认](https://daiw.org/manual/grok-build/workspace-abstraction)更狠一层，适合「我还没想好要不要让它动」的场景。
</Callout>

## 批准往返

想退出 plan mode 开工，模型调 `exit_plan_mode`。这时不直接放行，而是发一个**反向请求** `x.ai/exit_plan_mode` 给客户端，把计划内容给你看，等你裁决：

- **Approved** → 执行、`deactivate_approved`，退出 plan mode 开工；
- **Cancelled** → 带上你的反馈(`revise_plan_message`),plan mode **继续**，让它改计划；
- **Abandoned** → 彻底放弃，注入「别再调了」。

客户端在批准途中断线？turn 标记 `Cancelled`、plan mode 保持 active，**重连后批准重新弹出**。

`PromptMode::Plan` 是这套的只读信号，和 [Part 1 的 `PermissionMode::Plan`](https://daiw.org/manual/grok-build/agent-loop) 同一个意图。持久化到 `plan_mode.json`，重启时瞬态(Pending/ExitPending)会塌回 Inactive。

## 和《从 LLM 到 Coding Agent》对照

教学最小实现里没有 plan mode——它是产品对「可控性」的回应。grok 的做法值得学：**用工具层的硬门控**(而非 prompt 约束)实现「只读规划」，再配一个可迭代的批准往返。这是「让用户在 agent 动手前拽住缰绳」的强形态。下一章看另一种运行形态：无头。

---

上一篇：[Sessions](https://daiw.org/manual/grok-build/sessions) · 下一篇：[Headless 模式](https://daiw.org/manual/grok-build/headless)
