@dreki-gg/pi-plan-mode
v0.31.0
Published
Two-phase planning workflow for pi — plan with claude-opus-4-6:medium, execute with gpt-5.5:low, with file-based plan-ledger handoff (default .taskman/plans/, configurable via .taskmanrc)
Readme
@dreki-gg/pi-plan-mode
Two-phase planning workflow for pi.
Plan with claude-opus-4-6:medium, execute with gpt-5.5:low. Plans are persisted as files in the plan ledger (default .taskman/plans/) for clean context handoff between models.
Install
pi install npm:@dreki-gg/pi-plan-modeWhere plans live (.taskmanrc)
The plans root is resolved the same way the taskman CLI resolves it: the default is .taskman/plans/, overridable per-project by a .taskmanrc JSON file in the working directory whose plans-root value IS the ledger folder (it contains plans.jsonl directly):
{ "plans-root": ".plans" }Resolution is cwd-only by design — no walk-up, no env var — so the extension, the taskman CLI, and the clean command always agree on which folder holds the ledger. A malformed .taskmanrc fails loudly at load instead of silently writing plans to the wrong place. External-target writes (submit_plan / revise_plan / add_task with target) honour the target repo's own .taskmanrc.
Throughout this README, .taskman/plans/ refers to the resolved plans root.
Recommended companions:
pi install npm:@dreki-gg/pi-questionnaireWhat it provides
| Feature | Name | Notes |
| -------- | -------------- | ---------------------------------------------- |
| Flag | --plan | Start pi in plan mode |
| Command | /plan [prompt] | Enter plan mode, optionally with a starting prompt |
| Command | /plan resume | Pick up an in-progress plan from disk |
| Command | /plan focus <name> | Pin a plan so tracking calls default to it (multi-plan repos) |
| Command | /plans | List/filter/sort plans |
| Command | /initiatives | List initiatives with member-plan rollup |
| Command | /todos | Show current plan progress |
| Shortcut | Ctrl+Alt+P | Toggle plan mode |
| Tool | revise_plan | Rewrite an existing plan in place (title/handoff/tasks) |
| Tool | update_task | Mark a task done / skipped / blocked |
| Tool | update_tasks | Mark several tasks done / skipped in one call |
| Tool | add_task | Capture a discovered follow-up (deferred) |
| Tool | plan_status | Read-only snapshot; progress table when many plans are active |
| Tool | set_active_plan | Pin a plan as active (tool form of /plan focus) so tracking calls target it |
| Tool | update_plan | Close/reopen a plan: done, superseded, abandoned, in-progress |
| Tool | submit_initiative | Create an initiative that groups multiple plans |
| Tool | update_initiative | Close/reopen an initiative: done, superseded, abandoned, in-progress |
| Tool | initiative_status | Snapshot an initiative: member plans, progress, ready/blocked |
| Tool | reconcile_plans | Detect & repair drift between tasks.jsonl and the registry (plans and initiatives) |
Initiatives — grouping large work
When a body of work is too large for a single plan, group it under an initiative. An initiative is one level above a plan; the same projection rule applies one level up:
Initiative status = projection of its member plans' statuses
Plan status = projection of its tasks' statuses
Task base stateAn initiative is done when it has ≥1 member plan and every member is terminal
(done / superseded / abandoned). Member plans link to the initiative by name and
carry plan-level depends_on (cross-initiative allowed), so the extension can compute
ready work — plans whose dependencies are all done. initiative_status surfaces, per
member plan, whether it is ready or blocked by which plans — the view you want when
splitting an initiative across sessions or subagents.
# 1. Create the initiative
submit_initiative(name: "auth-overhaul", title: "Auth Overhaul", overview: "...")
# 2. Submit member plans linked + ordered
submit_plan(name: "auth-schema", initiative: "auth-overhaul")
submit_plan(name: "auth-jwt", initiative: "auth-overhaul", depends_on_plans: ["auth-schema"])
submit_plan(name: "auth-ui", initiative: "auth-overhaul", depends_on_plans: ["auth-jwt"])
# 3. See what's ready to pick up
initiative_status(initiative: "auth-overhaul")Initiative lifecycle mirrors plans: done is projected automatically, while superseded /
abandoned (and reopen) are explicit via update_initiative with a reason. The clean
CLI archives closed initiatives the same way it archives closed plans.
Plan lifecycle status
The registry (.taskman/plans/plans.jsonl) status is a projection of task state, not a
hand-maintained flag. Marking every task done/skipped (via update_task, in any
session or model) automatically flips the plan to done — completion is no longer
coupled to a formal in-session execution run.
| Status | Meaning | Active? |
| ------------- | -------------------------------------------------- | ------- |
| in-progress | Active, tracked, eligible for auto-resolution | ✅ |
| done | All tasks resolved | — |
| superseded | Another plan absorbed the work | — |
| abandoned | Won't do / rejected | — |
superseded / abandoned are set explicitly via update_plan (with a reason) and are
never auto-overridden by task reconciliation. Only in-progress plans participate in
active-plan resolution.
In repos with many in-progress plans, an explicit { plan: "<name>" } on
update_task / add_task / plan_status always targets that plan — it is never
silently overridden by whatever plan was last submitted in the session.
Workflow
1. Plan (claude-opus-4-6:medium)
/plan add authentication middleware with JWT supportThe planner has access to read-only tools plus edit/write restricted to files inside the plans root. Bash is locked to a strict allowlist of safe commands.
The planner:
- Inspects the codebase using read-only tools
- Uses
questionnairewhen requirements are underspecified - Creates
.taskman/plans/<kebab-name>/PLAN.mdwith the full numbered plan - Creates
.taskman/plans/<kebab-name>/START-PROMPT.md— a self-contained handoff prompt with all context needed to execute without the planning conversation - Can add supporting files in the same directory for extra context
2. Choose next step
When the planner finishes, a menu appears:
| Option | Description | | ---------------- | ---------------------------------------------------------------------- | | Execute Plan | Extract todos from PLAN.md, switch to gpt-5.5:low, start with START-PROMPT.md | | Refine Plan | Adversarial review — planner critiques its own plan and updates files | | Follow up | Open an editor for additional instructions to the planner | | Exit plan mode | Disable plan mode and restore original model |
3. Execute (gpt-5.5:low)
When Execute Plan is selected:
- Todos are extracted from
PLAN.md - Model switches to
gpt-5.5:lowwith full tool access - The executor starts with a clean context window using
START-PROMPT.md - Each step must be marked with
[DONE:n]before moving to the next - Progress is tracked in a widget in the status bar
- When all steps complete, the original model and thinking level are restored
Plan directory structure
.taskman/plans/ # or your .taskmanrc plans-root
├── plans.jsonl # Plan registry — plan status lifecycle
├── initiatives.jsonl # Initiative registry — groups member plans
├── auth-overhaul/ # An initiative directory
│ └── INITIATIVE.md # Initiative overview + plan breakdown
└── auth-jwt/ # A member plan (linked by name in the registry)
├── HANDOFF.md # Self-contained executor handoff
├── tasks.jsonl # Tasks (gains optional initiative + plan-level depends_on)
└── ... # Optional supporting filesplans.json
The extension automatically maintains the ledger's plans.json to track plan lifecycle:
{
"add-auth-middleware": {
"status": "in-progress",
"title": "Add Authentication Middleware with JWT Support",
"created": "2026-05-08T12:00:00.000Z",
"completed": null
},
"fix-ci-flakes": {
"status": "done",
"title": "Fix CI Flaky Tests",
"created": "2026-05-07T10:00:00.000Z",
"completed": "2026-05-07T14:30:00.000Z"
}
}Plans start as "in-progress" when created and are marked "done" when all execution steps complete. This prevents accidental deletion of in-flight plans.
Cleaning completed plans
Use the CLI to clean closed plans (done / superseded / abandoned). By default it
archives plan directories to .taskman/plans/.archive/<name>/ — keeping HANDOFF.md and
tasks.jsonl as a record — rather than deleting them:
# Preview what would be cleaned (no changes)
npx @dreki-gg/pi-plan-mode clean --dry-run
# Archive closed plans to <plans-root>/.archive/ and update plans.jsonl
npx @dreki-gg/pi-plan-mode clean
# Permanently delete instead of archiving
npx @dreki-gg/pi-plan-mode clean --purgeIn-flight plans ("status": "in-progress") are never touched. Archiving is the default so
that closing out a finished plan never silently destroys its handoff + task ledger.
GitHub Actions
Clean done plans automatically after merge — similar to changesets:
name: Clean Plans
on:
push:
branches: [main]
paths: ['.taskman/plans/**'] # match your .taskmanrc plans-root
jobs:
clean:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with:
node-version: '24'
- run: npx @dreki-gg/pi-plan-mode clean
- name: Commit cleanup
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .taskman/plans/
git diff --cached --quiet || git commit -m "chore: clean completed plans"
git pushShould you gitignore the plans root?
No. Commit your plans — they provide decision history and execution context. Use the clean CLI to remove done plans after merge, keeping the directory lean. Plans are execution blueprints, not permanent documentation; for lasting decisions, use ADRs.
Footer indicators
📝 plan— plan mode active (opus-4-6:medium, strict bash)📋 exec 2/5— executing plan with gpt-5.5:low, 2 of 5 steps done
Bash safety
In plan mode, bash is restricted to read-only commands (ls, grep, git status, cat, rg, etc.). Destructive commands (rm, mv, git commit, etc.) are blocked.
CLI reference
pi-plan-mode clean [--dry-run] [--purge]| Option | Description |
| ----------- | ----------------------------------------------------------------- |
| clean | Archive closed plan directories to <plans-root>/.archive/, update manifest |
| --dry-run | Show what would be cleaned without changing anything |
| --purge | Permanently delete instead of archiving |
