Skip to content

skill · phase: maintenance

Retrospective

Purpose

Close the feedback loop: when an instance completes, capture what the work taught us while it is fresh, and write durable lessons where the next instance will read them. This is the system-level quality mechanism — gates and reviews protect one instance; retrospectives make the next one start smarter.

{{glossary:instance}}

When to Run

  • At every instance's completion moment, regardless of scope or template. The completion moment is the last applicable phase (template × scope) reaching complete — except when that phase is maintenance, where entering maintenance is the moment (maintenance is open-ended).
  • When a retro-pending marker exists for an instance: markers live in <git-common-dir>/aidlc/retro-pending/<instance> (resolve via git rev-parse --git-common-dir; fallback .aidlc/state/<instance>/retro-pending outside git). The entry-point and continue skills route here when they see one.
  • In consolidation mode when the user accepts a consolidation prompt (see Consolidation below).

Run the retro before any completion cleanup (worktree removal, claim release) — its outputs must be committed to the instance's branch first.

Retro Flow

{{glossary:retrospective}}

  1. Idempotency check. If retrospective.md already exists in the instance state dir, offer to update or skip — never duplicate. A skip still removes the retro-pending marker.

  2. Gather state. Read instance.yaml, phase-*.yaml, and transitions.log. For the cost summary, prefer aidlc cost <instance> (it applies fidelity precedence); only read costs.ndjson raw when the CLI is unavailable, and mark that summary approximate. No cost data → omit the cost section entirely, never write zeros.

  3. Draft, then ask — one round-trip. Draft your own answers to the three questions — what surprised us? what would we do differently? what took longer than expected? — from the record: transitions.log, the question files, .aidlc/state/<instance>/unattended-stops.md, test-results.md and the cost summary. Cite what each answer rests on. Show the three drafts in a single message and ask the user to correct them; a reply that changes nothing keeps them. For Micro scope, compress to one drafted answer covering all three. Unattended (AIDLC_UNATTENDED=1), write the drafts into retrospective.md under the line "Drafted by the agent from the record; not reviewed by a person." Declining the retro is fine: remove the marker, write nothing.

    Challenge the entries the work ran into. Only when the instance has a constitution-crossings.md, or its design.md or design-questions.md cites an ADR-<n>: in the same message, ask one question — should any of these entries change? — naming each one. For a NOT-<n>, count its exception lines across .aidlc/state/*/constitution-crossings.md; at two or more, give the count and the instances, so a rule that keeps being waived is visible. A yes goes to the aidlc-constitution skill's "Amending from work" section for a NOT-<n>, or to a superseding entry per The decision-register rule (.aidlc/resources/rules/decision-register.md) for an ADR-<n>; the retro edits neither document. With neither signal, ask nothing. Unattended, list the entries and counts and mark the question not asked.

  4. Write retrospective.md in the instance state dir: the answers, as the user corrected the drafts; when the challenge was asked or listed, a ## Constitution and register section with one line per entry and its answer, a "no" included; instance metadata (template, scope); per-phase durations (pair each transitions.log to: X with the next from: X; fall back to the phase YAML's entered_at/completed_at; note inconsistencies rather than guessing); and the cost summary when available.

  5. Distill lessons — 0 to 3. A lesson is a durable, project-general observation ("NDJSON merge=union false-dedups identical same-second events"), not an instance anecdote ("we finished late"). If nothing generalizes, write no lesson — an empty distillation is a valid outcome.

    Before distilling, search .aidlc/guidance/lessons.md and .aidlc/guidance/lessons-digest.md for an earlier lesson making the same claim — the same mechanism, not the same words. Then end every lesson with exactly one resolution tag, naming what stops it next time: [test: <path>], [check: <name or path>], [guidance: <file>], or [observation] when nothing does. A lesson the search matched cannot be tagged [observation]: the project has already paid for it as prose. It names the test, check or guidance file that now stops it, or it becomes one of the step 6 follow-ups with that artifact as its smallest change, and its tag names the artifact that follow-up will build.

  6. Cap the follow-ups — 0 to 2 queued roadmap items. Rank what the work turned up and queue at most the top two into .aidlc/roadmap/inbox/, each with its six-line executive summary (see aidlc-roadmap) and, when .aidlc/roadmap/milestones.yaml exists, a milestone: line naming a milestone id or none. Zero is a valid outcome, and often the right one. This is the same cap, in the same shape, as the 0–3 on lessons, and it exists because the lessons cap alone was half a brake: the framework capped what an instance learned and capped nothing about what it queued, so closing an instance reliably grew the backlog. One measured project emitted five to nine items per close; triage kept three of eighteen. A repeated lesson queued under step 5 takes one of the two slots; it does not add a third.

  7. Record the rest as observed, not queued. Everything past the cap goes into retrospective.md under ## Observed, not queued, one line each. The cap is on queued items, not on observations — a retro that noticed nine things writes nine and queues two. Findable, attributable, and costing nobody a triage decision. If one of them matters later, it is already written down; promote it then, with the same summary rule.

  8. Confirm, then append. Show the distilled entry verbatim and get one confirmation for the whole entry. Each lesson shows its resolution tag, and under each lesson the step-5 search matched, a line repeats: <earlier lesson> quoting the earlier lesson and its — from <instance>, <date> source — so the person can refuse a tag that leaves a paid-for mistake as prose. Never append unconfirmed text — lessons are auto-loaded into every future session, so this confirmation is the injection gate. Redact anything resembling credentials or secrets. On confirm, append to the lessons layer per the write rules below.

  9. Commit retrospective.md and the lessons append to the current branch now, before any worktree cleanup runs.

  10. Remove the retro-pending marker if one exists.

Unattended

Under AIDLC_UNATTENDED=1 nobody can confirm, so step 8 changes: append the lessons without the confirmation, inside the instance's section, under the line "Drafted by the agent from the record; not reviewed by a person." That line is what tells every later reader the text passed no injection gate. Still at most three lessons and two queued follow-ups; never consolidate, even when a trigger fires; never rewrite lessons-digest.md or index.yaml. A follow-up is a new inbox file — appending to an existing roadmap item is a person's choice. When the prompt says autopilot commits, as it does after an autopilot close-out, steps 9 and 10 are skipped: commit nothing, push nothing, write only the files the prompt names, and leave the retro-pending marker alone — it sits under .git/, which the agent cannot write, and autopilot removes it after its commit.

Lessons Layer — Write Rules

Target: .aidlc/guidance/lessons.md in the current checkout/worktree, on the instance's branch (entries travel with the merge — never write another checkout's copy).

First use. If .aidlc/guidance/ or index.yaml is missing, create them. index.yaml gains (or is created with) the entry:

layers:
  - name: lessons
    file: lessons.md
    last_consolidated: null

If index.yaml already exists, add only the lessons entry — never modify other entries. After registering, verify the layer loads (e.g. aidlc update --dry-run or re-reading the index); surface any loader warning to the user instead of swallowing it.

File shape. The frontmatter is immutable — created once, never rewritten (all mutable metadata lives in index.yaml):

---
name: lessons
description: Lessons from completed instances — historical observations, not directives.
---

The body is append-only between consolidations: one ## <instance> — <YYYY-MM-DD> section per retro run, containing 1–3 bullet lessons, each ending with — from <instance>, <date>. The resolution tag from step 5 sits just before that source: <lesson> <resolution tag> — from <instance>, <date>. Lessons written before tags existed carry none and stay valid. A lesson that belongs in a context doc gets the suffix [promote-to-context] instead of editing .aidlc/context/ directly — the retro never touches context docs. [promote-to-context] says where a lesson should live, not what stops it: it is not a resolution, and the lesson still carries one of the four tags.

Re-runs supersede by appending: write a new dated section for the same instance rather than editing the old one; readers use the latest section per instance; consolidation collapses the rest.

Concurrent-write discipline (two sessions may complete instances simultaneously): write the full updated file to a temp name in the same directory, rename it over lessons.md, then re-read and verify your section is present. If it vanished (a concurrent writer won the rename), re-append and re-verify.

Consolidation Mode

Three independent triggers — any one of them offers consolidation. lessons.md exceeds:

  • 20KB (20,480 bytes), or
  • 25 instance sections (count ## headings), or
  • 90 days since last_consolidated in index.yaml.

The retro checks at step 2 and offers it; aidlc status surfaces the same notice. The size trigger exists because the other two are the wrong dimension: this project's file reached 88KB at 23 sections, 12 days after a consolidation — long and old were both still in the future while big had long since arrived, and bytes are what a session pays for.

Run only in the primary checkout (not a linked worktree — check git rev-parse --git-common-dir resolves to ./.git):

  1. Propose merges of duplicate/superseded sections, retirement of stale entries, and application of [promote-to-context] flags (drafting the context-doc edit for approval).
  2. Every edit is confirmed by the user individually. Nothing is deleted silently.
  3. Regenerate lessons-digest.md — the always-read distillation that stands in for the full corpus (see The always-read rule (.aidlc/resources/rules/always-read.md)). Rewrite everything under its ## Entries heading with the lessons this project has paid for more than once, each ending with — from <instance>, <date> as in lessons.md. Keep the whole file at or under 4096 bytes; that bound is the point of the file, so a digest that needs more entries needs shorter ones, not a larger cap. Leave the text above ## Entries alone — it states that the digest is lossy and names the full corpus, and a reader who only has the digest depends on both.
  4. Confirm what the digest omits, not only what it keeps. A digest is a lossy read of a safety mechanism: show which entries did not make it and get the same individual confirmation step 2 requires. Dropping a lesson from the always-read layer is a decision the user makes, never a side effect of fitting a byte budget.
  5. Report what changed; set last_consolidated in index.yaml to today.

Rules

  • The retro never blocks completion: it is non-blocking, declinable, and its absence is never an error.
  • The follow-up cap is never a reason to not notice something. Merge first — if an open roadmap item already owns the area, append a dated ## Received from <instance> section to it rather than spending one of the two slots on a file that duplicates it.
  • Never write lessons without the step-8 confirmation, except unattended under the line above. Never record credentials or secrets.
  • Lessons are historical observations, not directives — phrase them as what was learned, not as instructions to obey.