# Plan mode

> Structured planning before edits: plan files, approval gates, mode entry/exit from the TUI, and how plan mode interacts with tools and permissions.

- Repository: xai-org/grok-build
- GitHub: https://github.com/xai-org/grok-build
- Human docs: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458
- Complete Markdown: https://grok-wiki.com/public/docs/xai-org-grok-build-90205de50458/llms-full.txt

## Source Files

- `crates/codegen/xai-grok-pager/docs/user-guide/19-plan-mode.md`
- `crates/codegen/xai-grok-shell/src/session/goal_planner.rs`
- `crates/codegen/xai-grok-shell/src/session/goal_orchestrator.rs`
- `crates/codegen/xai-grok-shell/src/session/goal_strategist.rs`
- `crates/codegen/xai-grok-pager/docs/user-guide/22-permissions-and-safety.md`
- `crates/codegen/xai-grok-pager/src/slash/commands/mod.rs`

---

---
title: "Plan mode"
description: "Structured planning before edits: plan files, approval gates, mode entry/exit from the TUI, and how plan mode interacts with tools and permissions."
---

Plan mode is a session-scoped lifecycle enforced by the shell’s `PlanModeTracker` and surfaced in the TUI as an ACP session mode (`plan`). While **Active**, the agent explores and writes only the session plan file (`plan.md`); edit tools targeting any other path are rejected before execution—even under always-approve. Entry is either user-driven (`/plan`, Shift+Tab) or agent-driven (`enter_plan_mode`); exit for implementation goes through `exit_plan_mode` and a scrollable approval surface (`a` / `s` / `c` / `q`).

## What plan mode does

When plan mode is **Active**, the agent:

1. Reads and searches the codebase (and may use other non-edit tools subject to normal permission rules).
2. Writes and revises an implementation plan in the session plan file.
3. May call `ask_user_question` to clarify requirements.
4. Calls `exit_plan_mode` so you can approve, request changes, or abandon the plan.

Separating planning from implementation lets you correct the approach before any product code is written. The model is steered with injected system reminders (full / sparse alternation, reentry, and exit variants) that name the plan path and the only allowed turn-ending tools for planning.

## Enter plan mode

### User-initiated

| Surface | Behavior |
| ------- | -------- |
| **`/plan`** | Turns plan mode on (Pending until the next prompt). |
| **`/plan <description>`** | Turns plan mode on and starts a turn with that description after the mode switch completes (`SetModeThenPrompt`). |
| **Shift+Tab** | Cycles session mode: Normal → Plan → Always-approve → Normal. From Normal, one press lands on Plan. |
| **Dashboard** | `/plan` is also offered without a session so the *next* spawned agent can start in plan mode. |

If you are already in plan mode, `/plan` is idempotent (toast: use `/view-plan` for the saved plan). After a plan exists, **`/view-plan`** (aliases `/show-plan`, `/plan-view`) reopens the saved preview or parked approval UI.

### Agent-initiated

When the agent judges the task ambiguous enough to warrant planning, it calls **`enter_plan_mode`** (empty input). That tool:

- Requires **user approval** before it runs. Decline → result `"User declined to enter plan mode."` and normal mode continues.
- Emits a `PlanModeEntered` notification and activates plan mode **directly** (skips `Pending`).
- Seeds an empty session `plan.md` if missing; **never truncates** existing non-empty content.
- Returns path + tool-name hints (`ask_user_question`, `exit_plan_mode`, optional task/delegate name).

`enter_plan_mode` and `exit_plan_mode` are registered as a pair; the tool registry refuses to load one without the other.

### When plan mode fits

**Use plan mode for:** architectural ambiguity (multiple reasonable approaches), unclear requirements that need exploration first, high-impact restructuring where the wrong approach is expensive.

**Skip plan mode for:** clear one-path changes, obvious bug fixes once understood, features that follow existing conventions, trivial renames/formatting/tests, and pure research (prefer read-only or explore subagents instead).

## The plan file

Canonical location:

```text
~/.grok/sessions/<encoded-cwd>/<session-id>/plan.md
```

`<encoded-cwd>` is a directory-name encoding of the workspace path, not the literal path. The tracker always recomputes this path from session metadata; it is not stored inside the plan-mode snapshot.

