Skip to content
| Marketplace
Sign in
Visual Studio Code>Visualization>Work PlanNew to Visual Studio Code? Get it now.
Work Plan

Work Plan

stylusnexus

|
8 installs
| (0) | Free
Browse and manage GitHub issues as tracks — dependency graph, per-track detail, and read/write (slot, move, reconcile, close) in the sidebar.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Work Plan — VS Code Extension

The human face of the work-plan CLI. One engine, two faces: the extension is a UI — every read goes through work-plan export --json and every write shells to a work-plan subcommand, so there's no planning logic duplicated in TypeScript and no drift from the CLI's rules.

What it does

See

  • A sidebar tree (repos → tracks) showing the live state of every tracked GitHub repo — status dot, open count + a closed/total count (#220), blocked/next hints, a ⚠ badge on public repos, a per-track visibility × tier badge (🔒 private / 🌐 public repo, ☁ shared tier) that flags the one exposed state — a plan committed to a public repo's shared tier is world-visible — and a · N references count (#458) with a tooltip listing which issues are owned by other tracks, for a track that's added cross-track coordination references. The shared tier can be pinned to a dedicated canonical plan branch (set up with the CLI's plan-branch command) so planning lives off your code branches and out of PR/deploy diffs; the viewer reads it transparently from any checkout. The Work Plan activity-bar icon carries a badge (#215) — blocked-track count, falling back to total open — for at-a-glance status without expanding the view.
  • A Mermaid dependency graph webview + per-track detail panel (issue table — capped at 50 rows with a collapsible overflow — blockers, depends-on chips, ordered next-up, a Plan affordance, a thin open/closed progress bar #220, and a separate Referenced issues table (#458) for cross-track coordination refs — excluded from the track's own status/progress, capped and collapsible the same way as owned issues) — with a focus toggle that zooms in on the selected track, and a full map scoped to the track's repo. Track and issue identity stays repo-qualified throughout, so same-named tracks and same-numbered issues in different repos remain separate in the graph, panel, and write actions (#430). The graph has zoom / pan / fit-to-width controls (scroll-wheel + drag, or the header buttons) and Export as SVG / PNG (#216), so a dense map stays navigable.
  • A Plan link on the detail panel (#285): when a track declares its plan/spec doc (plan: in frontmatter), the panel shows that doc's execution badge — verdict glyph + files/phases, with ✋ confirmed / ⚠ lie-gap / stalled markers — as a one-click button that opens the plan. The badge is computed by the same evaluator as the Plans view, so the two never disagree; only the declared link is shown (no fuzzy name-matching). Links that are missing, symlinked, or resolve outside the configured repository stay inactive and read as a quiet "not found" note.
  • Lenses (filter by milestone / status — active, shipped, parked — / blocked) and sort (default / blocked / most-open / name). Each milestone band in the detail panel has a filter button that applies that milestone's lens to the whole view (the band header itself collapses); the resulting filter is clearable straight from its confirmation toast. Repo auto-focus (#357, opt-in): turn on workPlan.autoFocusRepo (off by default) and the repo lens is selected automatically when the open workspace folder is a configured repo, so you start scoped to the project you're in — a manual lens choice always wins. The Select View picker has a single repo-scope toggle at the top — Focus current repo ↔ Display all repos — that flips scoping and updates workPlan.autoFocusRepo to match.
  • An "Untracked" bucket under each repo: open GitHub issues that no track references — click to open on GitHub, or right-click to slot one into a track. For a registered repo with no tracks (whose issues export doesn't pull automatically), a Fetch open issues affordance under the repo pulls them on demand (#303) and renders them as that repo's Untracked bucket — also available as a right-click on the repo to refresh.
  • Auto-slot suggestions (#241, opt-in). Right-click the Untracked bucket (or a repo) → Suggest Tracks for Untracked Issues scans the repo and relays an AI prompt to the Work Plan output channel; ask Claude to write the suggestions JSON to the path shown, and a Suggested sub-bucket (high-confidence, clear-margin) and a Needs review sub-bucket (lower-confidence / close calls) appear under Untracked. A Suggested issue is a one-click Accept (pick/confirm the track, then it's slotted with a compare-and-swap staleness guard so a track that changed since the scan re-offers instead of clobbering); a Needs review issue just opens the issue. Accept All and Dismiss / Dismiss All round it out. Each item leads with the rationale + target track; the confidence percentage lives in the tooltip. No Claude session? Suggest Tracks (offline heuristic) (#373) scores matches locally (milestone / label / keyword overlap) and fills the buckets immediately — flagged "heuristic" and lower-trust, but it works standalone. Enable via workPlan.autoSlotSuggestions; tune the one-click cutoff with workPlan.autoSlotConfidenceThreshold (default 0.7).
  • A read-only tier-duplicate advisory (#361): if a track is left in both a repo's shared .work-plan/ and the private notes tier (a stray copy after promotion), a ⚠ row appears under the repo — N tracks duplicated across tiers — naming the dedupe-tiers command to resolve it (with a safe-vs-needs-review breakdown in the tooltip). It surfaces a condition that otherwise only warns to stderr; the actual cleanup stays in the CLI, so the viewer never deletes anything.

Act — every action runs the CLI under the hood:

  • Edit fields (status / priority / milestone / blockers / next-up / cross-track dependencies), Set next-up, Slot an issue, Add Cross-Track Reference (#458 — right-click a track → adds a coordination reference to another track's issue via github.references, without taking ownership; goes through the same public-repo confirm flow as any other write), Move Issue from Track (source-first: pick a destination track in the same repo), Close a track (shipped / parked / abandoned), Refresh a track body, Reconcile (draft preview + one-click apply), Run hygiene, New track, and Push to Shared Tier (promote a private track to the repo's shared plan branch — confirm modal names the repo and warns when it's public/world-visible; #306).
  • Track lifecycle — Mark / Archive / Delete (#329/#328/#330). Right-click a track → Mark for Cleanup flags it (🧹) as a retirement candidate (reversible); Archive Track sets it aside into archive/parked/ (reversible — a Show Archived Tracks title-bar toggle reveals archived tracks greyed with 📦, right-click → Unarchive Track to restore); Delete Track… removes the track's .md behind a hard modal that states GitHub issues are untouched and the recoverability (notes-vcs undo for private, git history for shared) — a shared track delete additionally requires typing the track name to confirm. None of these touch GitHub issues.
  • Public-repo confirm modal. Before any write into a repo that's public (or whose visibility gh can't determine), the extension surfaces the CLI's heads-up as a "Write anyway / Keep private" dialog and re-invokes with a confirm token — the leak guard, moved from a terminal prompt to a GUI. Private repos write straight through with no friction.
  • Close an issue on GitHub (#305). Right-click an Untracked issue → Close Issue on GitHub…, or use the ⊗ action on a tracked issue row in the detail panel. Pick a reason (Completed / Not planned), optionally add a closing comment, and confirm a mandatory "Close on GitHub? — cannot be undone" modal (fires on every close, public or private). For the common case where a PR merged to dev left its issue open.
  • Mark / clear in-progress on GitHub (#271). Use the in-progress toggle on a tracked issue row in the detail panel to add or remove the work-plan:in-progress label. Public repos go through the confirm-token modal. The viewer also derives in-progress automatically from a hot feat/<n>-/fix/<n>- branch — the label is for issues with no hot branch yet. These two actions are the only GitHub writes the extension makes; everything else is read-only on GitHub.
  • Archive shipped plans. Right-click a ✅ shipped plan → Archive Plan… (moves it to archive/shipped/), multi-select several (Cmd/Ctrl/Shift-click) → Archive Plan… to archive the batch behind one confirm, or right-click a repo → Archive shipped plans… to sweep every clean shipped plan at once. Archived plans live in a collapsed Archived (N) folder per repo — right-click one → Restore to Live to move it back out of archive/ (#388). Unverified (lie-gap) shipped plans are archivable individually (with a warning) and excluded from the repo-wide sweep by default. The toast says whether each archive/restore is a staged git mv (a tracked doc — commit & push to share it) or a local filesystem move (a gitignored/untracked doc — moved on disk, not git-tracked) (#399).

Get started from empty — a cold-start a new user can drive without the CLI:

  • Not signed in to GitHub? Because all issue data comes through the GitHub CLI (gh), the view fast-fails instead of showing a misleadingly empty tree: a "Not signed in to GitHub" banner replaces the tracks, with a Sign in to GitHub button that opens gh auth login in a terminal and a Retry once you're done. A distinct "GitHub CLI not found" banner covers the case where gh isn't installed (with an install link). A third "Couldn't verify GitHub sign-in" banner covers the case where the work-plan CLI ran but returned no usable result — a missing CLI dependency (gh / git / yq), not a GitHub problem — so a missing tool no longer masquerades as "not signed in" and sends you into a futile sign-in loop. Signed-in users never see any of this.
  • When you have no repos yet, the tree shows a welcome with Add a repo and Set notes location buttons.
  • Add Repo runs init-repo; Set Notes Location runs set-notes-root so your private track notes live wherever you choose (not just the hidden default). Config itself is auto-seeded by the CLI on first run.

A loading bar shows while the CLI fetch runs, and concurrent refreshes are coalesced (single-flight) so a burst of triggers can't spawn overlapping fetches.

Screenshots

Repos → tracks in the Work Plan sidebar Repos → tracks: status dots, open counts, and a ⚠ badge on public repos.

Mermaid dependency graph and track detail The dependency/flow graph and per-track detail panel — showing blockers, cross-track dependency chips, next-up flow, and per-issue move buttons.

Public-repo confirm modal The "Write anyway / Keep private" modal before any write into a public repo.

The Untracked bucket Open issues that no track references — slot one in with a right-click.

Cold-start onboarding Get started from empty: add a repo and choose where your notes live — no CLI needed.

Command menu The ⋯ menu: New Track, Add Repo, Set Notes Location, Run Hygiene (track verbs are on each track's right-click menu).

Install

  1. The extension — search "Work Plan" (publisher stylusnexus) in the Extensions view, or:
    • VS Code: code --install-extension stylusnexus.work-plan-viewer
    • VS Codium / Cursor / Windsurf (Open VSX): ovsx get stylusnexus.work-plan-viewer
  2. The CLI (the extension drives it) — npm install -g @stylusnexus/work-plan, or any method in the toolkit README.
  3. If work-plan isn't on your editor's PATH (common when VS Code is opened from the Dock/Finder, not a terminal), set workPlan.cliPath to an absolute launcher path and reload the window.

WSL / Remote-SSH / dev containers: install the CLI inside the remote, not on your local machine. If the window shows WSL: <distro> (or a remote) at the bottom-left, the extension runs there and looks for work-plan / gh / python3 / yq on the remote PATH — a Windows-native install is invisible to it. Run npm install -g @stylusnexus/work-plan in the WSL/remote terminal and reload the window. (gh auth login is also per-environment — sign in inside WSL so the WSL gh the extension reads is authenticated.)

Requirements

  • The work-plan CLI must be on your PATH (or set workPlan.cliPath). The extension checks the CLI version at activation and points you at an update if it's too old to have the read/write surface it needs.
  • VS Code 1.90.0 or later.

Commands & controls

Every action runs the CLI under the hood. Commands live where they're relevant — the title bar (icons + the ⋯ overflow), a track's right-click menu, and the command palette.

View controls — filtering & sorting (title bar)

Control What it does
Refresh (↻) Re-fetch live state from the CLI and redraw the tree + graph.
Select View (filter icon) Filter the tree and graph by a lens: a milestone, a status (Active / Shipped / Parked), or only blocked tracks. Choose "All tracks" to clear the filter. A single repo-scope toggle sits at the top: Focus current repo when showing every repo, flipping to Display all repos once focused (shown only when the open workspace folder maps to a configured repo). Choosing it also sets workPlan.autoFocusRepo, so the view's default scope follows your last choice.
Sort Tracks Order tracks within each repo: Default (discovery order), Blocked first, Most open, or Name (A–Z).
Daily Brief Multi-track daily snapshot across all your tracks — what's in-progress, closure-ready, and up next — relayed to the Work Plan output channel. Read-only. Equivalent to work-plan brief. Also in the command palette.
Search Issues Find issues by title across every track (and the Untracked bucket). Type a term with optional % wildcards — %depends% (contains), fix% (starts-with), %audit (ends-with); a bare word matches anywhere. Case-insensitive. Matches open in a dedicated Issue Search tab (grouped by repo, open issues first); click a row to open the issue on GitHub, or use the per-row reveal button to jump to its track in the tree. Searches the loaded snapshot — a Refresh & re-run link in the results re-pulls and re-searches.
Open Settings (⚙ gear, last icon) Open the Settings UI scoped to this extension's settings (@ext:stylusnexus.work-plan-viewer) — workPlan.stallDays, workPlan.plansAutoRefresh, etc. — without searching. Also Work Plan: Open Settings in the command palette.

When a lens or non-default sort is active, it's shown inline next to the Tracks view title (e.g. milestone: v2.0.0 · blocked-first) so the active filter is always visible — no need to reopen the quick-pick to remember why tracks are hidden. The label clears once you return to "All tracks" with the default sort.

Track actions (right-click a track)

The menu is organized by how often you reach for each action — the daily-driver verbs are surfaced at the top, the rarely-touched and config actions are tucked behind a More Actions ▸ submenu, and the one genuinely destructive action (Delete) is fenced alone at the very bottom. Order top to bottom: open the file → session verbs → next-up → issues → refresh → lifecycle (Close / Archive — both reversible or archived, not deletions) → More Actions ▸ → a Help link → Delete. A What Do These Actions Do? entry opens this section in your browser.

Command What it does
Open Track File (.md) Open the track's underlying .md in an editor tab — for hand-edits the other verbs don't cover. Opens beside the active editor in preview mode, and reveals an already-open tab instead of duplicating it. Also available as an Open file button in the detail panel's header (disabled, with a tooltip, when the file path isn't resolvable — e.g. a remote/WSL workspace where the CLI's path doesn't match the editor's filesystem). Distinct from a single left-click on the track, which opens the Work Plan detail panel ("Show in Work Plan"), not the file.
— separator —
Where Was I? (Re-orient) Print the track's paste-ready ~15-line "where it stands" snapshot — priority, milestone, last session, open items — to the Work Plan output channel. Read-only. Equivalent to work-plan where-was-i <track>.
Wrap Up Session — Log & Handoff Append a session-log entry (derived from git + GitHub activity since the last handoff) and stamp last_handoff, then relay the paste-ready fresh-session prompt to the output channel. A public-repo write is gated by the leak-guard modal. Equivalent to work-plan handoff <track>.
— separator —
Set Next-Up (pick manually)… Set the ordered next-up issue list and append a session-log entry (runs handoff --set-next, which also refreshes the status table). Pick the track's open issues one at a time, in priority order (pick 1st, 2nd, … then Done) — pick order is the next-up order. To set next_up as a plain field with no session log, use Edit Track Fields → next_up instead.
Set Next-Up (auto-suggest)… The sibling that lets the tool choose. Native equivalent of the CLI's handoff --auto-next (#274): reads an algorithmic priority-sorted suggestion (open, non-blocker issues, sibling-claimed ones dropped) via the read-only handoff --suggest-next, shows it pre-checked in a multi-select QuickPick (order = priority order), and on confirm writes via the same audited handoff --set-next path (public-repo confirm modal, session log). Uncheck any candidate to drop it. No CLI TTY prompt.
— separator —
Add Issue to Track (owned)… Add a GitHub issue the track owns — it counts toward the track's open/closed progress. Pick from the repo's open issues (#142 Add SSO, filterable; issues already in the track are excluded) — or choose Enter an issue number… to type one not in the list. Falls back to a plain number prompt if the repo's issues can't be fetched. (Contrast Reference Issue from Another Track under More Actions, which links an issue without owning it.)
Move Issue to Another Track… Move an issue to another track in the same repo. Pick the issue from the source track's list (#87 Fix auth, filterable by typing — no number to recall), then pick the destination.
— separator —
Refresh Track from GitHub Pull live GitHub state into the track's status table. Run this after closing or merging issues — it re-fetches each issue's open/closed state and rewrites the status cells, refreshing the dependency graph and next-up display. Equivalent to work-plan refresh-md <track> --yes.
— separator —
Close Track… Mark it shipped / parked / abandoned (with an optional wrap-up note); shipped & abandoned get archived. Abandon asks for confirmation first (it's the destructive close). Reversible via Restore from Archive on the archived track.
Archive Track (Set Aside) Set the track aside reversibly — it drops out of the active views but is kept, not deleted. Restore it later with Restore from Archive. Distinct from Close (a lifecycle verdict) and Delete (permanent).

More Actions ▸ (rarely-touched and config actions)

Command What it does
Edit Track Fields (status, milestone…) Change one field — status, launch priority, milestone, blockers, or next-up.
Change Next-Up Ranking… Configuration, not a next-up list edit. Sets the ranking preset (flow / priority-driven / backlog) that Set Next-Up (auto-suggest) uses to order its suggestion — it does not change the current next-up list. Set once and forget. Equivalent to work-plan set-next-up <track>.
Reference Issue from Another Track… Link an issue for cross-track coordination without taking ownership — it's shown separately and excluded from this track's status and progress counts (contrast Add Issue to Track (owned)). Niche; for coordination scope only.
Preview Label Drift (label-driven tracks)… Only useful for tracks whose membership comes from a GitHub label. Drafts where the track's frontmatter membership disagrees with those labels, then offers an Apply reconcile action that writes the ADDs/MOVEs (work-plan reconcile <track> --yes) without a terminal trip — local frontmatter only, MOVEs into public tracks are self-skipped, and a public-repo write trips the leak-guard modal (#221). If you add issues to tracks by hand (via Add Issue to Track), there's no label to drift from — use Refresh Track from GitHub instead.
Publish to Team (Shared Tier)… Promote a private track to the shared tier so teammates see it — moves the file into the repo's .work-plan/ and pushes it on the plan branch. Requires a local clone + a configured plan branch. Pushing to a public repo is confirm-token gated. Equivalent to work-plan push-track <track>.
Rename Track… Rename the track's slug — moves its file and updates the frontmatter. Enter a new lowercase slug, then confirm; a public-repo write is additionally gated by the leak-guard modal.
Mark as Stale 🧹 Does not delete anything. Writes a reversible cleanup_candidate flag so the weekly hygiene sweep surfaces the track (🧹) as worth reviewing later — a sticky-note, not a shredder. Clear it with Clear Stale Flag.
Clear Stale Flag 🧹 Remove the "stale" flag set by Mark as Stale.

Help & destructive

Command What it does
What Do These Actions Do? Open this documentation section in your browser — the reference for every right-click action, including the "when do I use it?" cases the short labels can't spell out.
Delete Track (Permanent)… Permanently delete the track file — irreversible, fenced alone at the bottom of the menu. For setting a track aside reversibly, use Archive Track or Close Track instead.

On an archived track, right-click gives Open Track File (.md), Restore from Archive (the inverse of Archive / Close), and Delete Track (Permanent).

(On an Untracked bucket item, right-click gives Add Untracked Issue to Track — file a loose issue into a track.)

Plans view

A second tree below the Tracks view, in the same Work Plan container. Where the Tracks view is about issues, the Plans view is about documents — the plan/spec docs in your repos and their plan-status health. Its reason to exist is to catch the plans that started executing and then drifted off — half-built work scattered across repos that no issue-tracker view surfaces. It's read-only except for one frontmatter-only write (Confirm Verdict, below).

Every plan row carries a verdict icon. Because a panel full of red ✕'s reads as "errors" until you know what they mean, the icons are decoded by a title-bar ℹ️ legend button (Show Plan Icon Legend) that opens a self-demonstrating list — each row shows the real icon, its plain name, and a one-line meaning — and the hover tooltip leads with the same plain label (#348):

Icon Verdict Means
🕐 clock Stalled A partial plan whose declared manifest files have gone cold — no commit touched them within the staleness window. "Started executing, drifted off." (Reads the manifest's git activity, not the plan doc's own date — that's null for gitignored docs.)
✕ error Unverified (lie-gap) Scored shipped by its file manifest, but fewer than a quarter of its own phase checkboxes are ticked — marked done while its phases were left open. Often a false alarm: the work genuinely shipped, nobody ticked the boxes. Confirm Verdict (below) silences it.
issue-reopened Drifted You stamped a verdict baseline on this plan, and the live verdict has since diverged from it (e.g. a once-shipped plan whose declared files were deleted → now partial). Shows ⚠ drifted (shipped → partial). Opt-in per plan (only stamped plans can drift), and a Confirm Verdict override suppresses it.
● circle-filled In progress A partial plan recently touched — actively in progress.
✓ pass-filled Shipped Done — phases checked and declared files present.
⊘ circle-slash Abandoned Marked dead — intentionally dropped.
? question Unknown No clear verdict (foreign or manifest-less doc).
○ circle-outline Acknowledged Dimmed — you acknowledged or confirmed this row, so it's muted (a modifier on any of the above).

The first three are made loud; the rest stay quiet. Every state stays distinguishable by icon shape, never colour alone (#208).

A plan whose declared manifest points outside the repo (an absolute, ~, ..-escape, or junk / path — usually a typo or misfiled plan) also gets a read-only ⚠ N off-tree path marker, with the offending paths named in its tooltip. These silently drag the file score down, so surfacing them explains a verdict that looks worse than the work. Read-only — the viewer never edits a manifest.

  • Lazy scan. Each repo scans its plans on first expand, so opening the view is cheap. A title-bar "Scan All Plans" command opts into a cross-repo sweep that builds a stalled roll-up across every repo (bounded-concurrent, results stream in as repos finish).
  • Auto-updates on git activity (#287). Once a repo is scanned, the view watches its .git refs and re-scans that repo when a commit lands — so committing a stalled plan's declared files clears its stalled state without a manual Refresh (debounced to ride out a rebase; only expanded repos are watched). Time-relative staleness (a plan going cold as days pass) re-evaluates on view/window focus. Toggle with workPlan.plansAutoRefresh (default on).
  • Click to open. Clicking a plan opens its .md in an editor tab.
  • Acknowledge / dismiss. Right-click a stalled or dead plan → Acknowledge (stop flagging) to stop it surfacing as loud — it's demoted, not hidden, and the ack persists per machine (in workspaceState, off in git). A title-bar Toggle Show Acknowledged button brings the acknowledged ones back into view. Multi-select several stalled/dead plans (Cmd/Ctrl/Shift-click) to acknowledge them in one batch (#396).
  • Acknowledge & Save to Doc (writes frontmatter). Right-click → Acknowledge & Save to Doc persists the ack durably as acknowledged: true in the plan's frontmatter (#286) — committed with the repo and shared with teammates, unlike the per-machine ack above. Gated by the same file-naming modal + public-repo confirm as Confirm Verdict; a saved-acked plan reads ✅ ack'd (saved). Clear Saved Acknowledgment removes it. The per-machine Acknowledge stays the default; this is the opt-in shared variant. Multi-select several to save the ack on a batch behind one confirm (#396).
  • Stamp Baseline — Watch for Drift (writes frontmatter). Right-click → Stamp Baseline records the plan's current verdict as verdict_baseline in frontmatter (#286). The row then carries a faint 📌 baseline while it still matches, and goes loud — ⚠ drifted (shipped → partial) — if the live verdict later diverges (a once-shipped plan whose files were deleted/moved). Re-stamping accepts the new reality; Clear Baseline stops watching; a drifted row can be acknowledged like any loud signal. Same file-naming + public-repo gates. Multi-select several plans to stamp a baseline on the batch behind one confirm (#396).
  • Confirm Verdict (writes frontmatter). Right-click a plan → Confirm Verdict…, pick shipped / partial / dead, and the extension writes a verdict_override into the doc's YAML frontmatter — behind a mandatory modal that names the exact file and states the write touches only frontmatter (never the prose body, checkboxes, or declared-file manifest). plan-status then pins that verdict and the lie-gap goes quiet; the row shows a ✋ confirmed marker. Clear Confirmation removes it. This is the only viewer-initiated write to a plan doc; unlike Acknowledge (which persists per-workspace, off in git), it's a real frontmatter edit you commit. On a public repo it also passes through the public-repo confirm modal. Single-only (unlike Acknowledge / Save-to-Doc / Stamp Baseline): it picks one verdict per doc, so it isn't batched across a multi-selection (#396).
  • Every configured repo with a local clone is listed — not just repos that already have tracks. A freshly registered repo (with a local path) shows up here ready to scan, so plans aren't hidden behind having a track first.
  • No local clone. Repos without a local checkout show a greyed "no local clone" state — there's no working tree to read manifest git activity from.
  • workPlan.stallDays setting controls the staleness window applied to the displayed state — Match CLI (the default, follows the CLI's own threshold) or a fixed 14 / 30 / 45 / 60 / 90 days. Changing it re-evaluates what's stalled instantly, no refetch.

Read-only on git apart from a few writes: the frontmatter-only Confirm Verdict write above, Archive Plan… / Archive shipped plans… (a git mv of a shipped doc into archive/shipped/), and Restore to Live (the inverse git mv back out, #388). No stamp or issue-opening from the GUI — those stay CLI-only. Track ↔ plan navigation (jumping from a track to its plan and back) is tracked in #285.

Create & setup (the ⋯ overflow)

Command What it does
New Track Create a new track for a repo (pick the repo + a slug).
Add Repo Register a repo — a key, the org/repo slug, and an optional local checkout path. The repo appears in the sidebar straight away even with no tracks; right-click it → New Track to start. The local path is what enables plan scanning (the Plans view), so add it when you have a checkout. Re-running Add Repo on a key that's already registered offers to set/update its local path instead of erroring — the fix for "I skipped the path the first time."
Clear Local Path (right-click a repo) Drop a repo's saved local checkout path while keeping it registered — handy when the checkout moved or you no longer want it scanned. Asks first; the repo and its tracks stay put.
Remove Repo (right-click a repo) Unregister a repo so it leaves the sidebar and brief. Config-only: your notes, tracks, and the local clone are left untouched (any notes folder or tracks that referenced it are simply orphaned — clean them up by hand if you want). Asks for confirmation first.
Set Notes Location Choose where your private track notes live (the CLI's notes_root).
Run Hygiene Weekly all-in-one cleanup. Three steps: ① refresh every active track's status table from GitHub, ② reconcile track frontmatter against GitHub labels, ③ scan for duplicate issues. Use "Sync Issue States from GitHub" instead when you just need to update one track after closing issues.

Before any write into a public (or unknown-visibility) repo, a "Write anyway / Keep private" modal appears — the public-repo leak guard, surfaced as a dialog. Private repos write straight through.

GitHub access is read-only by default, with two explicit opt-in writes. All issue data comes from read-only gh CLI calls. Every routine write — status table updates, frontmatter, session logs — goes to your local markdown files only. The two GitHub writes the extension can make are both user-initiated and gated: Close Issue on GitHub (mandatory confirm modal on every close) and Mark/clear in-progress (adds or removes the work-plan:in-progress label; public-repo confirm-token gated). Nothing else touches GitHub state.

Configuration

Setting Default Description
workPlan.cliPath "work-plan" Path to the work-plan CLI launcher. Read at activation — reload the window after changing it.
workPlan.expandReposByDefault false Expand all repo groups on load (a single-repo workspace always expands).
workPlan.autoFocusRepo false When the open workspace folder is a configured repo, default the Tracks lens to that repo (resolved by clone path, then git remote) so you don't read another repo's issues by accident. Off by default — the Tracks view shows every repo. A manual lens choice always wins, and the Select View → Focus current repo / Display all repos toggle flips scoping any time — and rewrites this setting to match, so your last choice becomes the default.
workPlan.autoRefreshInterval 0 (off) Re-poll the CLI silently in the background. Options: 0 (off), 30 s, 60 s, 5 min, 15 min. Useful when teammates are pushing shared-track changes and you want the tree to stay current without manual refreshes.

Config-drift indicator

On activation, the extension silently checks for config drift (a renamed local folder or GitHub repo that config.yml no longer matches, an invalid notes_root, a stale per-track repo slug, etc.). If it finds anything, a ⚠ Work Plan: N config issues item appears in the status bar — click it to see the details in the "Work Plan" output channel. Nothing appears when everything's clean. Run work-plan doctor --fix from a terminal to correct the safe subset automatically, then reload the window.

Build & run

# From the vscode/ directory:
npm install          # esbuild, TypeScript, @types/vscode, mermaid
npm run typecheck    # tsc --noEmit
npm test             # node --test (pure modules; no VS Code host needed)
npm run build        # compiles extension + copies the Mermaid bundle into dist/

Then launch the extension host to try it live (the last arg is the workspace folder to open, which carries workPlan.cliPath):

code --new-window --disable-extensions --extensionDevelopmentPath=./vscode <workspace-folder>

The build step copies node_modules/mermaid/dist/mermaid.min.js into dist/ automatically. dist/ is gitignored — the Mermaid file is never committed.

Architecture

Pure logic lives in vscode-free modules (model.ts, cli.ts, treeModel.ts, write.ts, singleFlight.ts, webview/graph.ts/detail.ts/html.ts/lenses.ts) and is unit-tested by Node's native test runner — no VS Code host required. Only tree.ts, webview/panel.ts, and extension.ts import vscode. The write layer maps a UI action to CLI argv in write.ts (actionToArgs + the confirm-token flow in executeWrite); extension.ts is the thin glue that gathers input and shows dialogs.

How Mermaid is loaded

The webview loads dist/mermaid.min.js — the UMD bundle from Mermaid 11 (mermaid@^11.15.0): a single self-contained file (~3.2 MB) that exposes a global mermaid via a classic <script nonce="…" src="…"> tag (not the ESM build, which needs ~160 chunk files). If the graph fails to render, verify dist/mermaid.min.js was copied (ls vscode/dist/) and that the webview CSP allows 'wasm-unsafe-eval' (Mermaid needs it). The webview uses a strict CSP, a per-document nonce, and a single acquireVsCodeApi() call.

Status

Published — v0.19.9 on the VS Code Marketplace and Open VSX (publisher stylusnexus).

  • v0.19.9 — Clarifies and reorganizes the track right-click menu. The 18 flat, mechanism-named actions are now grouped by how often you use them, with clearer intent-first labels: Sync Issue States from GitHub → Refresh Track from GitHub, Mark for Cleanup → Mark as Stale 🧹 (moved out of the destructive group — it deletes nothing), Set Next-Up Order → Change Next-Up Ranking (it's config, not a list edit), and the two next-up methods paired as Set Next-Up (pick manually / auto-suggest). The rarely-touched and config actions (Edit Fields, ranking, cross-track reference, label-drift, publish, rename, stale flags) move into a More Actions ▸ submenu; Delete Track (Permanent) is now the only item in the fenced danger zone; and Close / Archive move to a reversible "lifecycle" group. Adds a What Do These Actions Do? help entry that opens the docs, and a track hover tooltip showing the next-up glance plus a left/right-click hint. Extension-only; CLI unchanged.
  • v0.19.8 — Follow-up wording fix for a convergence track's tree row: the previous N open · X references (Y open) label used "open" for two different scopes (issues the track owns vs. issues it references elsewhere) with no visual cue for the shift, reading as self-contradictory at a glance. Reworded to N owned · Y of X referenced still open, scoping each number to a distinct noun; the tooltip's fuller explanation is unchanged.
  • v0.19.7 — Fixes a misleading tree-row count: a convergence track that owns zero issues but has open cross-track references (github.references) showed only a bare 0 open · N references, which reads as "nothing to do" even when references are still open. The row now shows 0 open · N references (M open), and the tooltip states how many referenced issues are open; the underlying demote-to-reference migration CLI command (#462) is what surfaced the gap.
  • v0.19.6 — Adds cross-track issue references (#458): a track can now point at an issue owned by another track for coordination visibility — via github.references — without taking ownership of it (github.issues stays the sole ownership list slot/move/reconcile use). Right-click a track → Add Cross-Track Reference; the sidebar tree shows a · N references count, and the detail panel gets a separate Referenced issues table excluded from the track's own status/progress. Paired with a CLI release that adds batch-slot --reference and fixes a data-loss bug where dedupe-tiers --apply could delete a private track whose only content was cross-track references, plus a missing CAS staleness guard on reference writes, a duplicate-entry bug, and a next_up-filtering bug.
  • v0.19.5 — Fixes a bug where a failed GitHub open-issues fetch (outage, auth lapse, rate limit) silently looked like "zero untracked issues" instead of an error. The repo tree row now shows a "⚠ GitHub fetch failed" warning and retains its last-known Untracked bucket instead of implying full coverage; Suggest Tracks warns distinctly on a fetch failure too. Paired with a CLI fix (#454) that stops converting fetch failures into indistinguishable empty results.
  • v0.19.4 — Adds a CHANGELOG.md so the Marketplace listing shows a proper Changelog tab (seeded from the last 3 published versions), and republishes with the paired CLI's yq-capability installer fix (#433) plus brief/export GitHub-read batching for a faster daily brief and viewer refresh (#420, #424, #422). Extension code unchanged.
  • v0.19.3 — Config-drift detection (#439): a new quiet status-bar indicator silently checks, once at activation, whether config.yml still matches reality — a renamed local folder or GitHub repo, a broken local path, duplicate entries, an invalid notes_root, an orphaned notes folder, or a stale per-track repo slug. Shows ⚠ Work Plan: N config issues only when something's actually wrong; click it for the details in the "Work Plan" output channel. Pairs with the CLI's new work-plan doctor [--json] [--fix] — --fix corrects the two safe cases (a GitHub-confirmed rename, a stale track slug) automatically. CLI floor raised to 2026.07.15.
  • v0.19.2 — Security and identity hardening. Tracks and issues now remain repo-qualified end to end (#430), preventing same-named tracks or same-numbered issues in different repositories from colliding in graph state, detail selection, or write actions. Declared plan links are opened only when the repo-relative file resolves safely inside the configured clone; absolute, traversal, missing, and symlinked escapes stay inactive (#195). The paired CLI release also contains shared-tier containment, hard-link-safe plan stamping, and content-verified installer ownership (#431).
  • v0.19.1 — Maintenance. Fixes a brief crash (#417): brief / brief --repo=<key> raised TypeError: '<' not supported between 'str' and 'int' for any track whose next_up mixed issue numbers with a non-issue token (e.g. an epic name like golden-path-v2) — non-issue string tokens are now dropped from the issue fetch. Also least-privilege allowed-tools scoping (#415) on the work-plan and repo-activity-summary skills, so Claude Code grants scoped Bash (the CLI / python3 / gh) rather than unrestricted shell. Extension code unchanged; republished for version parity.
  • v0.19.0 — Track lifecycle (#329/#328/#330): right-click a track → Mark for Cleanup (reversible 🧹 flag), Archive Track (set it aside into archive/parked/; a Show Archived Tracks toggle reveals archived rows greyed 📦, right-click → Unarchive), or Delete Track… (removes the .md only — GitHub issues untouched — behind a hard modal, with type-to-confirm on shared tracks and honest permanent-vs-recoverable messaging). Restore an archived plan (#388): right-click a doc in the 📦 Archived folder → Restore to Live, the inverse of Archive Plan. Also a CLI-side auth fix (#410/#411): a missing yq no longer masquerades as "Not signed in to GitHub" (the viewer distinguishes a failed probe from a real sign-out).
  • v0.18.0 — Plans-view + onboarding batch. Onboarding no longer shows for configured users (#398): the auth probe was a hard gate (any gh blip wiped the tree to the "Connect to GitHub" banner) and "No repos yet" keyed on track count; now a last-good cache survives a transient probe/load error, and the empty-states partition cleanly into truly-new (onboarding) / configured-but-no-tracks ("No tracks yet") / load-error ("Couldn't load — Retry"). Batch Acknowledge / Save-to-Doc / Stamp Baseline (#396): multi-select stalled/dead (or any) plans and apply behind one confirm, mirroring the multi-select archive (Confirm Verdict stays single-only). Archive reports staged vs local (#399): a tracked plan archives as a staged git mv ("commit & push to share"), a gitignored/untracked plan as a plain filesystem move — no more silent "git mv failed" on an untracked path. CLI floor unchanged.
  • v0.17.2 — Fixes a misleading "Not signed in to GitHub" banner (#402): in a Remote-WSL window the extension host runs inside WSL and spawns the work-plan CLI there, so a CLI installed only on Windows ENOENTs — surfacing as a GitHub-auth failure rather than a missing CLI. The viewer now distinguishes a missing CLI (new banner calling out the WSL/remote "install it where the host runs" gotcha) from not signed in and gh not installed; the README gains WSL / Remote-SSH / dev-container install guidance. CLI unchanged.
  • v0.17.1 — Fixes a dependency-graph crash on free-text blockers (#400): a blockers: entry can be a free-text note, not just an issue number; the prose was being spliced into a Mermaid node id → "Syntax error in text" across the whole graph pane. Free-text blockers now drop from graph edges (the track still shows ⛔ blocked) and render as an escaped chip in the detail panel; a string-form ref like "#5548" still draws a real blocks edge and dedupes against its blocked-by edge. Pairs with a CLI fix so brief/orient print a free-text blocker as prose instead of #<sentence>. CLI floor unchanged.
  • v0.17.0 — Adds multi-select batch archive (#393): select several shipped plans in the Plans view (Cmd/Ctrl/Shift-click) → Archive Plan… archives them all behind one confirm, with one refresh per affected repo. Pairs with a CLI perf fix (#391) that batches plan-status's per-doc/per-path git calls into one walk (~40s → ~14s on large repos), so the post-archive refresh no longer hangs the view.
  • v0.16.0 — Adds archive a shipped plan (#387): right-click a ✅ shipped plan → Archive Plan… (moves it to archive/shipped/ via git mv), or a repo → Archive shipped plans… for a bulk sweep; archived docs leave the live verdict buckets and surface in a collapsed Archived (N) folder per repo, with a post-archive toast and a repo "· N shipped" count. Unverified (lie-gap) shipped plans are archivable singly (with a warning) but excluded from the bulk sweep by default. CLI floor unchanged (≥ 2026.06.15); older CLIs degrade gracefully (the Archived folder just won't populate).
  • v0.15.0 — Fixes a repo-focus regression and reworks repo scoping (#383): a repo lens (including #357 auto-focus) had forwarded the full configured-repos list, making every other repo's tracks look gone. Fixed: applyLens now scopes the forwarded repos to the lens; workPlan.autoFocusRepo now defaults to OFF; autoFocusRepo reacts at runtime (no reload); the per-repo lens enumeration is replaced by a single Focus current repo ↔ Display all repos toggle that also writes workPlan.autoFocusRepo. Also a security pass: undici / form-data / dompurify bumped to clear 5 Dependabot alerts (#384).
  • v0.14.2 — Renames the AI command to "Suggest Tracks for Untracked Issues (with AI)…" so it mirrors the (offline, no AI) variant and matches the offline toast's "try Suggest Tracks (with AI)" hint (which previously pointed at a label that didn't exist).
  • v0.14.1 — Fixes v0.14.0's auto-slot UX: (1) Suggest Tracks crashed with "could not parse auto-triage JSON" on a repo with no active tracks — the CLI's --json scan now emits a machine-readable {note} and the viewer shows a "create a track first" message. (2) The opt-in enable setting was removed — running Suggest Tracks is itself the opt-in; the Suggested / Needs review buckets now appear whenever you've run a scan. (3) The offline variant is renamed "Suggest Tracks (offline, no AI)" and its toast now reports the real match count.
  • v0.14.0 — Adds proactive auto-slot suggestions (#241, opt-in via workPlan.autoSlotSuggestions): right-click the Untracked bucket → Suggest Tracks scans the repo and an AI session fills a Suggested sub-bucket (one-click Accept, with a compare-and-swap staleness guard + shared-tier rebase) and a Needs review sub-bucket; Suggest Tracks (offline heuristic) (#373) fills them with no AI, scoring matches locally (milestone / label / keyword). Also a critical webview fix (#374): escaped quotes in an inline-script template literal had been collapsing to a syntax error since 0.9.0, killing every webview click handler — now fixed, with a parse-guard test so an inline-script syntax error fails CI instead of shipping dead. CLI floor unchanged (≥ 2026.06.15).
  • v0.13.0 — Adds repo auto-focus (#357): when the open workspace folder is a configured repo, the Tracks view defaults its lens to that repo — a manual lens choice always wins, and workPlan.autoFocusRepo (default on) turns it off. Plus a one-click Apply on Check Label Drift (#221): the reconcile preview now offers an Apply reconcile action in-viewer. And a read-only tier-duplicate advisory (#361): when a track is left in both tiers, a ⚠ row under the repo names the dedupe-tiers CLI command. CLI floor unchanged (≥ 2026.06.15).
  • v0.12.0 — Feature batch: dependency graph gains zoom / pan / fit-to-width + Export as SVG/PNG (#216); Plans view auto-updates on git activity (#287) via per-repo .git watcher (debounced; workPlan.plansAutoRefresh toggle); native Suggest Next-Up (auto) picker (#274) brings the CLI's --auto-next to the viewer; Plans verdict icons get a legend (#348) — an ℹ️ title-bar button opens a self-demonstrating QuickPick with plain labels; and a gear button (#352) opens the Settings UI scoped to this extension. Requires CLI ≥ 2026.06.15.
  • v0.11.1 — Makes Edit Track Fields affordances for launch_priority and milestone_alignment consistent with New Track (#213): editing priority now offers a P0–P3 QuickPick, and editing milestone offers a QuickPick of existing milestones (deduped + sorted) with a "Type a new milestone…" escape hatch and a "Clear milestone" option.
  • v0.11.0 — Adds toggle auto next-up on/off from the Set Next-Up Order… picker (#338): the QuickPick shows "Auto next-up: ON / OFF" items at the top (with ✓ on the current state), writing set-next-up --auto=on|off through the existing confirm flow; the detail panel's "Next-up order:" row appends · auto when auto is enabled.
  • v0.10.1 — Adds a Set Next-Up button in the track detail panel — a small "Set Next-Up" button inline in the "Next up:" section fires the existing workPlan.setNext command so the next-up flow is reachable from the detail view without right-clicking the Tracks sidebar.
  • v0.10.0 — Adds per-track next-up ordering presets — Set Next-Up Order… command + detail-panel indicator (#326): a QuickPick of flow / priority-driven / backlog presets; the selected preset is written via set-next-up --preset=<name> through the existing public-repo confirm flow; the active preset name appears in the detail panel when workPlan.showNextUpPreset is on. Requires CLI ≥ 2026.06.14 for the write; degrades gracefully on older CLIs.
  • v0.9.2 — Hardens detail-panel issue links: they now carry a real GitHub href (instead of href="#") so clicking an issue number opens GitHub even if the webview script is blocked/stale/errored. Also adds a font-src CSP directive.
  • v0.9.1 — Hotfix: v0.9.0 set its minimum-CLI gate one day ahead of the release (2026.06.15 vs the 2026.06.14 CLI it shipped beside), causing a false "CLI version may be incompatible" warning for every updated user — v0.9.1 corrects the gate to 2026.06.14 and adds a guard test so the gate can never again exceed the repo's own CLI VERSION.
  • v0.9.0 — Adds GitHub-native blocked-by / blocking surfacing (#257, read-only): a same-repo blocked-by edge in the focused dependency graph, and an expandable ⛓ dependency disclosure on detail-panel issue rows showing ⊘ blocked-by / ⇒ blocking chips. Requires CLI ≥ 2026.06.14.
  • v0.8.0 — Adds per-issue in-progress badge + toggle (#271): a work-plan:in-progress label appears as a live badge on tracked issues in the detail panel, with a toggle to mark or clear it; the viewer also detects in-progress automatically from a hot feat/<n>-/fix/<n>- branch (no label needed). Also fixes the v0.7.0 regressions carried into v0.7.1: the Close-on-GitHub button renders correctly, and the open-plan webview button no longer errors when the plan file path isn't resolvable. Requires CLI ≥ 2026.06.14.
  • v0.7.1 — Accessibility + polish follow-up to v0.7.0: a dark-mode contrast pass (status/verdict icons moved to theme-tuned, list-semantic tokens meeting WCAG non-text contrast; detail-panel action icons legible at rest), plus two small features: a per-track open/closed progress bar in the detail card with a closed/total count in the tree (#220), and an activity-bar badge showing blocked-track (else total-open) count (#215). Also fixes two v0.7.0 regressions: Fetch Open Issues now excludes already-tracked issues, and the detail-panel Close-on-GitHub button renders correctly.
  • v0.7.0 — Large feature batch making the Plans view act, not just report: Plan frontmatter writes (all confirm-gated, frontmatter-only) — Confirm Verdict, Acknowledge & Save to Doc, Stamp Baseline — Watch for Drift, and a read-only off-tree manifest flag. Track ↔ plan link in the detail panel. GitHub-path hardening: a fast-fail "Not signed in to GitHub" banner with a Sign-in path, Fetch Open Issues for trackless repos, and Close Issue on GitHub (the viewer's gated issue-close). Push to Shared Tier promotes a private track to the repo's shared plan branch. Requires CLI ≥ 2026.06.13.
  • v0.6.3 — A repo that has tracks but no registered local clone now shows in the Plans view as a greyed "not registered" row with a click to Add Repo (prefilled with the slug), instead of being silently absent. Pairs with v0.6.2, which fixed the inverse: a registered repo with no tracks was missing from Tracks because applyLens was silently dropping the configured-repos list.
  • v0.6.2 — Fixes registered repos with no tracks vanishing from the Tracks view (#288): applyLens now forwards repos unchanged, so empty registered repos appear in Tracks (right-click → New Track to start).
  • v0.6.1 — Polishes the new Plans view: Plans section collapsed by default (Tracks stays the hot path), "Scan All Plans" empty-state is clickable to run the scan directly, the title-bar icon changed to $(telescope) (no longer ambiguous with Search), and Show-Acknowledged moved to the … overflow.
  • v0.6.0 — Adds a Plans view — a read-only second tree surfacing plan/spec docs and their plan-status health, making stalled and lie-gap loud across repos, with a cross-repo "Scan All" stalled roll-up, lazy per-repo scanning, acknowledge/dismiss, a workPlan.stallDays threshold setting, and click-to-open. Registered repos are now first-class in the sidebar even with no tracks, with Add Repo / Remove Repo / Clear Local Path management. Also new: Open Track File and pick-from-a-list for Move, Set Next-Up, and Add Issue to Track. Requires CLI ≥ 2026.06.13.
  • v0.5.1 — Small fix to the Daily Brief title-bar button: a clearer $(checklist) icon (the previous hamburger glyph read as a generic menu) and a re-entrancy guard so repeat-clicks no longer spawn concurrent brief runs.
  • v0.5.0 — Daily-driver + discoverability release: a new Search Issues command with %wildcard% substitution, opening matches in a dedicated Issue Search tab grouped by repo; Daily Brief / Re-orient / Wrap Up Session (Handoff) verbatim-relay verbs now runnable from the title bar and track menus; the active lens + sort surfaced inline under the Tracks view title; and milestone entries in the Select View filter now sort numeric-aware (v0.5.0 before v0.10.0).
  • v0.4.2 — Fixes visibility × tier badge rendering: the codicon tokens ($(globe)/$(lock)/$(cloud)) leaked as literal text in the tree because TreeItem.description is plain text; the badge now uses Unicode glyphs (🌐 / 🔒 / ☁️, ⚠️ for the exposed state).
  • v0.4.1 — Adds the per-track visibility × tier badge (🔒 private / 🌐 public repo, ☁ shared tier) on every tree item — flagging the one exposed state where a plan committed to a public repo's shared tier is world-visible (pairs with the CLI's new plan-branch workflow).
  • v0.4.0 — Broad UX + accessibility pass: a de-noised command palette (category-namespaced commands) with clearer names, a frequency-grouped track menu with confirmation modals on destructive actions, editor-theme-adaptive graph + detail panel (light/dark/high-contrast), a per-milestone filter in the detail panel, progress feedback on every write, and an accessibility sweep (distinct status-icon shapes, keyboard-operable disclosures and chips, table semantics, graph alt text).
  • Earlier v0.3.x — Added the Local History command, Rename Track, milestone bands, Move Issue from Track, and cross-track dependency chips.

Development notes

Tests run via Node's native type-stripping; the manifest stays CJS (no "type": "module") because the VS Code extension host and esbuild.js require CommonJS — that's why the test script suppresses the MODULE_TYPELESS_PACKAGE_JSON warning. vscode/ has its own CI job (.github/workflows/vscode.yml: typecheck · node --test · esbuild · vsce package), separate from the Python matrix; the local gate is npm run typecheck && npm test && npm run build.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft