Feedback triage
Skill grimaldost/craft-collection/plugins/session-workflow/skills/feedback-triage
Triage a tool's accumulated dogfooding feedback reports into a leverage-ordered improvement backlog — reconcile what already shipped, cluster findings by underlying cause rather than symptom, assign each cluster a disposition (attack this tool, route out to the tool that owns it, or decline), apply a promotion gate (reinforced across reports, specific, actionable), and emit a triage document with a status-tracked promotion table. Use on "triage the feedback backlog", "cluster the feedback reports", "what should this tool fix next", "promote the recurring feedback", or "/feedback-triage". Explicitly invoked maintenance — never run proactively; it reads a whole corpus. If the tool's binding registers its own triage template (e.g. keel's reflection-triage), follow that template. Not for consolidating journal entries into guidance (that is consolidate-knowledge), not for a corpus of one report with no prior triage (nothing to cluster yet — a 1-report delta over an existing baseline IS a valid later pass), not for triaging GitHub issues or a PR queue, and not for triaging a governed series' own reflections into durable checks — the owning method tool's triage skill (e.g. keel's keel-triage) does that, not this generic feedback pass.From its SKILL.md
npx -y skills add grimaldost/craft-collection --skill feedback-triageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 1 command, including `uv run --no-project python "${CLAUDE_PLUGIN_ROOT}/skills/feedback-triage/scripts/build_feedback_index.py" <dir>`.
SKILL.md
12.3 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it
Feedback Triage
The downstream half of the tool-feedback loop. tool-feedback captures one report
per session; this pass reads the accumulated corpus and turns it into the tool's
improvement backlog. Capture is tuned for recall; triage is tuned for precision —
the bar is a maintainer can pick the top item and build it without re-reading the
reports. It ends at the backlog document: building promotions, version bumps,
and CHANGELOGs belong to the tool's release process.
The pipeline — run in order
-
Scope. Resolve the tool from the
feedback-targetstable in loaded context (ask once if absent; never hunt). Rebuild the dir'sINDEX.mdfirst (runuv run --no-project python "${CLAUDE_PLUGIN_ROOT}/skills/feedback-triage/scripts/build_feedback_index.py" <dir>): its### Untriagedsection is the input list — reports in no triage doc's Inputs, detection by input lists, not dates — and theextends-lookup in steps 2–3 is one Read. A triage doc is detected by its# TriageH1 — the rule the index builder stamps into its header; the filename is deliberately NOT a signal (references/mechanics.mdhas the misclassification cases). State the count:N un-triaged reports. N of 1 with no prior triage doc is too thin — stop with a note (nothing to cluster); 1 new report over an existing baseline is a valid delta pass (step 7). When the invocation names a different count or set, the directory is authoritative — note the discrepancy under Inputs. Note any triage doc already dated today and re-check at emit (step 7). -
Reconcile shipped first. Read the tool's CHANGELOG since the last triage — on a first run, the whole CHANGELOG to date. For a component without its own CHANGELOG (a harness, a scripts dir, a doc set), also read
git logover the window — increments land as commits, invisible to CHANGELOG-only reconciliation. Map each finding to the version or commit that resolved it. Open the doc with "Already shipped — NOT re-proposed"; a cluster that goes further than a shipped change is marked as extending it. Reconcile OPEN rows too, not only shipped ones: the INDEX's## Triage coveragelists every triage doc in the dir, so carry or re-disposition each one's openproposed/watchrows into this pass — a row is not closed until a later doc lists it. An off-main-chain cycle-scoped triage otherwise orphans its rows (keel'sreflection-triageP3a is the twin; co-land). -
Cluster by underlying cause, not symptom. Three reports saying "the cited file didn't exist", "the helper didn't handle our shape", and "the precedent was counterfactual" are one cluster: ungrounded referents. Collapsing has a dual — split one super-cause into separate clusters when its corollaries have distinct homes and distinct concrete fixes; each piece must be promotable on its own. Follow
extendschains while clustering: a finding belongs with its ancestors, and chain length is recurrence evidence. Cite each cluster's evidence as finding IDs (or stem + section for narrative findings), with counts. For a same-wave-execution/-authoringpair, read-executionfirst — it holds the evidence. -
Assign a disposition per cluster:
- ATTACK — a real increment to this tool; name the home (template / gate /
skill / doc / ADR) and the fix shape, derived from the cause, not the
symptom. Prefer shapes in this order: remove/simplify what produces the
failure; restructure the section or mechanism so the class can't recur;
mechanize (test / script / gate / hook); append prose — last, and
only naming what it displaces (a clause folded, tightened, or retired) —
loop bodies measurably grow one clause per promoted finding until a cold
reader drops load-bearing ones. Escalate the layer on a recurrence: when
a finding recurred after a fix already shipped at the same enforcement
layer (≥2 post-fix reports) and its cause is mechanically reachable at
the next layer, attack one rung down — advisory prose → required structure →
script/gate → hook → linter/CI — instead of re-prosing the same advice. A
judgment-bound recurrence no mechanism can reach (a dispatch-timing nudge, a
naming call) takes sharper prose or DECLINE, not a forced rung —
skill-authoring's rule, loop-side: what needs caps to hold needs a gate, not louder prose. - ROUTE OUT — it belongs to another registered tool; record the target.
- DECLINE — project-specific or out of charter; record why.
Tie-breaker when this tool's artifact participates in behavior another tool owns: route by where the fix lands, not where the artifact lives. Fan-out digest briefs must enumerate each tool's own components in the owner taxonomy — misrouting case in
references/mechanics.md. - ATTACK — a real increment to this tool; name the home (template / gate /
skill / doc / ADR) and the fix shape, derived from the cause, not the
symptom. Prefer shapes in this order: remove/simplify what produces the
failure; restructure the section or mechanism so the class can't recur;
mechanize (test / script / gate / hook); append prose — last, and
only naming what it displaces (a clause folded, tightened, or retired) —
loop bodies measurably grow one clause per promoted finding until a cold
reader drops load-bearing ones. Escalate the layer on a recurrence: when
a finding recurred after a fix already shipped at the same enforcement
layer (≥2 post-fix reports) and its cause is mechanically reachable at
the next layer, attack one rung down — advisory prose → required structure →
script/gate → hook → linter/CI — instead of re-prosing the same advice. A
judgment-bound recurrence no mechanism can reach (a dispatch-timing nudge, a
naming call) takes sharper prose or DECLINE, not a forced rung —
-
Ground, then apply the promotion gate. Before writing a row, ground it against the tool's current source: verify the mechanism it names is actually absent (or present, for an extension), implementable as stated (the API allows it), and truthfully named for the shape it will carry — cite the check in the ledger. A CHANGELOG window cannot see work shipped releases ago; only the source can — ungrounded rows have re-proposed the shipped and proposed the impossible. Then promote only clusters that are reinforced (≥2 reports, ideally across arcs — a single-report BLOCKER is exempt), specific (a concrete change with a home), and actionable. The exemption's scope is the BLOCKER's own row — siblings from the same report justify themselves in the ledger or take
watch(the middle disposition: keep the row, hold the build, wait for a second report). Under-promote rather than pollute; unpromoted clusters stay listed as raw, and the Promotion-gate ledger shows the gate's work either way. -
Consolidate before you grow. A standing debt check on every pass: a home that takes an appending promotion this round, carries clauses no report has exercised across recent rounds, or nears the validator's size cap gets a consolidation row of its own — fold accumulated sub-cases into a reference file, merge overlapping clauses, retire dead ones. Shrink rows ride the same table and statuses as any other promotion; a loop that can only add converges on bodies too dense to execute.
-
Emit the triage doc (template below) into the tool's feedback dir as
<YYYY-MM-DD>-triage-<scope>.md, clusters leverage-ordered. A later pass over a corpus with a baseline emits a NEW doc in the delta form — Inputs list only the new reports, the new table supersedes the baseline as status of record, a consolidated backlog table carries every open row, cluster IDs continue the baseline's namespace (references/mechanics.md). Before emitting, assert input coverage: every finding<stem>#<n>in the Inputs' INDEX entries appears in the doc under a disposition — a cluster's evidence, Routed out, Declined, or an explicit "no action: <reason>" — so a finding leaves the loop only with a disposition, never by omission (a dropped extends-chain surfaced two passes late). Then re-list the dir: a same-corpus triage doc that appeared since step 1 is reconciled with, not duplicated. Close by re-running the index builder: just-triaged stems still under### Untriagedmean the Inputs did not parse (fragmented stems) — fix before ending. -
Defer to a tool-owned template. If the binding's
extrasregisters a triage template (keel'sreflection-triage), follow its structure and homes; otherwise the template below is authoritative — don't hunt for one. Triaging "everything" when one tool owns its own flow? That tool's slice is a digest-for-handoff: extracted, clustered, owner-tagged (per step 4) findings written as INPUT to its flow (a<date>-new-findings-digest.md) — not a competing triage, not skipped.
Triage doc template
# Triage — <tool> feedback backlog (<N> reports, <date-range>)
## Already shipped — NOT re-proposed
<changelog reconciliation; clusters below that extend shipped work say so>
## Inputs
<full report stems, one per line; the coverage parser matches whole stems —
a factored-out date prefix reads as zero coverage>
## Headline
<2–4 sentences: what this round establishes about the tool>
## Clusters
### T1 — <underlying cause> (<disposition>; <recurrence count>)
<evidence: cited finding IDs / report stems>
| # | proposed promotion | fix shape | home | status |
|---|--------------------|-----------|------|--------|
| T1a | <the concrete change> | <remove / restructure / mechanize / prose (displaces: …) / new artifact> | <template/gate/skill/doc/ADR> | proposed |
### T2 — …
## Routed out
<cluster → target tool, what was routed>
## Declined
<cluster → reason>
## Promotion-gate ledger
<the gate's work, auditable per cluster: which cleared on reinforcement, which
promoted via the BLOCKER exemption (name the exempting finding), which sit at
`watch`, which stayed raw — and why. Close with three assertions: no singleton
non-BLOCKER was promoted, no prose append shipped without a named displacement,
and every Inputs finding is dispositioned (input coverage).>
Status vocabulary: proposed / watch / accepted / shipped(<version>) /
declined — watch parks an anchored-but-singleton row until a second report
corroborates it; later passes update statuses. (Report finding IDs <stem>#<n>
are minted by tool-feedback; promotion IDs T1a are minted here — two
namespaces, don't conflate them.)
Anti-patterns — hunt these
- Re-proposing shipped work — the reconciliation step exists to kill this.
- Symptom clusters — grouping by where it hurt instead of why it happened produces ten shallow clusters where two deep ones exist.
- Over-promotion — a singleton observation promoted as if reinforced; the
gate exists to kill this, and
watchkeeps the anchored singleton. - Absorbing what should be routed — an engine defect "fixed" with a method doc; honor each tool's ledger and route out.
- Re-prosing a recurrence — a finding that recurred past a shipped prose fix needs a stronger enforcement layer, not a fourth sentence of the same advice.
Relationship to neighbors
tool-feedback captures (per session, recall); this consolidates (per corpus,
precision) — the same shape as journaling-sessions → consolidate-knowledge,
specialized to tool dogfooding. (A governed series' own reflections belong to the
owning tool's triage flow — see step 8.)
What this skill does NOT do
- Build promotions, edit the tool, bump versions, or write CHANGELOG entries.
- Run proactively, or on a corpus of one report with no baseline (a 1-report delta over an existing baseline is a valid later pass).
- Triage GitHub issues, PR queues, or task backlogs.
What ships with it: 3 files
32.4 KB alongside SKILL.md, 2 of them executable
references/
- mechanics.md2.6 KB
scripts/
- build_feedback_index.pyruns11.4 KB
- test_build_feedback_index.pyruns18.4 KB