Claude
Skills
Sign in
Back

pm-spec

Included with Lifetime
$97 forever

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.

General

What this skill does


# 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)

1. `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).
2. **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).
3. Then run the normal drive loop below to take candidates to `decided`.

## Driving decisions (the loop)

1. `next` → take the open decision.
2. **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).
3. `decide` with answer + rationale + rejected + evidence + component.
4. 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.

1. `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.
2. Reviewers open the surface and **comment inline** on any decision they want to
   challenge (selecting the text anchors the comment).
3. `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

1. `plan` — derive Technical steps from decided decisions → `technical.md` (local preview).
2. `publish` — renders the `## Technical` section into the surface from the decisions.
3. `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.

Related in General