The session that shipped a bug, and the retro that said smooth
Claude Code shipped a numbering bug on a real repo, and four approved changes made it impossible to ship again. The session wrote credit notes for a small invoicing API, the test suite came back green, and a check run afterwards by hand found that a rejected request had burned an invoice number. We then ran a retro on that session, approved the fixes one by one, and ran the same task again: it came back clean.
A retro is the review a team holds after an incident, run here on Claude Code's own session log. Our first retro opened with "This session was smooth", and none of its findings was the bug. The fix is seven gestures, in order: install, run the task, run the retro and tell it what failed, trace each candidate, approve each survivor into a carrier, commit and audit, and re-run the task.
What a retro is, and installing /retro
/retro is a skill by Matt Pocock that reviews a coding session instead of your code. It reads the session log, the file Claude Code keeps of every prompt and every tool call, and looks for candidates in seven categories, such as a check that could have caught a mistake. It presents them by severity and, per its docs, only proposes: nothing changes until you pick a candidate.
Installing it is the first gesture: in your repo, update the official marketplace, then install the skills pack at project scope so it lives in this repo only. Our marketplace was pinned to an older release without the retro, so the update came first. In a new session, type a slash and the retro command is in the list.
One limit: a cloud session cannot read the logs on your machine, so run the retro where the session happened.
Run your task and let it finish: our session shipped the bug
The second gesture is the one you already do every day: type your real task into a plain session, let it finish, and keep the session open, because that is what the retro will read.
We used a small invoicing API in Node and TypeScript, with its own test suite and no instructions file, no pipeline and no commit hook anywhere. The task was short, the way you would type it yourself: add credit notes to paid invoices, numbered in sequence, and let a paid invoice be voided by crediting what is left.
The session wrote the route, a migration and its own tests, and ran the suite before stopping. Then we ran the check finance would run by hand, a hidden test written beforehand, and a requirement failed.
| Signal | Result |
|---|---|
| Test suite | 42 tests passing |
| Type check | clean |
| Hidden finance check | failed: got a later credit note number than expected |
The cause: the handler takes the next number from the counter before it validates the request, and the counter is saved the moment it is read. A credit note that is too big is rejected, which is correct, and the number is gone anyway, which is not. The session copied that order from the existing issue route, which leaks invoice numbers the same way.
We ran the task twice and the other run came back clean, so this is what a plain session does some of the time.
Run /retro, then tell it what failed
The third gesture is to type the retro command in that same session, then run it again with the failure written after it. Ours began: "This session was smooth."
It ranked a handful of items, none the bug: a missing guardrail, a migration rule nobody checks, and nothing for a reviewer to enforce. The retro reads the session log, and the session never learned it had failed.
So you tell it: run the command again with the failure as its argument, the text after the command. Ours said that finance had tested the build, that a credit note too big was rejected, that the next valid note came out late, and that the retro should fix nothing.
This time it found the cause in its own code: it takes the number first and validates second, and it said it copied the order from the existing issue handler. New candidates followed: a test it had written that ran the failing sequence but only checked status codes, a counter function that looks pure and is not, and a convention nobody wrote down.
Whatever you found after the session, type it into the argument, or the retro audits a session it believes went fine.
Trace every candidate to a moment before you approve
The fourth gesture is the one the skill does not do by itself: ask the retro to quote the moment of the transcript behind each candidate, and drop every candidate it cannot show.
The docs explain why a ranked list is not enough: once a job is finished, the model forgets the struggles of the session and invents generic advice. So discard any candidate you cannot trace to a specific moment: one sentence asking the retro to quote the transcript for each.
On our first retro the answer was blunt: most candidates had no support in the transcript. It kept the missing guardrail, because its own listing of the hooks folder had printed nothing, and dropped the migration check as a hypothetical.
On the second retro, the one that knew about the bug, the trace kept four candidates and dropped one.
| Candidate | After the trace |
|---|---|
| The test it wrote (accepted, rejected, accepted, number never checked) | kept, firm |
| The counter function with no warning | kept, firm |
| The unwritten convention | kept, weaker |
| The missing guardrail | kept, though it said a guardrail would not have caught this bug |
| The last candidate | dropped: it counted the same moment twice |
An open issue on the skill's repo counts most retro runs followed by a user asking for proof. A traced candidate is still the model reading its own log, so a row marked weaker is a judgement, and you decide which ones you carry forward.
Approve each survivor into its carrier
The fifth gesture is where the loop pays off: approve one survivor at a time, each into its carrier, the place where the rule will live. The skill gives you the ladder. A mechanical violation gets a deterministic check, full stop: a rule in your linter, a commit hook, or a job in your pipeline. A judgement call goes into a coding standards file that the reviewer reads. Your instructions file is used, in the docs' words, "incredibly sparingly", for pointers to other files.
We approved four changes:
- The missing guardrail became a tracked commit hook that runs the type check and the tests and blocks the commit if either fails. The harness refused to make the file executable, so we ran that command ourselves.
- The test became one
vitesttest that locks the rule: a credit note accepted, a credit note rejected, and the next valid one must carry the next number. It failed on its first run, which is the point: it caught the bug the session had shipped. - The judgement call became one line in a new
CODING_STANDARDS.md: take a sequence number only once every validation has passed, so a rejected request leaves the sequence gapless. - The navigation gap became one comment above the counter function: it persists the counter at once, so the number is spent even if the caller then fails, so call it only after validation.
That is four files changed and zero lines in CLAUDE.md, because both retros declined to write one. The first said a steering-file pointer would cost context on every turn and go stale; the second said to keep it as a comment on the function. The docs back them up: Claude treats those files as context, not enforced configuration, and to block an action you use a hook instead.
Two limits: a hook only protects commits, and the comment is, in the retro's own words, a bet on the next caller, not a proven fix.
Close the loop: the hook blocks your commit, audit, commit, re-run
The sixth gesture is the commit, and the last one is running the same task again, which is where you find out whether the loop held.
When we staged the approved files and committed, the hook ran first and refused the commit. The type check passed, then the new numbering test failed, receiving a later number than it expected. The hook checks the files as they are on disk, and the disk still held the buggy code.
So go back to the session and ask for the fix only: take the number after validation passes, run the checks, do not commit. Then commit again, the hook runs green, and you get two commits: the retro changes, then the feature with its fix. The retro itself committed nothing, which an open issue on the repo describes word for word, so you commit.
Next, run /doctor prompt-audit, Claude Code's own check of your instruction files for stale lines. Here is a trap: without a path, it audits your global files, not the repo. Given the path, it called the new standards file clean, and flagged that the older issue route violates the rule, a code bug and not a prompt problem.
The last gesture is a fresh session with the same task. Ours read the coding standards file, the readme, the hook and the red numbering test before writing any code, then wrote in its own summary that the number is taken only after all those checks pass, so a rejected request leaves no gap in the sequence.
| First session | Fresh session after the loop | |
|---|---|---|
| Tests passing | 42 | green |
| Hidden finance check | failed | 5 of 5 |
| Numbers after a rejected request | burned, a gap | gapless |
One honest caveat: this fresh session was handed the lesson as a red test and a standards line, so it is a run after the loop, not a benchmark.
Verdict: when to run a retro, when not, the one rule
The retro reads the session, so what the session did not see, you write into the argument. That is the part you will trip on.
Run a retro after a session that went wrong, before you clear it, or on the old session's log. Do not run it on autopilot or wire it into a hook: the skill's author says it in his own words, you do not want to automate this. The docs add a limit: it does not audit the checks it proposed last month, so you still prune them yourself.
The one rule to remember is the docs' own sentence: treat your instructions file like code, review it when things go wrong, prune it regularly, and test changes by observing whether Claude's behaviour actually shifts. the loop does not make the agent right, it makes the same wrongness faster to catch, and the checks you add are code you now maintain.
The free pack for this video has the retro checklist with every gesture, the trace question and the carriers, plus the commit hook script and the numbering test from our run, so you can start from ours.
AIDive