What it does
batch-triage is the one-pass version of triage, for a backlog that arrived with the repo. The
plugin’s mattpocock-skills:triage handles one item arriving now. An inherited backlog has a
different shape: hundreds of items of unknown age, written by people who have left the project,
describing code that moved long ago. This skill classifies each item by reading the item’s own
text and the code it names, merges the duplicates the wording hides, marks the dead ones, and
creates tracker tickets carrying labels and blocking edges. Its rule is extract, never
invent: every classification cites the item’s own text or the code it names, and an item that
cannot be classified from evidence lands as NEEDS-OWNER, a valid outcome that costs one line.
The problem it handles shows up on Thomas’s first day on an adopted repo: an inherited backlog
with no edges has no frontier. The frontier query returns every ticket whose blockers are all
done and whose assignee is empty, so in a backlog where nothing blocks anything, every ticket
looks ready at once and the ordering falls back to guesswork. The skill also carries a correction
measured inside this harness. It used to ask for “the code map” in prose, which is why
CODE-MAP.md survived for weeks as an artifact a filename grep called an orphan while a shipped
skill wanted it on every run (AST-071). It now resolves each item against the current tree with
rg and git log. That is what it should have said from the start, because a stale map is wrong
exactly where triage needs it most: on code that moved or died.
When Thomas reaches for it
| What is in front of you | Reach for |
|---|---|
| A repo you are adopting already has a backlog | batch-triage, invoked by name, once per repo |
| One new item just landed in the inbox | Not this skill. mattpocock-skills:triage is the one-item-at-a-time shape |
| The backlog is larger than one pass can finish | batch-triage batched by area, reporting where you stopped |
| An empty repo with no backlog at all | Skip it. It reads something that does not exist yet |
| The tracker and git have drifted since | reconcile-tracker, the skill that measures state rather than classifying items |
Prerequisites
docs/agents/triage-labels.mdexists and is loaded first. The label set belongs to the project and is produced bysetup-matt-pocock-skills, so inventing a parallel vocabulary inside this skill would split it into two versions.- The current tree, not a map of it. Most triage decisions turn on whether the code an item names
still exists, so each item resolves against
rgandgit logon the tree as it stands now. - Thomas owns this skill as a phase. It is user-invoked, runs once per repo and again when it goes stale, and it ends on owner review. A user-invoked skill cannot reach another one, which is why the role exists.
- A tracker adapter is in play, since the live items become real tickets. Which adapter you pick
(
github-issue-tracker,jira-issue-tracker,linear-issue-tracker) does not change the classification, only how the tickets get written.
What it leaves behind
| What happened | Where it lands |
|---|---|
| Counts per class | The report, published before the tracker is touched, so the owner sees the shape of the backlog they inherited |
STALE and DONE items with their evidence |
The report only. Closures wait for the owner, because closing something that was real is the most expensive mistake here |
| Duplicate groups | The report, grouped by code path and symptom rather than by title |
| A live item | A real tracker ticket, labelled from the project’s vocabulary, sized as one ticket or as an effort needing wayfinder |
| A dependency one item plainly has on another | A blocking edge on the tracker, which is what the frontier query reads |
| An item the evidence cannot settle | NEEDS-OWNER in the report, one line, no guess |
| The assignee field on everything created | Left empty. Assignment is the claim, and it belongs to Thomas at dispatch time |
Known failures
Pulled from harness/.agents/memory/recurring-failure-modes.md.
- AST-071 · promoted. Seven reachability checks asked whether a thing was named, whether a
path existed, whether an address was callable. None asked whether anything read what the package
produced.
batch-triageis the entry’s counter-example: it asked for “the code map” in prose, so a filename grep declared that artifact an orphan while a shipped skill wanted it on every run. A grep for a name is not a search for a consumer. Fixed: check 8 requires a hand-written registry row naming a reader, andbatch-triagereads the tree directly rather than a map. - AST-050 · promoted. This is not the skill’s own defect, but it landed on the file this skill
loads first: a blanket regex rewriting
/triagealso rewrote threedocs/agents/triage-labels.mdpaths into nonsense, because\bmatched mid-path. Caught by reading the diff, not by any check.
It’s working if
- Every classification cites the item’s own text or the code it names, and nothing was classified from the title alone.
- The counts-per-class report reached the owner before any ticket was created or closed.
- No
STALEorDONEitem was closed by this run. Those are proposals awaiting the owner. - Blocking edges are set wherever one item plainly depends on another, because a missing edge makes a ticket ready too early.
- Every created ticket is unassigned, and Thomas can run the frontier query against the result immediately.
Where it fits
batch-triage runs early, beside the other bootstrap phase Thomas owns: /skills/bootstrap-glossary
seeds the vocabulary from the code, and batch-triage reads the backlog against that same code.
Both are invoked by name, run once per repo, and end on owner review, so neither becomes work
everyone assumes someone else ran. Its output feeds straight into the frontier query in
thomas.md, which is what /skills/dispatch-ticket claims from. An item too big for one ticket
moves to mattpocock-skills:wayfinder and a Shaper session; a single new item arriving later
moves to mattpocock-skills:triage, not back here.