work-plan toolkit

work-plan CLI command reference

The work-plan CLI has 49 subcommands for planning work across GitHub issues: run them as work-plan <subcommand> from npm, as /work-plan <subcommand> after the install script, or as /work-plan:run <subcommand> from the Claude Code plugin.

This reference is generated from the help text in skills/work-plan/work_plan.py; run work-plan --help for the same list in your terminal.

Daily workflow

These four commands make up the daily rhythm: a morning snapshot, a re-orient for each new session, a handoff when you stop, and a weekly cleanup.

brief

work-plan brief [--repo=<key>]

Multi-track snapshot with time-aware framing. --repo scopes the brief (and the archived-reopen callouts) to one configured repo.

Example: /work-plan brief --repo=myproject

where-was-i (alias: orient)

work-plan where-was-i [track | track@repo] [--pick] [--repo=<key>]

Re-orient. With a track name: track paste-block. With no args: cwd snapshot (branch, recent commits, modified files). Add --pick to force the interactive track picker. Use --repo=<key> or track@repo to disambiguate when the same track slug exists in multiple repos.

Example: /work-plan where-was-i ux-redesign (or just `/work-plan orient` for cwd snapshot)

handoff

work-plan handoff [track] [--set-next 1,2,3 | --auto-next] [--interactive]

Wrap up a session: capture touched/next/blockers, update body status table. Use --set-next to set the next_up list explicitly — note this is a full handoff, so it also appends a session-log entry (use set next_up= for a field-only change with no log). Use --auto-next to suggest a priority-sorted list from open issues (interactive: apply / edit / skip).

Example: /work-plan handoff tabletop --auto-next

hygiene

work-plan hygiene [--yes] [--no-duplicates] [--repo=<key>] [--timeout=N]

Weekly cleanup wrapper: refresh-md + reconcile + dedupe-tiers (report-only) + milestone-drift (report-only) + duplicates. With --repo=<key>, steps 1–4 scope to that repo; the duplicates step (a global similarity scan) is skipped. --timeout=N sets the gh subprocess timeout for the duplicates step (default 30s).

Example: /work-plan hygiene --repo=myproject

Create and edit tracks

These commands create tracks, add or move issues, and edit track frontmatter.

new-track

work-plan new-track <repo> <slug> [--priority=P0..P3] [--milestone=<m>] [--private] [--confirm=<token>]

Create a brand-new track file under notes_root in one headless call. <repo> is either a configured key (e.g. 'myproject') or a bare org/repo slug (e.g. 'your-org/myproject'). Writes frontmatter with status=active and optional priority/milestone. Gates on public repos — prints {needs_confirm, token} and exits cleanly; re-run with --confirm=<token> to proceed.

Example: /work-plan new-track stylusnexus/work-plan-toolkit my-feature

init

work-plan init <path-to-md>

Add frontmatter to an existing track .md file.

Example: /work-plan init '<notes_root>/<repo-key>/foo.md'

list

work-plan list [--all] [--sort=recent|priority]

List active tracks (or all including parked/archived).

Example: /work-plan list --all

slot

work-plan slot <issue-num> [track | track@repo] [--repo=<key>]

Add a GitHub issue to a track's frontmatter. If the issue is already in another active track in the same repo, prompts to move it (remove from source) rather than duplicate. Use --repo=<key> or track@repo to disambiguate when the same track slug exists in multiple repos.

Example: /work-plan slot 4234 tabletop

batch-slot

work-plan batch-slot <issue-num>... <track | track@repo> [--repo=<key>] [--move|--no-move|--reference]

Slot multiple GitHub issues into a track at once. --reference adds cross-track scope without changing issue ownership or removing source-track membership. Use --move to relocate ownership.

Example: /work-plan batch-slot 100 101 102 tabletop --move

move

work-plan move <issue-num> <from-track> <to-track> [--repo=<key>]

Move an issue from one track to another (remove from source frontmatter, add to destination). Source-first — the verb is the intent. Both tracks must be active and in the same repo.

Example: /work-plan move 4234 platform-health org-sharing

demote-to-reference

