Skip to main content
/pm:status runs the conductor engine’s render command, then reads PROJECT.md and summarizes the project’s position: what’s actively being built, what’s paused and why, what’s queued next, and how many epics exist per lane. It’s the fastest way to re-orient yourself at the start of a session or after any state-changing operation.

What the briefing shows

NOW

The active epic with its lane icon, priority badge, and live story progress derived from checkbox counts in the epic’s tasks.md file. If no epic is active, this section prompts you to triage.

DETOUR STACK

All paused epics in LIFO order, each annotated with the reason it was pushed onto the stack. Any frame with a pending reconcile-on-resume gate is flagged with ⚠ to remind you to reconcile before resuming.

NEXT UP

The top-priority queued epics, ordered by effective priority — an epic inherits the best priority of everything that transitively depends on it, so a P1 blocked by a backlog P2 lifts that P2 into view instead of starving behind it. Renders as P2 → P1; never written to state. reorder sets a manual rank as the final tie-break.

DEPENDENCY WARNINGS

An epic that is blocked with no live depends-on edge, or a dependency inversion — naming both endpoints, both statuses, and the lift. Rendered in PROJECT.md as well as the brief, because /pm:next reads PROJECT.md and would otherwise never see them.

LANE COUNTS

A snapshot of how many epics exist across each lane (openspec, superpowers, claude-code, decision, external) broken down by status, so you can see the overall shape of the backlog at a glance.

TRACKER SYNC

Where a tracker’s direction calls for it, this section lists any currently active epics that are missing an externalId. These are candidates for /pm:sync or manual tracker linkage.

UNGATED ARCHIVES

Epics archived with no Gate 2 review from anyone. A standing condition, not an episode: it is recomputed from state.json at every composition and never consumed, so every session sees it until a real passing verdict supersedes it.

HANDOFFS

Work carried out of an archived epic, shown from both ends — the epic that carried it out and the epic that inherited it. A relationship visible from one side only is how a remainder disappears.

RELEASES

Each release renders as N epics, M deferred, with every deliberate exclusion’s reason reachable from state.json — so “what is in this release, and what did we cut and why” survives the session that decided it. A release holding two or more spec files also carries its cross-spec review state: fresh, ⚠ stale, ⚠ unverifiable, or ⚠ no cross-spec review (N specs).

TOOL CURRENCY

Where the project uses OpenSpec, whether the installed CLI and this project’s generated artifacts agree. pm and superpowers update themselves; OpenSpec is upgraded by hand and openspec update is a separate per-project step — see /pm:upgrade.

Progress excludes lifecycle bookkeeping

A task that is bookkeeping about a change’s own lifecycle — above all the task that archives the change itself — carries the literal marker {/* pm:lifecycle */} on its own task line, and is excluded from progress. It renders as · N lifecycle beside the ratio, or 0/0 · N lifecycle where every task is excluded. The engine infers this from nothing else: not the wording, not the commands the text names, not the position in the file. Mark it when the task source is authored or amended. Without the marker, the archive task counts as outstanding work forever — it cannot be ticked before the thing that ticks it — and the archive gate would demand a handoff for a change that delivered everything.

Auditing the record itself — integrity

integrity is a read-only audit of the conductor’s own record: shapes that cannot be true. An archived epic whose task source exists with nothing ticked. One change registered under two lanes. A recorded commit sha the repository can no longer resolve — orphaned by a squash-merge and due for deletion at the next gc, or already gone. An epic left open in a release that already delivered, and not among the epics that release cut on purpose. An epic something else declares it supersedes, still sitting queued or active. A gate verdict whose recorded range does not reach the commits its own note cites. A gate recorded as bookkeeping rather than review. A delivered epic that attributed no commits. An archived openspec-lane epic with a passing Gate 2 and no Gate 1. An epic archived with an ungated Gate 2. An epic the archive-drift heal flipped that reads outcome: unknown while carrying a passing Gate 2. A dangling epic reference. An archive directory no epic corresponds to.
Every check is reported with its count including the ones that found nothing, so a check that measured nothing is visibly a check that ran. It writes no state, blocks no command, and repairs nothing — each finding names the epic, and the remediation is a command you run.
On the first run after upgrading to 0.27.0, expect a burst of heal-archived-epic-passed-gate-2. Every repo that followed the documented /opsx:archive then heal flow lands on outcome: unknown rather than delivered: the migration only stamps epics already archived in state, and the heal flips the rest afterwards. Expected, not a bug — each finding carries the exact remedy.

Design-document coverage — verify-specs

