pi-extensions GitHub

pi-plan-mode — Codex-like Plan Mode for Pi

Adds a read-only /plan collaboration mode: the agent explores your repo, grills you for the full scope (design-tree rounds of decision questions, each with a recommended answer), and only then produces a Markdown plan file you review and edit before implementation — the same review-before-do loop Copilot CLI's plan mode gives you.

Usage

/plan <prompt>      plan the request (read-only); /plan approve starts implementation
/plan               status (state + plan file path)
/plan approve       approve the written plan: leaves plan mode, restores tools,
                    and tells the agent to implement the plan file
/plan check         optional fresh-context comprehension check (see below)
/plan edit          edit the plan in the editor dialog (Ctrl+G hands off to $EDITOR)
/plan exit | off    cancel plan mode without implementing

Keyboard and CLI:

ctrl+alt+p          toggle plan mode on/off
ctrl+alt+e          edit the plan file (same as /plan edit)
pi --plan           start pi already in plan mode

While plan mode is active, tool membership comes from annotations (packages/plan-mode/tool-policy.mjs), not a name list:

The plan check

The repo's AGENTS.md asks for a judgment before a plan is presented: does each step name how it will be verified, and are the callers it affects identified? That is per-step, so plan-review.mjs splits the plan into steps (list items first, then headings, then the plan as one step), asks both questions for every step in one request, and appends what falls short to the plan file:

## Plan check

TypeSafe read the steps above and found:

No verification named:
- step 3 — Add a cache layer between the loader and the store

Affected callers not identified:
- step 5 — Rename config.timeout to config.deadline

This is a reading of the plan text, not of the code. Edit the step or say why it holds.

It costs one request with an 8-second timeout and is never allowed to block the plan: no key, a failed request or an unusable answer means the plan is written exactly as submitted. A plan where every step holds up gets a one-line "every step names its verification" instead of silence, so the check is visible when it passes too.

/plan check (comprehension)

Before /plan approve, you can run /plan check: one hidden read-only child (via subagents/spawn.mjs runChild, pinned to cross-family, no fleet widget or panes) reads only the plan file path — it never sees the planning chat — and may read files the plan names. It must restate the plan under What the plan changes and How it will be done, then list Gaps (undefined terms, unstated assumptions, missing verification). TypeSafe (Jev) then answers two yes/no questions: whether the restatement matches the plan goal, and whether any step depends on something the plan never states. The result is appended to the plan file as ## Plan comprehension check, and Jev's answers are logged in the usual jev-decision ledger like the step review above.

Cost: one child run (up to 8 turns, 120s timeout) plus one Jev request (12s). It is opt-in and advisory — it never blocks or changes /plan approve.

Hard failures are reported honestly:

You then read/edit .pi/PLAN.md — directly, via /plan edit or ctrl+alt+e (Ctrl+G inside the dialog opens your $EDITOR; the plan is written back when you close it), or in any editor of your choice — and run /plan approve. That ends plan mode, restores your tools, and automatically tells the agent to implement the plan file — no separate exit/implement step. The file is the durable artifact — it survives compaction and is the implementation handoff, so plan mode needs no in-memory plan retention.

Notes and non-goals (for now)

Answering a question the context already settles

plan_mode_question is where a discoverable question becomes a dialog, so it is also where that can be enforced: the tool, not the prompt. Before showing a dialog it asks Jev one thing — which option the agent's own recommended answer names — and answers only when that reading lands on the recommendation at 0.9 confidence or above. A question is a dialog because the agent was in two minds about it; a reading that agrees with the recommendation was not going to be news.

The decision is about the agent, not the user, and it is conservative: a preference, a cost, an interface others rely on, a deletion, no recommended answer, an unfamiliar option, a reading that disagrees or is unsure all ask the user exactly as before. That list is deterministic, in ask-gate.mjs, not the judge's opinion. When it does answer, the user sees one line naming the reason and the agent is told the answer was inferred rather than given, so the plan cannot claim the user chose it.

A first version asked the judge whether "the context settles this" and got 0.32 and 0.57 on the most inferable questions in node scripts/judge-live.mjs — the right answer to the wrong question, since one line of request is not context. Reading the recommendation needs nothing the tool does not already have.

PI_PLAN_JUDGE=off disables it, and without a TypeSafe key it is skipped silently. Same failure mode as everywhere else: a slow or missing judge means the dialog happens, never that a question is answered by nobody.

Development

npm test          # node --test against shared/bash-policy.mjs, plan-file.mjs, dialog-queue.mjs
npm run check     # syntax-check entrypoints + tests