work-plan demote-to-reference <issue-num>... <track | track@repo> [--repo=<key>]

Migrate issues a track lists in github.issues purely for count-surfacing into github.references, once a specialist track has taken real ownership. All-or-nothing: refuses (no changes) if any issue isn't currently owned by the target, or has no other active owner in the same repo (would orphan it). Idempotent — an issue already referenced is reported as skipped, not refused.

Example: /work-plan demote-to-reference 100 101 102 mvp

set

work-plan set <track | track@repo> field=value [field=value …] [--repo=<key>] [--confirm=<token>]

Guarded edit of a track's frontmatter fields (status, launch_priority, milestone_alignment, blockers, next_up). Validates field names + status values; blockers/next_up take comma-separated issue numbers. Setting next_up here writes ONLY the frontmatter field — for next_up plus a session-log entry (and a body refresh), use handoff --set-next instead. Writes into a PUBLIC repo only with a confirm token: without one it prints {needs_confirm, reason, token} and makes no change (the VS Code viewer surfaces that as a modal, then re-invokes with --confirm=<token>).

Example: /work-plan set ux-redesign status=parked

set-next-up

work-plan set-next-up <track | track@repo> (--preset=<name> | --order=a,b,c | --clear | --auto=on|off) [--repo=<key>] [--confirm=<token>]

Configure the ranking preset and/or auto-derivation flag for a track's next_up list. --preset sets one of the named presets (flow, priority-driven, backlog) or 'custom' (which requires --order). --order=a,b,c sets a custom comma-separated criterion list (milestone, dependency, priority, recency, aging). --clear reverts to the global or default preset. --auto=on activates auto-derivation (brief/orient/export derive next-up live via the ranking preset instead of the curated list); --auto=off reverts to the curated list. --auto can be used standalone or combined with --preset/--order/--clear. Writes next_up_order and/or next_up_auto into the track's frontmatter (does NOT touch the next_up issue list). Public-repo gated: without --confirm it prints {needs_confirm, reason, token} and makes no change.

Example: /work-plan set-next-up my-track --preset=priority-driven --auto=on

canonicalize

work-plan canonicalize <track | track@repo> | --all [--force] [--repo=<key>]

