Plan mode
Plan mode is the default interactive posture. The model can read your repo and propose a plan, but it cannot edit until you approve. On approve, tsforge validates the model’s fenced plan JSON, writes a session-bound plan file, shows it in the Tasks rail, and the same session implements it.
plan mode (default) → discuss or paste → model calls present_plan { goal, items } → TUI renders PLAN card (+ Tasks preview) → approve / go / lgtm → <cwd>/.tsforge/worklist/plans/<planId>.json → session.activePlanId binds that plan → implement in-session (task_* tools + /gate as usual) → finished = gate green AND checklist done → tsforge --continue resumes the session (+ activePlanId + rail)The status bar shows ◆ plan / ◆ normal.
Switching modes
Section titled “Switching modes”- Press Shift+Tab to cycle the mode (plan → normal → …), or type
/planto toggle it - When the plan looks right, reply
approve,go, orlgtm
There is no disable flag: it’s a mode you cycle with Shift+Tab. (tsforge --plan forces plan mode on for an interactive session even in a repo that configured an autonomous policy.mode. One-shot and headless runs are autonomous regardless.)
What gets saved on approve
Section titled “What gets saved on approve”When the plan is ready, the model calls present_plan with a structured { goal, items } tree (nested children, optional detail / files / verify / kind). The harness validates it, holds it as a pending proposal, and renders a PLAN card in the TUI (not a JSON dump in chat). Revise by calling present_plan again.
How to structure items
Section titled “How to structure items”Decomposition rules the planner should follow (soft warnings may appear in the tool result if it strays):
- Order — contracts/types → implementation → sibling tests (nest tests as children when useful)
- One outcome per item — actionable titles (
Create src/notes.ts), not vague prose - File bounds — when known, set
filesto 1–3 relative paths; split by module boundary if more - Prefer parent + children over one mega-item covering the whole feature
- No gate chores — never an item for “run tests / lint / the gate”; the harness gate validates every
task_complete verify/kind— optional hints only (kind:investigate|create|modify|test); not harness-executed commands
Approve (approve / go / lgtm):
- Takes the pending proposal from
present_plan(fenced JSON in chat is a fallback only) - Writes
<project>/.tsforge/worklist/plans/<planId>.json, updatesindex.json, sets the session’sactivePlanId - Updates the Tasks side rail
- Turns plan mode off and continues in the same session
If there is no pending plan (and no valid fenced JSON fallback), approve is refused — stay in plan mode.
Concurrent sessions in one project each bind their own activePlanId; plan files do not clobber.
Resume with tsforge --continue (or --resume <id>): the conversation and activePlanId return from the session store, and the Tasks rail reloads that plan.
Task tools (after approve)
Section titled “Task tools (after approve)”When activePlanId is set:
task_list— nested tree with idstask_focus— set the active itemtask_complete/task_uncomplete— status changes (tools only; not invented in prose)task_add— append discovered work (optionalparent_idto nest)task_update— edit an item’s title/detail/files/verify/kind
The checklist is living: if you or the model discover work the approved plan missed, it should go on the list via task_add (not only in chat). Drift in an item’s scope → task_update; done work that must be redone → task_uncomplete.
task_complete runs the acceptance gate and only marks the item done when green. If the gate is red, the item stays open and the errors are returned — fix, then complete again. Do not put “run tests / lint / the gate” as a checklist item; that is the harness’s job on every complete. A session cannot claim finished while the bound plan still has open items.
What the model can do in plan mode
Section titled “What the model can do in plan mode”Read tools only:
read,search, and LSP navigation (symbol_search,find_references,go_to_definition,type_at,impact,symbol_context,diagnostics)git_context: structured, read-only repo history/diffs (see Git context)runfor read-only shell commands (no installs, no writes)
Blocked until approval: edit, create, edit_lines, scaffolders, and the task_* tools (offered only after a plan is bound).
Whole-app builds (different path)
Section titled “Whole-app builds (different path)”Plan mode is for interactive work in a repo. Building a new app from scratch is a separate headless loop: tsforge scaffold then tsforge --greenfield, which keeps its own checklist under .tsforge/greenfield/. That path does not use plan-mode approve or the Tasks rail plan files.
Leaving plan mode without approving
Section titled “Leaving plan mode without approving”- Shift+Tab (or
/plan) drops to normal mode for hands-on edits - One-shot runs (
tsforge "task" --accept …) and headless/eval runs are autonomous already