Claude
Skills
Sign in
Back

pm-ledger

Included with Lifetime
$97 forever

Track a SINGLE running parent issue, epic, project, or label commit-by-commit — a focused phase ledger of which child issues are done, in progress, and next, with each child's shipping commit aligned to its phase. Use whenever the user is working a parent/epic/project and asks "where am I on this", "what's left on <ID>", "show progress on this epic", "what's next here", "pick up where I left off", "resume <ID>", or wants commits mapped to phases — or asks about a cross-cutting workstream sharing a label ("where are we on all the pm-spec work?", "progress on everything labeled X") via `tree label:<name>`. Also use to re-orient when resuming work on a tracked parent in a fresh session. This is DEPTH on one parent (or label set) — distinct from pm-status (whole-backlog breadth) and pm-report (stakeholder documents). When the user names or implies a specific parent/epic/project/label and wants its internal progress, prefer pm-ledger even if they say the word "status".

General

What this skill does


# PM Ledger

A focused, commit-aligned status view for ONE running parent issue, epic, or
project — and a resume view to pick work back up. This is depth on a single
parent; for whole-backlog breadth use `pm-status`, for stakeholder documents use
`pm-report`.

All derivation lives in `hooks/bin/pm-ledger.js` (a thin CLI over the pure
`ledger-builder` + `commit-resolver` libs). This skill RUNS that CLI and prints
what it returns — do not re-derive anything by hand.

## Commands

```bash
PML="$CLAUDE_PLUGIN_ROOT/hooks/bin/pm-ledger.js"

node "$PML" tree    <ID>     # full tree view (returns { model, text }) — print .text
node "$PML" resume  [<ID>]   # "where we left off" view (resolves focus if no ID)
node "$PML" model   <ID>     # the raw ledger model as JSON (if you need the data)
node "$PML" focus   <ID>     # set the active focus pointer
node "$PML" clear            # clear the focus pointer
node "$PML" discover         # list candidate parents + candidate labels
```

`<ID>` is an issue id (`FUNC-33`), a project name, or `label:<name>` (e.g.
`label:pm-spec`) — a flat, cross-cutting set of every open/recently-closed issue
carrying that label. Every verb prints a single JSON object; for `tree`/`resume`,
print the `.text` field verbatim — it is already formatted (see
`references/output-formats.md` for the visual spec).

## How to choose a verb

- The user names a specific parent/epic/project and wants its progress →
  `tree <ID>`.
- The user asks about a cross-cutting workstream sharing a label — "where are we
  on all the pm-spec work?", "progress on everything labeled X" → `tree
  label:<name>` (e.g. `tree label:pm-spec`). This is a flat set, not a hierarchy:
  every open (and recently-closed) issue carrying that label.
- "pick up where I left off", "resume", "where was I" → `resume` (no ID lets it
  resolve focus from the git branch or the saved pointer).
- The user wants to START tracking a parent for the session → `focus <ID>`
  (then the Stop hook will nudge automatically as commits land).

## Decision logic (what this skill must handle)

The CLI does the resolution; your job is to react to what it returns.

1. **Focus resolution order** (`resume`/bare): explicit ID → current git branch →
   saved pointer (`.claude/pm/focus.json`) → discovery. You don't implement this;
   the CLI returns `source: "arg" | "branch" | "pointer" | "none"`.

2. **Pointer ≠ branch conflict.** If `resume` returns a `conflict`
   `{ pointer, branch }`, do NOT silently pick one. Ask the user:
   "Resume `<pointer>` (your saved focus) or switch to `<branch>` (the branch
   you're on)?" Then call `tree`/`resume` with their choice (and `focus <choice>`
   to update the pointer). This includes a **label pointer vs branch**: a saved
   `label:<name>` focus can never be derived from the branch (branches name issue
   ids), so a `label:` pointer plus an issue-bearing branch is always a real
   conflict — the CLI prefers the branch and surfaces `{ pointer: "label:…",
   branch: "<ID>" }`; ask which to use.

3. **No focus resolves** (`source: "none"`, `focus: null`). The CLI returns a
   `candidates` list (candidate parents) AND a `labels` list (candidate labels —
   those carried by ≥2 open issues, shaped `{ label, issueCount, done }`). If
   either is non-empty, show them and ask which parent or label to track (a label
   choice becomes `tree label:<name>`). If both are empty, tell the user there's
   no active focus and they can run `/pm-ledger focus <ID>` (or name a parent /
   `label:<name>`).

4. **Entry-mode framing is already in the text.** `resume` opens with
   *Resuming* (something in progress), *Continuing* (some done, none in flight),
   or *Starting* (nothing started) — all derived from cursor state. Just print it.

## The automatic nudge (no action needed)

A Stop hook (`pm-ledger-tick.js`) watches for new commits while a focus is set
and prints a one-line nudge (e.g. `● FUNC-33 · 10/13 ✓ · FUNC-27 ← next ·
/pm-ledger`). It is silent unless there's an active focus AND a commit landed
since the last turn — that is what keeps pm-ledger "mostly transparent." You do
not invoke it; it runs on its own once `focus` is set.

## Where this fits

pm-ledger is **depth on one parent** — a single epic/project's child issues,
commit by commit. For **breadth across the whole backlog** ("what's in progress
everywhere", "what's stale", "what should I pick up next") use `pm-status`
instead. The two are complementary, not interchangeable: pm-status answers
"across everything, where are things?", pm-ledger answers "inside this one
parent, where am I?".

This skill reports status; it never cuts a branch or does work. The next-up child
it surfaces is just an issue ID — if you want to *act* on it, that's `/pm-branches`
(cut the branch) or the `pm-issue-to-pr` Workflow (work the epic's afk
descendants autonomously). Those are things you might do next, not steps
pm-ledger performs or orchestrates.

## Notes

- Commit attribution is layered PR → branch → message-ref; only the shipping
  (most recent) commit per child is shown. Old issues whose commits never
  carried the identifier simply show no commit — that's expected, not a bug.
- Canceled children render with `⊘` and are excluded from the `X/Y` bar.
- If the cache is stale, the ledger is stale — suggest `/pm --refresh` if the
  user's tracker state looks out of date.

Related in General