Insert a canonical master issue table at the top of a track. The table has a Milestone column and is ordered active-milestone-first (the track's milestone_alignment milestone, then other milestones grouped with a blank divider row, then no-milestone last) so near-term work sits above someday work (#101). Refresh-md then targets ONLY this table, re-deriving it (so the order self-heals) and leaving narrative tables alone. Use --repo=<key> or track@repo to disambiguate; with --all, --repo=<key> scopes to one repo.

Example: /work-plan canonicalize ux-redesign

rename-track

work-plan rename-track <old-slug | old@repo> <new-slug> [--repo=<key>] [--fix-refs] [--commit] [--confirm=<token>]

Rename an active track's slug: moves the .md file, updates the frontmatter track field + last_touched. Resolve <old-slug> with track@repo or --repo when ambiguous. Validates <new-slug> like new-track and rejects a name already taken in the same repo/tier. For shared tracks, --commit stages + commits the move (else prints a 'commit to share' hint). --fix-refs rewrites sibling tracks' depends_on that reference the old slug (otherwise they're just warned about). Gates on public repos — prints {needs_confirm, token} and exits cleanly; re-run with --confirm=<token>.

Example: /work-plan rename-track old-project-name new-project-name

close

work-plan close <track | track@repo> [--repo=<key>]

Retire a track: shipped / parked / abandoned. Moves to archive/. Use --repo=<key> or track@repo to disambiguate when the same track slug exists in multiple repos.

Example: /work-plan close tabletop

Track lifecycle

These commands flag, archive, restore or delete a track. None of them touch GitHub issues.

mark-cleanup

work-plan mark-cleanup <track | track@repo> [--repo=<key>] [--clear] [--reason=<text>] [--confirm=<token>]

Flag a track as a cleanup candidate by writing cleanup_candidate: true (and an optional cleanup_reason) into its frontmatter — a lightweight earmark that hygiene surfaces so stale/consolidatable tracks don't get lost. --clear removes both keys. Gates on public repos — prints {needs_confirm, token} and exits cleanly; re-run with --confirm=<token>.

Example: /work-plan mark-cleanup old-experiment --reason='superseded by v2'

archive-track

work-plan archive-track <track | track@repo> [--repo=<key>] [--confirm=<token>]

Set a track aside REVERSIBLY: move its .md into archive/parked/ so it drops out of the active views but is kept for reference (distinct from close, which is terminal). Git-aware — a shared track archives as a staged git mv (commit & push to share), a private one as a filesystem move. Never touches GitHub. Gates on public repos. Restore with unarchive-track.

Example: /work-plan archive-track spike-idea

unarchive-track

work-plan unarchive-track <track | track@repo> [--repo=<key>] [--confirm=<token>]

Restore an archived track (parked/shipped/abandoned) back into the active set — the inverse of archive-track and of close's move. Git-aware staged/local move; never touches GitHub. Gates on public repos.

Example: /work-plan unarchive-track spike-idea

delete-track

work-plan delete-track <track | track@repo> [--repo=<key>] [--confirm=<token>]

DESTRUCTIVE: remove a track's local .md file. NEVER touches GitHub — the issues it referenced outlive the track. Private tier: the deletion is an undoable notes-vcs commit. Shared tier: a staged git rm you commit & push (recoverable from git history until then). Gates on public repos (the VS Code viewer adds a hard modal + type-to-confirm for shared tracks). Prefer archive-track for a reversible set-aside.

Example: /work-plan delete-track abandoned-spike

Sync and audit against GitHub

These commands keep track files consistent with live GitHub state and report drift.

refresh-md

work-plan refresh-md <track> | --all | --repo=<key> [--yes]

Sync issue STATE (open/closed, status labels) from GitHub into the track body's status table. Does not change track membership. For a canonical table it re-derives the whole block from live data, milestone-ordered, so the table self-heals and stays grouped; narrative tables are updated in place.

Example: /work-plan refresh-md --repo=myproject

reconcile

work-plan reconcile <track> | --all | --repo=<key> [--draft] [--yes]

Update track MEMBERSHIP (the github.issues list in frontmatter) by syncing it against a GitHub label. Default label is track/<slug>; override per-track via github.labels: [...] in frontmatter. Read-only on GitHub. In an --all/--repo sweep it also detects MOVEs — an issue relabeled from one track to another in the same repo is moved (removed from the old track, added to the new). Add --draft to preview the label drift (proposed ADDs/MOVEs/FLAGs) without prompting or writing; add --yes to apply without prompting (non-interactive, e.g. from the VS Code extension; PUBLIC-repo move destinations are skipped under --yes). NOT for hand-curated tracks — see refresh-md if you only want to update issue state.

Example: /work-plan reconcile --repo=myproject --draft

coverage

work-plan coverage [--repo=<key>] [--list] [--limit=N]

Report how many open issues are not referenced by any track (per repo). --list prints issue titles (default: show 20; override with --limit=N). Read-only; derives live from gh.

Example: /work-plan coverage --repo=myproject --list

duplicates

work-plan duplicates [--min-similarity=0.7] [--limit=20] [--state=open] [--timeout=N]

Find likely-duplicate issues by title similarity.

Example: /work-plan duplicates --min-similarity=0.85

milestone-drift

work-plan milestone-drift [--repo=<key>] [--unranked]

Audit each track's hand-curated next_up queue against live GitHub (#489). Reports three kinds of rot that are invisible from inside the file, because the list still reads like a plausible order: RANKED BUT CLOSED (finished work still occupying the queue — one real track's entire HEAD was closed issues), MILESTONE INVERSION (an issue ranked above another while carrying a LATER milestone, so the ranking and the release plan disagree), and RANKED WITH NO MILESTONE. Milestone order comes from due_on, falling back to title; when a repo's milestones cannot be read the inversion check is SKIPPED rather than guessed. --unranked additionally lists open track issues absent from next_up — off by default, because next_up is a shortlist for most tracks (measured on 33 real tracks: ~1000 findings with it, ~30 without). Report-only always — either side of an inversion can be the wrong one, so the fix is a judgement call.

Example: /work-plan milestone-drift --repo=myproject

dedupe-tiers

work-plan dedupe-tiers [--repo=<key>] [--apply]

Remove private track copies that a shared twin in a repo's .work-plan/ supersedes (#359). When a track is promoted to the shared tier, the private original under notes_root is sometimes left behind (bulk/manual promotion, or a failed unlink) — discover_tracks then warns 'exists in both shared and private' on every run with no cleanup path. This removes the safe orphans and REFUSES any whose private copy references issue numbers the shared one lacks (no silent data loss; the invariant is issue_refs(private) ⊆ issue_refs(shared)). Covers active and archived tiers. Default is a dry-run report; --apply deletes (auto-committed to notes_root, so undoable).

Example: /work-plan dedupe-tiers --repo=myproject --apply

lift-rationale

work-plan lift-rationale [--repo=<key>] [--track=<name>] [--apply]

Move a track's rationale out of YAML frontmatter comments and into a '## Ranking rationale' body section (#491). Writes preserve frontmatter comments, but the body is the only place rationale is VISIBLE — frontmatter comments never render, never reach the VS Code viewer, and never appear in export --json. Comments attached to a next_up entry become bullets naming that issue; section headers become paragraphs. The body is also the only place rationale is VISIBLE — frontmatter comments never render, never reach the VS Code viewer, and never appear in export --json. Dry-run by default; --apply writes.

Example: /work-plan lift-rationale --repo=myproject --apply

AI-assisted, two-step commands

These commands print a prompt for your agent, which saves a JSON answer; re-run with --apply to write. The CLI never calls a model itself.

group

work-plan group [--milestone=X] [--label=Y] [--repo=Z] [--apply] [--limit=N]

AI-cluster GitHub issues into thematic track files. --limit controls how many issues are shown in the prompt (default 100).

Example: /work-plan group --milestone='v1.0.0 — Public Launch'

auto-triage

work-plan auto-triage [--repo=<key>] [--apply] [--json] [--heuristic] [--limit=N]

AI-assign untracked open issues to existing tracks. Step 1 (no --apply): fetches untracked issues + existing tracks, prints an AI prompt and writes a per-repo batch file stamped with a batch_id; --json emits that batch (+ prompt + answers path) as one JSON object on stdout for the VS Code viewer instead of the human prompt. --heuristic (#373) skips the LLM entirely: it scores each issue against the candidate tracks using local signals (milestone match, track-label overlap, title/scope keyword overlap), writes the v2 answers file itself (stamped source:"heuristic", abstain-first), so suggestions work with no Claude session — lower-trust, but offline. Step 2 (--apply [--repo=<key>]): reads the answers (v2 abstain-first shape preferred — only clear-margin suggestions are slotted; legacy v1 [{track,issues}] still accepted) and slots each assignment into track frontmatter. Complements group (which creates new tracks); auto-triage assigns to tracks that already exist. --limit controls how many untracked issues are shown (default 100).

Example: /work-plan auto-triage --repo=myproject

suggest-priorities

work-plan suggest-priorities [--repo=<folder>] [--apply]

AI-assisted batch backfill of priority/PN labels.

Example: /work-plan suggest-priorities --repo=myproject

Repos, config and diagnostics

These commands register repos, move your notes, add local history and check your setup.

init-repo

work-plan init-repo <key> --github=<org/repo> [--local=<path>] [--update [--clear-local]]

Bootstrap a new repo: create <notes_root>/<key>/archive/{shipped,abandoned}/ and add the repo block to your config. With --update on an existing key, change its local/github; --update --clear-local drops the saved local path (keeps github + other fields). --clear-local and --local are mutually exclusive.

Example: /work-plan init-repo myproject --github=your-org/myproject

remove-repo

work-plan remove-repo <key>

Unregister a repo: delete its block from your config (config-only). The notes folder, any tracks, and the local clone are LEFT UNTOUCHED — if a notes folder or tracks reference it they're now orphaned and can be cleaned up by hand.

Example: /work-plan remove-repo myproject

set-notes-root

work-plan set-notes-root <path>

Update notes_root in ~/.claude/work-plan/config.yml to an absolute path. Creates the target directory if absent. Prints a WARN if existing frontmatter'd tracks live at the old location (they won't be moved — manual migration required). Non-interactive: safe to call from a GUI or script.

Example: /work-plan set-notes-root ~/Documents/work-plan-notes

notes-vcs

work-plan notes-vcs <init|enable|disable|status|undo> [<sha>] [--no-enable] [--json]

Opt-in LOCAL version control for the private notes_root tier — history/undo for tracks you keep on your machine, never pushed. init git-inits notes_root as a personal repo (initial commit of existing tracks) and turns on auto-commit; with --no-enable it inits without enabling. For safety it REFUSES a notes_root that already has a git remote or is a repo work-plan didn't create, and only ever commits the files a command changed — private notes stay un-pushable and your unrelated edits are never swept in. enable/disable toggle auto-commit (history is kept either way). status reports whether notes_root is a repo, whether auto-commit is on, and the last commit (add --json for the machine-readable shape the VS Code viewer polls). undo [<sha>] reverts a commit (default HEAD) — the last edit, by default. When auto-commit is on, every track-mutating command (slot/group/handoff/close/set/…) writes an undoable commit; the shared tier is unaffected (it's versioned by its own repo).