Expected plan content (model guidance):

- **Context** — why the change is needed
- Recommended approach (not an exhaustive alternative dump)
- Critical file paths to modify
- Existing functions/utilities to reuse (with paths)
- Verification — how to test end to end

Path resolution for the tools prefers an explicit session `PlanFilePath` resource; without it, fallbacks include `<cwd>/.grok/plan.md` (and related display defaults). Runtime sessions use the session-directory `plan.md` above.

## Approval gate (`exit_plan_mode`)

When planning is done, the agent calls **`exit_plan_mode`** (empty input). The tool **reads the plan from disk** (it does not accept plan body as arguments), so the UI shows the same bytes on disk as the model wrote. It emits `PlanModeExited` with plan content (or empty) and parks an ACP reverse-request until you decide.

### Approval UI

The TUI opens a scrollable plan preview with an action bar:

| Key | Action |
| --- | ------ |
| `a` | **Approve** and start building. With pending line comments, the label becomes approve-with-comments and those comments ride with the approval. |
| `s` | **Request changes** — focus the prompt; type notes and press Enter. Plan mode stays active for revision. |
| `c` | **Comment** on the selected line or line range (or Enter on a line). |
| `q` | **Quit plan** — abandon without approving; turn plan mode off. |
| `Tab` | Toggle focus between preview and freeform prompt. |
| `Esc` | From the prompt, return focus to the preview. |

Focus states: **Preview**, **Commenting**, **Prompt**.

### Empty or missing plan

If `plan.md` is missing, empty, or whitespace-only, approval still opens with a clear empty-state body (placeholder starts with “No plan written yet”). You can still approve (leave plan mode and implement), request changes (back to planning), or quit. Status line distinguishes “Waiting on plan approval” vs “No plan written — approve or request changes”. In minimal mode the empty notice is committed into scrollback and the controls strip header reads **No plan written yet**.

### Wire outcomes

Shell-side outcomes map from the ext response string:

| Outcome | Effect |
| ------- | ------ |
| `approved` | Leave plan mode; implement. |
| `abandoned` | Quit path; plan mode off. |
| anything else (incl. cancel / disconnect) | Fail closed: stay in plan mode (no silent auto-approve). |

If the reverse-request cannot be delivered at all (no interactive client — e.g. some headless/SDK setups), behavior follows the ACP channel failure path; delivery-then-drop keeps approval pending rather than auto-approving.

### Resume

`awaiting_plan_approval` is persisted. On session resume, the shell can re-park `exit_plan_mode` so approval chrome returns instead of treating every Active + `plan.md` session as “still planning.”

## Lifecycle state machine

`PlanModeTracker` owns four states:

| State | Meaning |
| ----- | ------- |
| `Inactive` | Normal operation; no plan-mode edit constraints. |
| `Pending` | Client toggled plan mode on; model not yet instructed (no prompt / no tool entry yet). |
| `Active` | Planning; plan-file edits allowed, other edits rejected. |
| `ExitPending` | User toggled plan mode off while a turn is in flight; exit completes when the turn ends. |

```text
Inactive    --> Active      (enter_plan_mode approved — skips Pending)
Inactive    --> Pending     (/plan or Shift+Tab on)
Pending     --> Active      (first user prompt, or mid-turn activation)
Active      --> Inactive    (exit approved, or toggle off while idle)
Active      --> ExitPending (toggle off mid-turn)
ExitPending --> Inactive    (turn completes)
ExitPending --> Active      (toggle plan mode back on before turn ends)
```

**Persistence:** snapshot is written as `plan_mode.json` under the session directory. On restore, transient states collapse: `Pending` → `Inactive`, `ExitPending` → `Inactive` with a pending exit reminder. `awaiting_plan_approval` is retained so parked approval survives restart.

**Mid-turn toggle on:** activation can buffer a system-reminder until a safe drain point; toggle off before delivery rolls activation back so the model is not told it exited a mode it never saw.

**Status flag:** TUI shows `plan` while plan mode is active. Always-approve (if armed underneath) reappears in the status chrome after plan mode exits.

## Edits, tools, and permissions

Plan mode’s edit restriction is **not** the same as the permission-mode enum value `plan` (that value is accepted for Claude-compat config but does not itself implement this lifecycle). Enforcement is a shell **`plan_mode_edit_gate`** that runs for edit-class tool calls while the tracker is Active.

