| name | papercut-review |
| description | Analyze, triage, fix, and lifecycle-manage a papercuts corpus (the local friction-capture CLI). Use this whenever the user mentions papercuts in the context of reviewing, analyzing, triaging, prioritizing, fixing, addressing, resolving, or reopening them — "review my papercuts", "what's hurting", "papercut report", "what should I fix first", "address that papercut", "did that fix stick" — and whenever the user has just run `papercuts stats/list/export` and wants insight, or asks whether recorded friction has actually been fixed. Also use it when the user wants to mark papercuts resolved or bring one back: the lifecycle rules here (resolve only after a verified fix; reopen = regression) are part of the skill, not obvious from the CLI. |
Papercut Review
Papercuts capture friction. Capture alone fixes nothing — an unreviewed corpus
is a write-only diary. This skill closes the loop: snapshot → cluster →
rank → skeptically verify → fix → resolve, ending in a report with the
tables that make pain visible and a lifecycle state that stays trustworthy.
Three principles govern everything below:
-
Requested scope is the deliverable. A review request is not a fix
mandate; "fix the worst papercut" is not a mandate to also fix the
second-worst. When the analysis surfaces adjacent verified-fixable
clusters, propose them in the report's recommendations — with the
evidence that makes them cheap to approve — and stop there. The corpus
owner is prioritizing with their own budget; unprompted scope expansion
spends it for them and muddies attribution of changes. The same rule
governs lifecycle: resolve only records covered by the user's ask and
a fix you landed and verified inside that ask.
-
Volume is the pain signal. Papercuts are deliberately recorded on
every encounter, including repeats. Never dedupe records away during
analysis — nine records of one gate false-positive in a day is not noise,
it is the strongest prioritization evidence in the corpus. Count them,
don't collapse them.
-
A papercut's diagnosis is a hypothesis, not a fact. Records are written
mid-frustration, often by an agent that just got burned. The observation
("output was mangled") is usually reliable; the attributed cause ("a
redaction hook mangled it") frequently is not. Verify before you fix, and
verify before you report.
Phase 0 — Snapshot the corpus
Establish ground truth before interpreting anything:
papercuts stats --repo all
papercuts stats --repo all --include-resolved
papercuts list --repo all --limit 1000 --json > corpus.json
If bun is available, scripts/snapshot.ts (bundled with this skill) turns
corpus.json into the working views; otherwise build them with whatever
runtime is at hand:
- compact view — one line per record, chronologically indexed:
#idx [date] [repo] [source] body…. Every later claim cites #idx.
- the by-repo / by-day / by-source count tables.
Note the resolved-vs-active delta. A corpus where nothing has ever been
resolved tells you the loop has never closed — say so in the report; it is a
finding, not a footnote.
Phase 1 — Cluster into recurrence signatures
Category tags and repo names are weak groupings. Cluster by failure
signature: the underlying mechanism, expressed as a pattern over record
bodies (e.g. "shell variable clobbers PATH", "gate denies read-only command",
"output silently truncated"). Grep the compact view; iterate the patterns
until the big clusters are clean.
For each signature compute three numbers — together they distinguish
environmental problems from one-off stumbles:
- count — total records (remember: volume = pain, repeats count)
- day-span — distinct days, first → last occurrence
- repo-spread — distinct repositories
A signature with high count across many days and repos is environmental
(the tooling, the shell, a global config) and fixing it pays everywhere. High
count in one repo on one day is usually a single bad session or one broken
gate — cheap to fix, but verify it isn't already fixed before proposing work.
Phase 2 — Split false-evidence from friction, then rank
Classify every major signature into one of two severity classes:
- False evidence: the tool returned a plausible, confident, wrong
answer — exit 0, no error, output that reads as real. Silent flag
misparses that rewrite output, empty results that compare equal to empty
expectations, silently-capped listings, defaults that hide data. These
corrupt conclusions and decisions made downstream.
- Friction: cost time, retries, or annoyance, but failed visibly.
False evidence outranks friction regardless of count. A 3-record
false-evidence signature that fed a wrong audit conclusion matters more than
a 20-record papercut about noisy logs. Within each class, rank by
count × day-span × repo-spread, weighted toward recency.
When the user delegates the pick ("fix the worst one"), the ranking is a
judgment call between defensible candidates — highest-volume friction vs. a
smaller false-evidence signature. Make one pick, and state in the report
which criterion decided it and what the runner-up was, so the owner can
see the tradeoff and redirect cheaply if they weight it differently.
Phase 3 — The skeptic pass (required before fixing or reporting)
This is the step that keeps the loop honest, and it applies at two levels.
3a. Skeptic-verify each papercut you intend to act on
Before treating a record's stated cause as the thing to fix:
- Read the actual artifact it blames. If it blames a hook, gate, or
config — open that file. Does the blamed mechanism exist at all? Does it
behave as claimed?
- Reproduce the failure with the original (or equivalent) command, in a
way that cannot cause damage. A reproduction converts hypothesis to fact.
- Grep the corpus for the same signature under a different diagnosis.
Earlier records often contain the correct root cause for the symptom a
later record misattributes. The motivating case: a corpus held the correct
diagnosis of an
rg -r flag collision (output silently rewritten to the
replacement string) for two weeks while three newer records blamed a
"redaction hook" that did not exist — and the reviewing agent then
reproduced the same flag collision itself mid-review. The corpus knew; the
sessions didn't. When this happens, the fix must include propagation
(see Phase 4), not just a patch.
3b. Skeptic-review your own review before shipping it
You are as capable of a confident wrong conclusion as any tool. Before the
report or any resolve goes out, adversarially re-check it — and scale the
pass to the stakes. Anything that ends in a resolve, a landed fix, or a
shareable report gets the full pass (as a dispatched independent subagent if
the harness supports one). A quick informational question gets the checklist
applied inline — the pass exists to catch wrong conclusions, not to make
every task maximally expensive. The checklist:
- Are the counts reproducible from
corpus.json (not from memory)?
- Does every named finding cite record indices that actually say what you
claim they say? Spot-check by re-reading the raw bodies.
- For every "root cause" you assert: did you reproduce it, read the blamed
code, or find corroborating records — or are you pattern-matching?
- Did you check whether a "new" finding is already diagnosed, or already
fixed, elsewhere in the corpus or the codebase?
- Is anything in the report an artifact of your own tooling mistakes? (Run
your greps twice; the tools that generated the corpus's false-evidence
class are the same tools you are using now.)
Downgrade or drop any claim that fails. Report verified claims plainly and
unverified ones explicitly as hypotheses.
Phase 4 — Address a papercut
Fix at the root, with the smallest change, at the layer that is actually
loaded:
- Prefer fixing the tool/gate/template over training the human or agent.
A gate that false-positives on read-only commands gets a flag-aware
matcher; a doc telling everyone to be careful gets forgotten.
- Prefer the always-loaded layer — a global instructions file, a hook, a
scaffold template — over documentation nobody re-reads. If the corpus
proved a correct diagnosis failed to propagate (3a), the fix is
propagation: put the lesson where every future session sees it.
- Look for the fix pattern nearby. Inherited codebases often contain the
same lesson already learned in an adjacent rule (e.g. a DDL gate that
exempts read-only text tools, twenty lines below a file gate that doesn't).
Back-port it rather than inventing a new mechanism.
- Verify with the original failing command. The papercut's own text
usually contains the reproduction. Run it (or its test-suite equivalent)
after the fix. If the target has a gate/hook test suite, add the papercut's
case to it — must-allow cases are as load-bearing as must-deny.
- Probe the other direction before declaring victory. When you loosen an
over-broad gate/matcher/check, prove the things it exists to stop are
still stopped — including compound and indirect forms (
cd x && bad-cmd,
env-prefixed, absolute paths, git -C path …). Narrowing a matcher is the
classic way to open a bypass, and a fix that trades a false positive for a
silent hole is strictly worse than the papercut it resolved. Encode these
probes as new deny cases in the suite, not just a one-off check.
Phase 5 — Lifecycle
- A pure review applies no lifecycle changes. If the task was analysis
("review my papercuts", "what's hurting"), the report proposes
resolutions — listing exactly which records a given landed fix would
close — and touches nothing. Resolving is the corpus owner's lever unless
they asked you to pull it (a fix mandate, "clean up those records",
lifecycle management).
papercuts resolve <id> — only after the fix is verified, and then for
every record that fix addresses within the asked scope, not just the
newest. Partial resolution leaves the signature looking half-alive;
resolution beyond the ask is scope creep (see principle 0).
- Leave open any record that looks related but has a different root cause —
and say in the report why it stayed open.
papercuts reopen <id> — when a resolved cut recurs. A reopen is a
regression signal: the fix didn't hold (or got reverted). Treat it as
such, don't just re-resolve it.
- Never resolve as housekeeping. "Stopped recurring because the project
ended" and "fixed" are indistinguishable in an unresolved corpus —
resolution-after-verified-fix is exactly what makes the data trustworthy.
If the user asks to bulk-clear stale records, push back once with this
reasoning, then do what they decide.
The report
Every review ends in a report. Follow the exact structure and table formats in
references/report-format.md (read it before writing). Non-negotiables:
- the corpus overview table (per-repo: records, active, resolved, span,
top signature)
- the signature table (count / day-span / repo-spread / first→last /
class / status)
- a false-evidence section listing each plausible-wrong-answer case
- fixes applied, each with its verification evidence
- resolutions: how many records, against which fix, with IDs — plus what
was deliberately left open and why
- skeptic-pass outcome: what was verified, what was downgraded, anything
refuted
Cite record indices (#idx) throughout so every claim is checkable.