Example: /work-plan notes-vcs init

which-repo

work-plan which-repo [--json]

Resolve the current directory to one configured repo — by local clone path first, then the git origin remote. Prints the matched config key + GitHub slug, or reports no match. Read-only. Underlies brief cwd auto-scope and the VS Code viewer's repo auto-focus.

Example: /work-plan which-repo --json

doctor

work-plan doctor [--json] [--fix]

Detect drift between config.yml, local git clones, GitHub, and notes_root track frontmatter — a renamed local folder or GitHub repo that config.yml no longer matches, a non-git local path, duplicate entries, an invalid/missing notes_root, an orphaned notes folder, or a stale per-track github.repo. --fix corrects only the two mechanically-safe cases (a GitHub-confirmed rename, a stale track slug) and always re-scans afterward before deciding success. Also runs a read-only preflight first: Python 3.9+, git, gh and its sign-in, mikefarah/yq, config loading and notes_root access; text mode exits 0 healthy, 1 warning, 2 blocking, and --json adds status + checks.

Example: /work-plan doctor --fix

Shared tracks

These commands publish tracks to a repo's shared tier on a canonical plan branch.

plan-branch

work-plan plan-branch <init|status|push> <repo> [--branch=<name>] [--confirm=<token>] [--dry-run] [--json]

