Agile teams hold retrospectives to look at what went well and what hurt, while it's still fresh enough to fix. I wanted the same for my work with Claude, so both of us learn from accumulated experience, beyond the last session. The retrospective skill keeps a journal of decisions, scores each one against what was expected, and ties every finding to evidence.
- Write down what you expect when you make a decision.
- The retro scores each decision against what happened, and every finding has to point at evidence.
- Every action comes back at the next retro until it's done, carried with a reason, or dropped.
In this post
- 01What the skill does
- 02Why not just critique or handoff
- 03Inside the folder
- 04How it connects to the rest of the ecosystem
- 05A real example
- 06When a retro never gets filed
- 07A silent fault in the capture path
- 08Design decisions
- 09Best practices
- 10Limits
- 11Next
flowchart TB
D["Decision +<br/>expected outcome"] --> O["Observed result<br/>+ evidence"]
O --> V["Verdict against<br/>the expectation"]
V --> A["Owned action<br/>with a due date"]
A --> R["Next retro:<br/>done, carried or dropped"]
What's not obvious: the last step closes the loop. An action nobody did comes back by name, and carrying or dropping it needs a reason.
What the skill does
~2 minA good decision can have a bad outcome, and a weak one can get lucky. A later review can tell them apart only if the expectation was written down at the time, the way a pre-registered study fixes its hypothesis before the data arrives.
This skill uses a hook to turn raw activity, decisions made, results observed and friction hit into structured journal lines tagged DECISION, EVENT, RESULT,
FRICTION, WIN. Re-examining past events no longer relies on shaky memory after the fact or on the tedious pressure to multitask between doing
the work and documenting it.
The journal is an append-only JSONL file. Each line is one record with a timestamp, a type, the session and, for a decision, the expected outcome. It keeps only what a later review can act on, and it never guesses a decision from a transcript.
You can type lines by hand, or a Stop hook can pull them from the transcript with a regular expression and no model call. The hook fires at the end of every turn. It takes decisions only from your own text, and the other four types from either side, with a separate cap on the assistant's share. If a decision comes without an expected outcome, the hook asks you for one and never guesses.
Each retro answers four questions
What happened to the actions?
Each gets a verdict of done, carried or dropped, with a reason.
Expected, then actual
What did each decision expect, and what happened?
What does it support?
A panel of lenses reviews the period. Each lens raises at most three findings, all anchored.
What changes?
Who owns it, and by when?
These map to eight phases, R0 to R7, listed at the end. The retro grows with the number of journal lines since the last one, from two lenses on a single task to the full panel at a project's close.
Question 2 gives one number, the share of resolved decisions that turned out as expected. The skill calls it a calibration rate. Strictly, it's an expectation-match rate, and it says nothing about probability calibration.
Why not just critique or handoff
~1 minThe project already has two other review skills that might appear very similar, but only on the surface. Critique remembers its own findings on one file but nothing of the project around it, and Handoff looks exactly one session ahead. Each can trigger a small, bounded version of Retrospective skill directly when their own signals cross a threshold such as a defect that survives two review cycles or a repeating pattern in handoff snapshots, but neither of them is built to track on its own.
| critique | handoff | retrospective | |
|---|---|---|---|
| Looks at | One file, right now | One session's state | Everything logged on a subject |
| Timeframe | A single pass | This session, for the next one | Accumulates across many sessions |
| Checks | Is this specific thing correct | What's decided, open, unverified | Did past decisions turn out as expected |
| Output | Findings, graded and patched | A labelled snapshot | Root causes, an owned action list, a self-score |
Inside the folder
~1 minretrospective/
├── SKILL.md
├── README.md
├── references/
│ ├── panel.md
│ ├── lite.md
│ ├── formats.md
│ └── destinations.md
└── scripts/
└── retro_capture.py
SKILL.md is the protocol and README.md the setup. The references cover the panel, the LITE test, the document template and where files go. The script is the Stop hook, and it logs every session where it found nothing, so a quiet hook and a broken one look different.
How it connects to the rest of the ecosystem
~1 min
flowchart TB
CR["critique"] -->|"same finding in 2+ runs"| LT["LITE retro"]
HO["handoff"] -->|"PATTERN not empty"| LT
LT --> J[("journal")]
CR -->|"review log"| R1["R1 Facts"]
HO -->|"snapshots"| R1
CR -->|"cost counters"| FL["finance lens"]
J -->|"recurring friction"| HO
Every link here is optional.
- Critique or handoff can start a small LITE retro. It runs only if its own test finds two signals, writes at most 12 journal lines and one action, and skips the panel.
- The finance lens uses cost data, such as critique's counters or the time between journal entries. With neither, it reports nothing.
- Close-session runs retrospective, critique and handoff in sequence at the end of a working session.
A real example
~2 minThis one comes from another project of mine, a solo pipeline that collects listings on a schedule and publishes a small dataset.
That week's journal was empty on purpose. The project keeps its record in an action ledger and daily notes, so the invocation named those as the sources.
One decision, traced
| Decision | Redesign the collector so every fetched record is kept along with the decision made about it |
| Expected | Records persisted equal records fetched |
| Evidence | The first output line under the new schema, checked against the real output file |
| Verdict | landed as expected verified directly |
Two earlier actions that paid off
ROTI is the retro's score for its own usefulness, from 1 to 5. This one named its weakest part as a five-lens panel against a cap of four. The quotes are word for word, with names, paths, commit hashes and dates removed from the whole document.
See every table this retro produced →
When a retro never gets filed
~1 minA retro ends with two writes, the document and a closing marker in the journal. The next retro reads the marker to know where its period starts.
In the blog project behind this series, both writes failed:
- The session couldn't write to the skill's state folder.
- One retro ended up as a project document, with a copy in a stray folder.
- The other sat for two days beside a script meant to file it, and nobody ran the script.
- With no marker, the next retro would have counted zero new lines.
What changed since:
- Lines that can't land go to a
prepared/folder marked "staged, not landed". - The stray-folder rule lives in project memory.
- The actions file has existed since 15 September.
- Still open: a proposal to apply R0's rule for ignored actions to open questions as well, after one question went through three retros unanswered.
A silent fault in the capture path
~1 minWhile I was writing this post, a critique run found two faults that failed silently.
Markers lost after the first turn
The hook assumed Stop fired once per session, so it skipped any session already in the journal. A four-turn test kept one marker of two.
A health check that couldn't fire
R1 looked for an error type the hook no longer wrote, so it could never flag dead capture.
Hook v2.5 and protocol v1.8 fix both. The hook now deduplicates by marker type and text within a session, and reads the last turn from the hook input, since the transcript file can lag.
The lesson: a capture path needs its own health signal, so a quiet week and a dead hook leave different traces.
Design decisions
~1 minFiling is a commit
The period ends only when the document and the closing marker are both written. The incident above is what a half-done commit looks like.
Caps keep it short
Three findings per lens, capped actions, word limits, and a thread with no new causes gets closed. Extra analysis costs almost nothing with AI, and the caps stop a retro from bloating.
High-stakes lenses run separately
At the largest tier, the two highest-stakes lenses run as separate subagents where possible. In one audit they caught a figure no command had produced and a patch promoted without approval, both missed by the author's own review.
A finding that isn't filed doesn't exist yet. The next retro only learns from what's written where it looks.
Best practices
~1 min- Check that capture works. Read the hook's error log now and then. Where the hook can't run, as in this project's Cowork sessions, every journal line so far was typed by hand.
- Give each action a file or a command. By 12 September, the blog project had finished 1 of 12 tracked items, and every action in its last three retros was a habit for a future session.
- Put fixes where they load automatically. A fix buried in a retro document needs someone to reread it. In another project, a self-monitoring rule failed twice and was replaced by a check stated in the same turn as the action.
Limits
~1 min- An anchor shows traceability, and validity needs its own check. The example retro found a rollout where "every earlier claim about it had been citing other claims about it". A chain of citations is only as strong as its first primary source. A missing log is weaker still, since it can mean nothing happened or that the collector failed.
- Some surfaces can't run the hook or write skill state. Lines staged in
prepared/stay outside the journal, so the next retro has to be pointed at them. - ROTI is self-reported. Nothing acts on a low score yet, and the open-questions rule hasn't shipped.
A proposed fix stays a proposal until someone applies it.
Next
The finance lens reports nothing when nothing measures cost. The next post covers the skill that does.
Technical detail: phases, tiers, schemas and budgets
The eight phases
| Phase | What happens |
|---|---|
| R0 Reconcile | Every open action from earlier retros gets a verdict of done, carried or dropped, with a reason. Zero follow-through across two retros in a row is itself a finding |
| R1 Facts | A dated timeline from the journal, handoff snapshots, review logs and commits, with gaps named. Open questions are asked or dropped first |
| R2 Decision review | Each decision scored as good call, bad call, good call with bad luck, bad call with good luck, or unresolved |
| R3 Panel | A facilitator runs the lenses, quieter ones first, merges findings that share a cause and names blind spots |
| R4 Synthesise | Root causes, with any cause seen in an earlier retro flagged RECURRING |
| R5 Actions | Each with one owner, one horizon, one due date and one target |
| R6 Meta-changes | A change to a skill or config file becomes a proposed diff, exact old and new lines, held for review |
| R7 Close | The document is filed and a retro-marker line goes into the journal. The document ends with a ROTI score and its weakest part |
Tiers
| Tier | Trigger | Panel | Document cap |
|---|---|---|---|
| T1 Task | A single task, or 15 lines or fewer | Facilitator + 2 lenses | 500 words |
| T2 Milestone | A week or sprint, 16 to 60 lines | Facilitator + 4 lenses | 1,200 words |
| T3 Project | More than 60 lines, or a request for a full retro | Up to 8 lenses, the 2 highest-stakes as separate subagents where supported | 3,000 words |
| LITE | Started by critique or handoff, then 2 signals from its own test | No panel | 12 journal lines, 1 action |
Marker vocabulary
DECISION: <text> | expect: <expected outcome> (expect required)
EVENT: <text>
RESULT: <text>
FRICTION: <text>
WIN: <text>
The hook reads all five from your turns and the last four from the assistant's, with at most 8 assistant lines within the session's 20. A DECISION with no | expect: becomes a question. Unless RETRO_ASK=0 is set, the hook pauses once at the end of the turn to ask it. Questions come one at a time, and one left open for 30 days is dropped as stale.
Journal line
{"ts":"<iso8601 utc>","slug":"<slug>","type":"decision|event|result|friction|win","txt":"<one line, 300 chars max>","expect":"<expected outcome, decisions only, else null>","links":["<path or url>"],"sid":"<session id>","src":"hook|hook-assistant|manual|lite"}
Action line
{"id":"A<n>","ts":"<iso8601>","retro":"<retro filename>","horizon":"S|M|L","action":"<imperative, one line>","owner":"<person or target; defaults to the user>","target":"skill:<name>|config:<file>|project:<slug>|habit","due":"<yyyy-mm-dd>","status":"open|done|dropped|superseded"}
A status change appends a new line with the same id, and the last one wins. Horizons are S up to 2 weeks, M up to 3 months, L beyond. New actions are capped at 3 for T1 and T2 and 6 for T3. The owner defaults to the user. That fits a solo project, and a shared project should name one.
Ground rules
- The retro looks at the system, meaning process, tooling, information flow and skill design, and assumes each decision was the best available at the time.
- A decision is judged against its own recorded expectation, with no hindsight.
- A finding with no quote, file, diff, log entry or named absence behind it is dropped.
- If it's unclear what would change, the finding is rewritten or dropped.
- Wins count as much as problems, named with what made them work.
- Every logged friction is admissible, and the debate is about cause and fix.
- Each phase has a share of the budget, and a thread with no new causes gets closed.
Budgets and cadence
Phases R1 to R4 run on a tool-call budget of 6, 12 or 25 by tier. Running out is a valid stop, as long as the retro says what it didn't examine. The hook suggests a retro once a subject has 10 or more journal lines and no retro in 7 or more days, at most once a week.