### Rules

- **Grok edit tools** (`AccessKind::Edit`): only the exact plan file path auto-approves and is allowed. Any other path is rejected with a short model-facing message naming the plan file as the only editable path.
- **Compat Write/StrReplace:** any **markdown** path (`.md`, `.markdown`, `.mdown`, `.mkd`, `.mkdn`, `.mdx`) is allowed for plan-doc style writing; non-markdown is rejected. **Delete** is not on that carve-out—it stays plan-file-only.
- **`apply_patch`:** always rejected in plan mode (targets are not known until after parse).
- **Non-edit tools** (bash, read, grep, MCP, web, `enter_plan_mode` / `exit_plan_mode` as read-scoped): not blocked by the plan gate; they use the normal permission pipeline.
- **Bash is not scanned for redirects:** plan mode blocks edit tools, not shell side-effects.

### Always-approve / YOLO

Always-approve remains “armed” underneath plan mode. YOLO does not know about plan mode; the plan edit gate still rejects non-plan-file edits. Non-edit tools may still auto-run under always-approve. After you approve exiting plan mode, always-approve resumes for implementation if it was enabled.

### Hooks and deny rules

`PreToolUse` hooks and configured deny/ask/allow rules still apply in the usual order for tools that reach the permission path. Plan-mode rejections for non-plan edits happen as a dedicated gate before the agent can mutate the tree through edit tools.

### Subagents

Subagents are **not** covered by the parent’s plan-mode edit gate. Each child starts with a fresh tracker (`Inactive`), so a write-capable type such as `general-purpose` can edit files while the parent is still planning, and it inherits the parent’s permission mode (including always-approve). Read-only types (e.g. `explore`) stay limited by their own toolset.

## Compaction and reminders

- **`/compact` during Active plan mode:** plan-mode state is preserved. Compaction context includes a reminder that plan mode is still active so the agent continues planning after compact. The reminder alternation counter resets so the next injection is the full template.
- **Reminders:** full template includes plan path and tool names; sparse template is a short “still in plan mode” line; reentry and exit templates cover re-toggle and leave-plan paths.

## Tools and notifications (integration)

| Piece | Role |
| ----- | ---- |
| `enter_plan_mode` | Agent entry; seeds plan file; `PlanModeEntered`. |
| `exit_plan_mode` | Present plan; `PlanModeExited`; parks approval. |
| `ask_user_question` | Clarifications while planning. |
| ACP session mode `plan` | Client ↔ shell mode sync (`SetSessionMode` / `CurrentModeUpdate`). |
| `plan_mode.json` | Lifecycle snapshot + `awaiting_plan_approval`. |
| `plan.md` | Authoritative plan body for approval UI. |

Claude-compat aliases `EnterPlanMode` / `ExitPlanMode` match the same tools for allowlist/compat surfaces.

## Related pages

<CardGroup cols={2}>
  <Card title="Permissions and safety" href="/permissions-and-safety">
    Allow/deny/ask rules, always-approve, hooks, and how they layer with plan-mode edit gates.
  </Card>
  <Card title="Slash commands" href="/slash-commands">
    `/plan`, `/view-plan`, and other interactive session commands.
  </Card>
  <Card title="Keyboard shortcuts" href="/keyboard-shortcuts">
    Shift+Tab mode cycle and TUI focus behavior.
  </Card>
  <Card title="Sessions" href="/sessions">
    Session directories, resume, compact, and persistence layout that host `plan.md`.
  </Card>
  <Card title="Subagents and personas" href="/subagents">
    Child agents and why they do not inherit the parent plan-mode edit gate.
  </Card>
  <Card title="Agent mode (ACP)" href="/agent-mode">
    Session modes, reverse-requests, and client surfaces that host approval.
  </Card>
</CardGroup>

## Next

<CardGroup cols={2}>
  <Card title="Permissions and safety" href="/permissions-and-safety">
    Tune deny/ask rules and always-approve for post-approval implementation.
  </Card>
  <Card title="Headless mode" href="/headless-mode">
    Non-interactive runs: plan approval needs a client; headless paths fail closed when no interactive approval channel exists.
  </Card>
</CardGroup>