Set up and share a repo's canonical SHARED-tier plan branch (#260). The shared .work-plan/ tier is pinned to ONE per-repo plan_branch, read/written through a dedicated git worktree, so planning never diverges across code branches or pollutes PR / deploy diffs. init <repo> creates that branch + a .work-plan/ skeleton (default an ORPHAN work-plan/plan, zero shared history with code like gh-pages; override with --branch) and records plan_branch in config — or CONNECTS to a teammate's already-published branch if one exists. init is LOCAL ONLY (no push). status <repo> reports whether the branch exists, is published to origin, and how many commits are unpushed (--json for the machine shape). push <repo> shares it: on a PUBLIC repo it prints a confirm heads-up + token and exits (re-run with --confirm=<token>); --dry-run previews the commits that would push. Requires a repo registered via init-repo with a local clone path.

Example: /work-plan plan-branch init work-plan-toolkit

push-track

work-plan push-track <track | track@repo> [--repo=<key>] [--no-push] [--confirm=<token>]

Promote a PRIVATE track (local-only, in notes_root) to the repo's SHARED tier and publish it (#306). Moves the track's .md into the repo's .work-plan/ (on its plan_branch, via a worktree), removes the private copy so it isn't duplicated, commits to the plan branch, and pushes — unless --no-push (keeps it local). The tier is derived from location, so this is a file move, not a frontmatter edit. Requires the repo to have a local clone + a plan_branch (else hints plan-branch init). Pushing to a PUBLIC repo makes the track world-visible, so the push is confirm-token gated (prints needs_confirm + token; re-run with --confirm=<token>).