Once epics can name the design document they came from (--spec), “which design documents produced no work?” becomes mechanically answerable.
It lists every design document under the root with the epics drawn from it, and names the ones with none. A document counts as any .md under the root, recursively, minus README/INDEX/CONTRIBUTING — the same named-exclusion rule the plan scan uses, so the two cannot disagree. Point --root at a plans directory and it answers the same question about plans.
This is a listing verb, not an integrity check, and the distinction is deliberate. integrity reports shapes that cannot be true. A design document with no epic can be true and often is — a note, a reference, an abandoned sketch. Filing every one as a finding is exactly the noise that made the freshness warning ignorable before 0.31.0 scoped it. So verify-specs reports only when asked, always exits 0, and never speaks on its own.An absent root prints “no spec root” rather than “0 uncovered” — a repository that keeps its designs elsewhere should not get a confidently empty report.
Coverage is status-blind: an archived epic for one chunk of a design is coverage of that chunk.

--headers — let the documents propose their own epics

New in 0.34.0. Design documents usually name their epics in a header. verify-specs --headers reads the leading metadata block of each document and reports the epic ids it finds, so populating specPath on a repository that already has designs is a confirmation rather than a hand-backfill.
It proposes; you confirm. The engine must not decide that a document and an epic belong together, and a header is prose an author can typo — so this is the same split /pm:triage uses for asks: a mechanical candidate set, a human verdict.
The parse is label-agnostic and region-bounded — any **Anything:** line opens the block, the first blank line closes it, and backtick-quoted tokens matching the epic-id format are candidates. That was chosen empirically rather than guessed: a label allowlist dropped three genuine ids filed under **Depends on (all three must land first):**, and matching bare backticks anywhere would read state.json out of any document opening with prose.Measured against ten real documents: 26 of 26 ids, zero false candidates, including both cases where one design produced three epics — which is exactly what deriving the mapping from filenames could not do.
A header id that names no epic in the record is reported as a finding rather than inventory — a stale header, a removed epic, or a typo. Covered documents are checked too: a document whose first named epic shipped can still name a second that never existed.

This shape is a default, not a house style

New in 0.36.0. The layout above is what PM emits for someone who has configured nothing. If you have an output style or a communication contract in your project file, yours wins — PM’s shape is a default, and a plugin’s preference does not outrank your instructions. What does not bend is anything PM records: a disposition’s reason, a gate verdict’s range, an attribution. Those are writes to the state file rather than sentences, so no communication contract reaches them — applying “be brief” to a recorded reason is data loss, not brevity. Nor do the field names agents exchange between themselves, which are a wire format another agent branches on; the prose inside those fields is ordinary writing and does follow you.
Deference has a limit, and it is stated in the emitted rules: your contract governs how you report, never what PM instructs you to do. A brevity preference does not excuse a required task item, a gate, or a recorded reason. And where your shape has no slot for something required — a notification read-back, a deferral list, a blocked child — the rule is reshape, never drop: add a slot.

Which verbs write — verb-effects

render writes PROJECT.md. brief does not. Until 0.33.0 nothing said so, and the only way to find out was to run one and check git status. Every dispatched verb now carries a declared effect — mutates or read-only — and the declaration is verified rather than asserted: the suite checks it covers every verb the dispatcher actually has, then runs each read-only verb against a repository with a render pending and hashes the tree by content and mtime.
That measurement corrected two claims while it was being written. render is content-conditional — it skips the rewrite when only the timestamp would change — so a content-only hash reported it clean, which would have shipped a wrong declaration. It is still mutates: idempotent-when-nothing-changed is not the same as read-only, and both facts are now asserted so they cannot be conflated. Adding mtime then caught three more verbs writing on every call.

Release planning — release

A release is a named grouping of epics the agent declares: an id, intent prose, an optional target, and the epics deliberately cut from it. It exists because a release’s scoping judgments otherwise survive only in the session that made them.
  • Intent prose is required to create one — an id with no statement of what it is for is unreadable later, which is the failure this records against.
  • Membership is one-way. It lives on the epic as epic.release, at most one, and the release object carries no member list to fall out of step with it.
  • The engine proposes nothing. No epic is auto-assigned; adding, re-prioritizing, or archiving epics changes membership for none of them. Grouping is a scope judgment, and the scope judgment is the thing being preserved.
  • An exclusion is not an ending. A deferred epic keeps its status and gets no disposition of its own — it stays in the backlog because it is still work someone may do. What it loses is membership of that release.

When to run it

Run /pm:status at the start of every session to confirm where you left off, after /pm:resume to verify the detour stack contracted correctly, after /pm:sync to see newly registered epics, and any time you want to re-orient mid-session. The SessionStart hook fires it automatically when Claude Code opens your project — running it manually just forces a fresh render at any point you choose. Story progress counts come from each epic’s openspec/changes/<id>/tasks.md checkboxes in real time. If the counts look stale, the tasks.md file is the source of truth — /pm:status will recount on the next render.

Sample PROJECT.md output