by OthmanAdi
The visual Kanban for long-running AI agents. Watch your agent's plan organize itself: dependencies unlock into Ready, the critical path lights up, the one next move is obvious. Nobody wants to read a markdown plan.
# Add to your Claude Code skills
git clone https://github.com/OthmanAdi/plandeckplandeck is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by OthmanAdi. The visual Kanban for long-running AI agents. Watch your agent's plan organize itself: dependencies unlock into Ready, the critical path lights up, the one next move is obvious. Nobody wants to read a markdown plan. It has 51 GitHub stars.
plandeck's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/OthmanAdi/plandeck" and add it to your Claude Code skills directory (see the Installation section above). plandeck ships a SKILL.md manifest, so compatible agents can discover and load it automatically.
plandeck is primarily written in JavaScript. It is open-source under OthmanAdi on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh plandeck against similar tools.
No comments yet. Be the first to share your thoughts!
Unlocks once the catalog security scan passes (runs nightly).
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
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.
Reach for Plandeck when the work is multi-step and worth tracking:
/clear.Skip it for one-shot work:
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.
| file | role |
|---|---|
plan.yaml |
The single source of truth (the board). You read and write it; the board re-renders live. |
archive.yaml |
Completed cards moved out of the live plan. Their ids still satisfy dependencies. |
plan.md |
The charter a human or agent reads first: north star, why, constraints. |
cards/*.md |
Optional long receipts. plandeck check warns about unreferenced files and missing card references. |
NEXT.md |
Generated re-entry breadcrumb. A running board refreshes it when the generated content changes. |
.plandeck/ |
Derived continuity data: journal.ndjson, last-state.json, and the newest 20 valid plan snapshots. Gitignored. Never edit it by hand. |
plan.yaml.corrupt |
Content replaced by the most recent explicit doctor restore. Kept beside the plan for inspection and gitignored. |
.plandeck-board/ |
Generated static board app. Gitignored, rebuilt on every plandeck board. |
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. An omitted estimate counts as one point everywhere. |
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 and observed velocity for done cards. |
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 # optional points/day override; otherwise observed from completion history
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"]
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] scaffolds plan.yaml and plan.md in dir (default .).plandeck board <dir> [--once] [--json] [--port N] [--host H] [--actor NAME] starts or registers a live board. The first process becomes the hub and writes a temporary plandeck-hub.json breadcrumb. Later processes verify it through GET /api/boards, so they can find the hub on a fallback or ephemeral port, hand over their plan and actor, and exit. Every occupied ladder port is also probed for a compatible hub. Edit plan.yaml and the watcher records observed transitions, snapshots changed valid plans, refreshes NEXT.md only when its content changes, and streams the board plus hub index over SSE. --once generates the static app and exits.plandeck archive <dir> [--json] [--actor NAME] moves cards with status: done or column: done into archive.yaml and records lifecycle entries. It preserves all plan text outside the removed card ranges, writes each file through a temporary file plus rename, and refuses an id already present in the archive. Archived ids satisfy dependencies, and archived points remain in progress totals.plandeck check <dir> [--json] validates the plan and runs the completion gate. It exits 1 on 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, unreferenced note files, missing note files) as warnings without failing. Archived dependencies and note references count. It reports COMPLETE only when every live or archived card is done and the plan is structurally clean.plandeck next <dir> [--write] [--json] [--since HASH] [--actor NAME] observes the plan and prints the ONE next action. JSON includes stateHash; pass it back with --since to receive only an unchanged marker when no card id, effective column, or status changed. --write atomically emits NEXT.md with recent journal entries.plandeck journal <dir> [--since ISO] [--limit N] [--json] reads observed history newest-first. Without --since, it returns the newest 20 entries. A live hub exposes the same entries at GET /<slug>/api/journal.plandeck doctor <dir> [--restore TIMESTAMP|latest] [--json] [--actor NAME] reports plan health and last-known-good snapshots. Restore is never automatic. An explicit restore atomically replaces plan.yaml and saves the replaced content as plan.yaml.corrupt.The hub binds to 127.0.0.1 by default. Its POST /api/boards and DELETE /api/boards endpoints accept only application/json sent with an exact Host header for 127.0.0.1, localhost, or plandeck.localhost on the active port. A breadcrumb is only accepted after the hub handshake succeeds.
Plandeck remembers observed changes, not only current state. .plandeck/journal.ndjson is an append-only mission journal for plan loads, cards added or removed, effective column changes, authored status changes, receipt fingerprints, archive lifecycle events, and doctor restores. NEXT.md carries the newest five entries under Since you left in chronological order. Never edit the journal or .plandeck/last-state.json by hand. They are derived data, like NEXT.md.
If you know which model or agent you are, set PLANDECK_ACTOR or pass --actor to board, next, archive, or doctor. Flag value wins over the environment, and the fallback is unknown-agent. Actor attribution is best-effort and session-scoped. A board attributes every transition it observes to the actor that registered that plan most recently, regardless of which process changed the file.
A successful board refresh or plandeck next snapshots changed, valid plan.yaml content into .plandeck/snapshots/. The newest 20 are retained. plandeck check deliberately remains read-only and creates neither journal state nor snapshots. If plan.yaml stops parsing, run plandeck doctor <dir> first. Review its parse error and snapshots, then use --restore latest or a compact snapshot timestamp only when rollback is warranted. Restore is explicit every time and keeps the replaced content in plan.yaml.corrupt.
Polling agents should retain stateHash from plandeck next --json and pass it to the next call as --since <hash>. A matching hash returns only unchanged plus the hash. This avoids repeatedly loading the full next-action result when no card id, effective column, or status changed.
Known limits are intentional. The journal grows without rotation. Journal appends have no lockfile, so concurrent processes can rarely duplicate, miss, or interleave a line. The last-state file is only a cache, so this cannot corrupt plan.yaml. Continuity write failures warn once and never block board, next, or archive.
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.
plan.velocity is the configured rate. When it is unset, Plandeck derives an observed rate after at least three dated done or archived cards span one day or more. The payload reports a configured or observed basis.updated_at after one day blocked, two days in doing or review, or five days in ready.plandeck check warns about note files with no live or archived reference and card references whose note file is missing.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.Before the first observing command in a session, set PLANDECK_ACTOR to the current agent name when known.
plandeck init ., or write plan.yaml by hand. Give plan.md a north star, the observable proof the work is done.plandeck board ..column: doing, status: active. Keep exactly one card active; plandeck check warns (it does not fail) if it finds more than one.result, summary, changed_files, commands, evidence. For a large receipt, write cards/<id>.md and point receipt.note at it.column: done.plandeck next .. It names the next card. Set that card status: active. Cards that were waiting on the finished one appear in Ready on their own.plandeck archive .. Dependencies and progress remain correct, and hand formatting outside the archived card ranges stays untouched.plandeck check .. It reports COMPLETE only when the plan is clean and every live or archived card is done.If a read fails because plan.yaml is malformed or missing, run plandeck doctor . before attempting a manual reconstruction or git rollback.
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, recent Since you left history, and the board URL) is written to NEXT.md by plandeck next --write. A running board refreshes it after every valid plan change and skips an unchanged write. Read Since you left before resuming so you see the transition sequence that led to the current card. 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)
## Since you left
- C004 moved doing → blocked — claude-sonnet-4, 2026-07-13 14:02 UTC
- C004 moved blocked → doing — gpt-5, 2026-07-14 09:10 UTC
- Live board: http://plandeck.localhost:41747/ship-onboarding-flow/
The hub root lists every live board on one port, including archived cards in its done count. Its live dot changes state when SSE disconnects. Each 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 and its configured or observed velocity basis, and the header shows an archive count when present. A gold "Do this next" banner names the one move. The critical path is drawn as a gold chain. Each card shows its id, estimate, role, priority, risk, and dependency indicators. If YAML stops parsing, a red banner explains that the lanes are the last good state. It is theme-aware (auto, light, dark), Notion and Linear clean, with zero dependencies.
plandeck board, archive, check, next, journal, doctor).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.

The visual Kanban for long-running agentic work. Nobody wants to read a markdown plan or stare at raw HTML while an agent grinds for an hour. Plandeck turns your AI agent's plan into a live board that organizes itself: dependencies unlock into Ready, the critical path lights up in gold, estimates roll up, and the one next move is always obvious. It stays a plain file on disk underneath, so it survives /clear and a context reset.
npx skills add https://github.com/othmanadi/plandeck --skill plandeck
Zero dependencies, so there is nothing to install. Prefer a global plandeck command over node scripts/cli.mjs? Run npm link in the repo. A published npx plandeck release is planned.
=18">

AI coding agents lose the thread. After a context compaction or a /clear, an agent drops half the TODO list and stops mid-task, or it picks up the wrong thing next because the plan never said what was actually blocked. Flat markdown plans make this worse: a checklist cannot express that card C003 needs C002 done first, so "what should I do now" stays ambiguous even in popular planning tools. The agent guesses. The guess is often wrong.
Plandeck is the fix. It turns the plan into a structured, queryable task graph. Dependencies are explicit. A ready-queue is computed, not guessed. There is exactly one unambiguous next move, and it survives a context reset because it lives in a file on disk.
Plandeck grows out of planning-with-files (OthmanAdi/planning-with-files, MIT), which gave crash-proof markdown plans that survive /clear plus a deterministic completion gate. Plandeck keeps that DNA (durable plans on disk, and a check command that only says COMPLETE when the work truly is) and adds the thing a wall of markdown can never give you: a live visual board with a brain.
That brain is a deterministic intelligence layer with no AI and no LLM anywhere in it. It is pure functions over YAML: given the cards, it computes the ready-queue, the critical path, the rollups, and the one next action. Because it is pure, it is fully testable, and it gives the same answer every time. The board server, the YAML reader, and the rendering are all Plandeck's own, with zero dependencies.
# 1. Start the live board for the bundled example
node scripts/cli.mjs board examples/ship-onboarding-flow
# 2. Open the URL it prints, e.g.
# http://plandeck.localhost:41747/ship-onboarding-flow/
# 3. In another window, open the plan and mark a card done:
# edit examples/ship-onboarding-flow/plan.yaml
# set one card's column: done
# 4. Watch the board without touching the browser.
The payoff is immediate. When you set a card to done, every backlog card whose dependencies are now satisfied auto-promotes to Ready, the gold critical path recomputes and re-draws itself, the progress ring ticks up, and the "Do this next" banner points at the new single move. All of it streams over SSE. You never drag a card.
No Node handy? Open media/board-preview.html in any browser to see the board with the sample data baked in, no server required.
The first plandeck board process becomes a local hub. It publishes a small plandeck-hub.json breadcrumb in the operating system's temporary directory. Later commands verify that breadcrumb with GET /api/boards, register their plan with the confirmed hub, hand over their file watcher, then exit. This also discovers a hub that had to use a fallback or ephemeral port. A stale process id or port is ignored and normal port selection continues. Open the root URL printed by the command to see every live plan as a card with progress, lane counts, and its next action.
plandeck board ./plans/api
plandeck board ./plans/web
# Both boards now live on port 41747, with an index at the root URL.
Plan slugs stay readable. If two different roots both use slug: launch, their paths become /launch/ and /launch-2/. Registering the same root twice refreshes the existing board. When a plan disappears, the hub closes its watcher and SSE clients, then removes it from the index. Every occupied port in the Windows-safe ladder is checked for a compatible hub before Plandeck moves on.
Security posture: the hub binds to 127.0.0.1 by default. POST /api/boards and DELETE /api/boards require Content-Type: application/json and an exact Host header for 127.0.0.1, localhost, or plandeck.localhost on the active port. Other hosts are rejected. The temporary breadcrumb is only a discovery hint and is never trusted without the hub handshake.
Six lanes. A card lands in Blocked when a dependency is unmet or you set status: blocked (or column: blocked). Ready is computed, never placed by hand.
Six lanes carry the flow: Backlog, Ready, In Progress, Review, Done, plus a
Blocked lane. The dependency graph below is the bundled sample. You author only
the depends_on edges; Plandeck computes the rest.
flowchart LR
C001["C001 · Map onboarding"] --> C002["C002 · Design schema"]
C002 --> C003["C003 · Signup API"]
C002 --> C005["C005 · Welcome UI"]
C002 --> C007["C007 · Optional SSO"]
C002 --> C010["C010 · Update docs"]
C003 --> C004["C004 · Email verify"]
C004 --> C006["C006 · Analytics"]
C004 --> C008["C008 · E2E test"]
C005 --> C008
C006 --> C009["C009 · Launch audit"]
C008 --> C009
classDef done fill:#d7f0e0,stroke:#2f8f5b,color:#14532d,stroke-width:1px
classDef crit fill:#fbf1d6,stroke:#e0a100,color:#6b4e00,stroke-width:3px
classDef ready fill:#eaf6ef,stroke:#2f8f5b,color:#14532d,stroke-dasharray:5 3
classDef blocked fill:#fbe9e9,stroke:#c23b3b,color:#7a1c1c
classDef backlog fill:#f2f2ef,stroke:#c9c9c4,color:#3a3a38
class C001,C002 done
class C003,C004,C008,C009 crit
class C005,C010 ready
class C007 blocked
class C006 backlog
Green is done, the gold chain is the critical path (17 points, the longest one),
dashed green auto-promoted to Ready the moment C002 finished, and red is blocked.
plandeck next reads exactly this graph and points at the one card to do now.
Each card shows its id, an estimate chip, role / priority / risk badges, and dependency indicators (⛓ after X, 🔓 unlocks N). Click a card for full detail: dependencies met and unmet, verify commands, and the receipt.
A broken YAML edit does not wipe the board. Plandeck keeps serving the last good payload and places a red parse-error banner above the lanes. Fix plan.yaml and the live board resumes from the new state.
After a context reset, an agent runs plandeck next . (or reads NEXT.md) and instantly knows the one move to make. While a board is running, its watcher refreshes NEXT.md after every valid plan change and skips the write when the content is unchanged. The breadcrumb stays current without creating a watcher feedback loop. NEXT.md is a tiny separate file, never an in-place rewrite of the big plan. That is deliberate: rewriting the large plan on every step would invalidate the model's prompt cache, so the breadcrumb is kept small and standalone to stay cache-safe.
# ▸ 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)
## Since you left
- C004 moved doing → blocked — claude-sonnet-4, 2026-07-13 14:02 UTC
- C004 moved blocked → doing — gpt-5, 2026-07-14 09:10 UTC
- Live board: http://plandeck.localhost:41747/ship-onboarding-flow/
Every one of these is a pure function of the YAML, cycle-guarded, and tested. No AI.
depends_on cards is done. A card caught in a dependency cycle is never marked Ready, and the cycle is flagged instead.plan.velocity is the configured points-per-day rate. When it is unset, Plandeck derives an observed rate once at least three dated done or archived cards span one day or more. The payload labels the basis as configured or observed.updated_at after one day blocked, two days in doing or review, or five days in ready.plandeck check warns when a cards/*.md file has no live or archived card reference, or when a card references a note file that does not exist.Plandeck remembers observed change as well as current state. Each successful board refresh or plandeck next observation compares the live cards with .plandeck/last-state.json and appends column, status, receipt, card, and lifecycle events to .plandeck/journal.ndjson. Receipt events contai