Retro
Overview
A retrospective built from evidence, not memory. Miner agents read the window's raw session transcripts for friction; the session lead clusters findings into candidates with typed remedies; Jerry decides each one. The miner proposes, Jerry commits.
Memory-based retros re-report what a journal entry already concluded. The transcripts hold what actually happened — the corrections, the retries, the abandoned approaches.
Flow
1. Window. Read ~/.claude/retro/last-retro (ISO date). Absent → 7 days back.
1b. Report last retro's remedy status before mining anything. Read the previous
~/.claude/scratchpad/retros/*.md, take every kata ref it recorded as approved, and
kata show each one. State in the recap how many landed and how many are still open.
This is not bookkeeping. On 2026-08-15 all five remedies approved the previous retro were still open, and three of them produced repeat findings in that same window — the retro was re-mining friction its own last output was supposed to have fixed. Approving remedies that sit unworked is worse than approving fewer, because the filed-and-ignored ones make the next retro's evidence noisier without changing anything. If the previous retro's remedies are mostly unworked, say so up front and consider capping this retro's approvals.
Then append this window's metrics row and paste the trend under the remedy-status lines:
python3 ~/.claude/skills/retro/retro_metrics.py --append # tiles from the previous row
python3 ~/.claude/skills/retro/retro_metrics.py --trend
The trend is per pattern, per window, split by Claude Code version when a window mixes
versions. Read the version split before proposing a remedy for any refusal class: on
2026-09-02, 326 of 467 worktree-guard refusals were a harness bug fixed in 2.1.257, not a
process failure. Patterns and their remedies live in patterns.toml; add a remedy's kata
ref there when the retro approves it, and its landed date follows the issue's close.
Only interactive sessions (at least one human turn in the top-level transcript) count, so
headless kata-dispatch runs are excluded, and a session counts in the window it last wrote to,
not the one it started in.
2. Prefilter (deterministic, do this before dispatching anything).
python3 ~/.claude/skills/retro/mine_transcripts.py --days N > /tmp/mine.md
Transcripts run to tens of MB per week; this cuts ~300× by keeping only human turns and
failed tool results, each stamped file:line. Read the header — it reports session counts,
raw MB, and headless sessions skipped. Those numbers go in the recap.
3. Mine. One general-purpose subagent on sonnet per project in the prefilter
output, highest distinct count first — the projects are already printed in that
order, capped at 6. Rank on distinct, not raw human turns: a launched agent
session, a probe, or a batch job replays one templated prompt across dozens of
sessions, and raw counts let that outweigh a project with real back-and-forth.
Turns matching a template are tagged [TEMPLATE] in the slice; a run of them is
protocol, not signal. Give each miner the prefilter
slice for its project (--project <substring>) and this instruction:
Each entry begins with a pointer
/full/path/session.jsonl:LINE, optionally followed by[TEAMMATE](relayed from another agent session — not Jerry) or[TOOL ERROR]. Findings come only from the slice provided. Every finding cites the pointer exactly as it appears at the start of the entry, copied verbatim, with the quoted text beside it. If a pattern is real but you cannot cite a pointer for it, report it underUncited impressions— do not promote it to a finding.
Give the miner the pointer format verbatim like that. Tested: miners handed a bare L648:
marker cited the slice file's own line numbers instead about 40% of the time, because two
coordinate systems were visible at once. A whole-token pointer removes the ambiguity.
Miners return their report as message text; the lead transcribes it to
report-<project>.md. Do not instruct them to write the file — the harness denies subagent
Write for report files ("Subagents should return findings as text, not write report files"),
so every miner burns an attempt on it and some then go quiet. This is confirmed, not
suspected: three miners independently hit the refusal on 2026-08-15, which settles the open
question the 2026-08-06 retro carried. Do not re-test it, and do not write a
write-the-file instruction into any dispatch brief.
Instruct miners to send one finding per message from the start. The relay drops long message bodies. On 2026-08-15, 5 of 8 miners lost their report twice each on a full-body send; all four holdouts then completed cleanly, ~15 messages, zero further drops, once switched to one-finding-per-message. Payload size is the variable. Put this in the miner brief:
Send your report one finding per message — the pattern line, its Evidence pointers with quoted text, and the Cost line, and nothing else in that message. Send a final message with
Uncited impressions. Do not wait for acknowledgement between messages. A single long report message will be dropped by the relay.
Expect to re-prompt anyway: idle notifications arrive with the report dropped (see
reference_subagent_report_relay_drop). The reliable recovery is a SendMessage asking for a
chunked resend — asking for a full resend usually drops again.
Run these in parallel alongside two more miners:
- journal — mnemosyne entries in window. (
.remember/was the disabledrememberplugin's output; retired 2026-09-02 after three retros reporting it stale.) - kata — closed / deferred /
needs-review/needs-decisiondeltas across projects in the window.needs-decisionis the one to read as a backlog rather than a delta:wakeysurfaces it per-project, so a ruling nobody is waiting on in a project Jerry hasn't opened lately is visible only here. Report the standing count per project, not just what changed.
4. Synthesize (session lead, not a subagent). Dedupe across miners and cluster.
5. Retro conversation. Accomplishments recap first — short, unembellished. Then walk candidates one at a time, waiting for Jerry on each.
6. Commit phase. Apply only what Jerry approved. Write
~/.claude/scratchpad/retros/YYYY-MM-DD.md, journal via mnemosyne, then write today's date
to ~/.claude/retro/last-retro.
Candidate contract
Every friction candidate has exactly these five parts, in this order:
- Pattern — one sentence, what recurs
- Evidence — one pointer per instance, as
path/to/session.jsonl:LINEwith the quoted text. Two instances is what makes it a pattern rather than an incident. A single vivid instance is not a pattern; keep it, label it as one-off, and let Jerry judge. The prefilter emits one line per event, so a second pointer means it happened twice — not two citations for the same event. - Cost — what it actually cost (time, rework, a wrong turn taken)
- Remedy type — exactly one of:
hookify rule·skill edit·new skill·feedback memory·kata issue·tooling fix - Draft remedy — the concrete change, specific enough for Jerry to say yes to
A candidate missing any part is not ready to present. Fix it or drop it to
Uncited impressions.
Verify citations before presenting
Run every miner's output through the checker. It resolves each pointer and confirms the quoted text is actually at that line:
python3 ~/.claude/skills/retro/verify_citations.py <miner-output.md>
Non-zero exit means something did not check out:
| Status | Meaning |
|---|---|
TEXT-MISMATCH |
Quote is not at that line. It reports where the quote does live, if anywhere — usually an off-by-N to fix, occasionally an invention to drop. |
ABBREVIATED-POINTER |
Written .../session.jsonl:21. Not resolvable by a reader; make the miner emit the full path. |
NO-SUCH-LINE / NO-SUCH-FILE |
Pointer into empty space. |
UNVERIFIABLE |
Pointer with no quoted text beside it. Add the quote or drop the finding. |
Fabricated-but-plausible citations are the characteristic failure of mining agents and are invisible in a clean-looking report. State the checker's summary line in the recap.
The gate is the point
Jerry approves each candidate before anything is applied. Nothing in step 6 runs early.
Red flags — stop:
- "I'll apply this obvious one and show him the rest"
- "He approved a similar remedy last retro"
- "Applying it is the fastest way to demonstrate the candidate"
- Writing a hook, skill, or memory file during steps 2–5
All of these mean: present it as a candidate and wait.
Report what you did not cover
The recap states per-source status: which projects were mined, which were dropped by the cap and why, and any source that failed or returned nothing ("mnemosyne unavailable", "kata: no closes in window"). A source that is silently missing reads as a source with nothing in it.
Common mistakes
| Mistake | Fix |
|---|---|
| Retro built from journal entries | Journal is one miner of three; transcripts are the primary source |
| "Recurred several times in alexandria" | Cite file:line per instance or it is an impression |
| Bundling candidates into one verdict | One at a time — Jerry decides each |
| Silent cap at 6 projects | Name the dropped projects in the recap |
Grouping project dirs by splitting on -- |
Dotfile and /tmp paths contain -- too (.claude → -claude). Worktree siblings are <known-slug>--*, only identifiable against a known project root |
| Skipping the stamp write | Next retro re-mines the same window |