| name | pm-spec |
| description | Work on a spec as a grounded decision ledger — capture decisions from notes or a blank start, drive open decisions to closure one at a time (grounding each against the real code), and watch for drift as the code changes. Use when the user says "work on a spec", "capture this decision", "drive the spec decisions", "ground this spec", "what's still open on the spec", "is the spec still true", "/pm-spec". This is the UPSTREAM of pm-projects / pm-issues — capture and ground decisions locally, publish to Linear for the comment-resolution alignment cycle, then decompose to tracked issues. |
| version | 0.44.4 |
pm-spec — grounded decision ledger
The spec's canonical truth is docs/pm/_drafts/<project>/<spec>/decisions.md — a
list of decision records. The CLI computes; this skill drives the conversation.
CLI: PMS="$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-spec.js" then node "$PMS" <verb> --spec <slug> ….
Print the returned .text verbatim where present.
Verbs
seed --spec <slug> --blank --title "<title>" — start a blank ledger (one open decision).
seed --spec <slug> --from <transcript> --title "<title>" — Pass 2a: deterministic candidate floor from a transcript; returns flagged excerpts for Pass 2b.
add --spec <slug> --title "<t>" [--question "<q>"] — append one open candidate (Pass 2b write).
render tree --spec <slug> / render canvas --spec <slug> — print .text.
next --spec <slug> — the next open decision to resolve.
decide --spec <slug> --id D# --answer … --rationale … --rejected … --evidence … --component … — record a grounded decision; flips it to decided.
check --spec <slug> — list decisions whose evidence file changed (candidate drift).
publish --spec <slug> [--title "<t>"] [--into project|issue] [--issue <ID>] — render the spec into a single Linear surface: by default a per-spec Project (the spec body becomes the project Overview content); with --into issue --issue <ID> it becomes that issue's description (for small specs, or specs that live inside someone else's project). The body opens with a native at-a-glance status table (emoji icons) + a status-colored Mermaid decision-dependency diagram + a ## Technical section — all render natively in Linear (markdown + mermaid; raw HTML <img> is stripped). No separate Process/Technical Documents, no seed comments. Posts a "Round N" project update (project surface only). Idempotent across rounds.
ingest --spec <slug> — read the surface's stakeholder comments (project comment stream, or the issue description's documentContent thread); map each unresolved one to a decision and reopen any decided decision that carries open feedback. Mapping (strongest first): explicit D# in the anchor → that decision; else a unique block-substring match (markers + whitespace normalized, so bold/cross-line anchors match) → that decision; >1 match (or >1 id) → unmapped with a reason for human routing. Reports openFeedback + unmapped.
respond --spec <slug> --comment <id> --body "<text>" — reply (threaded) to a feedback comment on the spec's surface.
resolve --spec <slug> --comment <id> — mark a feedback comment resolved once addressed; resolved comments stop reopening their decision.
plan --spec <slug> [--title "<t>"] — derive Technical implementation steps into technical.md (local preview); publish renders the ## Technical section into the surface from the decided decisions.
decompose --spec <slug> [--title "<project>"] [--apply] — propose component-grouped issues (AC + D# lineage) from decided decisions; --apply files them through the pm-issue.js gate and writes tracked:<ID> back.
canvas --spec <slug> [--title "<t>"] — generate a self-contained two-tab (Process / Technical) canvas.html that deep-links into the spec's Linear surface (header) + the D#-linked issues (per card). The rich, interactive artifact; Linear can't host interactive HTML (images only), so open it locally or host it externally — a gated manual step. For in-Linear visuals, the surface itself already carries the native table + Mermaid + Technical section.
focus --spec <slug> / focus / clear — manage the active-spec pointer.
Seeding from a transcript (two-pass)
seed --from <transcript> runs Pass 2a — a deterministic floor of open candidates
(from notes-extractor kind:'decision' units) — and returns flagged excerpts
(segments that might hide a decision but carry no deterministic cue).
- Pass 2b (your judgment): read each
flagged excerpt; where it implies a real
fork, draft a crisp candidate and persist it with add --title … --question ….
Also refine any floor candidate whose title is a raw snippet (edit decisions.md
directly, or re-title via the parser).
- Then run the normal drive loop below to take candidates to
decided.
Driving decisions (the loop)
next → take the open decision.
- Ground the answer against the real code — use
repo-sme / grounding to find
the file/line evidence before recording. Do NOT record an answer with no evidence;
the CLI rejects it (the grounding gate).
decide with answer + rationale + rejected + evidence + component.
- Repeat until
next returns nothing.
Publish & align (Linear)
The alignment loop is exception-based: the tool publishes the spec into one
surface, stakeholders comment only where they disagree, and silence = alignment.
A surface is { kind: 'project' | 'issue', id } (in state.json):
- project (default) — the spec body is the project Overview (
content);
feedback is the project comment stream.
- issue (
--into issue --issue <ID>) — the spec body is the issue
description; feedback is the description's documentContent thread. Use for
small specs or specs that live inside someone else's project.
publish — writes the rendered body (table + Mermaid + ## Technical) into the
surface + (project only) a "Round N" update. Re-run each round (idempotent via
state.json). It does not seed comments — anchored comments aren't
API-creatable (the anchor lives in Linear's Y.js editor state); stakeholders'
own inline comments are anchored, the normal way.
- Reviewers open the surface and comment inline on any decision they want to
challenge (selecting the text anchors the comment).
ingest — reads the surface's comments, maps each unresolved one to a decision,
and reopens any decided decision that carries open feedback. Re-ground the
reopened decision (decide again), then respond + resolve the comment. Once
all of a decision's comments are resolved it stands as decided. Writes
decisions.md only when something reopened.
Decompose to tracked work
plan — derive Technical steps from decided decisions → technical.md (local preview).
publish — renders the ## Technical section into the surface from the decisions.
decompose (dry-run) — review the proposed component-grouped issues; then
decompose --apply files them through the pm-issue.js create-gate (AC + D#
lineage) and marks each decision tracked:<ID> (renders ⊡). Pass --title
to target the spec's Linear Project by name.
Record schema & output formats
See references/record-schema.md and references/output-formats.md.
Scope
All ledger verbs are implemented (seed / drive / check / render / publish /
ingest / plan / decompose / canvas). canvas produces a local HTML showpiece
that deep-links into Linear; hosting it live is an optional, gated manual step.