Prompt file imported from cinjoff/firehorse (
.claude/commands/triage.md). Fill in{{arguments}}before use. Copyright stays with the author.
Triage
Purpose
Use this workflow when the tracker has drifted: issues filed across several sessions, each one sensible on its own, with no shared position on what belongs together or what to do next. It re-judges every open issue and leaves the tracker grouped, labelled, and ranked.
pnpm triage does the judging. It asks Jev four questions per issue — which map's outcome it moves, what kind of work it is, whether an agent could finish it from the body alone, and what it costs to leave undone — plus three yes/no questions that map onto this repo's label vocabulary. The thresholds and the label policy live in scripts/triage.ts, not in the model, so tightening a rule never needs a new model call.
What the script cannot do is see that a cluster has no map. That is this workflow's job, and it is where most of the value is: an issue Jev cannot place is usually not a bad issue, it is an issue whose goal was never chartered.
Usage
Invoke with no arguments to judge and report, changing nothing. {{arguments}} may carry --apply to run the actions that cleared their threshold, and --only <numbers> to judge a named subset.
Run it when a research or retro burst has just landed a batch of issues, before charting a new map, or on any session that opens with "I can't tell what to work on".
Inputs
{{arguments}}: an optional--apply, an optional--only.TYPESAFE_API_KEYin the environment. Without it the script exits and nothing else in this workflow runs.- Every open issue in the tracker, and every open
wayfinder:mapwith its sub-issues, read throughgh. docs/agents/issue-tracker.mdfor the label vocabulary and the sub-issue mechanics.docs/agents/triage-labels.mdfor what each triage role means.
Outputs
- A report under
.firehorse/local/triage/, with the raw judgments beside it as JSON. - Issues labelled and attached to maps, when
--applyran. - A named list of clusters that no open map owns, each with the map it argues for.
- The issues left to a person, and what makes each one undecidable by the pass.
Supporting Capabilities
pnpm triagesupplies the judgments and owns the policy;ghperforms every tracker write.- This workflow orchestrates no upstream skill.
upstreamSkillsis empty by design, as inupstreams-check.
Orchestration Intent
The script judges one issue at a time against the maps that exist. You read the low-confidence bucket, which is the pass's real output: when several issues land there together and share a subject, the tracker is missing a map, and a map you charter changes what the next run can see. So the sequence is judge, charter, re-judge, apply — never apply first.
Gotchas
- Jev judges each issue against the maps present at that moment. A new map changes the grouping of issues nobody touched, which is why step 5 re-runs rather than reusing the first report.
- A high group confidence is a claim about fit, not about whether the map should exist. Three issues placed at 1.00 under a map whose destination they only half serve is still a mis-grouping.
- The model reads "found while working on X" as session history. The
retrolabel therefore needs the judgment and the body citing a session artifact; it over-applies on the judgment alone. candidateis never applied by the pass.docs/agents/issue-tracker.mdfiles a candidate throughgh issue create --template candidate.ymlwith the five intake fields, and a label alone would fake that.- An issue already carrying a triage label keeps it. Disagreeing with a human's readiness call is a report line, not an edit.
Safety Gates
- The dry run comes first.
--applyruns after a report has been read, never as the first call. - A new map is written by hand. The pass names the cluster; the map's destination, notes and out-of-scope are authored, not generated.
- Existing triage labels are never overwritten, and
wayfinder:tickets never receive one. - A
parkedissue is not judged. A parked concept is not a work item, and triaging one turns a deferral into a work item by accident. - Nothing is closed, and nothing is removed. The pass adds labels and attaches sub-issues. Deciding an issue is dead is a person's call.
- The report stays local. It lands under
.firehorse/local/, which is gitignored, because it quotes issue bodies and names judgments the tracker does not carry.
Procedure
-
Run
pnpm triagewith no arguments and read the report it names. → Done when: the report exists and the ranked table has been read. -
Read the low-confidence bucket for clusters. Group the issues the pass could not place by subject, and for each cluster of three or more, say whether it is a missing map or a set of genuinely unrelated leftovers. → Done when: every cluster has one of those two verdicts.
-
Charter a map per missing cluster, with the destination, notes, standing preferences, and out-of-scope sections the existing maps carry. Label it
wayfinder:map. → Done when: each missing cluster has an open map issue, or was ruled a leftover in step 2. -
Check the vocabulary section. Every violation it lists is a rule from
docs/agents/issue-tracker.mdthat an open issue breaks. Fix each by hand. → Done when: the section is empty, or each remaining line has a reason to stand. -
Re-run
pnpm triageso the new maps are in the criteria, and read the grouping again. → Done when: the clusters from step 2 have landed under their maps, or the confidence says they have not. -
Apply:
pnpm triage --apply. Then verify the attachments landed with the sub-issue query indocs/agents/issue-tracker.md. → Done when: each map's children match what the report proposed. -
Place what the pass left over by hand. For each issue still unattached, read the top three probabilities in the JSON and decide, or record that it has no home yet. → Done when: every leftover is attached or named as homeless.
-
Report the actions applied, the maps chartered, the vocabulary fixes, and the issues left to a person with what each one waits on. → Done when: all four are present.
Handoff
Render this block only when step 3 chartered a map. A pass that changed labels and grouping alone ends at the step-8 report.
───────────────────────────────────────────────
## ▶ Next · <repo name>
**Chart the new map** · <n> maps chartered, tickets not yet cut
/clear then:
/firehorse:map
───────────────────────────────────────────────
- No new map, no handoff. Re-grouping under maps that already exist is maintenance, and the session that ran it can keep working.
- Never offer
--applyin the block. It has already run by then, and a block that suggests it invites a second pass over a tracker nobody has re-read. - Advisory voice. The block offers a command. It never says the user must chart the tickets now.
