The loops, stage by stage
Every loop's stages, skills and gates, with a generated diagram per loop — what each takes, what it produces, and what a mistake costs.
Why loops exist and why there are five lifecycle loops is in Why loops. This page is the reference: what each one takes and produces, and its stages.
skilldrop ships loops, not just parts. A loop is a named sequence of stages over existing skills with a gate between them: packs/<pack>/loops/<name>/LOOP.md is what an agent reads, loop.json is the machine-readable contract (RFC-0028). Nothing comes out of a loop until it passes that loop's gate.
A loop sequences skills — it never contains one. Every skill stays independently installable and runnable on its own, which is what keeps a single-folder copy working in Cursor, Kiro, or Aider.
Five loops cover the lifecycle, and they are separated by reversibility — how expensive the mistake is to unwind — which is why each gets its own gate rather than folding into a neighbour:
| Loop | Takes | Gate | Produces | Mistake costs |
|---|---|---|---|---|
discover | interviews, journeys, a strategy question | G0 human — a person ratifies the brief | a ratified requirement | a re-brief |
design | a ratified requirement | G1 review — council-review's panel | a recorded decision (ADR) | months, unwound in code |
build | an agreed requirement or triaged defect | G2 mechanical — pre-merge-review's gate script decides | merged code | a revert |
release | merged code | G3 review — launch-readiness on evidence; G3.1 human go/no-go | a live, reversible rollout | users and data, often irreversible |
operate | a shipped service | G4 human — the incident is closed | a postmortem and runbook deltas | live users, irreversible |
Plus one wrapper, which is not a lifecycle stage but the two passes either side of any generator:
| Wrapper | Takes | Gate | Produces |
|---|---|---|---|
ship-a-draft | raw notes, a transcript, a ticket | G5 review — doc-critique's verdict | a stakeholder-ready artifact |
And five loops outside the delivery lifecycle, each for one job that runs alongside it:
| Loop | Takes | Gate | Produces | Mistake costs |
|---|---|---|---|---|
apply | a job posting and a resume | G6 human — the candidate decides to apply; G6.1 human — the candidate confirms every line is true | a tailored resume and cover letter, ready to send | a claim the candidate cannot back at interview |
research | a question that turns on why something happened, and the sources | G7 review — does diagnostic evidence separate the leading explanation? | an answer with its confidence, tied to the decision it serves | a decision made on a favourite theory |
comply | a change that carries risk: a launch, a vendor, new personal data | G8 mechanical — the register's own script; G8.1 human — the risk owner signs | a register, a DPIA and an evidence map that agree, signed by the owner | a risk accepted on a control that doesn't exist |
measure | a dashboard request and the SQL behind its numbers | G9 review — every query reviewed; G9.1 human — each metric's owner confirms its definition | a dashboard spec whose numbers are defined and reviewed | a wrong number made to look settled by a chart |
modernize | a legacy component to rewrite or move | G10 mechanical — the new component matches recordings of the old; G10.1 human — the cutover | a replacement that behaves the same, cut over by a person | a migration that changes behaviour nobody approved |
Every gate emits a verdict from one shared vocabulary (contracts/terminals.json) in five classes — pass, conditional, revise, redirect, blocked — so READY, PROCEED and SHIP IT are recognisably the same kind of answer. The diagrams below render on GitHub; their Mermaid sources live in docs/loops/ for re-rendering.
Diagrams below are generated from each loop's loop.json by build_loops.py — edit the contract, not the picture.
discover — raw signal to a ratified requirement
Interviews, journeys and strategy questions become one tagged brief, then numbered requirements a human ratifies before any design starts.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
gather["gather<br/><small>requirements-interview +3</small>"]:::gen
structure["structure<br/><small>brief-intake</small>"]:::gen
specify["specify<br/><small>prd-draft</small>"]:::gen
ratify["ratify<br/><small>doc-critique</small>"]:::gate
G0{"G0 · human"}:::gate
DONE(["complete"]):::ship
gather --> structure
structure --> specify
specify --> ratify
ratify --> G0
G0 == "PROCEED" ==> DONE
G0 -- "REVISE (max 3)" --> structure
design — a requirement to a recorded decision
Constraints first, then structure and diagrams, then an attack, then a panel that must agree — and only then is the decision written down as an ADR.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
constrain["constrain<br/><small>context-graph·nfr-spec</small>"]:::gen
shape["shape<br/><small>design-doc·architecture-diagrams</small>"]:::gen
threat["threat<br/><small>threat-model</small>"]:::review
ratify["ratify<br/><small>council-review</small>"]:::gate
record["record<br/><small>adr-generator·context-graph</small>"]:::gen
G1{"G1 · review"}:::gate
DONE(["complete"]):::ship
constrain --> shape
shape --> threat
threat --> ratify
ratify --> G1
G1 == "PROCEED" ==> record
record --> DONE
G1 -- "REVISE (max 3)" --> shape
build — a requirement to merged code
A vertical slice becomes shippable code through a self-correcting loop, gated by a script whose exit code decides. The inner generate-challenge cycle is the feature-implement-loop skill.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
shape["shape<br/><small>user-story-splitter +2</small>"]:::gen
implement["implement<br/><small>feature-implement-loop</small>"]:::gen
verify["verify<br/><small>pre-merge-review</small>"]:::review
decide["decide<br/><small>council-review</small>"]:::gate
G2{"G2 · mechanical"}:::gate
G2_1{"G2.1 · human"}:::gate
DONE(["complete"]):::ship
shape --> implement
implement --> verify
verify --> G2
G2 == "READY" ==> decide
decide --> G2_1
G2_1 == "PROCEED" ==> DONE
G2 -- "NOT READY (max 3)" --> implement
G2_1 -- "REVISE (max 3)" --> shape
release — merged code to live users
Plan the rollout and the way back, judge readiness on evidence, draft the release notes, then a human makes the go/no-go call. The gap between a merge you can revert and a launch you often cannot.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
plan["plan<br/><small>migration-plan·rollout-plan</small>"]:::gen
ready["ready<br/><small>launch-readiness</small>"]:::review
announce["announce<br/><small>release-notes</small>"]:::gen
go["go<br/><small>council-review</small>"]:::gate
G3{"G3 · review"}:::gate
G3_1{"G3.1 · human"}:::gate
DONE(["complete"]):::ship
plan --> ready
ready --> G3
G3 == "PROCEED" ==> announce
announce --> go
go --> G3_1
G3_1 == "PROCEED" ==> DONE
G3 -- "REVISE (max 3)" --> plan
G3_1 -- "REVISE (max 3)" --> plan
operate — a shipped service through detection and learning
Instrument, write the runbook, communicate the incident, then feed the postmortem's runbook deltas straight back into the runbook. The one loop whose failures are live.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
instrument["instrument<br/><small>observability-plan</small>"]:::gen
document["document<br/><small>runbook-generator</small>"]:::gen
respond["respond<br/><small>incident-comms</small>"]:::gen
learn["learn<br/><small>postmortem-generator</small>"]:::review
G4{"G4 · human"}:::gate
DONE(["complete"]):::ship
instrument --> document
document --> respond
respond --> learn
learn --> G4
G4 == "PROCEED" ==> DONE
G4 -- "REVISE (max 3)" --> document
ship-a-draft — raw input to a stakeholder-ready artifact
The wrapper: structured intake before any generator, critique and a machine-residue scrub after. Loops back through intake — not the draft — until it's approved.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
intake["intake<br/><small>brief-intake</small>"]:::gen
draft["draft<br/><small>*</small>"]:::gen
critique["critique<br/><small>doc-critique</small>"]:::review
polish["polish<br/><small>output-hygiene</small>"]:::review
G5{"G5 · review"}:::gate
DONE(["complete"]):::ship
intake --> draft
draft --> critique
critique --> G5
G5 == "SHIP IT" ==> polish
polish --> DONE
G5 -- "MAJOR REWRITE (max 3)" --> intake
apply — one posting and one resume to an application ready to send
An honest fit check first, and the candidate decides whether to apply before anything is written. Then a tailored resume and a cover letter that claim nothing the candidate didn't supply, which the candidate confirms line by line before sending.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
fit["fit<br/><small>job-fit-analysis</small>"]:::gate
tailor["tailor<br/><small>resume-tailor</small>"]:::gen
letter["letter<br/><small>cover-letter</small>"]:::gen
form["form<br/><small>application-form-answers</small>"]:::gen
confirm["confirm<br/><small>output-hygiene</small>"]:::review
G6{"G6 · human"}:::gate
G6_1{"G6.1 · human"}:::gate
DONE(["complete"]):::ship
fit --> G6
G6 == "PROCEED" ==> tailor
tailor --> letter
letter --> form
form --> confirm
confirm --> G6_1
G6_1 == "READY" ==> DONE
G6_1 -- "NOT READY (max 3)" --> tailor
research — a why question to an answer the evidence carries
A plan that fixes what would change the decision before any source is read, a synthesis with every claim cited, and rival explanations ranked by how little evidence contradicts them. The gate sends the work back for the one observation that would tell the leaders apart.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
plan["plan<br/><small>research-plan</small>"]:::gen
synthesise["synthesise<br/><small>source-synthesis</small>"]:::gen
compare["compare<br/><small>hypothesis-comparison</small>"]:::review
G7{"G7 · review"}:::gate
DONE(["complete"]):::ship
plan --> synthesise
synthesise --> compare
compare --> G7
G7 == "PROCEED" ==> DONE
G7 -- "REVISE (max 3)" --> synthesise
comply — a risky change to a risk position its owner signed
A risk register, a DPIA when personal data is processed, and the evidence behind every control the ratings rely on, made to agree: a control with no evidence gives no credit. The register's own script checks it, then the owner signs.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
register["register<br/><small>risk-register</small>"]:::gen
assess["assess<br/><small>dpia</small>"]:::gen
evidence["evidence<br/><small>soc2-evidence-map</small>"]:::gen
check["check<br/><small>risk-register</small>"]:::review
sign-off["sign-off<br/><small>doc-critique</small>"]:::gate
G8{"G8 · mechanical"}:::gate
G8_1{"G8.1 · human"}:::gate
DONE(["complete"]):::ship
register --> assess
assess --> evidence
evidence --> check
check --> G8
G8 == "READY" ==> sign-off
sign-off --> G8_1
G8_1 == "PROCEED" ==> DONE
G8 -- "NOT READY (max 3)" --> register
G8_1 -- "REVISE (max 3)" --> register
measure — a dashboard request to numbers people can defend
The spec runs first, so only the queries behind charts that serve the decision get reviewed. A fixed query goes back through the spec, because the fix moves the number, and each metric's owner confirms its definition before anything is built.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
spec["spec<br/><small>dashboard-spec</small>"]:::gen
review["review<br/><small>sql-review</small>"]:::review
sign-off["sign-off<br/><small>doc-critique</small>"]:::gate
G9{"G9 · review"}:::gate
G9_1{"G9.1 · human"}:::gate
DONE(["complete"]):::ship
spec --> review
review --> G9
G9 == "READY" ==> sign-off
sign-off --> G9_1
G9_1 == "PROCEED" ==> DONE
G9 -- "NOT READY (max 3)" --> spec
G9_1 -- "REVISE (max 3)" --> spec
modernize — a legacy component replaced without changing what it does
The old system's behaviour is recorded before anything is rebuilt, so the evidence can't be shaped by the new code. A script compares the new component against the recordings, and a person decides the cutover, knowing what the recordings don't cover.
%%{init: {'theme':'base','themeVariables':{'fontFamily':'Segoe UI, Helvetica, Arial','fontSize':'15px','lineColor':'#9AA5B1'},'flowchart':{'curve':'basis','rankSpacing':70,'nodeSpacing':50,'padding':16}}}%%
flowchart LR
classDef gen fill:#E8F0FE,stroke:#4C7DF0,stroke-width:1.5px,color:#1A3A8F;
classDef review fill:#FDEAEA,stroke:#E05B5B,stroke-width:1.5px,color:#8A1F1F;
classDef gate fill:#FBE3A2,stroke:#D9971E,stroke-width:2px,color:#6B4500,font-weight:bold;
classDef ship fill:#E6F7EC,stroke:#34A853,stroke-width:2px,color:#0F6B33,font-weight:bold;
survey["survey<br/><small>codebase-tour·context-graph</small>"]:::gen
plan["plan<br/><small>refactor-plan·migration-plan</small>"]:::gen
capture["capture<br/><small>behaviour-equivalence</small>"]:::gen
rebuild["rebuild<br/><small>feature-implement-loop</small>"]:::gen
prove["prove<br/><small>behaviour-equivalence</small>"]:::review
cutover["cutover<br/><small>launch-readiness</small>"]:::gate
G10{"G10 · mechanical"}:::gate
G10_1{"G10.1 · human"}:::gate
DONE(["complete"]):::ship
survey --> plan
plan --> capture
capture --> rebuild
rebuild --> prove
prove --> G10
G10 == "READY" ==> cutover
cutover --> G10_1
G10_1 == "PROCEED" ==> DONE
G10 -- "NOT READY (max 3)" --> rebuild
G10_1 -- "REVISE (max 3)" --> capture