Example: /work-plan push-track my-feature --repo=myproject

Plan and spec documents

These commands judge which plan and spec documents shipped and record decisions in their frontmatter.

plan-status

work-plan plan-status [--repo=<key>] [--json] [--stamp [--draft]] [--llm [--apply]] [--archive | --issues] [--draft] [--since-days=N] [--type=plan|spec]

Reach a verdict on every plan/spec doc in a repo by correlating each plan's declared file-manifest (Create/Modify/Test paths) against the filesystem + git — not the unreliable checkboxes. Read-only: reports ✅ shipped / 🟡 partial / 💀 dead / 👻 manifest-less. --json for machine output. Add --stamp to write each verdict into its doc as an idempotent status header (--draft previews without writing). Add --llm for a two-step AI pass that judges prose/ambiguous docs (writes a prompt; you save JSON to the cache; re-run with --llm --apply). --archive moves dead plans to archive/abandoned/ (gated); --issues opens a GitHub issue per partial plan listing its unsatisfied files (gated). Both honor --draft.

Example: /work-plan plan-status --repo=myproject

plan-confirm

work-plan plan-confirm --repo=<key> --verdict=shipped|partial|dead [--clear] [--confirm=<token>] -- <rel>

Affirm a human verdict on ONE plan/spec doc by writing verdict_override into its YAML frontmatter — FRONTMATTER-ONLY (never the body, manifest, checkboxes, or status banner) (#286). plan-status then pins that verdict over the mechanical one and silences the 'shipped but boxes unchecked' lie-gap. Use when a plan genuinely shipped but its phase checkboxes were never ticked, so the red lie-gap X is a false alarm. <rel> is the repo-relative doc path from plan-status --json. On a PUBLIC repo it prints a confirm heads-up + token and exits (re-run with --confirm=<token>) — the VS Code viewer surfaces this as a modal. --clear removes the override.

Example: /work-plan plan-confirm --repo=myproject --verdict=shipped -- docs/superpowers/plans/2026-03-16-idea-mode-ui.md

plan-ack

work-plan plan-ack --repo=<key> [--clear] [--confirm=<token>] -- <rel>

Persist an acknowledgment into ONE plan/spec doc's YAML frontmatter only (acknowledged: true) — never the body/manifest/checkboxes/banner (#286). Unlike the VS Code viewer's default ack (per-machine, ephemeral workspaceState), this is durable + shared: it's committed with the repo, and plan-status reads it back to demote the doc. <rel> is the repo-relative doc path. Public-repo gated (prints needs_confirm + token; re-run with --confirm=<token>). --clear removes it.

Example: /work-plan plan-ack --repo=myproject -- docs/superpowers/plans/2026-03-16-idea-mode-ui.md

plan-baseline

work-plan plan-baseline --repo=<key> [--clear] [--confirm=<token>] -- <rel>

Stamp the CURRENT computed verdict into ONE plan/spec doc's YAML frontmatter only as a drift baseline (verdict_baseline) (#286). Distinct from plan-confirm (a human pin) and the body banner. plan-status then flags drift when the live verdict diverges from the baseline — catching a once-shipped plan that silently regressed (its declared files were deleted/moved). The baseline value is computed authoritatively here. Public-repo gated; --clear removes it. verdict_override, if present, suppresses drift.

Example: /work-plan plan-baseline --repo=myproject -- docs/superpowers/plans/2026-03-16-idea-mode-ui.md

plan-archive

work-plan plan-archive --repo=<key> [--draft] [--yes] [--json] -- <rel>

Archive ONE plan/spec doc whose effective verdict is shipped: history-preserving git mv into archive/shipped/. Refuses non-shipped docs; skips (never overwrites) a name collision. --draft previews; --yes skips the prompt for non-interactive callers (the VS Code viewer); --json emits a single {action,rel,outcome,dest} object. <rel> is the repo-relative doc path from plan-status --json.

Example: /work-plan plan-archive --repo=myproject -- docs/superpowers/plans/2026-03-16-idea-mode-ui.md

plan-unarchive

work-plan plan-unarchive --repo=<key> [--draft] [--yes] [--json] -- <rel>

Restore ONE archived plan/spec doc back OUT of archive/<kind>/ to its live location — the inverse of plan-archive (#388). Refuses (never overwrites) a collision with a live doc of the same name. Git-aware staged/local move. --draft previews; --yes / --json for non-interactive callers. <rel> is the archived doc's repo-relative path (from plan-status --json --include-archived).

Example: /work-plan plan-unarchive --repo=myproject -- docs/superpowers/plans/archive/shipped/2026-03-16-idea-mode-ui.md

Commands that write to GitHub

These are the only commands that change GitHub issues, alongside plan-status --issues. Each one is opt-in.

close-issue

work-plan close-issue --repo=<key|slug> [--reason=completed|not_planned] [--comment=<text>] -- <number>

⚠️ A GitHub-mutating command (others: in-progress, plan-status --issues) — closes a GitHub issue via gh issue close (most of the toolkit is read-only on GitHub). PRs merged to dev don't auto-close issues (GitHub auto-closes only from the default branch), so done-but-OPEN issues pile up; this closes one. --reason maps to GitHub's completed/not-planned; --comment posts a closing note. --repo takes a config key or an org/repo slug. The VS Code viewer gates this behind a mandatory 'Close on GitHub?' modal on every close.

Example: /work-plan close-issue --repo=stylusnexus/work-plan-toolkit --reason=completed --comment='Closed via dev merge' -- 287

in-progress

work-plan in-progress <n> [--clear] [--repo=<key|slug>] [--confirm=<token>]

Mark a tracked GitHub issue as in-progress by adding the work-plan:in-progress label (or remove it with --clear). Repo-scoped: resolves <n> to the one tracked repo that lists it, or pass --repo to disambiguate. The label is auto-created. Writes into a PUBLIC repo only with a confirm token (prints {needs_confirm, token} otherwise — the VS Code viewer surfaces it as a modal). brief/orient/the viewer also derive in-progress for free from a hot feat/<n>- or fix/<n>- branch.

Example: /work-plan in-progress 271

Read surfaces for the VS Code extension

Work Plan Viewer calls these read-only commands for its data.

export

work-plan export --json

Emit the viewer-ready JSON read surface (schema 1): every frontmatter'd track with repo, tier, status, visibility, blockers, next_up, an open/closed rollup, and per-issue state/assignee/milestone. Read-only; derives live from gh. Consumed by the VS Code extension.

Example: /work-plan export --json

list-open-issues

work-plan list-open-issues --repo=<owner/name> [--exclude=<csv-issue-numbers>]

Emit a repo's OPEN issues as JSON ({repo, issues:[{number,title,state,assignee,milestone}]}) — the same issue shape as export. Read-only; derives live from gh. --repo takes a bare org/repo slug; --exclude drops the given issue numbers (the viewer passes a track's current issues so already-slotted ones don't reappear). Unlike export's untracked, this includes issues tracked by OTHER tracks, since those are valid slot targets.

Example: /work-plan list-open-issues --repo=stylusnexus/work-plan-toolkit --exclude=87,91

auth-status

work-plan auth-status [--json]

Report whether gh is installed and signed in to GitHub, using a read-only gh auth status probe. --json emits gh_present, authenticated, probe_ok, user and error. Exit codes: 0 signed in, 1 gh present but not signed in, 2 gh not found, 3 the probe could not reach a verdict (for example a network failure), which callers treat as unverified rather than signed out.

Example: /work-plan auth-status --json

The public-repo confirm gate

Every write into a public repository, or one whose visibility gh cannot determine, stops and prints {"needs_confirm": true, "reason": …, "token": …} without changing anything; re-run with --confirm=<token> to proceed. Private repositories write straight through. Set assume_private_when_unknown: true in config.yml to skip the prompt only for unknown visibility; public repositories always prompt.

Back to the work-plan toolkit overview or the Work Plan Viewer extension.