plandeck 是做什麼的?
Plandeck keeps a plan on disk as plan.yaml and renders it as a live Kanban board that reorganizes itself as you edit. You author cards (id, estimate, dependencies, next action). Plandeck computes the rest: which cards are Ready, the critical path, progress rollups, and the single next move. It grows out of planning-with-files (crash-proof file plans plus a completion gate). What is new in Plandeck is the live visual board plus a deterministic intelligence layer over the yaml. It contains no AI and no LLM, only pure, tested functions.
When to use it
Reach for Plandeck when the work is multi-step and worth tracking:
- A task that needs 5+ steps, spans a long session, or will outlive a
/clear. - Work with real dependencies, where order matters and one card unblocks others.
- Anything you want to see: a board with lanes, estimates, and a critical path.
When not to use it
Skip it for one-shot work:
- A single edit, a quick answer, a two-step fix.
- Anything you will finish before the next context reset.
Do not build a board for work that does not need one. The overhead pays off only when the plan has to persist and coordinate.
Files in a plan directory
| file | role |
|---|---|
plan.yaml | The single source of truth (the board). You read and write it; the board re-renders live. |
plan.md | The charter a human or agent reads first: north star, why, constraints. |
cards/*.md | Optional long receipts, for when a card's receipt is too big to sit in plan.yaml. |
NEXT.md | Generated re-entry breadcrumb. Regenerated by plandeck next --write. |
.plandeck-board/ | Generated static board app. Gitignored, rebuilt on every plandeck board. |
Card schema
Author these fields on each card in plan.yaml:
| field | required | shape | purpose |
|---|---|---|---|
id | yes | C001, C002 | Stable card id. |
title | yes | short imperative | What the card delivers. |
column | yes | backlog / ready / doing / review / done | The lane you place the card in. Never place a card in Ready by hand; Plandeck promotes it. |
status | no | queued / active / blocked / done | active marks the ONE card in flight. Mark a blocker with status: blocked (or column: blocked); both route the card to the Blocked lane, and an unmet dependency lands it there on its own. |
role | no | scout / worker / judge / pm | Who does the card. |
estimate | no | story points 1/2/3/5/8/13 | Powers percent complete, velocity, and the critical path. No hours. |
confidence | no | 0..1 | How firm the estimate is. |
priority | no | P0..P4 | P0 is drop everything. |
risk | no | low / med / high | Risk band. |
depends_on | no | [ids] | Plandeck promotes the card to Ready once every listed card is done. |
verify | no | [commands] | Commands that prove the card is really finished. |
next_action | no | one sentence | The single concrete next move on this card. |
tags | no | [..] | Free labels. |
updated_at | no | ISO timestamp | Powers aging. |
receipt | no | {result, summary, changed_files, commands, evidence, note} | What happened when the card was finished or blocked. |
Derived fields are recomputed on every read. Never hand-set them. In the board payload they serialize as ready, onCriticalPath, unblocks, unmetDeps, ageDays, the rollups, and the single next pointer. You place a card in backlog with its depends_on, and Plandeck is the one that shows it in Ready the moment those dependencies are done.
A minimal plan.yaml:
version: 1
plan:
title: "Ship the onboarding flow"
slug: ship-onboarding-flow
north_star: "A new user signs up and lands on the dashboard, proven by the e2e test."
velocity: null # points/day, set once known; powers the ETA
cards:
- id: C001
title: "Map the problem and the verification path"
role: scout
column: doing
status: active
estimate: 2
priority: P1
next_action: "Read the auth code, write the exact command that proves signup works."
- id: C002
title: "Build the signup API"
role: worker
column: backlog
estimate: 5
priority: P1
depends_on: [C001]
verify: ["npm test -- signup"]
Commands
From the repo root, run each command with node scripts/cli.mjs <cmd>, or as plandeck <cmd> after npm link (a published npx plandeck release is planned). The commands below use the plandeck name for brevity.
plandeck init [dir]scaffoldsplan.yamlandplan.mdindir(default.).plandeck board <dir> [--once] [--json] [--port N] [--host H]starts the live board athttp://plandeck.localhost:41747/<slug>/. Editplan.yamland the board re-organizes itself over SSE.--oncegenerates the static app and exits. The board is Windows-safe: if41747lands in a Windows-reserved range and fails withEACCES, it falls back down a port ladder.plandeck check <dir> [--json]validates the plan and runs the completion gate. It exits1on a hard error (a parse error, a duplicate id, a dependency cycle, or a dangling dependency) and reports softer issues (more than one active card, aging) as warnings without failing. It reportsCOMPLETEonly when every card is done and the plan is structurally clean. This is the planning-with-files completion gate.plandeck next <dir> [--write] [--json]prints the ONE next action.--writeemitsNEXT.md.
The deterministic brain (no AI)
Everything Plandeck computes is a pure function over the yaml. There is no model call anywhere in it, so the output is identical every run and safe to trust after a reset.
- Ready detection: a topological pass, cycle-guarded. A card whose dependencies are all done becomes Ready. A card inside a dependency cycle is never marked Ready; the cycle is flagged instead.
- Critical path: the longest points-weighted dependency chain, drawn in gold on the board.
- Rollups: an honest percent complete from points, plus per-column point sums.
- Velocity and ETA: opt-in. Set
plan.velocityand Plandeck derives the ETA. It never manufactures one. - Aging: cards that sit too long in
doingorrevieware flagged fromupdated_at. next: exactly one tie-broken id. It prefers the active card, then a Ready card on the critical path, then priority, then how many cards it unblocks.
The working loop
- Start the plan: run
plandeck init ., or writeplan.yamlby hand. Giveplan.mda north star, the observable proof the work is done. - Open the board (optional, recommended):
plandeck board .. - Work the ONE active card, the one at
column: doing,status: active. Keep exactly one card active;plandeck checkwarns (it does not fail) if it finds more than one. - Record a receipt on that card:
result,summary,changed_files,commands,evidence. For a large receipt, writecards/<id>.mdand pointreceipt.noteat it. - Move the card to
column: done. - Run
plandeck next .. It names the next card. Set that cardstatus: active. Cards that were waiting on the finished one appear in Ready on their own. - Repeat from step 3.
- Gate completion:
plandeck check .. It reportsCOMPLETEonly when the plan is clean and every card is done.
After a /clear
This is the reason Plandeck exists. After any context reset, do not re-read the whole plan. Run:
plandeck next .
The terminal prints the single move: the card id, why it is next, and what is Ready now. The fuller breadcrumb (progress, what is blocked, the critical path, and the board URL) is written to NEXT.md by plandeck next --write, and automatically at plandeck board startup. NEXT.md is a tiny separate file, never an in-place rewrite of plan.yaml, so reading or writing it does not invalidate the model's prompt cache.
Example NEXT.md:
# ▸ NEXT
**C003 · Build the signup API** `P1` `critical path` `5 pts` `unblocks 1`
Resume the card already in progress.
- Progress: 15% (5/34 pts, 2/10 cards)
- Ready now: C005, C010
- Blocked: C007
- Critical path: C001 → C002 → C003 → C004 → C008 → C009 (17 pts)
- Live board: http://plandeck.localhost:41747/ship-onboarding-flow/
The board
The board renders six lanes: Backlog, Ready, In Progress, Blocked, Review, Done. In Progress is your doing column. Blocked is derived from unmet dependencies and status: blocked, so you never place a card there by hand. A progress ring shows points done over total with the ETA. A gold "Do this next" banner names the one move. The critical path is drawn as a gold chain. Each card shows its id, an estimate chip, role, priority, and risk badges, plus dependency indicators (⛓ after X, 🔓 unlocks N). Click a card for the full detail: dependencies met and unmet, the verify commands, and the receipt. It is theme-aware (auto, light, dark), Notion and Linear clean, with zero dependencies.
Where it runs
- Claude Code, as a skill and via the CLI, tested on Windows 11.
- Any agent that runs a shell and reads files can use the CLI (
plandeck board,check,next). - This file follows the open SKILL.md standard, so it loads anywhere that reads SKILL.md (Codex, Cursor, and others).
Lineage
Plandeck grows out of planning-with-files (MIT): durable plans on disk that survive /clear, plus the deterministic completion gate. The live board, the YAML reader, and the intelligence layer (dependencies, critical path, estimation, velocity, the next-action picker) are Plandeck's own, with zero dependencies.