This is the full developer documentation for SDLC Studio # How it verifies > Every candidate faces a panel of sceptics briefed to refute it. Survive on a quorum, not a majority of whoever turned up - an incomplete panel marks a candidate unjudged, never refuted. Plus the loop-until-dry rule and the pre-flight cost gate. A finder agent is optimistic by construction. Ask something to hunt for defects and it will find them, including ones that are not there. So nothing a finder produces is a finding yet - it is a **candidate**. ## The refute panel [Section titled “The refute panel”](#the-refute-panel) Each candidate faces **N sceptics**, and their brief is not “is this real?” but *destroy this*. It survives only on **M of N** votes. The shipped default is three sceptics, surviving on at least two. The framing matters. A verifier asked to confirm will confirm; a verifier asked to refute has to do work to fail. Defaulting to “refuted when uncertain” is what keeps plausible-but-wrong findings out of your backlog. Caution **A vote that never arrives is not a refutation.** If the panel is incomplete, the candidate is marked `UNJUDGED` - never refuted, never quietly filed. “Two sceptics said no” and “one sceptic did not answer” must not read the same, exactly as elsewhere in the toolchain. That distinction sounds pedantic until you have shipped on a quorum of one. ## Perspective, not just repetition [Section titled “Perspective, not just repetition”](#perspective-not-just-repetition) Three identical sceptics catch a claim that is obviously wrong. They do not catch a claim that is wrong in a way none of them looks for. Where a finding can fail in more than one way, the stronger form gives each verifier a **distinct lens** - correctness, security, does-it-actually-reproduce - because diversity catches failure modes that redundancy cannot. ## Loop until dry [Section titled “Loop until dry”](#loop-until-dry) Finders do not run once. Each is re-run **until dry**: it keeps going until two consecutive rounds produce nothing new. A fixed number of rounds finds the obvious defects and stops. The interesting ones are in the tail, after the easy surface has been stripped - so the stopping condition is “nothing new twice”, not “we did three rounds”. Candidates beyond the run’s cap are **carried**, not silently discarded. A run that hit its cap says so and says how many it carried, because a truncated sweep reported as complete is worse than no sweep. ## The pre-flight cost gate [Section titled “The pre-flight cost gate”](#the-pre-flight-cost-gate) An audit can spend millions of tokens across hundreds of agents. Most harnesses only tell you a workflow was large after it has launched, which is too late to be a decision. ```bash audit_cost.py --lenses 8 --rounds 2 --votes 3 ``` It reports `~agents · ~tokens · ~minutes` and a verdict: * **large** - roughly 50 or more agents, or a million tokens and up. You see the estimate and the scope, and nothing fans out until you explicitly say go. * **small** - a couple of lenses, one round. It just runs. The gate exists for expensive runs, not for every audit. The seeds are calibrated against a measured reference run: **7 lenses produced 57 candidates across 192 agents, about 6.9M tokens, about 29 minutes**. ### And the estimate is measured against reality [Section titled “And the estimate is measured against reality”](#and-the-estimate-is-measured-against-reality) ```bash audit_cost.py record --run-id RUN-xxxx \ --lenses 5 --est-agents 50 --est-tokens 1000000 \ --actual-agents 55 --actual-tokens 1200000 ``` Estimates and actuals both go into a committed ledger, and the medians recalibrate the seeds. This is the same discipline the sprint forecast uses: a number that is never checked against what happened is not an estimate, it is a wish. Note An honest example from that ledger. One run estimated 209 agents and 7.5M tokens; it spent 282 agents and **14.26M** - a 1.9x overrun, because 112 candidates turned up against an estimate of 64. The carry-over run that followed estimated 2M and spent 2.5M. Both rows are in the record, which is the only reason the seeds get better. ## Where to next [Section titled “Where to next”](#where-to-next) * [The six profiles](/audit/profiles/) - what gets asked in the first place. * [Audit overview](/audit/overview/) - the pipeline, end to end. * [Two-role review](/concepts/two-role-review/) - the same independence principle, applied to code review. * [Evidence](/evidence/) - the measured numbers on this page, with their caveats. # Audit - the adversarial pressure-test > A multi-agent sweep that hunts for weakness rather than inconsistency, puts every candidate through a panel that tries to refute it, and files only the survivors as real bugs and change requests. Point it at a repository that has never seen SDLC Studio. Most code-scanning tools optimise for recall and hand you the triage. You get four hundred findings, you read thirty, and you stop trusting the tool. `audit` inverts that. It hunts for **weakness and incoherence** rather than mere inconsistency, then makes every candidate survive an independent panel whose job is to **refute** it. What reaches your backlog has already been argued against and won. ## Try it before you adopt anything [Section titled “Try it before you adopt anything”](#try-it-before-you-adopt-anything) The fastest way to see what it does is to point it at a repository that has never heard of SDLC Studio: ```text /sdlc-studio audit --profile repo ``` It reads the code, hunts three things - architecture, code quality and defensive security - and files what survives as bugs and change requests with allocated ids. It restructures nothing, asks for no PRD, and requires no adoption. If the findings are not worth having, you have lost an afternoon of compute and nothing else. ## The pipeline [Section titled “The pipeline”](#the-pipeline) ```text find ──► verify ──► merge ──► file (lenses, (refute (dedup + (bug / CR / RFC, until-dry) panel, classify) ids allocated) N-of-M) ``` **Recall first.** Before any of it, the project’s ranked lessons are read - because a lesson this project already paid for *is* a lens. What went wrong last time is where to look first. **Find.** One finder agent per lens, each re-run **until dry**: it keeps going until two consecutive rounds turn up nothing new. A simple “run it once” pass misses the tail, and the tail is where the interesting defects live. **Verify.** Every candidate faces N sceptics whose brief is to destroy it. See [how it verifies](/audit/how-it-verifies/). **Merge.** Survivors are deduplicated by file and claim, so one defect found through three lenses is one finding, not three. **File.** Findings become real artefacts through the same tooling everything else uses, which **refuses a hollow artefact**. Triage-then-approve is the default for a whole-project audit; auto-filing is opt-in, because auto-filing once produced shallow artefacts nobody could act on. ## It composes, it does not replace [Section titled “It composes, it does not replace”](#it-composes-it-does-not-replace) `audit` sits alongside the cheap passes rather than above them. `review`, `reconcile` and `verify` are fast and run constantly. An audit is the expensive, deliberate sweep you run when you want to know what you are not seeing. ## Cost is estimated before it is spent [Section titled “Cost is estimated before it is spent”](#cost-is-estimated-before-it-is-spent) An audit can spend millions of tokens across hundreds of agents, and most harnesses only tell you a workflow was large **after** it has launched. So the estimate comes first: ```bash audit_cost.py --lenses 8 --rounds 2 --votes 3 ``` It reports agents, tokens and minutes with a **large or small** verdict. Large means you see the number and the scope and give an explicit go-ahead before anything fans out. See [how it verifies](/audit/how-it-verifies/#the-pre-flight-cost-gate). Caution It is a confirmation gate, not a cap - and the estimate is a guide, not a promise. One recorded run estimated 7.5M tokens and spent 14.3M, because it found 112 candidates against an estimate of 64. The ledger records both, which is how the estimate improves. ## Findings are attributed [Section titled “Findings are attributed”](#findings-are-attributed) A filed finding can name the **lens** that found it and the **audit run** it came from. That pairing is what turns an audit from a one-off into a measurement: > A lens seen once is the lens working. A lens seen across two runs is a **detector owed** - the same class keeps recurring, so it deserves a mechanical check rather than another sweep. The two go together or not at all, and an unregistered run id is refused, so a typo cannot manufacture a second run and with it a false verdict. ## Where to next [Section titled “Where to next”](#where-to-next) * [The six profiles](/audit/profiles/) - what each one hunts, including the pack that detects vibe coding. * [How it verifies](/audit/how-it-verifies/) - the refute panel, the quorum rule and the cost gate. * [Brownfield walkthrough](/walkthrough/brownfield/) - adopting a codebase properly, once the audit has convinced you. # The six profiles > A profile chooses the lenses. Project, skill, repo, code, test and process - including the pack that hunts for vibe coding, which exists because this project caught its own author doing it. A **profile** is a pack of lenses. Each lens is one adversarial question, asked by its own finder agent. The profile decides what gets asked; it never decides what gets *believed* - every lens in every profile runs through the same [refute panel](/audit/how-it-verifies/). | Profile | Invocation | Hunts | | --------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `project` | `audit` (the default) | per artefact type - PRD, TRD, TSD, personas, epics and stories, code, design and RFCs - plus cross-artefact traceability | | `repo` | `audit --profile repo` | architecture, code quality, defensive security | | `code` | `audit --profile code` | correctness, security smells, pattern violations, drift between code and its acceptance criteria | | `test` | `audit --profile test` | can it fail, does it reach the code, does the docstring match the assertion, is it incidentally green | | `process` | `audit --profile process` | how the work was *produced*: path-from-memory, count-by-hand, accepted-without-running, repair-without-plan, skipped-preflight | | `skill` | `audit --profile skill` | over-engineering, token economy, determinism, external benchmark | ```bash # see a pack's lenses and its refute threshold before launching readiness.py profile --name repo ``` A name no profile declares is **refused**, and the refusal names the ones that exist. An audit never runs an empty lens set. ## `repo` - the one to start with [Section titled “repo - the one to start with”](#repo---the-one-to-start-with) Three lenses, no adoption required, and one binding rule worth stating plainly: Caution **Security findings are remediation-only, by design.** They report location, weakness class, realistic impact and a concrete fix. No proof-of-concept exploits, no payloads. A committed secret is reported by its **location plus rotation instructions**, and the value is left where it is - never copied into a finding, an index or a report. That is a constraint on the output format, not a disclaimer. An audit that pastes your secret into a markdown file has leaked it a second time. ## `test` - the tests that prove nothing [Section titled “test - the tests that prove nothing”](#test---the-tests-that-prove-nothing) The most expensive kind of green is the kind that was never earned. This pack reads source and tests **together** and asks four questions a passing suite cannot answer about itself: * **Can it fail?** Break the code on purpose - does the test die? * **Does it reach the code?** A test that never executes the branch it claims to cover is decoration. * **Does the docstring match the assertion?** A test named for one behaviour and asserting another will mislead the next reader for years. * **Is it incidentally green?** Passing for a reason unrelated to the thing under test. ## `process` - the pack that hunts vibe coding [Section titled “process - the pack that hunts vibe coding”](#process---the-pack-that-hunts-vibe-coding) The most on-brand thing in the toolchain, and it exists for an uncomfortable reason. This project’s own description is *the antidote to vibe coding*. In one recorded run, its author vibe-coded repeatedly - ten repair rounds written by reading a finding and immediately editing, no plan, no approach weighed, and every round from the third onwards found a defect the previous repair had created. A path was written from memory with the wrong prefix six times, twice inside artefacts *about that very defect*. The failure was not ignorance. The rule had just been written down. So the pack looks for the **shape** rather than trusting the discipline: | Lens | The question it asks | | -------------------------- | ----------------------------------------------------------------------------- | | `path-from-memory` | was this path, id or field resolved against the tree, or written from memory? | | `count-by-hand` | is this count kept by hand beside a mechanism that already derives it? | | `accepted-without-running` | did this check execute, or was a green read off something that never ran? | | `repair-without-plan` | was this repair attacked as an approach before it was written? | | `skipped-preflight` | was a cheaper, scoped or already-existing form of this work looked for first? | The class is uniform: **work done before the contract it depends on was established.** Tip A tool that claims to be the antidote to vibe coding and cannot detect it in its own delivery is making a claim it does not check. That is why this pack was written. ## Every lens declares its detector, or admits it has none [Section titled “Every lens declares its detector, or admits it has none”](#every-lens-declares-its-detector-or-admits-it-has-none) This is the part that keeps a lens pack honest. Each lens must name the **signature** that finds it - a runnable detector, naming a path that is actually on disk - or explicitly declare itself `manual` **and state why no search can single the class out**. Two of the five process lenses are honestly `manual`. `repair-without-plan` is manual because a plan is not kept in the tree a search can reach. `skipped-preflight` is manual because whether somebody looked for a cheaper form first is a choice that leaves no artefact behind. Saying so is the point. A reader can tell a detector from a hope. ```bash readiness.py profile --validate # hold every pack to its contract readiness.py profile --name code --validate ``` It exits non-zero on any breach and names the pack and the lens. Run it after adding a lens of your own - packs are extensible, and a new lens is held to the same bar as the shipped ones. ## Where to next [Section titled “Where to next”](#where-to-next) * [How it verifies](/audit/how-it-verifies/) - the refute panel that decides what survives. * [Audit overview](/audit/overview/) - the pipeline and the cost gate. * [Mutation testing](/concepts/mutation-testing/) - the mechanical cousin of the `test` pack. # How it compares > How SDLC Studio differs from spec-driven and single-tool approaches - the unit of work, the planning-versus-proving axis, and where a lighter tool is genuinely the right answer. A factual look at the category, not a scoreboard. A wave of good tools is bringing structure to AI coding. They are worth knowing, and they solve real problems. This page is about **where SDLC Studio sits in the category** - not a scoreboard, and not a claim that the others are wrong. ## Three axes that separate the field [Section titled “Three axes that separate the field”](#three-axes-that-separate-the-field) ### The unit of work [Section titled “The unit of work”](#the-unit-of-work) This is the one that decides the most, and it is the least discussed. The common shape is **one ticket at a time**: describe a change, the agent writes a spec, plans it, breaks it into tasks, builds it. Then start again from an empty page. SDLC Studio’s unit is a **sprint** - a prioritised batch driven to a goal. That is not a preference about ceremony; it is where the overhead pays for itself. Our own published measurement is that on one small, well-specified change the full pipeline costs around **3.1x the tokens** and buys little. The value shows up in the fan-out, where the fixed cost of planning and reviewing is spread across everything delivered under it. Several things simply do not exist below batch size two: ranking a backlog, parallel file-disjoint lanes, a boundary between delivery and close at which to review, and any way to see two changes contradict each other. See [a spec per run, or a sprint?](/sprint/overview/) for the argument in full, with the measurements. ### Planning versus proving [Section titled “Planning versus proving”](#planning-versus-proving) Spec-driven approaches get the agent to write intent down first - a spec, a plan, tasks - and build to it. That is a real step up: the model has a target. SDLC Studio adds the half that comes *after* the plan. The acceptance criteria are executable and get run; status is recomputed from a census of the files; an independent reviewer signs off, and the author can never be that reviewer. It does not only *align* the agent on intent, it *argues back with facts*. ### Agent-agnostic versus single-tool [Section titled “Agent-agnostic versus single-tool”](#agent-agnostic-versus-single-tool) Some tools are one editor or one model - the discipline lives inside that product. SDLC Studio is a standard Agent Skill that Claude Code, Cursor, Codex, Copilot, opencode and Gemini all read. If you change agents, or run several at once, the practice travels with you. ## Where SDLC Studio concentrates [Section titled “Where SDLC Studio concentrates”](#where-sdlc-studio-concentrates) * **[Executable acceptance criteria](/concepts/executable-acceptance-criteria/).** Done is a test that runs, not a checkbox. * **[Independent review as a gate](/concepts/two-role-review/).** The author can never sign off their own change, and a delegate the author controls is refused. * **Evidence as an artefact.** The verify report, the review record, the mutation ledger. The proof outlives the sprint. * **[A source of truth the tools recompute](/concepts/reconcile-drift/).** Claim a count and reconcile recomputes it from the files; drift fails a gate. * **[The sprint as the unit](/sprint/overview/).** Ranked, budgeted, reviewed at its boundary, closed with a retro that has to produce work. * **[Audit](/audit/overview/).** A refute-panel-verified hunt you can run on a repository that has never seen the tool. * **[Brownfield](/walkthrough/brownfield/).** It reads the code you already have and extracts a spec, then makes that spec earn its place by passing against the real implementation. ## Picking the right tool [Section titled “Picking the right tool”](#picking-the-right-tool) If you want a lightweight way to make an agent plan before it codes, a planning-first tool may be all you need - and SDLC Studio’s own *lite* profile occupies that space. Our own numbers say so: **on small, well-specified tasks the pipeline adds nothing** that the baseline did not already do. If you want the fuller engineering discipline - executable done, independent review, evidence that survives, a batch you can rank and budget and learn from - and you want it to work across whichever agent you drive, that is the gap this is built for. Note The measured evidence - including where the discipline makes no difference, and where frontier models no longer fall into the traps it guards against - is on the [evidence page](/evidence/) and in the [white paper](https://github.com/DarrenBenson/sdlc-studio/blob/main/docs/whitepaper.md), whichever way it points. # The engagement floor > Delivery flows through stories and sprints. Work becomes a sized unit with acceptance criteria before it becomes a diff - the floor that catches ad-hoc coding. The engagement floor is one rule with teeth: **no ad-hoc coding.** Work becomes a story or a bug with acceptance criteria before it becomes a diff. ## What it enforces [Section titled “What it enforces”](#what-it-enforces) * A request (a CR or RFC) is **not work** until `refine` decomposes it into sized units - the [two-backlog rule](/concepts/two-backlog/). * A commit that touches delivery-relevant files is attributed to the unit it delivers, so an understated `Affects` - a change that quietly touches more than its story admits - is caught rather than shipped invisibly. * A subject naming more than one work item carries a `Refs:` trailer per owning id, so the floor can attribute the change per unit. ## Why a floor and not a guideline [Section titled “Why a floor and not a guideline”](#why-a-floor-and-not-a-guideline) Under time pressure, the tempting move is to “just make the change” and paper over the process afterwards. A guideline that relies on the agent remembering it fails exactly when it matters. The floor is mechanical: the commit gate refuses a change with no unit behind it and names the fix, so the discipline does not depend on good intentions at the moment of stress. ## It scales down [Section titled “It scales down”](#it-scales-down) The floor is not maximal ceremony for everything. A small repo can run a **lite profile** that collapses the pipeline to PRD → story → implement; a change flows at the weight it warrants. What the floor guarantees is not heaviness - it is that *something sized and reviewable* stands behind every diff. ## See also [Section titled “See also”](#see-also) * [Two-role review](/concepts/two-role-review/) - review is independent of the author at every tier. * [Sprint planning](/sprint/planning/) - the breakdown gate that refuses an un-ready batch. # Executable acceptance criteria > Acceptance criteria carry a Verify line the tooling actually runs. A story reaches Done only when they pass - so "done" is a machine-checkable fact, not a claim. An acceptance criterion in SDLC Studio is not just prose. It carries an executable `Verify:` line, and the Done gate runs it. ## The shape of a criterion [Section titled “The shape of a criterion”](#the-shape-of-a-criterion) ```markdown ### AC1: dropping a unit removes it from the open batch - **Given** an open run whose batch contains a unit - **When** `sprint batch drop --reason "..."` runs - **Then** the unit leaves the batch and the change is recorded - **Verify:** pytest tests/test_run_state.py::BatchMutationTests::test_drop_removes_unit - **Verified:** yes (stamped with the date the command passed) ``` The Given/When/Then states the behaviour a human reads and edits. The `Verify:` line is what the machine runs. ## The verifier DSL [Section titled “The verifier DSL”](#the-verifier-dsl) A `Verify:` line names a check the tooling executes - a `pytest`/`jest`/`vitest`/`go` test, a shell command, an HTTP probe, a `grep` for a required string, and more. `verify_ac run` executes them and writes a report: ```text verify_ac.py run --id US0433 [APL] US0433: ac=3 pass=3 fail=0 manual=0 unspecified=0 changes=0 ``` In conversation you rarely type that: `/sdlc-studio reconcile --verify` runs the criteria across the backlog and updates the stamps, and the sprint loop runs them at delivery without being asked. A criterion can be `manual` when a human must observe the outcome - but the tooling names the manual ones honestly rather than counting them as proven. ## Why Done is gated on it [Section titled “Why Done is gated on it”](#why-done-is-gated-on-it) `transition -> Done` is not a free edit. It reads the verify report, and a story whose executable criteria have not passed is refused. That closes the gap between “someone wrote Status: Done” and “the deliverable actually meets its criteria” - a hand-edited status walks round the tool, and conformance re-checks it as a backstop. Tip Run the criteria at **delivery**, not only at close. A `Verify:` line that points at a renamed or deleted test verifies nothing while reading as green - so a test rename is a cross-unit coupling worth catching early. ## Coverage by construction [Section titled “Coverage by construction”](#coverage-by-construction) Because a test spec maps every criterion to a named test case, coverage is built in, not reverse-engineered at the end. The acceptance criteria are the oracle that closes the build loop: the agent builds until they pass, and the close proves they did. ## See also [Section titled “See also”](#see-also) * [Two-role review](/concepts/two-role-review/) - the other condition for Done. * [Mutation testing](/concepts/mutation-testing/) - proving the criteria’s tests can actually fail. * [Reconcile & drift](/concepts/reconcile-drift/) - keeping the verify stamps honest. # Lessons - how it gets better each sprint > Two tiers of failure memory. A lesson learned on your project stays on your project until you deliberately promote it; the cross-project registry ships with the skill and a new project inherits it on day one. The next sprint's plan prints them unasked. A lesson that stays in the retrospective that wrote it is read by nobody after that sprint. The tooling’s own comment on the function that moves them is the clearest statement of the problem: > Without this, the retro is a diary. ## Two tiers, and the default is local [Section titled “Two tiers, and the default is local”](#two-tiers-and-the-default-is-local) **Per-project.** A lesson learned here stays here. It is the default, because a lesson learned on your project is not automatically true on any other. Agentic waves load it at wave start and inject it into every agent prompt as *known pitfalls on this project*. **Cross-project.** The skill ships its own registry of *generalisable* engineering and process lessons - the ones that improve decisions on any project at all. A brand-new project inherits it on day one, before it has made a single mistake of its own. ```text /sdlc-studio lessons add # a lesson for this project /sdlc-studio lessons add --global # promote it - the deliberate act, not the reflex /sdlc-studio lessons recall # anything we should know before deciding this? /sdlc-studio lessons list /sdlc-studio lessons revalidate # which of these still hold? /sdlc-studio lessons summary /sdlc-studio lessons prune --older EP0003 ``` Note A project-specific **fact** - a config path, a box name, an incident - is memory, not a lesson. Lessons are things that change a decision. Promotion needs a version-controlled destination. Without one it is refused rather than written into a copy the next update deletes. ## The loop is gated, not hoped for [Section titled “The loop is gated, not hoped for”](#the-loop-is-gated-not-hoped-for) Five rungs, and three of them fail a gate: 1. **The retro exists.** The gate fails until the batch’s retrospective is on disk. 2. **Its lessons are lifted.** `retro extract` moves them into the store, titled from the first sentence rather than the first physical line - a headline cut mid-clause is one the next sprint skims past. It is idempotent by content, so re-running converges rather than duplicating. 3. **Open lessons are re-validated - gated.** The gate fails while any open lesson sits past its validity horizon, or carries none at all. The log cannot silently grow into unread noise. 4. **The rolling summary is refreshed - gated.** A lesson **closed** since the last regeneration fails it exactly as an added one does. 5. **The next plan reads it - emitted, not requested.** `sprint plan` **prints the still-valid lessons inside the plan itself**. It does not point at a file the agent may not open. That last rung is the one that makes the difference. The batch you approve already contains the lessons the last sprints paid for. ## Recall is also how an audit starts [Section titled “Recall is also how an audit starts”](#recall-is-also-how-an-audit-starts) Before an [audit](/audit/overview/) fans out, the ranked lessons are read first - because a lesson this project already paid for *is* a lens. What went wrong last time is where to look first. ## And the estimate learns too [Section titled “And the estimate learns too”](#and-the-estimate-learns-too) The same principle runs through the forecast. Every project starts on a shipped default rate. Once it has **five units** of its own measured evidence, its own numbers replace the default - and the plan always says which of the two it is quoting. A rate re-fitted to one or two units is fitting noise. This project has twice had to delete a rate that hardened into an article of faith, which is why the threshold exists and why nothing is allowed to hard-code it. ## Where to next [Section titled “Where to next”](#where-to-next) * [The retrospective](/concepts/retro/) - where lessons come from. * [Sprint planning](/sprint/planning/) - where they are printed back. * [Audit](/audit/overview/) - where they become lenses. # Mutation testing > A test that stays green over broken code proves nothing. The mutation gate injects declared faults into the changed surface and reports killed vs survived - so a green suite is earned. A passing test suite is only reassuring if the tests can actually fail. Mutation checking proves it: inject a fault, and confirm a test dies. ## How it works [Section titled “How it works”](#how-it-works) ```text /sdlc-studio mutation run --since ``` The gate mutates the changed surface - flips a comparison, drops a guard, changes a return - and re-runs the covering tests per mutation. Each mutant is reported **killed** (a test caught it) or **survived** (nothing did). A surviving mutant is a finding: the code path it changed is not really under test. ## Honest by construction [Section titled “Honest by construction”](#honest-by-construction) * An un-mutatable surface reads **un-checked**, never as a silent pass. * A stale report reads **STALE**. * A mutation run that was refused is **named**, not quietly skipped. * The bytecode cache is purged and the mutation applied to the call site, so a same-length mutant cannot reuse a cached `.pyc` and report SURVIVED without ever running. Tip The discipline in one line: **mutate the call site, purge the cache, and assert the patch changed the file.** A mutation harness that does not do all three can report a kill it never earned. ## Where it fits [Section titled “Where it fits”](#where-it-fits) Mutation checking is the backstop under [executable acceptance criteria](/concepts/executable-acceptance-criteria/). The criteria prove the behaviour is present; the mutation check proves the *test* would notice if it broke. A guard worth trusting is a guard whose mutant was killed. ## See also [Section titled “See also”](#see-also) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - the tests mutation checking hardens. * [Reconcile & drift](/concepts/reconcile-drift/) - keeping the evidence honest. # Personas - who the product is for > Alan Cooper-style personas model who the product serves, defined by goals not demographics - a full cast of primary, secondary, negative, customer and served users, plus stakeholder cards with veto lines. Model the people who use the product now and the ones who will. SDLC Studio has two distinct casts, and it is worth not confusing them. **Design personas** are *who the product is for* - the users and stakeholders it serves. The [Three Amigos](/concepts/three-amigos/) are *who builds and reviews it* - your team. This page is about the first. ## Cooper-style, goal-directed [Section titled “Cooper-style, goal-directed”](#cooper-style-goal-directed) A persona is a **specific, goal-directed person the product serves - defined by its goals, not its demographics** (Alan Cooper’s model). “A 34-year-old urban professional” is a market segment; “someone who needs to reschedule three overlapping meetings from a phone on a train” is a persona. The second one tells you what to build. Every user story names the persona it serves, so the work always answers *for whom*. ## The full cast [Section titled “The full cast”](#the-full-cast) Personas are not just the one obvious user. SDLC Studio models a cast, because a real product serves and affects more people than the person clicking the button: | Role | Who they are | | ---------------- | ------------------------------------------------------------------------------------------------------- | | **Primary** | The single precise individual the interface is designed for. One Primary per interface (Cooper’s rule). | | **Secondary** | Served by the Primary’s interface, but with one extra need. | | **Supplemental** | Uses the product, but their needs are already met by serving the others. | | **Negative** | The anti-persona - explicitly *not* who you are designing for. Naming them stops scope creep. | | **Customer** | Buys or authorises the product but does not use it. | | **Served** | Affected by the product without using it at all. | Only Primary and Negative are mandatory; the rest are there when the product warrants them. This is how you model both the people using the product **now** and the ones who **will** - an aspirational Primary for where the product is going is a first-class persona, not an afterthought. ## Stakeholders and their veto lines [Section titled “Stakeholders and their veto lines”](#stakeholders-and-their-veto-lines) Beyond users, a distinct **stakeholder** card models the people who can block a release without ever opening the app - the economic buyer, a compliance or regulatory authority, ops and support, groups served but not using. Each stakeholder card carries: * **Veto lines** - what makes them block a release outright. * **The evidence they read** - what actually moves them. * A built-in arbitration rule: **a stakeholder’s goals never override the Primary persona’s interface.** The person the product is *for* wins the design argument; the stakeholder wins the release argument. ## Generating the cast [Section titled “Generating the cast”](#generating-the-cast) ```text /sdlc-studio persona create # interactive, or --from-archetype /sdlc-studio persona generate --from-prd # a cast from the PRD /sdlc-studio persona generate --stakeholders # the stakeholder panel ``` Note Archetypes are **seeds** - a role plus a one-line disposition - not fifteen ready-made characters. `persona create` grows the full, project-specific persona from a seed on demand, so your cast is about your product, not a stock library. A well-formed persona has a fixed shape - Quick Reference, Who They Are, ordered End Goals, Experience Goals, Behaviours & Context, Frustrations and a Scenario (its context and the key path the persona takes; validation scenarios live in the test specs, not the card). “Well-formed” is **structural, not evidential**: SDLC Studio checks the persona is complete, not that you did field research - that part is still your job. ## Where to next [Section titled “Where to next”](#where-to-next) * [The Three Amigos](/concepts/three-amigos/) - the team that builds and reviews the work these personas define. * [PRD](/specs/prd/) - the requirements the personas’ goals justify. * [The two-backlog model](/concepts/two-backlog/) - how a persona’s goal becomes a sized story. # Reconcile & drift > Status is recomputed from a census of the files, not asserted. Reconcile detects and fixes index, status and count drift - so what the project claims matches what exists. The status a project claims is only worth trusting if something checks it against reality. `reconcile` is that something: it recomputes state from a **census of the files** and reports where the claim and the files disagree. ## What drifts [Section titled “What drifts”](#what-drifts) * **Index rows** - an artefact with no index row, or a row pointing at a file that no longer exists. * **Status mismatches** - an index row that says Open while the file says Fixed. * **Counts** - an epic’s “3/5 stories done” checkbox that no longer matches its children. ```text /sdlc-studio reconcile # detect: read-only, reports drift /sdlc-studio reconcile apply # fix the mechanical drift /sdlc-studio reconcile --verify # also run the executable Verify: lines ``` `detect` writes nothing; `apply` fixes the mechanical drift; the index is *derived*, never hand-authored. ## Why derived beats asserted [Section titled “Why derived beats asserted”](#why-derived-beats-asserted) A spec-driven tool writes the status down and trusts the agent to keep it current. A week and ten changes later, the documents and the code have quietly diverged and nothing noticed. Reconciliation removes the trust: the count is recomputed from the files every time, and a pre-commit gate refuses a commit whose counts, index or status do not match - naming the exact drift and the fix. Note This is the difference between *aligning* the agent on intent and *arguing back with facts*. Claim a count and reconcile recomputes it. Let a document drift from the code and the gate stops you. ## See also [Section titled “See also”](#see-also) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - `reconcile --verify` runs them. * [Mutation testing](/concepts/mutation-testing/) - proving those tests can fail. # The retrospective > A team that inspects and never adapts is holding a ceremony. So the retro is checked on its content, not its existence - every finding is filed as work or declined with a reason, and declining costs exactly what filing costs. Most retrospectives produce a document nobody reads and a set of intentions nobody tracks. A team that inspects and never adapts is holding a ceremony, not a retrospective. So the retro here is checked on its **content**, not its existence. Caution A gate that tests for a file is satisfied by `touch`. Existence is not evidence. ## Every finding takes a disposition [Section titled “Every finding takes a disposition”](#every-finding-takes-a-disposition) A retro records what it found, and each finding takes one of exactly two dispositions: * **filed** - it becomes a bug, a change request or an RFC, with an id, and it turns up in the next batch’s ordering * **declined** - with a stated reason Both are green. What is refused is the third option: a finding written down and left to rot. The cost symmetry is the load-bearing part: > **Declining must cost exactly what filing costs**, or the gate teaches people to file rubbish to go green. If honesty is cheaper than noise, you get honesty. If it is dearer, you get noise, and a backlog nobody trusts. ## It is scaffolded, never hand-authored [Section titled “It is scaffolded, never hand-authored”](#it-is-scaffolded-never-hand-authored) ```text /sdlc-studio sprint close # scaffolds the retro, then stops for you to fill it ``` Run the close with no retro id the first time and it allocates one, writes the template, wires the index row, and pre-fills the batch and the goal from the run. Then it stops. Hand-authoring a retro leaves the index unwired, which stalls the close reconcile - the scaffold is the one path that does both. ```text /sdlc-studio retro validate # is it complete on content? /sdlc-studio retro extract # lift its lessons into the store retro.py accuracy # how did the forecast actually do? ``` ## Carried issues get ruled [Section titled “Carried issues get ruled”](#carried-issues-get-ruled) Every open finding a sprint carries out the other side takes a **ruling**, with who ruled it and when: | Ruling | Means | | --------------- | ------------------------------ | | `stop-ship` | this holds the close | | `not-stop-ship` | known, judged, shipping anyway | | `accepted-risk` | a decision, on the record | | `deferred` | it goes in the next batch | An open finding with no row is reported **UNRULED**. That is the whole point: *“we carried it”* and *“nobody looked”* must never read the same in a report. ## The close is owed until it happens [Section titled “The close is owed until it happens”](#the-close-is-owed-until-it-happens) A sprint that delivers and never closes is easy to produce and hard to notice - the work is done, everyone moves on, and the ledger quietly says a close is outstanding. So it is detected. `gate --require-close` fails while a delivery unit has reached a terminal status with no retro behind it, and names the units. ## What it produces [Section titled “What it produces”](#what-it-produces) A retro must produce **work**, not prose. Once it is filled, its lessons are lifted into the store so the next sprint’s plan reads them - see [lessons](/concepts/lessons/). Note Honestly stated: the claim that this loop reduces repeat defects is registered as a claim **to be measured**, not asserted as a finding. The mechanism is real and shipped. The outcome is not yet evidence. ## Where to next [Section titled “Where to next”](#where-to-next) * [Lessons](/concepts/lessons/) - where the findings go, and how the next plan reads them. * [Review and close](/sprint/review-and-close/) - the chain the retro sits inside. * [Evidence](/evidence/) - what this project has measured about its own process, including the costs. # RFC vs CR > A change request is a request to change behaviour. An RFC is a design exploration that weighs options before committing. Both live in the discovery backlog; refine turns either into work. Both a change request and an RFC live in the [discovery backlog](/concepts/two-backlog/). The difference is what they are *for*. ## Change request (CR) [Section titled “Change request (CR)”](#change-request-cr) A **CR** is a request to change behaviour. “Add data export.” “The sprint close cannot converge.” It states what should be different and why, carries a priority and a T-shirt size, and is ready to be refined into delivery work as soon as it is accepted. Reach for a CR when the *what* is clear and the question is scheduling and sizing. ```text /sdlc-studio cr create ``` ## RFC [Section titled “RFC”](#rfc) An **RFC** is a design exploration. It weighs options against each other before anything is committed - the problem, the alternatives with their trade-offs, and a recommendation. It is the place to think, so that the decision is recorded with the reasoning that produced it, not just the outcome. Reach for an RFC when the *how* is genuinely open, or the decision is expensive to reverse. ```text /sdlc-studio rfc create ``` ## Both cross the same bridge [Section titled “Both cross the same bridge”](#both-cross-the-same-bridge) Whichever you file, it becomes delivery work the same way: `refine` decomposes it into sized epics and stories, and it reaches its terminal status only when those children are Done. A CR goes **Complete**; an RFC reaches its own terminal. Neither is closed by hand - both are derived from what shipped. ## See also [Section titled “See also”](#see-also) * [The two-backlog model](/concepts/two-backlog/) - the discovery/delivery split both live in. # The quality gate > One ecosystem-neutral command that runs the deterministic checks, judges the commit on what it actually changed, and never hides a repository-wide fault behind a narrow diff. Run it in CI or as a pre-commit hook. Everything else on this site is discipline that an agent could, in principle, skip. The gate is the part that does not depend on anybody remembering. ```text /sdlc-studio gate # are we clear to commit? /sdlc-studio gate --release # are we clear to tag? /sdlc-studio gate --require-retro RETRO0021 # can we close this sprint? /sdlc-studio gate --require-close # is a close still owed before I push? /sdlc-studio gate --format json # for a pipeline ``` It is **ecosystem-neutral**: no network, no CI assumption, no cloud. It runs in any pipeline, or as a pre-commit hook, or by hand. It prints a consolidated report and exits non-zero only when a **blocking** check fails; a non-blocking failure is reported as a warning and does not stop you. ## What it checks [Section titled “What it checks”](#what-it-checks) The deterministic lanes: conformance (does each unit meet the rules for the status it claims), reconcile (does the index match a census of the files), validate, artefact integrity, duplicate ids, documentation coverage, and the project’s own principles if you have declared any. `--release` adds an **executing** acceptance-criteria pass on top - because before a tag, “the criteria are written down” is not the same claim as “the criteria run and pass”. Caution **Nothing to prove is not proof.** On a release gate, no stories, no executable `Verify:` line, or a verifier your trust boundary refused to run all **fail** the lane. An empty checklist is not a green one. ## The commit is judged on what it changed [Section titled “The commit is judged on what it changed”](#the-commit-is-judged-on-what-it-changed) The conformance and validate lanes run **diff-scoped** in the ordinary gate. They judge the artefacts this working tree actually touched, so a commit that changes nothing about a workspace’s pre-existing backlog debt is not held hostage by it. That narrowing is a deliberate design decision with a hard-won reason behind it: **a guard whose cost is paid on every commit gets switched off**, and disarming the hook disarms every lane, not the noisy two. A gate people route around protects nothing. Three rules keep the narrowing honest: * **It states its own scope.** Every scoped run prints the units it judged, the untouched ones it reported as advisory by id, and the stages it therefore did not judge. A verdict is only readable next to what it did not examine. * **Nothing is dropped from the report.** An untouched error is still printed, marked `ADVISORY`. Only the count that decides the exit code narrows. * **A repository-wide failure still blocks.** The census, the index, documentation coverage and the id-named-file sweep all still run over everything. Narrowing the per-unit ledger is not a way to hide a repository-wide fault. And when the probe cannot answer - no git, no commit to diff against, a root that is not the repository top - it falls back to judging the **whole workspace**. A check that cannot determine scope does not quietly assume the smallest one. ## Selecting lanes [Section titled “Selecting lanes”](#selecting-lanes) ```text /sdlc-studio gate --only reconcile,duplicate-id /sdlc-studio gate --skip constitution ``` Useful in a pipeline stage that only cares about one thing. Not a way to make a red gate green. ## A blocking check earns its place on a number [Section titled “A blocking check earns its place on a number”](#a-blocking-check-earns-its-place-on-a-number) Not every lane blocks, and that is on purpose. When a new check ships, it ships **advisory** while its yield is measured. If it turns out to find real defects, it is promoted to blocking. If it turns out to be noise, it is removed rather than left on to be ignored. This matters more than it sounds. A gate that is already close to its time budget cannot afford a new blocking check that earns its place on an assertion. The discipline applies to the discipline. ## Where to next [Section titled “Where to next”](#where-to-next) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - what `--release` actually runs. * [Reconcile & drift](/concepts/reconcile-drift/) - the lane that recomputes truth from the files. * [Review and close](/sprint/review-and-close/) - where `--require-retro` and `--require-close` fit. * [Configuration](/reference/configuration/) - turning gates on for your project. # The Three Amigos > Your own personal engineering team - Product, Engineering and QA - who specify together, build apart and review independently. Named people with a working method and an honest weakness, who both do the work and review it, and never the same instance on the same unit. The “Three Amigos” is a long-standing software practice: before work starts, three viewpoints look at it together - **Product** (what and why), **Engineering** (how), and **QA** (what if it goes wrong). SDLC Studio ships that team as real, named people and wires them into the lifecycle, so the practice happens by default instead of when someone remembers to book the meeting. They are not role prompts. Each is a card with goals, a proficiency, a working method, the things they will not trade away - and an honest account of how they fail. ## Meet the team [Section titled “Meet the team”](#meet-the-team) | Amigo | Viewpoint | Brings | | ----------------------------- | ------------ | -------------------------------------------------------------------- | | **Lena Marsh** - Product | *What & why* | user value, scope discipline, “is this what was actually asked for?” | | **Dani Okafor** - Engineering | *How* | feasibility, [TRD](/specs/trd/) alignment, blast radius | | **Sam Eriksson** - QA | *What if* | testability, [TSD](/specs/tsd/) alignment, “what breaks?” | ### The Shadow [Section titled “The Shadow”](#the-shadow) Every card carries a mandatory **Shadow**: *how this amigo fails when it is trying hardest to be good*. Dani gold-plates. Sam can block on a risk nobody will ever hit. Lena trades depth for reach. This is not decoration. Off-script, a charter reverts to the base model’s agreeableness, and a reviewer with no named failure mode drifts back into agreeing with you. Writing the failure down is what keeps the pressure-test honest - and it lets you read a review with its bias visible. ## Do the work, then review the work - never the same instance [Section titled “Do the work, then review the work - never the same instance”](#do-the-work-then-review-the-work---never-the-same-instance) Each amigo has a **dual render**: * The **work render** - craft goals, how they work, non-negotiables - frames the seat when it builds, authors or tests. * The **review render** - lens, pushes back when, Shadow - frames it when it critiques. The two are **always separate instances on one unit**. A seat never reviews its own output. Each is consulted as an independent subagent and the views are synthesised, so a blind spot in one is caught by another. Tip This is the whole idea in one line: **specify together, build apart, review independently.** The people who agreed what to build are not the single point of failure who also decides it is done. ## The critic is a seat, not an anonymous instance [Section titled “The critic is a seat, not an anonymous instance”](#the-critic-is-a-seat-not-an-anonymous-instance) When a batch is reviewed, the adversarial full-diff pass runs **as the QA seat’s review render**. The card’s lens and its “pushes back when” list are the critic’s attack angles, and the verdict is recorded under the seat’s name - so the verdict log reads as *Sam’s* verdict, not an unattributed thumbs-down. Record a verdict under a reviewer that matches no declared seat and the tool says so. ## Accountability: who answers for a document [Section titled “Accountability: who answers for a document”](#accountability-who-answers-for-a-document) Two further seats exist, and they are **review-only** - they do not build: | Seat | Accountable for | Applies | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------- | | **Product Owner** | the [PRD](/specs/prd/): that its requirements are complete, current and **satisfied by the work**. Signs the PRD review leg. | every project | | **Product Manager** | the [PVD](/specs/pvd/): that its product requirements are satisfied and each maps to a child PRD. Signs the PVD review leg. | only when a PVD exists | Caution A seat is never accountable for reviewing a document it wrote. The Product amigo decomposes a **ratified** PRD into stories and reviews requirements against it - she does not author the PRD she is accountable for. A single-repo project runs with the Product Owner alone; the Product Manager seat appears only once several repos form one product. ## Grown from your project, not shipped identically [Section titled “Grown from your project, not shipped identically”](#grown-from-your-project-not-shipped-identically) Ask for your team and it is generated from *your* project: ```text /sdlc-studio persona generate --team ``` It reads the PRD, the stack and the risk signals, asks the few questions it cannot infer (risk class, compliance regime), and writes named seats whose non-negotiables come from your domain - a payments QA paranoid about idempotency, a games QA about frame budgets, a security seat that vetoes card data outside the vault. The seat that argued for a requirement is the one who refuses to sign off work that misses it. Edit a card and generation treats it as authored - it is never overwritten. It does not make the model smarter, and SDLC Studio does not claim it does. It makes the review **cover the risks this project actually has**, instead of a generic role-prompt walking past them. Zero setup still works. With no seats defined the skill falls back to the three shipped amigos, so the independence rules apply from the first commit. Seats are matched on a machine-readable role marker inside the card, never the filename - so a card named after a person still resolves deterministically. ## When they are consulted [Section titled “When they are consulted”](#when-they-are-consulted) The Amigos are consulted **automatically** at the ceremonies where a decision is expensive to get wrong - creating an epic, creating a story, planning the code for a story, and fixing a bug. The decomposition commands bake the lead in: `refine` is **engineering-led** (a request is largely a build breakdown), `triage` is **QA-led** (is it reproducible, and what is the real defect?). You can also call them by hand, or talk to them: ```text /sdlc-studio consult team # the panel, on one artefact /sdlc-studio consult stakeholders # the wider cast, with their veto lines /sdlc-studio chat # talk to a seat directly ``` Controls: `--with-personas` / `--skip-personas`, `--persona ` for one voice, and `--quick` / `--thorough` for depth. A consult leaves an audit trail on the artefact - a `Consulted:` line and the panel’s output - so a decision can be read back months later. Note A panel where every seat ratifies the original proposal is suspicious. If you keep getting unanimous agreement, the panel is rubber-stamping; widen it. ## How this becomes a hard gate [Section titled “How this becomes a hard gate”](#how-this-becomes-a-hard-gate) The Amigos’ review feeds the [two-role review gate](/concepts/two-role-review/), which separates two jobs that must never be the same actor: * The **adversarial reviewer** - an amigo’s review render - always runs, and its pass is recorded as **evidence**. It is input to the sign-off, never the sign-off itself: the author’s own automation approving its own work is not a review. * The **reviewer of record** - an independent principal (the operator, or a named delegate in a separate trust boundary) - records the sign-off. A delegate drawn from the author’s own session is refused, loudly. Past a configured point in a project’s life, a unit needs **both** records before it can reach Done. Done means signed off, by someone who did not write it. Independence has a floor and a ceiling. A separate instance of the same model catches self-favouritism, and that is the floor. It still shares that model’s blind spots, so for high-stakes work a **cross-model** review is the stronger form. ## Where to next [Section titled “Where to next”](#where-to-next) * [Two-role review & sign-off](/concepts/two-role-review/) - the independence gate the Amigos run under. * [Personas](/concepts/personas/) - the other cast: who the product is *for*. * [The specification layer](/specs/overview/) - the documents the team writes and answers for. * [Review and close](/sprint/review-and-close/) - where the adversarial pass actually runs. # The two-backlog model > A request is not work. In SDLC Studio a discovery backlog of change requests and RFCs becomes delivery work - sized epics, stories and bugs - only via refine. This is the biggest shift in v5. The single biggest change to how SDLC Studio is used: **there are two backlogs, and a request only becomes work by crossing between them.** ## The two backlogs [Section titled “The two backlogs”](#the-two-backlogs) * **Discovery backlog** - *what someone wants.* Change requests (**CRs**) and RFCs. An idea, a bug report, a design question. Cheap to file, unsized, not yet committed. * **Delivery backlog** - *what the team will build.* Epics, stories and bugs, each carrying acceptance criteria and a size. This is the sprint’s raw material. A request in the discovery backlog is **not work**. It becomes delivery work only when [`refine`](#refine) decomposes it into sized units. That crossing is the whole point. ```plaintext Discovery backlog Delivery backlog ───────────────── ──────────────── CR: "export my data" ─refine─▶ EP: Data export RFC: "should we cache?" ├─ US: request + queue (3 pts, ACs) └─ US: deliver the file (2 pts, ACs) ``` ## Why the split exists [Section titled “Why the split exists”](#why-the-split-exists) Merge the two and every idea looks like committed work. A one-line “wouldn’t it be nice” sits in the same list as a sized, accepted story, and planning quietly treats them alike - so the plan fills with things nobody scoped, estimates collapse to a floor, and “the backlog” stops meaning anything. Keeping them separate makes one rule enforceable: **you cannot plan a sprint over an un-refined request.** The breakdown gate refuses it. A change that arrives without a sized unit behind it is caught, not shipped. ## `refine` - the crossing [Section titled “refine - the crossing”](#refine---the-crossing) []() `refine` reads a CR or RFC and produces the delivery units that satisfy it: an epic and its stories (or bugs), each with Given/When/Then acceptance criteria and a point size relative to work you have already delivered. ```text /sdlc-studio refine show --request CR0421 # is it refinable, and what is in it? /sdlc-studio refine apply --request CR0421 # decompose it - epic + stories, links wired ``` It validates the whole breakdown before it mints anything, so a bad unit fails loud and empty rather than leaving half a decomposition on disk. A later slice of the same request is `refine add --request CR0421`; to decompose into an epic that already exists, add `--into EP0009`. Grooming is real work, and it sits on top of the points. A freshly refined story is a scaffold: its acceptance criteria are placeholders until you author them against the specific slice. Refine first, then groom the criteria, then plan. Note A request reaches its terminal status (a CR is **Complete**, an RFC has its own terminal) only when the delivery units it decomposed into are all Done. You do not close a CR by hand - it is **derived** from its children. Delivery drives discovery, never the other way round. ## Bugs and issues [Section titled “Bugs and issues”](#bugs-and-issues) * A **bug** is delivery work: a defect with a severity and a size, filed straight into the delivery backlog. It is fixed through a story-like path and its Done gate. * An **issue** is a discovery-tier report you have not yet triaged. `triage` turns an issue into bugs (or closes it). Like a CR, an issue is not work until it is decomposed. ## Sizing is compulsory [Section titled “Sizing is compulsory”](#sizing-is-compulsory) Every delivery unit carries a size - modified Fibonacci story points on a story or bug, a T-shirt size on a CR/RFC/epic. Sizing is what makes the estimate a number rather than a guess, and it is what lets the planner see that two units touch the same file and cannot run in parallel. The tooling **refuses** an un-sized unit into a plan; a bug’s severity is its urgency, a different axis from its size. ## What this means day to day [Section titled “What this means day to day”](#what-this-means-day-to-day) 1. Someone has an idea → file a **CR** (or an **RFC** for a design question). Cheap, unsized. 2. You accept it → **`refine`** it into an epic + sized stories, then **groom** their acceptance criteria. 3. Now it is delivery work → **`sprint plan`** a batch of it, build, verify, review, close. 4. The CR goes **Complete** automatically when its stories are Done. ## See also [Section titled “See also”](#see-also) * [RFC vs CR](/concepts/rfc-vs-cr/) - which kind of request to file. * [Sprint planning](/sprint/planning/) - how a delivery batch becomes a sprint. * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - what grooming produces. # Two-role review & sign-off > The author of a change can never record its sign-off. An adversarial reviewer files findings as evidence; a reviewer of record ratifies. The separation is mechanical, not a convention. Review in SDLC Studio is **independent of the author, by construction**. This is a gate, not a guideline. ## Two roles, never merged [Section titled “Two roles, never merged”](#two-roles-never-merged) * **The adversarial reviewer** - a fresh context that did not write the code. It runs an adversarial pass, tries to break the change, and files findings as *evidence*. It does not approve. * **The reviewer of record** - the operator, or a named delegate in a separate trust boundary. It ratifies the evidence and records the sign-off. The author is neither. A self-review never clears the Done gate: the check compares the reviewer id against the author id, and a unit whose reviewer equals its author - or that has no recorded author - fails. ## Why mechanical [Section titled “Why mechanical”](#why-mechanical) Volume is the problem. When an agent authors most of the change, “please have someone review it” collapses under load, and the tempting shortcut is to let the author bless their own work. Making the separation mechanical removes the shortcut: the tooling refuses to record a sign-off the author controls, so the human ratifies *evidence someone else produced* rather than re-reading every line. ## The forward-only threshold [Section titled “The forward-only threshold”](#the-forward-only-threshold) A project sets `review.two_role_after` in its config. A delivery unit numbered past that threshold reaches Done only with an independent reviewer-of-record sign-off; earlier units keep the project’s prior behaviour. The discipline applies forward, so turning it on does not retroactively block delivered work. ## How a close uses it [Section titled “How a close uses it”](#how-a-close-uses-it) ```text /sdlc-studio sprint close --apply-signoff --principal "you" ``` `--apply-signoff` fans the reviewer-of-record’s approval into a per-unit sign-off for each story in the batch, transitions each to Done, and records the evidence. The adversarial pass is recorded separately (a sprint-level review can cover a batch as its evidence). Caution Be honest about what is mechanical and what is discipline. The tool enforces the mechanical case: a sign-off whose reviewer id equals the author id never clears the gate. Whether a *delegate* is genuinely independent - in a separate trust boundary, not one the author controls - is a judgement the record makes **auditable**, not an unforgeable lock. The value is that self-review becomes a deliberate, logged exception instead of the silent default. ## See also [Section titled “See also”](#see-also) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - the other half of Done: the criteria must pass *and* the sign-off must land. * [The engagement floor](/concepts/engagement-floor/) - why review is independent of the author at every tier. # Evidence > What has actually been measured about this discipline - the benchmark, the cost of the process, the estimation model - and, beside each of them, what the evidence does not prove. Published whichever way it points. This page exists because a paper about verifiable delivery that cannot show its own working would be a poor start. Everything here is published in the repository, including the findings that do not flatter. Note The benchmark is **vendor-housed**: it lives inside the repository of the tool it flatters. That is a real limitation and it is stated first rather than buried. The protocol was frozen in git before any run, and the commitment is to publish wherever it lands. ## The trap [Section titled “The trap”](#the-trap) The headline fixture is a notification service whose specification contains a rule: nothing non-urgent is delivered during a user’s quiet hours, and a suppressed delivery is deferred, never dropped. The ticket asks for an everyday feature - digest mode - and **never mentions quiet hours**. That silence is the trap. A digest is still a delivery, so the existing rule applies to the new feature, and the obvious implementation flushes a batch at 23:00 and wakes the user. This is the classic shape of a production regression: not a bug in the new code, but an interaction between a new requirement and an existing one nobody re-read. So the benchmark asks exactly one question: **does anything force the agent to re-read the spec it was given?** ## The engagement floor [Section titled “The engagement floor”](#the-engagement-floor) Three arms, same fixture, same models. The middle arm had the full pipeline *installed and available*, plus judgement about when to use it. | Defects escaped | Judgement-gated | No process | Mandated planning | | --------------- | --------------- | ---------- | ----------------- | | Mid-tier model | 5/5 | 2/5 | **1/5** | | Premium model | 3/3 | 3/3 | **0/5** | | Frontier model | 0/5 | 0/5 | not run | The judgement-gated arm behaved exactly like having no process at all. Under effort pressure it judged the ticket too small for ceremony, implemented the ticket text directly, went green on its own tests, and shipped the same defect. One premium run named the dangerous interaction *“the one genuinely ambiguous edge”* in its own delivery summary and shipped without resolving it. That result is why this toolchain gates rather than advises: > **A process step gated on judgement is the step that gets skipped.** An earlier study at n=5 found **10 of 10** unstructured runs shipping the same defect, with an auditability score of 0.88 for the governed arm against 0.60 for the baseline. ## What the discipline costs [Section titled “What the discipline costs”](#what-the-discipline-costs) | Approach | Tokens | Cost per ticket | Escapes | Audit trail | | ----------------------- | ------ | --------------- | ------- | ----------- | | Frontier, no process | 54.6k | $0.98 | 0/5 | none | | Frontier, full pipeline | 77.2k | $1.39 | 0/5 | full | | Premium, no process | 54.0k | $0.49 | 3/3 | none | | **Premium, mandated** | 57.9k | **$0.52** | **0/5** | full | | Mid-tier, no process | 67.1k | $0.24 | 2/5 | none | | Mid-tier, mandated | 79.2k | $0.29 | 1/5 | full | Mandated process costs **1.07 to 1.18x** the baseline tokens - a premium of **three to seven cents a ticket**. On the premium model that took the escape rate from 3/3 to 0/5 for three cents. Enforced process on a mid-tier model undercuts frontier prompt-and-hope by **47 to 70%** while producing an evidence trail the frontier run does not produce at any price. The worst value measured was a **premium model with no process**: it costs more than the governed run beneath it and shipped the defect every time. Caution July 2026 list rates, assuming an 80/20 input-output split. The ratios travel; the absolute prices will not. ## A story point is a unit of cost [Section titled “A story point is a unit of cost”](#a-story-point-is-a-unit-of-cost) Twenty-one delivered units, re-estimated **blind** by three independent estimators with no access to the outcomes. Nineteen had measured actuals. | Band | Tokens per point | | ------------- | ----------------------------------- | | 2 points | 22,370 | | 3 points | 26,153 | | 5 points | 27,396 | | 8 points | 25,171 | | **13 points** | **14,144** - 1.9x cheaper per point | Flat from 2 to 8, and then it breaks. The thirteens are systematically over-estimated, and all three estimators returned them with low confidence and the unprompted words *“should be split”*. That is the measurement behind the [8-point split threshold](/sprint/planning/#the-breakdown-gate). The model is `cost = points x ~25,000` tokens, flat. Adding a fixed base term to the fit made it slightly worse. **Story points predict cost; a computed metric does not.** Points scored `r = +0.68` pooled against measured cost, and `+0.78` on units of 8 points or fewer. A code-complexity metric built over two days scored `r = 0.03` and was dropped. Decomposition improves the *estimate*, not only the tracking. Four large requests sized in one shot came in at **0.56x** their forecast with a 2.3x spread. Decomposed first, their summed points against the same unchanged rate predicted the batch to **1.00x**. ## A run has a fixed cost [Section titled “A run has a fixed cost”](#a-run-has-a-fixed-cost) Fitting this project’s own measured sprints as *fixed plus marginal times points* gives a marginal of about **13,100 tokens per point** and a fixed of about **3.88 million per sprint**. An 18-point run measured at least 228,884 tokens per point. A 100-point run measured at least 51,945. That is 5.5 times the work for 1.26 times the tokens. > Under-forecasting is worst at **small** batch sizes, which is the opposite of the usual intuition. The model misleads most exactly when a team is being careful and keeping batches small. Caution Two data points, both lower bounds, both from sprints of different shapes. Two points always fit a straight line exactly, so the exact figures carry no confidence. What it gives is a falsifiable prediction, not a calibration. ## Where the review runs [Section titled “Where the review runs”](#where-the-review-runs) One measured run delivered in **five hours** and took **six hours thirty-five minutes** to close. Gate and test time across the whole close was about 70 minutes - roughly **18%**. The rest was repair generated by a review that ran at the close rather than at the batch boundary. A review of those repairs then found nine more surviving mutants, because the repairs had been written fast, late and self-reviewed. That single measurement is why [the adversarial review moved to the batch boundary](/sprint/review-and-close/). ## The audit’s own cost [Section titled “The audit’s own cost”](#the-audits-own-cost) The pre-flight estimator is calibrated against a measured reference run: **7 lenses produced 57 candidates across 192 agents, about 6.9M tokens and about 29 minutes**. It is an order-of-magnitude guide, not a promise. One recorded run estimated 209 agents and 7.5M tokens and spent 282 agents and **14.26M** - a 1.9x overrun, because 112 candidates turned up against an estimate of 64. Both numbers are in the committed ledger, which is the only reason the seeds improve. *** ## What none of this proves [Section titled “What none of this proves”](#what-none-of-this-proves) ### The benchmark is small [Section titled “The benchmark is small”](#the-benchmark-is-small) Five runs per cell, three for the premium model, and **two fixtures carry all the signal**. The headline 5-of-5 against 2-of-5 has a one-sided Fisher exact **p of 0.083** - the direction is consistent, the result is below conventional significance. The rubric is post-hoc and imperfectly blinded. Two escapes in the published results table turned out to be harness artefacts; they were disclosed and left in, because the oracle is the oracle. ### The token actuals are lower bounds [Section titled “The token actuals are lower bounds”](#the-token-actuals-are-lower-bounds) The meter is the session transcript, and it records **no subagent usage at all**. One sprint published a figure that understated its true cost by **64%**. Any sprint that delegated work to agents cost more than its row says. ### The 25,000 rate systematically under-prices [Section titled “The 25,000 rate systematically under-prices”](#the-25000-rate-systematically-under-prices) Measured tokens per point across real sprints spans **21,905 to 151,701 - a 6.9x range** - while the planner forecasts with a single constant at the bottom of it. Nothing auto-recalibrates; a human reads the trend and decides. Rates cannot be pooled across models, and several recent sprints were delivered by more than one, so they carry no rate at all. ### The process has a real cost [Section titled “The process has a real cost”](#the-process-has-a-real-cost) Review rounds on this project run at **62% REJECT**. One run spent 33.7 hours of which 25.2 - **75% of the run** - was review, across 18 rounds. Grooming a freshly refined story is real work and story points do not price it. There is an open change request arguing that the ceremony is disproportionate to blast radius, and it is in the public backlog rather than resolved quietly. ### There is no recommended batch size [Section titled “There is no recommended batch size”](#there-is-no-recommended-batch-size) The fixed cost pulls towards larger batches; review convergence cost pulls towards smaller ones. Both directions are visible in the measured history, the sample is small and noisy, and inventing a number would repeat a mistake this project has twice had to undo - writing a rate down as a constant until it hardened into an article of faith. ### The field results are uncontrolled [Section titled “The field results are uncontrolled”](#the-field-results-are-uncontrolled) A maintenance deliverable estimated at twelve months - thirty production websites - delivered in under seven days. Features estimated at a team of five for twenty weeks, delivered in under one. These are **operator-reported, not benchmarked**. Treat them as testimony. ### And the finding that cuts against the pitch [Section titled “And the finding that cuts against the pitch”](#and-the-finding-that-cuts-against-the-pitch) On the current frontier model the traps **do not bite in any arm** - 30 clean runs out of 30, and the overhead for the full pipeline is around 1.4x rather than 3.1x. If your whole fleet is frontier and your tickets look like this fixture, the discipline buys you the audit trail rather than the defect reduction. The honest reading of the whole table is narrower and more useful than the headline: **judgement-gated process converges on the model’s unaided behaviour exactly when the model most needs the process.** ## Where to next [Section titled “Where to next”](#where-to-next) * [The white paper](https://github.com/DarrenBenson/sdlc-studio/blob/main/docs/whitepaper.md) - the full study, its protocol and its claims register. * [A spec per run, or a sprint?](/sprint/overview/) - what these numbers argue for. * [How it compares](/compare/) - where the tool sits in the category. # FAQ > Plain-language answers to the common questions - what PRD, epic, story and acceptance criteria mean, the two-backlog model, refine vs triage, and how Done is decided. ## Do I need to know the commands? [Section titled “Do I need to know the commands?”](#do-i-need-to-know-the-commands) No. Say what you want in plain language - “plan the next sprint”, “extract the spec from this code”. The commands shown throughout the docs are the explicit form for people who prefer them. ## What do PRD, epic, story and acceptance criteria mean? [Section titled “What do PRD, epic, story and acceptance criteria mean?”](#what-do-prd-epic-story-and-acceptance-criteria-mean) A **PRD** is the product requirements - what to build and why. **Epics** are the big chunks of that work; **stories** are the small, testable pieces. **Acceptance criteria** are the checkable conditions that say a story is done. SDLC Studio writes them all as plain files you can read and edit. ## What is the two-backlog model? [Section titled “What is the two-backlog model?”](#what-is-the-two-backlog-model) A **discovery** backlog holds requests (change requests and RFCs) - ideas, not committed work. A **delivery** backlog holds sized epics, stories and bugs. A request becomes delivery work only when `refine` decomposes and sizes it. See [the two-backlog model](/concepts/two-backlog/). ## Refine or triage - what is the difference? [Section titled “Refine or triage - what is the difference?”](#refine-or-triage---what-is-the-difference) `refine` turns an accepted **CR or RFC** into sized delivery work (epics + stories). `triage` turns an untriaged **issue** into bugs (or closes it). Both cross a request from discovery into delivery. ## Issue or bug - which do I file? [Section titled “Issue or bug - which do I file?”](#issue-or-bug---which-do-i-file) A **bug** is delivery work: a defect with a severity and a size, fixed through its Done gate. An **issue** is a discovery-tier report you have not yet triaged into bugs. ## How is “Done” decided? [Section titled “How is “Done” decided?”](#how-is-done-decided) Two conditions. The story’s executable acceptance criteria must **pass** (`verify_ac` runs them), and - past the two-role threshold - an **independent reviewer** who is not the author must sign it off. You cannot simply write `Status: Done`; conformance re-checks it. See [executable acceptance criteria](/concepts/executable-acceptance-criteria/) and [two-role review](/concepts/two-role-review/). ## Greenfield or brownfield - which path? [Section titled “Greenfield or brownfield - which path?”](#greenfield-or-brownfield---which-path) You do not have to choose. `/sdlc-studio init guided` classifies the repo for you at the first stage and forks itself: on an empty repo it interviews you for the specs, on existing code it reverse-engineers them. The rule that makes the second path safe is that a generated spec stays a hypothesis until its tests pass against the real implementation. See the [greenfield](/walkthrough/greenfield/) and [brownfield](/walkthrough/brownfield/) walkthroughs. ## Where does it put files? [Section titled “Where does it put files?”](#where-does-it-put-files) Plain markdown under `sdlc-studio/` in your project, so everything is reviewable and version-controlled - `prd.md`, `epics/`, `stories/`, `bugs/`, `reviews/`, and more. Generated test code goes under `tests/`. ## Which agents does it work in? [Section titled “Which agents does it work in?”](#which-agents-does-it-work-in) Claude Code, Cursor, OpenAI Codex, GitHub Copilot, opencode and Gemini CLI - one install covers them. It is a standard Agent Skill. See [Works with your agent](/integrations/). ## Is it an npm package or an SDK? [Section titled “Is it an npm package or an SDK?”](#is-it-an-npm-package-or-an-sdk) No. It is a curl-installed Agent Skill - a folder of instructions, templates and scripts. There is nothing to import into your code, no account, and no server. ## What is the sprint loop? [Section titled “What is the sprint loop?”](#what-is-the-sprint-loop) `sprint` drives a prioritised **batch** of work along a goal ladder (`triage → plan → design → done`), stops when its acceptance criteria are met, and closes with a reconcile, a review and a retro. Run a single rung for a checkpoint, or `--goal done` to take it all the way. See [the sprint](/sprint/overview/). ## Why a sprint and not one ticket at a time? [Section titled “Why a sprint and not one ticket at a time?”](#why-a-sprint-and-not-one-ticket-at-a-time) Because most of what the discipline buys you is a property of a *set*. You cannot rank a batch of one, you cannot fan out across file-disjoint lanes, you cannot spot two units that contradict each other, and you have no boundary between delivery and close at which to review - so every finding arrives as close work. Measured on this project, the fixed cost of a run is spread over the batch: small batches are the *expensive* ones. See [a spec per run, or a sprint?](/sprint/overview/). ## What is an audit? [Section titled “What is an audit?”](#what-is-an-audit) A read-only sweep that hunts for real defects in a codebase, verifies each candidate through a panel that tries to *refute* it, and files the survivors as bugs or change requests with allocated ids. `audit --profile repo` runs on a repository that has never seen SDLC Studio, so it is the try-before-you-adopt path. See [audit](/audit/overview/). ## What is a sprint charter? [Section titled “What is a sprint charter?”](#what-is-a-sprint-charter) A run that has not happened yet: its goal, the rule that selects its batch, and its appetite. Charters queue up, and `sprint next` materialises the head of the queue against the backlog **as it stands at that moment** - never against the backlog as it stood when the charter was written. See [charters](/sprint/charters/). ## How do I upgrade an existing project? [Section titled “How do I upgrade an existing project?”](#how-do-i-upgrade-an-existing-project) Re-run the installer, or `/sdlc-studio skill-update`. It is a drop-in - existing projects keep working, and the v5 workflow gates are off until you turn them on. See [upgrading](/upgrading/). # For AI agents > The exact steps an AI agent follows to install SDLC Studio into a project and adopt the discipline. Machine-readable llms.txt and per-page markdown are provided. If you are an AI coding agent evaluating or installing SDLC Studio, this page is for you. A machine-readable index of the whole site is at **[/llms.txt](/llms.txt)**, with the full text at **[/llms-full.txt](/llms-full.txt)**. Every page is available as markdown by appending nothing special - request the page and read its content. ## What SDLC Studio is [Section titled “What SDLC Studio is”](#what-sdlc-studio-is) An open Agent Skill (the `SKILL.md` format) that runs the full software development lifecycle: a discovery backlog of requests (CRs/RFCs) becomes sized delivery work (epics, stories, bugs with acceptance criteria) via `refine`; a sprint plans, builds under TDD, verifies against executable acceptance criteria, and closes with an independent two-role review. It is agent-agnostic and runs entirely in the user’s repository. ## Install it into a project [Section titled “Install it into a project”](#install-it-into-a-project) Caution Confirm with the human operator before installing - this writes to their machine. 1. **Install the skill.** ```bash curl -fsSL https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.sh | bash -s -- --target auto ``` Or `--local` for the current project only. The entry point is `.claude/skills/sdlc-studio/SKILL.md` (name, description with use-when triggers, `allowed-tools`). Requires Python 3.10+. 2. **Orient before acting.** Read `sdlc-studio/reviews/LATEST.md` if it exists, then run `/sdlc-studio status` and `/sdlc-studio hint`. Fetch before trusting local state: a clone can be behind its remote. 3. **Adopt the discipline.** Do not hand-author `_index.md` files or hand-allocate ids. Create artefacts with `scripts/artifact.py new` (collision-free id + index row). A story reaches Done only when its executable acceptance criteria pass and an independent reviewer - not you, the author - signs it off. ## The rules you must not walk round [Section titled “The rules you must not walk round”](#the-rules-you-must-not-walk-round) * **Two backlogs.** A request is not work until `refine` decomposes it into sized units. * **Executable done.** `transition -> Done` is gated on the verify report. A hand-edited `Status: Done` is caught by conformance. * **Independent review.** A self-review never clears the Done gate. The reviewer id must differ from the author id. * **Reconcile, do not assert.** The index is derived from the files; `reconcile` syncs it. ## Zero-setup evaluation [Section titled “Zero-setup evaluation”](#zero-setup-evaluation) To evaluate the tool on a repository without changing it: ```text /sdlc-studio audit --profile repo ``` A read-only, refute-panel-verified audit of the host repo; findings are filed as Bug/CR artefacts, with remediation-only handling for secrets. ## See also [Section titled “See also”](#see-also) * [Getting started](/getting-started/) - the human-facing version of this. * [The two-backlog model](/concepts/two-backlog/) and [executable acceptance criteria](/concepts/executable-acceptance-criteria/) - the two rules most agents get wrong first. # Getting started > Install SDLC Studio in one line, learn the v5 mental model, and start your first project - new idea or existing code. SDLC Studio installs as an [Agent Skill](https://agentskills.io) - a folder of instructions, templates and deterministic scripts that your AI coding agent reads. There is nothing to import into your code, no account, and no server. It runs entirely in your own repository. ## The mental model (read this first) [Section titled “The mental model (read this first)”](#the-mental-model-read-this-first) If you last used SDLC Studio when it was mostly human-driven, or you have only ever vibe-coded, three ideas are worth thirty seconds before you install. 1. **Two backlogs, not one.** A **discovery** backlog holds requests - change requests (CRs) and RFCs. A request is not work yet. It becomes **delivery** work - epics, stories and bugs, each with acceptance criteria - only when `refine` decomposes and sizes it. This one rule keeps “ideas” and “committed, sized work” from ever being the same list. 2. **Done is proven, not declared.** A story reaches Done only when its executable acceptance criteria pass **and** an independent reviewer - never the author - signs it off. The tools recompute status from the files, so you cannot simply write `Status: Done` and have it stick. 3. **You are in the lead; the tooling holds the discipline.** You set the goal and approve each step. The agent carries the cost of the ceremony - authoring the spec, keeping it current, running the checks - so the discipline stays affordable. ## Install [Section titled “Install”](#install) []() * macOS / Linux ```bash curl -fsSL https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.sh | bash ``` * Windows ```powershell irm https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.ps1 | iex ``` * Every agent you have ```bash curl -fsSL https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.sh | bash -s -- --target auto ``` You do this once. It installs into your agent’s skills directory; `--list-targets` shows the map, `--local` installs into just the current project. See [Works with your agent](/integrations/) for the per-agent detail, and [For AI agents](/for-ai-agents/) if an agent is doing the install. Tip **Installing in a sensitive environment?** Pin a tagged release and make the checksum mandatory: ```bash curl -fsSL https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.sh \ | SDLC_STUDIO_REQUIRE_CHECKSUM=1 bash -s -- --version v5.1.0 ``` That verifies an archive built from the tag and published with its `.sha256` in the same automated step, so the bytes and the digest come from us together and cannot drift apart. Verification happens before extraction. Tags before `v5.0.1` published no assets, and the command refuses them rather than pretend otherwise. **Requirements:** Python 3.10+ for the bundled scripts (standard library only; PyYAML is the one optional dependency, needed only if you set a project `.config.yaml`). The `gh` CLI only for GitHub sync. Whatever test runners your acceptance criteria invoke. ## Your first project: one command [Section titled “Your first project: one command”](#your-first-project-one-command) You do not need to know the pipeline order. **`init guided`** walks you from an empty (or existing) repo all the way to a ready first sprint plan, one stage at a time: ```text /sdlc-studio init guided ``` It works out for itself whether you are **greenfield** (nothing yet) or **brownfield** (existing code) from the files in your repo, and forks each stage accordingly - you never have to choose `create` versus `generate`. It walks these seven stages: 1. **agents** - seeds `AGENTS.md` and `CLAUDE.md` so every AI agent you use reads the same discipline. 2. **prd** - the [PRD](/specs/prd/): interviewed from scratch on greenfield, reverse-engineered from your code on brownfield. 3. **trd** - the [TRD](/specs/trd/), generated from the PRD. 4. **tsd** - the [TSD](/specs/tsd/), the test strategy the sprint plan will later read. 5. **personas** - your project’s [team](/concepts/three-amigos/), grown from the PRD and its risk signals for you to accept or edit. 6. **decompose** - the PRD broken into epics and sized stories. 7. **plan** - your first sprint plan. Onboarding ends exactly where delivery begins. Each stage **drafts** its document for you to review, then advances only when you confirm: ```text /sdlc-studio init guided --confirm # accept the drafted stage and move on /sdlc-studio init guided --skip # skip this stage (a recorded decision) /sdlc-studio init guided --reset # start the walk again ``` Tip It is **resumable**. Progress is checkpointed, so you can stop after any stage and pick up later - `status` and `hint` keep pointing you back at `init guided` and naming the next stage until you reach that first plan. ## Try it before you commit to anything [Section titled “Try it before you commit to anything”](#try-it-before-you-commit-to-anything) You do not have to adopt the workflow to get value on day one. Point an audit at a repository that has never seen SDLC Studio: ```text /sdlc-studio audit --profile repo ``` It reads the code, hunts architecture, code-quality and defensive-security problems, puts every candidate through a panel that tries to **refute** it, and files only the survivors as bugs and change requests with allocated ids. It restructures nothing and it asks for no PRD. If the findings are not worth having, you stop there. See [audit](/audit/overview/). ## Never lose your place [Section titled “Never lose your place”](#never-lose-your-place) ```text /sdlc-studio status # the at-a-glance dashboard: what is specified, built, proven, checked /sdlc-studio hint # the single next thing to do ``` While guided onboarding is under way, `hint` points you straight back at the next stage; once you are past the first plan it becomes the ordinary next-step ladder. Either way you do not need to memorise commands - say what you want in plain language (“plan the next sprint”, “extract the spec from this code”) and the agent maps it. ## Where to next [Section titled “Where to next”](#where-to-next) * **[Greenfield walkthrough](/walkthrough/greenfield/)** - build a task-management app end to end. * **[Brownfield walkthrough](/walkthrough/brownfield/)** - adopt an existing app the same way. * **[The two-backlog model](/concepts/two-backlog/)** - the single biggest shift, explained properly. * **[FAQ](/faq/)** - PRD, epic, story, acceptance criteria, and the rest, in plain language. # Works with your agent > One install, six agents. Per-harness install locations and how to invoke SDLC Studio in Claude Code, Cursor, OpenAI Codex, GitHub Copilot, opencode and Gemini CLI. SDLC Studio is a standard [Agent Skill](https://agentskills.io) - a `SKILL.md` and a folder of deterministic scripts. Any agent that reads the skill format runs the same discipline. That is the whole point of *agent-agnostic*: switch agents, keep the practice. ## One install [Section titled “One install”](#one-install) ```bash curl -fsSL https://raw.githubusercontent.com/DarrenBenson/sdlc-studio/main/install.sh | bash -s -- --target auto ``` `--target auto` installs into every agent it finds. `--list-targets` shows the map; `--local` installs into just the current project; the installer refreshes other copies it finds (opt out with `--no-sweep`). ## Where it installs, and how to invoke it [Section titled “Where it installs, and how to invoke it”](#where-it-installs-and-how-to-invoke-it) | Agent | Global | Project-local | Invoke | | ---------------- | --------------------------- | ------------------ | ------------------------------------------ | | Claude Code | `~/.claude/skills` | `.claude/skills` | `/sdlc-studio` or model-invoked | | OpenAI Codex | `~/.agents/skills` | `.agents/skills` | `$sdlc-studio`, `/skills` | | Gemini CLI | `~/.gemini/skills` | `.gemini/skills` | auto via description; `/skills` to confirm | | opencode | `~/.config/opencode/skills` | `.opencode/skills` | auto via skill tool | | GitHub Copilot | (repo-scoped) | `.github/skills` | from chat | | Cursor / generic | `~/.agents/skills` | `.agents/skills` | via `AGENTS.md` | The generic `agents` location (`~/.agents/skills` / `.agents/skills`) is read by Codex, Gemini, Copilot and Cursor - so a single install covers the tools that share it. ## Requirements [Section titled “Requirements”](#requirements) * **Python 3.10+** for the bundled scripts (standard library only). PyYAML is the one optional dependency, needed only if you set a project `.config.yaml`; without it the scripts degrade to built-in defaults with a one-line warning, never a crash. * **`gh` CLI** only for the GitHub sync commands. * Whatever **test runners** your acceptance criteria invoke (pytest, vitest, go, …). ## Multi-agent, together [Section titled “Multi-agent, together”](#multi-agent-together) Because every project mints collision-free artifact ids, several people and agents on different machines can file bugs, stories and change requests concurrently and never clash. No coordination, no renumber-on-merge. See [the two-backlog model](/concepts/two-backlog/) for how that work is organised. # Command reference > The full catalogue, grouped the way the process runs - raise, break down, sprint and review, plus the levers, the support commands and the utilities. You rarely type any of them; say what you want and the agent maps it. Tip **You do not need this page to use the tool.** SDLC Studio is model-invoked: say *“plan the next sprint”*, *“extract the spec from this code”*, *“audit this repo”* and the agent maps it to the right command. This is the catalogue for when you want to know exactly what ran, or to script it. In your agent, `/sdlc-studio help` prints the same catalogue, and `/sdlc-studio help` prints one type’s page. The grouping follows the process spine: **raise** work into the discovery backlog, **break it down** into the delivery backlog, then **sprint and review** it to done. ## Raise [Section titled “Raise”](#raise) Intake into the [discovery backlog](/concepts/two-backlog/): a defect, a proposed change, an unsettled design, or a raw report nobody has diagnosed yet. | Command | Does | | ---------------------------------------- | -------------------------------------------------------- | | `/sdlc-studio bug` | create a bug interactively | | `/sdlc-studio bug list` | list bugs (`--status`, `--severity`, `--epic`) | | `/sdlc-studio bug fix --bug BG0001` | start fixing | | `/sdlc-studio bug verify --bug BG0001` | verify the fix, at a declared depth | | `/sdlc-studio bug close --bug BG0001` | close it | | `/sdlc-studio bug reopen --bug BG0001` | reopen a closed bug | | `/sdlc-studio cr create` | file a change request | | `/sdlc-studio cr list` | list them (`--status`, `--priority`) | | `/sdlc-studio cr review` | review CR statuses against the implementation | | `/sdlc-studio cr close --cr CR-0001` | complete, reject or defer | | `/sdlc-studio cr sync` | two-way sync with GitHub Issues (`--dry-run` to preview) | | `/sdlc-studio rfc create` | draft an RFC - an unsettled design, with options | | `/sdlc-studio rfc list` | list RFCs | | `/sdlc-studio rfc review` | flag stalled RFCs and unresolved decisions | | `/sdlc-studio rfc accept --rfc RFC-0001` | record the decision, spawn the workstream CRs | | `/sdlc-studio rfc close --rfc RFC-0001` | supersede or withdraw | | `/sdlc-studio issue create` | file a raw, undiagnosed report | ## Break down [Section titled “Break down”](#break-down) Discovery to delivery. See [the two-backlog model](/concepts/two-backlog/). | Command | Does | | ------------------------------------------------------------ | ------------------------------------------------- | | `/sdlc-studio refine show --request CR-0001` | is it refinable, and what is in it? | | `/sdlc-studio refine apply --request CR-0001` | decompose into an epic and stories, links wired | | `/sdlc-studio refine apply --request CR-0002 --into EP-0009` | decompose into an epic that already exists | | `/sdlc-studio refine add --request CR-0001` | a later slice of an already-decomposed request | | `/sdlc-studio triage show --issue IS0001` | is this issue triageable? | | `/sdlc-studio triage apply --issue IS0001` | decompose an issue into the bugs that fix it | | `/sdlc-studio epic` | generate epics from the PRD | | `/sdlc-studio epic plan --epic EP0001` | preview the epic workflow (`--agentic` for waves) | | `/sdlc-studio epic implement --epic EP0001` | execute it | | `/sdlc-studio epic review` | cascading review | | `/sdlc-studio story --epic EP0001` | generate stories from an epic | | `/sdlc-studio story generate` | extract stories **from code** - brownfield | | `/sdlc-studio story plan --story US0001` | plan and test-spec a story | | `/sdlc-studio story implement --story US0001` | build it (`--tdd`, `--from-phase`) | | `/sdlc-studio story review` | review story status from the codebase | | `/sdlc-studio story sync` | push and pull to GitHub Issues | ## Sprint and review [Section titled “Sprint and review”](#sprint-and-review) The delivery loop. See [the sprint](/sprint/overview/). | Command | Does | | --------------------------------------------------------- | ------------------------------------------------------ | | `/sdlc-studio sprint --goal ` | the goal-driven loop - the primary delivery workflow | | `/sdlc-studio sprint plan` | select, order and size a batch | | `sprint.py breakdown ` | the grooming census, read-only | | `sprint.py preflight --retro RETRO0001` | every refusal the close would raise, read-only | | `/sdlc-studio sprint close --retro RETRO0001` | the close chain (`--apply-signoff --principal`) | | `/sdlc-studio sprint boundary --retro RETRO0001` | close this cycle, open the next | | `/sdlc-studio sprint report --id RETRO0001` | the end-of-sprint report and its checklist | | `/sdlc-studio sprint decision defer` / `list` / `resolve` | set a unit aside pending your ruling | | `/sdlc-studio handoff generate` | where to pick up a run that stopped short | | `/sdlc-studio review` | unified PRD, TRD and TSD review (`--quick`, `--focus`) | Note Several sprint verbs are run through the script rather than the slash command - `sprint.py review-batch`, `batch swap/drop/add`, `appetite resize`, `next`, `queue show`, `call`, `stop`, `reopen`. They are documented on [delivery](/sprint/delivery/) and [charters](/sprint/charters/). ## The levers [Section titled “The levers”](#the-levers) The documents that steer everything else, and the people who speak for them. | Command | Does | | -------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | `/sdlc-studio prd create` / `generate` / `review` | the [PRD](/specs/prd/) - authored, or extracted from code | | `/sdlc-studio trd create` / `generate` / `review` | the [TRD](/specs/trd/) | | `/sdlc-studio trd visualise` | regenerate the C4 architecture diagrams | | `/sdlc-studio trd containerize` | add container design decisions | | `/sdlc-studio tsd` / `tsd generate` / `tsd review` | the [TSD](/specs/tsd/) | | `/sdlc-studio pvd create` / `pvd sync` / `pvd drift` | the [PVD](/specs/pvd/), for a product spanning repos | | `/sdlc-studio persona create` / `generate` / `list` / `review` | the [team](/concepts/three-amigos/) and the [design personas](/concepts/personas/) | | `/sdlc-studio persona import` | bring personas in from elsewhere | | `/sdlc-studio consult team [artefact]` | a Three Amigos review | | `/sdlc-studio consult stakeholders [artefact]` | the wider cast, with their veto lines | | `/sdlc-studio chat [persona]` | talk to a seat | | `/sdlc-studio chat --workshop [topic]` | a multi-persona discussion | ## Support [Section titled “Support”](#support) Keeping the backlog honest and visible. | Command | Does | | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | | `/sdlc-studio status` | the dashboard - what is specified, built, proven, checked (`--full`, `--brief`, `--testing`) | | `/sdlc-studio hint` | the single next thing to do | | `/sdlc-studio reconcile` | detect and fix status and count drift (`--dry-run`, `--scope`) | | `/sdlc-studio reconcile --verify` | run the acceptance criteria and update the stamps | | `/sdlc-studio gate` | the [quality gate](/concepts/the-gate/) (`--release`, `--require-retro`, `--only`, `--skip`) | | `/sdlc-studio audit` | the [adversarial pressure-test](/audit/overview/) | | `/sdlc-studio audit --profile repo` | the same hunt on an untouched repository, zero setup | | `/sdlc-studio decisions add` / `list` / `promote` | the project decisions log | | `/sdlc-studio lessons recall` / `add` / `list` / `rank` | [failure memory](/concepts/lessons/) (`--global` to promote) | | `/sdlc-studio lessons revalidate` / `summary` / `prune` | keep it from rotting into noise | | `/sdlc-studio retro create` / `validate` / `dispose` / `extract` | [the retrospective](/concepts/retro/) | ## Utility [Section titled “Utility”](#utility) Setting up, writing code, testing, migrating, shipping. | Command | Does | | ------------------------------------------------------------ | --------------------------------------------------------------------------------- | | `/sdlc-studio init` | initialise the project (`init guided` is the front door) | | `/sdlc-studio help` | the command reference, in your agent | | `/sdlc-studio code plan` / `implement` / `review` / `verify` | the code workflow (`--tdd`, `--story`, `--epic`) | | `/sdlc-studio code test` / `check` / `refactor` | run tests, lint with auto-fix, guided refactoring | | `/sdlc-studio test-spec` / `generate` / `review` | [test specifications](/testing/overview/) | | `/sdlc-studio test-automation` | generate executable tests (`--spec`, `--type`, `--framework`) | | `/sdlc-studio test-env setup` / `up` / `down` / `status` | containerised test environments | | `/sdlc-studio mutation` | [prove the tests can fail](/concepts/mutation-testing/) | | `/sdlc-studio repo map build` / `query` / `stats` | index the codebase so the agent reads the right files first | | `/sdlc-studio deploy` | the deploy last mile - gate, verify, record. Operator-triggered, never autonomous | | `/sdlc-studio migrate` | review every artefact and upgrade what is safe (dry-run; `--apply`) | | `/sdlc-studio project upgrade` | upgrade a consuming project’s artefacts and conventions | | `/sdlc-studio skill-update` | upgrade the installed skill itself | | `/sdlc-studio project plan` / `implement` | run whole epics in dependency order (`--agentic` for waves) | | `/sdlc-studio project sync` | sync CRs, stories and epics with GitHub Issues | | `/sdlc-studio plan list` / `archive` | manage Claude Code plan files | ## Deterministic artefact tooling [Section titled “Deterministic artefact tooling”](#deterministic-artefact-tooling) The scripts the sprint drives. Run them directly when you want the mechanical thing done the same way every time - and **reach for one before doing anything mechanical by hand**. | Script | Does | | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `artifact.py new --type --title ...` | create any numbered artefact: collision-free id, valid scaffold, index row, parent wiring, provenance stamps | | `artifact.py batch --type --count N` | reserve an id range and write N pre-wired scaffolds atomically | | `artifact.py close --id --verdict approve` | terminal-transition an artefact and record telemetry | | `next_id.py allocate --type ` | the next collision-free id (`--remote` also considers `origin/main`) | | `verify_ac.py run --id US0001` | execute a unit’s acceptance criteria | | `transition.py set ` | change status through the gate rather than by editing a line | | `file_finding.py file --type bug --fields-file ...` | file an audit finding; refuses a hollow artefact | | `provenance.py check` / `remake` | flag artefacts not created by the tool | | `telemetry.py show` | per-run outcomes - local only, gitignored | Caution Never hand-author an `_index.md`. It is **derived**, and `reconcile` syncs it. The same goes for a retro: `sprint close` scaffolds it, and that is the one path that also wires its index row. ## Where to next [Section titled “Where to next”](#where-to-next) * [Configuration](/reference/configuration/) - the keys that change what these commands enforce. * [The sprint](/sprint/overview/) - the workflow most of these serve. * [FAQ](/faq/) - what the artefact types mean, in plain language. # Configuration > The keys in .config.yaml that change what the tooling enforces - the gates you can turn on, the thresholds you can move, and the one deliberate exception where an absent setting does not block. Project settings live in `sdlc-studio/.config.yaml`. Defaults ship with the skill; you override only what you want changed. Caution **Omission is not an escape.** For most gate-bearing keys, an absent config **blocks** and an unknown mode falls back to enforcing. That is deliberate - a safety you get by forgetting is not a safety. There is exactly one exception, marked below. ## The gates you turn on [Section titled “The gates you turn on”](#the-gates-you-turn-on) | Key | Default | What changing it does | | ----------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `two_backlog.enforce` | `false` | **The one exception.** Deliberately off, so an upgrading project keeps its old flow until it opts in. Set `true` and `sprint plan` refuses a discovery item, a CR demands a T-shirt size, and terminal status derives from children. See [the two-backlog model](/concepts/two-backlog/) | | `sprint.breakdown` | `enforce` | `enforce`: `sprint plan` refuses a batch holding a unit with no `Affects` or no `Points:`, and prints no plan at all. `judgement`: the lane reports and does not block | | `review.two_role_after` | unset | The unit id past which Done requires **both** review records - adversarial evidence and an independent sign-off. Forward-only, so existing units keep today’s behaviour | | `engagement_floor` | `floor` | `floor`: work becomes a sized unit with acceptance criteria before it becomes a diff. `judgement`: the model decides when the process applies - which is [measurably the same as no process at all](/evidence/#the-engagement-floor) | | `lessons.loop` | `enforce` | `enforce`: the retro’s content is checked and every finding takes a disposition. `judgement`: reports, never blocks | ## The thresholds you move [Section titled “The thresholds you move”](#the-thresholds-you-move) | Key | Default | Notes | | ----------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `sprint.split_above` | `8` | The `Points:` value above which a unit is refused and must be split. [A point is a stable unit of cost up to here and breaks beyond it](/evidence/#a-story-point-is-a-unit-of-cost). Tighten to `5` for smaller units | | `max_points` | `13` | A story is flagged as too large above this | | `max_ac` | `10` | A story is flagged as too large above this many acceptance criteria | | `recommended_ac.min` / `.max` | `3` / `5` | Suggest more criteria below the minimum; the optimal upper bound | | `coverage.unit` | `90` | Coverage targets the TSD and the status dashboard read | | `coverage.integration` | `85` | | | `coverage.e2e` | `100` | Feature-file coverage target | | `lessons.validity_days` | `90` | Days before a lesson must be revalidated or closed | | `staleness_days` | `90` | Days without a touch before a persona is flagged stale | ## Capacity and appetite [Section titled “Capacity and appetite”](#capacity-and-appetite) ```yaml capacity: tokens: 500000 # forecast ceiling for the batch - a warning, never a gate minutes: 240 # wall-clock ceiling for the run units: 8 # unit-count ceiling appetite: minutes: 0 # 0 = inherit capacity.minutes units: 0 # 0 = inherit capacity.units ``` The appetite is the circuit breaker. It is resolved once at plan time and stamped on the run, never auto-extended, and zero on an axis means unbounded. See [sprint planning](/sprint/planning/#capacity-and-appetite). Tip Derive these from your own measured rows rather than picking round numbers. A ceiling every plan exceeds has stopped being an instrument and become a constant. ## Review policy [Section titled “Review policy”](#review-policy) | Key | Default | Notes | | -------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | `review.policy` | `block` | `carry-forward` files a REJECT’s findings and ships instead of holding until clean - every finding must still be filed or explicitly waived | | `review.repair_plan_gate` | `off` | `on` requires a REJECT to be answered by a written plan, reviewed before any code is written | | `review.repair_design_threshold` | `2` | Failed rounds of one approach before a repeat must **change the design** rather than propose another instance of it | ## Model-tier routing [Section titled “Model-tier routing”](#model-tier-routing) Opt-in. With `routing.enabled`, the plan stamps each unit with an advisory tier so cheap units run on your smaller model and hard ones on your bigger one. | Key | Default | Notes | | ---------------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `routing.enabled` | `false` | | | `routing.models` | `{}` | Map abstract tiers (`tiny`/`small`/`medium`/`large`/`xlarge`) to your own model identifiers. An undeclared tier degrades **upward** to the nearest declared larger tier, never downward | | `routing.floor` | `{bug: small, security: medium}` | Minimum tier per unit kind | | `routing.critic_tier` | `match` | The critic’s tier relative to the author. Never smaller than the author; `above` puts it one step up | | `routing.escalation.max_same_tier` | `2` | Failed attempts before escalating a tier, within the unchanged total attempt cap | ## Deploy [Section titled “Deploy”](#deploy) The skill is gate-and-verify only until you give it a command. Leave these empty and it never deploys anything. | Key | Notes | | --------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `deploy.command` | your own deploy command. Invoked only after the pre-deploy gate is green, and only on an interactive `deploy` - never by a sprint | | `deploy.smoke` | a post-deploy check as a `verify_ac` expression. Smoke green marks the deploy **rolled out** | | `deploy.soak_minutes` | minutes a rolled-out deploy must soak before it is **verified**. Smoke alone never means verified | | `deploy.rollback` | a documented rollback **procedure**. The agent never executes it; `deploy` surfaces it on a failed smoke | ## Workflow mode [Section titled “Workflow mode”](#workflow-mode) | Mode | Change gate | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `solo-dev` | commit straight to main. The PR ceremony is friction on a single-developer project; review happens through the amigos, verify and check | | `pr-required` | the default. `gh pr create`, review, merge | | `staged-rollout` | tag, deploy, soak, promote. The “live” verification depth needs a stable soak before a feature can be Done | ## Other [Section titled “Other”](#other) | Key | Default | Notes | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `skill_source_repo` | unset | Path to the sdlc-studio checkout that `lessons add --global` writes into. Without it, promotion is refused rather than written into a copy the next update deletes | | `provenance.enforce` | off | Gate on artefacts having been created by the tool, rather than reporting it | ## Where to next [Section titled “Where to next”](#where-to-next) * [Command reference](/reference/commands/) - what each of these gates. * [The quality gate](/concepts/the-gate/) - where most of them are enforced. * [Upgrading](/upgrading/) - turning the v5 gates on for an existing project. # The specification layer > PRD, TRD and TSD are the three documents that turn an idea into buildable, testable work - one owned by each of the Three Amigos. The PVD sits above them to coordinate a product built from many repos. Before a single story is planned, SDLC Studio writes down **what** to build, **how** to build it, and **how you will know it works**. Three documents, one owned by each member of your team: | Document | Answers | Owned by (Three Amigos) | | ----------------------------------------------- | --------------------------- | -------------------------- | | **[PRD](/specs/prd/)** - Product Requirements | *What & why* | Lena, the Product seat | | **[TRD](/specs/trd/)** - Technical Requirements | *How* | Dani, the Engineering seat | | **[TSD](/specs/tsd/)** - Test Strategy | *What if - how we prove it* | Sam, the QA seat | These are the biggest levers you can pull. Every epic, story and acceptance criterion downstream is only as good as the three documents it descends from, and each one is a real artefact you can read, edit and version - plain Markdown under `sdlc-studio/`, not a hidden prompt. ## How they stack [Section titled “How they stack”](#how-they-stack) ```text PRD (what & why) sdlc-studio/prd.md │ ▼ TRD (how) sdlc-studio/trd.md │ ▼ TSD (how we prove it) sdlc-studio/tsd.md │ ▼ Personas → Epics → Stories → Code ``` The TRD is gated on the PRD (you cannot design a solution to a problem you have not stated), and the TSD sets the coverage targets the whole pipeline is later measured against. The PRD is the richest input `persona generate --team` reads to grow your project’s team (the generator can also run standalone from a bare repo), and all three feed the `epic` and `story` decomposition into sized, testable work. ## Create, generate, review [Section titled “Create, generate, review”](#create-generate-review) Every spec document supports the same modes, and which of the first two you use is decided by whether the code already exists: * **`create`** - **greenfield.** An interactive conversation builds the document from scratch. Best when you are starting something new. * **`generate`** - **brownfield.** SDLC Studio reads your existing codebase and reverse-engineers the document, marking every inferred claim with a confidence marker - `[HIGH]` / `[MEDIUM]` / `[LOW]` on the PRD, and `[INFERRED]` on the TRD and TSD. * **`review`** - re-check a document against the current code and update it, so a spec cannot silently drift from reality. Caution A **generated** spec is a hypothesis, not the truth. It is worthless until its tests pass against the existing code - SDLC Studio marks the confidence of every inferred line so you can see what still needs proving. This is the difference between a migration blueprint and documentation. ## One product, many repos: the PVD [Section titled “One product, many repos: the PVD”](#one-product-many-repos-the-pvd) A single repository never needs more than a PRD - its PRD is the top of the tree. When several repos form **one product** (shared features, an inter-repo API, coordinated releases), the coordination itself needs an owner. That is the [**Product Vision Document**](/specs/pvd/): the product layer above the PRD that maps each product feature to the repo that owns it, kept honest by a read-only projection into every child repo. ## Where to next [Section titled “Where to next”](#where-to-next) * [PRD - Product Requirements](/specs/prd/) - what to build and why. * [TRD - Technical Requirements](/specs/trd/) - how it is built. * [TSD - Test Strategy](/specs/tsd/) - how you prove it works. * [PVD - Product Vision](/specs/pvd/) - coordinating a multi-repo product. * [The Three Amigos](/concepts/three-amigos/) - the team that owns and reviews each document. # PRD - Product Requirements Document > The PRD captures what to build and why. Author it interactively for a new project, or reverse-engineer it from an existing codebase with confidence markers. Owned by the Product seat of the Three Amigos. The **Product Requirements Document** is the top of the tree for a single repo: *what* the product does and *why*. It is owned by **Lena, the Product seat** of the [Three Amigos](/concepts/three-amigos/), and it is the richest input every later step reads - personas, epics, stories and the closing review all trace back to it. It lives as plain Markdown at `sdlc-studio/prd.md`. ## Three modes [Section titled “Three modes”](#three-modes) * create (greenfield) An interactive conversation builds the PRD from scratch: ```text /sdlc-studio prd create ``` 1. You are asked about the project name, purpose and target users. 2. You describe features one by one, with acceptance criteria. 3. You are asked about non-functional requirements - performance, security, scale. 4. The PRD is written to `sdlc-studio/prd.md`. Best for new projects. * generate (brownfield) SDLC Studio reads your existing code and reverse-engineers the requirements: ```text /sdlc-studio prd generate ``` 1. An explore pass reads your routes, components, tests and config. 2. Features are extracted and their acceptance criteria inferred. 3. The PRD is written with **confidence markers** - `[HIGH]`, `[MEDIUM]`, `[LOW]` - so you can see what is certain and what is a guess. Best for documenting a codebase that already exists. `generate --force` replaces an existing PRD. * review Re-check the PRD against the current codebase and update each feature’s status: ```text /sdlc-studio prd review ``` Every feature is marked **Complete**, **Partial**, **Stubbed**, **Broken** or **Not Started**, and features found in the code but missing from the PRD are surfaced. This is how the document stays honest after a few sprints. Caution A generated PRD is an extraction, not a specification, until its acceptance criteria pass against the code. Treat `[LOW]`-confidence lines as questions to answer, not facts to trust. ## What it captures [Section titled “What it captures”](#what-it-captures) The PRD is a structured document, not a free-form brief. Its sections: 1. Project Overview 2. Problem Statement 3. Feature Inventory 4. Functional Requirements 5. Non-Functional Requirements 6. AI/ML Specifications (when applicable) 7. Data Architecture 8. Integration Map 9. Configuration Reference 10. Test Coverage Analysis 11. Technical Debt Register 12. Documentation Gaps 13. Recommendations 14. Open Questions You do not have to fill every section for a small project - the point is that the shape is there, so nothing important is silently missing. ## What you can do with it [Section titled “What you can do with it”](#what-you-can-do-with-it) * **Grow your team from it.** The PRD is the strongest input `persona generate --team` will ever have - it reads the PRD to propose a project-specific engineering team and a stakeholder panel. * **Decompose it into work.** `epic` and `story` read the PRD to produce the delivery backlog, each story naming the persona it serves. * **Keep it true.** `prd review` re-checks feature status against the code every few sprints, so the document tracks reality instead of drifting into fiction. ## Where to next [Section titled “Where to next”](#where-to-next) * [TRD - Technical Requirements](/specs/trd/) - how the PRD’s *what* becomes a *how* (the TRD is gated on the PRD). * [Personas](/concepts/personas/) - the users the PRD’s features serve. * [The Three Amigos](/concepts/three-amigos/) - how Lena, Dani and Sam each review the spec from their angle. * [The two-backlog model](/concepts/two-backlog/) - how requirements become sized, planned work. # PVD - Product Vision Document (larger projects) > When several repos form one product, the Product Vision Document is the layer above the PRD - a single writable master that maps every product feature to its owning repo and coordinates a centralised vision, projected read-only into each child repo. Most vibe-coding and spec-driven tools assume one repo, one product. Real products are rarely that tidy - a web app, an API, a mobile backend and a shared library can be one product to a customer and four repositories to the team. The **Product Vision Document** is the layer above the PRD that holds that product together with a **centralised vision**. Note A single repo never needs a PVD - its PRD is the top of the tree. Reach for a PVD when several repos form one product: shared features, an inter-repo API, coordinated releases - and the coordination is currently living as stale prose in review notes and handovers. ## What it is [Section titled “What it is”](#what-it-is) The PVD **coordinates and traces - it never re-specifies.** It does not restate any feature; it points at the per-repo PRD that owns the spec. There is one writable master, read-only everywhere else, kept honest by a projection that fails loud if it drifts. * **One writable master:** `sdlc-studio/product/pvd.md`, in a product (anchor) repo, owned by the **Product Manager** persona - distinct from the Product Owner who owns each repo’s PRD. * **The manifest:** `sdlc-studio/product/manifest.yaml` lists each child repo by short id, local path and git URL. It is a coordination manifest, not a hard dependency: a repo that is not on disk yields an *unresolved* marker rather than a silent pass. * **The feature map:** in the master, each product feature `PF####` maps to its owning repo and the CR / RFC / PRD artefact that lands it. ## The workflow [Section titled “The workflow”](#the-workflow) ```text /sdlc-studio pvd create # render the tiered master into the product repo /sdlc-studio pvd sync # project the master read-only into each child repo /sdlc-studio pvd drift # fail loud if a child projection has gone stale ``` 1. **`pvd create`** renders the master into `sdlc-studio/product/pvd.md`. 2. List each repo in `manifest.yaml`. 3. Map each `PF####` to its owning repo and the artefact that delivers it. 4. **`pvd sync`** projects the master read-only into every child repo (a symlink in production, a synced copy in development); **`pvd drift`** is the standing seam-check that fails if a projection goes stale. ## Proportionality: two tiers [Section titled “Proportionality: two tiers”](#proportionality-two-tiers) * **Lean (always):** vision & scope, strategic goals, the master feature inventory, cross-repo dependencies, API contract commitments, a risk & conflict register, and a decisions log. * **Opt-in (large multi-team products only):** the master / domain / team PVD topology tree, G1–G5 governance stage-gates, and formal release coordination. Delete what you do not use - the tool does not want you carrying empty ceremony. Caution The feature map is reviewed by humans in the normal review cadence, **not machine-checked** - an automated cross-repo traceability check was tried and deliberately retired. The PVD makes the coordination visible and owned; it does not pretend to prove it. ## PVD vs the `project` command [Section titled “PVD vs the project command”](#pvd-vs-the-project-command) Do not confuse the two. The `project` command is **single-repo** orchestration - it builds a dependency graph of one repo’s epics and drives them to done in order. The **PVD is the multi-repo layer** - coordinating the separate products that together form one. Different scope, different jobs. ## Where to next [Section titled “Where to next”](#where-to-next) * [PRD](/specs/prd/) - the per-repo document the PVD coordinates but never restates. * [The specification layer](/specs/overview/) - how the PVD sits above PRD / TRD / TSD. * [Sprint planning](/sprint/planning/) - how each repo’s own backlog becomes sprints. # TRD - Technical Requirements Document > The TRD bridges what (PRD) and how (code) - architecture, technology choices with real rationale, API and data design, ADRs. Generate mode adds an architecture assessment. Owned by the Engineering seat. The **Technical Requirements Document** bridges the gap between *what* (the [PRD](/specs/prd/)) and *how* (the code). It captures the architecture, the technology choices and their rationale, the API and data design, and the decisions worth recording. It is owned by **Dani, the Engineering seat** of the [Three Amigos](/concepts/three-amigos/). It lives at `sdlc-studio/trd.md`, and it is **gated on the PRD** - you cannot design a solution to a problem you have not written down. ## Three modes (plus visualise) [Section titled “Three modes (plus visualise)”](#three-modes-plus-visualise) * create (greenfield) An interactive conversation builds the TRD, starting from the project type: ```text /sdlc-studio trd create ``` 1. **Project type classification** - Web App, API Backend, Mobile Backend, CLI, SDK. 2. Architecture recommendations for that type, which you accept or customise. 3. Technology-stack decisions - each one needs a **real justification**, not “we know it”; deviations from the recommended default are captured as ADRs. 4. API design, data architecture, infrastructure and security. Requires a PRD at `sdlc-studio/prd.md`. Best for greenfield or a major re-architecture. * generate (brownfield) Reverse-engineer the TRD from an existing codebase: ```text /sdlc-studio trd generate ``` It detects the project type and architecture pattern, extracts the stack from configs, maps API contracts from routes, documents data models from schemas, and reads deployment config for the infrastructure picture - all with `[INFERRED]` confidence markers. It then runs an **architecture assessment** (see below). Best for brownfield. * review Compare the TRD against the implementation and sync it: ```text /sdlc-studio trd review ``` New components and changes are folded in, significant decisions become new ADRs, and answered questions are resolved. Step four of review explicitly checks the TRD still aligns with the PRD - that the architecture supports every product feature. ## The architecture assessment (generate mode) [Section titled “The architecture assessment (generate mode)”](#the-architecture-assessment-generate-mode) On a brownfield project, `trd generate` does not just describe the architecture - it **judges** it against best practice for the project type, and reports findings with severity markers `[CRITICAL]` / `[REVIEW]` / `[INFO]`. It looks for: * pattern alignment with the project type, * architecture smells - Big Ball of Mud, Distributed Monolith, God Objects, * whether the technology selection is appropriate, * standards compliance for APIs and error handling. This turns “document the code” into “document the code and tell me where it hurts.” ## Visualise the architecture [Section titled “Visualise the architecture”](#visualise-the-architecture) ```text /sdlc-studio trd visualise ``` Parses the TRD’s Technology Stack, Architecture Decisions and Integrations, extracts the system boundaries, containers and components, and regenerates **C4-model diagrams as Mermaid** into the TRD’s Architecture Diagrams section - so the picture is generated from the document, never hand-drawn and left to rot. ## What it captures [Section titled “What it captures”](#what-it-captures) Project type classification and architecture implications · architecture decisions with rationale · technology stack with strong justifications · API contracts and data schemas · integration patterns · infrastructure approach · security considerations · ADRs · open technical questions · (brownfield) the architecture assessment. Tip The rule that a technology choice needs a real reason - not familiarity - is the TRD earning its keep. A stack chosen by habit is the most expensive kind of decision to unwind later. ## Where to next [Section titled “Where to next”](#where-to-next) * [TSD - Test Strategy](/specs/tsd/) - how the design is proven to work. * [PRD - Product Requirements](/specs/prd/) - the *what* the TRD answers *how* to. * [The Three Amigos](/concepts/three-amigos/) - Dani owns the TRD; the whole team reviews it. # TSD - Test Strategy Document > The Test Strategy Document defines what to test, how, when and by whom - coverage targets, test levels, quality gates. It sets the targets the status dashboard measures and is a leg of the closing review. Owned by the QA seat. The **Test Strategy Document** is the project-level answer to *how do we know it works?* It defines what to test, how, when, and who is responsible - one strategy per project, which the individual test specs then apply to specific stories. It is owned by **Sam, the QA seat** of the [Three Amigos](/concepts/three-amigos/). It lives at `sdlc-studio/tsd.md`. ## What a Test Strategy Document defines [Section titled “What a Test Strategy Document defines”](#what-a-test-strategy-document-defines) * **What** to test - scope, levels and types (unit, integration, E2E, performance, security). * **How** to test - frameworks and the automation approach. * **When** to test - CI/CD integration and the quality gates that block a build. * **Who** tests - roles and responsibilities. Its sections: Overview & Objectives · Test Scope (in / out) · Test Levels · Test Environments · Test Data Strategy · Automation Strategy · CI/CD Integration & Quality Gates · Defect Management · Roles & Responsibilities · Tools & Infrastructure. ## Three modes [Section titled “Three modes”](#three-modes) * **`tsd`** (create) - a guided conversation about objectives, test levels, framework preferences, the automation approach and the quality gates. A PRD should exist first, for context. * **`tsd generate`** - reads your test files and CI config, identifies the frameworks in use (Jest, Playwright, pytest, …), documents current coverage and gaps, and writes the strategy with `[INFERRED]` markers. * **`tsd review`** - re-checks the strategy against the codebase and updates tool versions, gates and levels. ## Quality gates [Section titled “Quality gates”](#quality-gates) The TSD is where you decide what blocks a build. A typical set: | Gate | Criteria | Blocking | | ----------------- | ----------- | -------- | | Unit coverage | ≥ 90% | Yes | | Integration tests | 100% pass | Yes | | E2E critical path | 100% pass | Yes | | Performance | p95 < 500ms | Yes | ## How the rest of the pipeline uses it [Section titled “How the rest of the pipeline uses it”](#how-the-rest-of-the-pipeline-uses-it) This is worth stating precisely, because it is easy to assume the TSD is checked line by line - it is not: * The **status dashboard** measures real coverage against the **targets the TSD sets** - that is how a project knows it is below its own bar. * At sprint close, the TSD is one leg of the **unified review** (PRD / TRD / TSD / personas, plus the code), so the strategy is re-examined against what actually shipped. Note `verify_ac` verifies each **story’s acceptance criteria** against the live code (`ac=N pass=N fail=0`) - it does not read the TSD directly. The TSD sets the project-wide targets and gates; the per-story `Verify:` lines are what prove an individual acceptance criterion. Two different instruments, both needed. ## Where to next [Section titled “Where to next”](#where-to-next) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - the per-story oracle the TSD’s targets sit above. * [PRD](/specs/prd/) and [TRD](/specs/trd/) - the other two documents in the specification layer. * [The Three Amigos](/concepts/three-amigos/) - Sam owns the TSD and reviews for testability. # Charters - queueing the runs you have not had yet > A charter is a run that has not happened - its goal, the rule that selects its batch, and its appetite. The queue materialises the head against the backlog as it stands at that moment, because a queue of frozen batches decays. You can usually see three sprints ahead. Writing them down as three fixed batches does not work, because units land and units get delivered between authoring a plan and running it - so by the time you reach sprint three, its batch is a description of a backlog that no longer exists. A **charter** solves that by writing down the *rule* rather than the *result*. ## What a charter holds [Section titled “What a charter holds”](#what-a-charter-holds) Three things, and no batch: | Field | What it is | | --------------- | ---------------------------------------------------------------------------- | | **Goal** | the Sprint Goal - one product-outcome sentence | | **Scope rule** | prose for the reader: what this run is for, and what it deliberately is not | | **Scope query** | the selector the tool can actually resolve, for example `--bugs Open` | | **Appetite** | optional; resolves from the project’s capacity at materialise time if absent | A charter carries no acceptance criteria of its own. It delivers nothing; the units it materialises carry theirs. ## The queue [Section titled “The queue”](#the-queue) ```bash # queue one, with prose for the reader and a query the tool can resolve artifact.py new --type charter --title "" \ --fields-file charter.json # {"goal": "...", "scope": "...", "scope_query": "--bugs Open"} # see the queue, and what the HEAD resolves to against the backlog right now sprint.py queue show # resolve the head against the backlog now, naming who is running it sprint.py next --runner "" # correct a plan somebody wrote sprint.py queue reorder --charter SC0002 --rank 1 sprint.py queue cancel --charter SC0003 --reason "" sprint.py queue clear --reason "" ``` `next` **reports** what it selects. `sprint plan --write` is what actually opens the run - so you always see the batch before it becomes one. Note Only the **head** is resolved by `queue show`. Resolving every charter would be arithmetic over a backlog that the earlier runs will have changed before the later charters are reached - a number that looks precise and is not. An unranked charter sorts after every ranked one, so adding a charter never quietly jumps the queue. ## The seat review lives on the charter [Section titled “The seat review lives on the charter”](#the-seat-review-lives-on-the-charter) A charter’s goal review is written **on the charter**, under a `## Seat review` heading - not in local state. That is deliberate. Local state does not travel. A charter pulled into another working copy must arrive carrying the review that judged its goal, or the next person runs a goal nobody assessed. ## Calling a sprint, and stopping one [Section titled “Calling a sprint, and stopping one”](#calling-a-sprint-and-stopping-one) These are different acts, and the distinction matters at the close. | | What it means | What happens to the remainder | | ------------- | --------------------------------------------------------------- | ----------------------------------------------------------- | | `sprint stop` | **abandons** a run: it did not reach its goal, and it says so | recorded in the handoff as carried | | `sprint call` | **finishes** a run: this is as far as it goes, and that is fine | descoped **back to the backlog**, then the close chain runs | ```bash sprint.py call --reason "" --retro RETRO0001 ``` `call` completes what it starts rather than telling you to. It takes the close’s own flags - `--retro`, `--goal-verdict`, `--note`, `--apply-signoff`, `--principal` - and forwards them, so the close’s messages never name a flag this verb rejects. With no `--retro` it scaffolds one and stops, exactly as `sprint close` does. Caution The remainder returns to the **backlog**, never forward to the next charter. Attaching it forward would make the next run inherit a batch it never approved. Each descoped unit keeps its own status, because a drop judges *this batch* and not the work. ## Where to next [Section titled “Where to next”](#where-to-next) * [Sprint planning](/sprint/planning/) - what happens once a charter is materialised. * [Review and close](/sprint/review-and-close/) - the close chain `call` forwards to. * [A spec per run, or a sprint?](/sprint/overview/) - why the batch is the unit at all. # Delivery > Sequential or parallel delivery, file-disjoint lanes, the per-unit loop, stall quarantine, and the in-flight controls that let you change a run without lying about what it delivered. You approve the plan, and the run goes. What happens then is deterministic enough to describe. ## The per-unit loop [Section titled “The per-unit loop”](#the-per-unit-loop) Each unit runs the same lifecycle: ```text decompose -> build (TDD) -> verify_ac -> conformance -> independent critic -> green commit ``` `verify_ac` runs the unit’s executable acceptance criteria. `conformance` is a hard-fail gate. The critic is an independent pass, not the context that wrote the code. Each ruling is appended to a decisions ledger, so it survives a context reset - a decision nobody can find was not made. Tip Run the criteria at **delivery**, not only at close. A `Verify:` line pointing at a renamed or deleted test verifies nothing while reading as green, which makes a test rename a cross-unit coupling worth catching early. ## Sequential or parallel [Section titled “Sequential or parallel”](#sequential-or-parallel) Every plan states whether the batch may be built in parallel worktrees, and why. Parallel is offered **only** when the batch partitions into two or more file-disjoint groups. A one-unit batch, an all-coupled batch, or a unit with no declared `Affects` is delivered sequentially. Three things count as coupling that people routinely miss: * **Test files.** A shared test module conflicts on merge exactly as a shared source module does. * **A shared temp directory.** A worktree isolates the tree; it does not isolate `/tmp`. * **The build tooling itself.** A unit that changes the pre-commit hook is coupled to every other unit in the batch, whatever its `Affects` says. The plan also emits a **lane partition** - the batch split so no file appears in two lanes - derived from the same `Affects` and verify files the clusters use. On one measured run, seven file-disjoint lanes worked; two units that straddled two lanes each were deliberately held back and built afterwards, and no lane collided with another. ## When a unit stalls [Section titled “When a unit stalls”](#when-a-unit-stalls) A run does not stop because one unit is stuck. At three attempts, or on a repeated failure signature, `loop_guard` **quarantines** the unit: it is marked Blocked, logged with why, skipped, and the batch continues. The completion oracle declares the batch done only when every unit is terminal - Done **or** Blocked. A blocked unit is a result, not an omission. With model-tier routing enabled, a failed attempt escalates one model tier before the cap quarantines, so cheap units run on your smaller model and the hard ones climb. ## Changing a run without lying about it [Section titled “Changing a run without lying about it”](#changing-a-run-without-lying-about-it) A run is a controllable object. Every control below is **recorded**, so the close can say what the delivered batch was and why it differs from the plan. ```bash # trade units - one recorded decision, not a drop that happens to sit beside an add sprint.py batch swap --out US0001,US0002 --in US0003 --reason "the blocking one first" # pull a unit from the batch the done-gate reads sprint.py batch drop US0001 --reason "premise unbuilt" # put one in, under the same gates as the rest sprint.py batch add US0004 # put an epic's stories in as one priced set - the growth is one number, not five entries sprint.py batch add-epic --epic EP0010 --status Ready # raise the ceiling on the record sprint.py appetite resize --units 16 --reason "an epic joined the batch" # end a run that will not reach its goal - the handoff records what is carried sprint.py stop --reason "the dependency slipped" # resume a stopped run rather than minting a fresh one over the same work sprint.py reopen --reason "the dependency landed" ``` Caution Dropping a unit judges **this batch**, not the work. The unit keeps its own status and returns to the backlog; it is not marked Deferred, which would leave it gated. ## Deferring a decision instead of guessing [Section titled “Deferring a decision instead of guessing”](#deferring-a-decision-instead-of-guessing) When a unit needs a ruling only you can give, the run does not stall on it and it does not guess. The unit is set aside and the batch continues: ```text /sdlc-studio sprint decision defer --unit US0001 \ --question "should a superseded verdict still count its reviewer?" \ --option "a|yes - the historical fact stands" \ --option "b|no - supersession retires the attribution" /sdlc-studio sprint decision list # every accumulated decision, asked together /sdlc-studio sprint decision resolve --index 1 --choice a # your ruling, recorded on the run and the ledger ``` Questions arrive together, structured, at the stop - rather than interrupting you one at a time across a run. ## When a run will not finish [Section titled “When a run will not finish”](#when-a-run-will-not-finish) A run that reached its goal owes a retrospective. A run that stopped for any other reason - budget spent, a unit blocked, you called it off - owes the person picking it up one thing: a document that says where to start. ```text /sdlc-studio handoff generate ``` It is a join over evidence the run already produced. It names **every** non-terminal unit with a pointer to start from - the failing criterion, the check it stalled at, the blocker, or the file - records the open decisions, links itself from the retro, and writes a worklist the next run can read straight back. ## Read-only, safe at any point [Section titled “Read-only, safe at any point”](#read-only-safe-at-any-point) ```text sprint.py breakdown --stories Ready --bugs Open # the census the planner reads sprint.py preflight --retro RETRO0001 # every refusal the close would raise /sdlc-studio status # the dashboard, and the open run ``` ## Where to next [Section titled “Where to next”](#where-to-next) * [Review and close](/sprint/review-and-close/) - the batch boundary and the close chain. * [Sprint planning](/sprint/planning/) - where the lanes and clusters are worked out. * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - what `verify_ac` runs. * [The gate](/concepts/the-gate/) - what refuses a commit on the way out. # A spec per run, or a sprint? > Spec-driven tools plan one ticket at a time. SDLC Studio's unit of delivery is a sprint - a prioritised batch driven to a goal, reviewed at its boundary and closed with a retrospective. Most of what the discipline buys you is a property of a set, not a ticket. Every tool in this category has a **unit of work**. That choice decides more than it looks like it does. The common shape is one ticket at a time: you describe a change, the agent writes a spec, plans it, breaks it into tasks and builds it. Ship it, then start again from an empty page. SDLC Studio’s unit is a **sprint**: a prioritised batch of work, driven to a goal, reviewed at its boundary, and closed with a retrospective that has to produce something. The batch is the thing you plan, the thing you review, the thing you learn from. ## Why the unit is the whole argument [Section titled “Why the unit is the whole argument”](#why-the-unit-is-the-whole-argument) This is not a preference. It is where the discipline pays for itself. SDLC Studio’s own published measurements say that on **one small, well-specified change**, the full pipeline costs around 3.1x the tokens of just asking the model, and buys little. That is an uncomfortable number to publish, and it is the honest one. The value shows up in the fan-out: one planning structure driving many units, with the fixed costs spread across everything delivered under it while the per-unit defect protection repeats. A tool whose unit is one ticket is permanently in the regime where the overhead does not pay. It cannot amortise, because it has nothing to amortise across. ## Five things you cannot do with a batch of one [Section titled “Five things you cannot do with a batch of one”](#five-things-you-cannot-do-with-a-batch-of-one) ### 1. Review at a boundary [Section titled “1. Review at a boundary”](#1-review-at-a-boundary) A batch of one has no boundary between delivery and close - they are the same instant. So every finding a review makes arrives *after* the work is nominally finished. It is repaired fast and late, by whoever is still holding the context, in the code that most needs care. One measured run here delivered in five hours and took **six and a half hours to close**. Only about 18% of that was gate and test time. The rest was repair generated by a review that ran too late to be cheap. That is why the [adversarial review runs at the batch boundary](/sprint/review-and-close/). Reviewed there, a finding is delivery work in the batch that caused it, priced against that batch, and fixed by a context still holding it. ### 2. Fan out across parallel lanes [Section titled “2. Fan out across parallel lanes”](#2-fan-out-across-parallel-lanes) Parallel delivery is offered only when the batch splits into two or more **file-disjoint** groups. The planner’s own contract puts it plainly: a one-unit batch is delivered sequentially. Fan-out is unavailable below batch size two - not by policy, but because there is nothing to fan out. ### 3. Prioritise [Section titled “3. Prioritise”](#3-prioritise) WSJF - cost of delay over job size - is a *ranking* function. A set of one has exactly one ordering. Point a per-ticket tool at your backlog and the prioritisation decision has already been made, by whoever typed the ticket. [Sprint planning](/sprint/planning/) ranks the batch and tells you what it chose and why. ### 4. Amortise the fixed cost [Section titled “4. Amortise the fixed cost”](#4-amortise-the-fixed-cost) A run has a fixed cost that has nothing to do with how much work is in it: the planning, the ceremony, the review setup, the close. Fitting this project’s own measured runs gives a marginal cost of roughly **13,000 tokens per story point** against a fixed cost of roughly **3.9 million per sprint**. The consequence is counter-intuitive and worth sitting with: Caution **Small batches are the expensive ones.** An 18-point sprint measured over 228,000 tokens per point; a 100-point sprint measured about 52,000. That is 5.5 times the work for 1.26 times the tokens. Keeping batches small feels careful, and it is where a cost model misleads you most. ### 5. See two units contradict each other [Section titled “5. See two units contradict each other”](#5-see-two-units-contradict-each-other) The most expensive defects are not inside a change. They are *between* two changes that were each individually correct. One review here found two units shipping in a single commit that contradicted one another - neither ticket was wrong on its own. A tool whose widest field of view is one ticket has nowhere to stand to see that. A sprint has [shared-file clusters](/sprint/delivery/), a whole-batch diff, and a review that covers the set. ## And it has somewhere to put things [Section titled “And it has somewhere to put things”](#and-it-has-somewhere-to-put-things) When a per-ticket run finds something outside its ticket it has two options: do it anyway, unpriced, or drop it silently. A sprint has a third. The finding is **filed**, ranked, and turns up in the next batch’s ordering. Blocked units are quarantined and named. Decisions you are not ready to make are deferred and asked together, structured, at the stop. Nothing goes missing quietly, which is a different property from nothing going wrong. ## It gets better each sprint [Section titled “It gets better each sprint”](#it-gets-better-each-sprint) The loop closes. A retrospective is checked on its **content**, not its existence - a gate that tests for a file is satisfied by `touch` - and every finding it records is either filed as work or declined with a stated reason. Both are green. What is refused is silence. The lessons are then lifted out of the retro into a store, because a lesson that stays in the retro file is read by nobody after the sprint that wrote it. The tooling’s own comment on that function is the clearest statement of it: *without this the retro is a diary*. The next sprint’s plan prints those lessons unasked, including a cross-project registry a brand-new project inherits on day one. And the estimate calibrates. Every project starts on a shipped default rate; once it has five units of its own measured evidence, **its own numbers replace the default**. A per-run tool has no denominator - a rate needs points delivered and a sprint to divide by. ## Batch-to-goal, not time-boxed [Section titled “Batch-to-goal, not time-boxed”](#batch-to-goal-not-time-boxed) A sprint here closes when its goal is verified, whether that takes an afternoon or a week. Coordination regimes change when the machine does; a fixed-length sprint is local sun time kept after the trains arrived. Note There *is* a ceiling, and it is a spend ceiling rather than a calendar. The [appetite](/sprint/planning/#capacity-and-appetite) caps units, minutes and forecast tokens, and it breaks the run when it is reached. Appetite is fixed, scope flexes - and raising it is a recorded decision, so the close still reports the overage rather than a run that neatly fitted. ## The run is one object [Section titled “The run is one object”](#the-run-is-one-object) A project holds **exactly one run at a time**, and it is a thing you can inspect and change rather than a train you either ride or abandon. * A batch sharing **no unit** with the open run is **refused, not merged**. Folding unrelated work into an open run would leave it with one goal describing a fraction of the work and a closing verdict nobody could give honestly. * An **overlapping re-plan** - a re-cut, or a sweep pulling blocked work in - accumulates into the same run under its unchanged id. That is the normal way a batch grows. * Every in-flight change is **recorded**, so the close can say what was actually delivered and why it differs from the plan. ## What it costs, honestly [Section titled “What it costs, honestly”](#what-it-costs-honestly) The batch is not free, and the trade is real: * **Review convergence cost rises with the batch.** A bigger diff carries more surface, more claims and more findings, so it takes more rounds to converge. Review rounds on this project run at **62% REJECT**. * **Grooming is unpriced work.** A freshly refined story arrives with placeholder criteria. Authoring them is real effort and story points do not cover it. * **There is no recommended batch size, and we will not invent one.** The fixed cost pulls towards larger batches and review convergence pulls towards smaller ones. Both directions are visible in the measured history, the sample is small and noisy, and picking a number off it would invent a target the data cannot defend. That last one is deliberate. Read your own velocity and decide per batch. ## Where to next [Section titled “Where to next”](#where-to-next) * [Sprint planning](/sprint/planning/) - the goal ladder, the breakdown gate, ordering and the appetite. * [Delivery](/sprint/delivery/) - sequential or parallel, and changing a run without lying about it. * [Review and close](/sprint/review-and-close/) - the batch boundary, the checklist, the retro. * [Charters](/sprint/charters/) - queueing the runs you have not had yet. * [Evidence](/evidence/) - every number on this page, with its source and its caveats. # Sprint planning > The goal ladder, the breakdown gate that refuses an ungroomed batch, seat-scored WSJF ordering, dependency waves, and the capacity and appetite ceilings that stop a run rather than warn about it. A sprint starts by selecting and ordering a batch. You can say it in plain language - *“plan the next sprint”*, *“break it down but don’t write code”*, *“deliver all the open bugs”* - and it maps to the explicit form. ```text /sdlc-studio sprint --bugs Open --goal done # deliver the open bugs /sdlc-studio sprint --crs Proposed --goal design # just the backlog, no code /sdlc-studio sprint --epic EP0007 --goal done # deliver an epic /sdlc-studio sprint --bugs Open --crs Proposed # one mixed backlog-clear tranche /sdlc-studio sprint --bugs Open --autonomous # unattended, guardrails on ``` ## The goal ladder [Section titled “The goal ladder”](#the-goal-ladder) The goal is a stop-point, and the rungs are cumulative. Ask for a lower rung when you want a checkpoint; ask for `done` to take it all the way. | `--goal` | Stops when | You get | | -------- | ---------------------------------------------------------------------- | ---------------------------------------------------- | | `triage` | the plan is approved | the ordered worklist, and the readiness of the batch | | `plan` | a sprint-sized batch is selected, sequenced and estimated | a committed sprint plan | | `design` | every unit is decomposed to Ready stories with criteria **and points** | a reviewable, estimated backlog | | `done` | every unit is implemented, verified, conformant and reviewed | the delivered increment | ## The Sprint Goal [Section titled “The Sprint Goal”](#the-sprint-goal) Separately from the rung, a run can carry a **Sprint Goal**: one sentence of product outcome that unifies the batch. Not a pipeline stage - an outcome. ```text /sdlc-studio sprint --bugs Open --sprint-goal "the release blocker list is empty and each fix has a regression test" ``` It is prompted for when absent and never invented. Before the run opens, the seats **review it**: is it achievable by this batch, what does done mean for it, and does it read as one increment? The verdict has an effect rather than being decoration - a seat that judges the goal unachievable, or not one increment, **refuses the plan**. At the close it is judged: `goal-verdict --verdict achieved|partial|missed`. A run whose plan set no goal is judged as a batch, honestly. The tooling will not invent alignment after the fact. ## The breakdown gate [Section titled “The breakdown gate”](#the-breakdown-gate) `sprint plan` **refuses** a batch whose units are not groomed. Every unit must declare two things: | Field | Why it is compulsory | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Affects:` | the files the unit will touch. Without it nothing can size the unit, and nothing can see that two units touch the same file - so the planner reports them as safely parallel when they will collide | | `Points:` | the job size on the modified Fibonacci scale (1, 2, 3, 5, 8, 13, 20). Not urgency, not a guess at hours. It is **relative**: is this bigger than the last 3 you delivered? | Ungroomed, it exits non-zero and prints **no plan at all**. This is deliberate - a plan over unsized units cannot be sized or safely parallelised, and it looks authoritative anyway. The refusal names each unit, what it lacks and the fix. ```text breakdown: 20 unit(s), 15 ungroomed, 0 above 8 points, 4 shared-file cluster(s) (mode=enforce) ungroomed - `sprint plan` refuses a batch holding any of these: BG0488 lacks: Acceptance Criteria (none at all) BG0513 lacks: Acceptance Criteria (restates the summary, so nothing states what passing is) ... opt out ONLY as a recorded decision. an absent config BLOCKS. ``` Take the same census read-only, before you commit to anything: ```text sprint.py breakdown --stories Ready --bugs Open ``` Note Opting out is possible and it costs a recorded decision: `sprint.breakdown: judgement` in `.config.yaml` makes the lane report instead of block. Omission is not an escape - an absent config **blocks**. ### Above 8 points, refused [Section titled “Above 8 points, refused”](#above-8-points-refused) A unit above the split threshold is refused and must be **split**, not estimated. This is not ceremony bolted on; it is the rule that makes the cost model work. A story point behaves as a stable unit of cost from 2 through 8 - measured across delivered units it lands between roughly 22,000 and 27,000 tokens per point, essentially flat. Above that it breaks: 13-pointers came in 1.9x *cheaper* per point, systematically over-estimated, and every estimator returned them with low confidence and the unprompted words “should be split”. So above 8 the estimate is not worth having, and the honest answer is to decompose - which is a triage decision, not an estimation one. A 7 is refused too: that is the false precision the scale exists to prevent. Decomposing also makes the *estimate* better, not just the tracking. Four large requests sized in one shot came in at 0.56x their forecast with a 2.3x spread. Decomposed first, their summed points against the same unchanged rate predicted the batch to 1.00x. ## Ordering [Section titled “Ordering”](#ordering) ```text /sdlc-studio sprint --order priority # default /sdlc-studio sprint --order wsjf # cost of delay over size /sdlc-studio sprint --order manual ``` **WSJF** is cost of delay divided by job size, with both on the same modified Fibonacci scale. It is seat-scored - sprint planning is a value, size and risk judgement rather than a bare priority sort - and the components are recorded in the plan artefact, so the ordering can be argued with later. ### Dependency waves and shared-file clusters [Section titled “Dependency waves and shared-file clusters”](#dependency-waves-and-shared-file-clusters) For `priority` and `wsjf`, the plan emits **waves** alongside the flat order: wave 1 is everything with no in-batch dependency, wave *n+1* is everything whose dependencies sit in earlier waves. Units inside one wave are independent, and therefore parallelisable. The planner also derives **clusters** from the `Affects` it already parses. A declared dependency is a claim; a shared file is a fact. Units touching the same file are one cluster and are **not** independent parallel work, whatever the declarations say. Without this the planner once reported two units as safely parallel while both were rewriting the same module. ## Capacity and appetite [Section titled “Capacity and appetite”](#capacity-and-appetite) Three ceilings, set in `.config.yaml`: ```yaml capacity: tokens: 500000 # forecast ceiling for the batch minutes: 240 # wall-clock ceiling for the run units: 8 # unit-count ceiling ``` The **appetite** is the circuit breaker built from those. It is resolved once at plan time and stamped on the run, so the ceiling the plan sized the batch against is the ceiling that stops the run. It is never auto-extended. Zero on an axis means unbounded. Raise it in flight and that is a recorded decision, so the close still reports the overage rather than showing a run that neatly fitted: ```text sprint.py appetite resize --units 16 --reason "an epic joined the batch" ``` Tip Set these from your own measured rows rather than picking round numbers. This project’s ceiling was once so low that **every** plan reported over budget - at which point the one instrument meant to say “this batch does not fit” had become a constant, and stopped being information. ## The forecast has two terms [Section titled “The forecast has two terms”](#the-forecast-has-two-terms) ```text forecast = fixed + sum(Points) x tokens-per-point ``` The fixed term prices what a point cannot: the ceremony, the review rounds and the close. Both terms are **measured** from the project’s own whole-sprint actuals rather than written down as constants - re-measured every time a plan is built, and the plan always says whether it is quoting your evidence or the shipped seed. Below five units of your own evidence the seed stands and says so. A rate re-fitted to one or two units is fitting noise, and this project has twice had to delete a rate that hardened into an article of faith. ## Where to next [Section titled “Where to next”](#where-to-next) * [Delivery](/sprint/delivery/) - what happens once you approve the plan. * [Review and close](/sprint/review-and-close/) - the batch boundary and the close chain. * [Configuration](/reference/configuration/) - every key named on this page. * [Evidence](/evidence/) - the measurements behind the 8-point threshold and the two-term forecast. # Review and close > The adversarial review runs at the delivery batch boundary, not at the close - because where it runs decides what its findings cost. Then a close chain that refuses uncovered units, a checklist derived from the tree, and a retrospective that has to produce work. ## Where the review runs decides what it costs [Section titled “Where the review runs decides what it costs”](#where-the-review-runs-decides-what-it-costs) Run the adversarial review at the close and every defect it finds is close work *by definition*. It arrives after the sprint is nominally over, is repaired fast and late by whoever is still holding the context, and lands in the most load-bearing code in the project. One measured run here delivered in five hours and took **six and a half hours to close**. Gate and test time across the whole close was about 70 minutes - roughly 18%. The rest was repair generated by a review that ran too late. There was a compounding effect too: a review of the *repairs* then found nine more surviving mutants, because the repairs had been written fast, late and self-reviewed. Repairs made under close pressure are the least-reviewed code in a sprint, and they sit in the most load-bearing paths. Tip A human sprint that spent two weeks delivering and two weeks closing would not survive the quarter. The shape here was identical: QA happening after sign-off rather than inside the sprint. So the review moved to the **delivery batch boundary** - the point the project already commits on. Reviewed there, a finding is delivery work in the batch that caused it, priced against that batch, and fixed by a context that still holds it. ## Reviewing a batch [Section titled “Reviewing a batch”](#reviewing-a-batch) Open a span over the units a batch will land, and review it when the batch is committed. ```bash # open the span as the batch starts sprint.py review-batch --open US0560,US0561,US0562,US0563 # ... deliver ... # record the independent pass and close the span sprint.py review-batch \ --reviewer "the fresh context that did not write this" \ --author "whoever wrote it" \ --verdict APPROVE \ --findings "what was probed, and what was found - 'none blocking' is a finding" ``` Reviewer and author **must differ**. A self-review is the context that wrote the code agreeing with itself, and it clears nothing. A `REJECT` is recorded - the range *was* reviewed - but it clears no gate. Any finding filed while a span is open is stamped against that span, so a sprint can report where its defects were found. Filed with no span open, the artefact says so rather than being silently attributed to the last one. ### A review judges the unit’s own diff [Section titled “A review judges the unit’s own diff”](#a-review-judges-the-units-own-diff) Scope is the unit’s declared `Affects` against the run’s base ref. Findings are sorted by origin - **regression**, **newly introduced**, or **pre-existing** - and that is decided by execution, not by impression. Only the first two block. Anything already true of the tree, or already recorded in an open bug or change request, is reported with its id and does not hold the gate. This is what makes reviews discriminating rather than uniformly negative. An unjustified REJECT is as much a failure as an unjustified APPROVE, and only a bounded review can tell the two apart. ## Pre-flight, before you commit to a close [Section titled “Pre-flight, before you commit to a close”](#pre-flight-before-you-commit-to-a-close) ```text sprint.py preflight --retro RETRO0001 ``` Read-only. It reports **every** unmet close prerequisite in one pass: the gate lanes, the retro’s missing sections, an unjudged goal, and the per-unit sign-off prerequisites. Those last ones otherwise surface only after the whole chain has passed, so a close used to take as many runs as it had unmet prerequisites, each costing a full gate run. ## The close [Section titled “The close”](#the-close) ```text /sdlc-studio sprint close # scaffolds the retro, then stops /sdlc-studio sprint close --retro RETRO0001 # the close ceremony as one chain /sdlc-studio sprint close --retro RETRO0001 --apply-signoff --principal "You" ``` Run it with no `--retro` the first time and it **scaffolds** the retro for you - allocated id, template, index row, batch and goal pre-filled from the run - then stops so you fill it. Never hand-author a retro; the scaffold is the one path that also wires its index row. The chain is deterministic: goal verdict, retro validate and extract, lessons summary, the close gate, handoff, reconcile. It stops loudly at the first failing step with the remedy named. `--apply-signoff` fans your reviewer-of-record approval into per-unit sign-offs and Done transitions. It is gated on the criteria having passed, it cascades, it is idempotent, and it stops at the first refusal rather than half-applying. It never runs without an explicit `--principal`. Caution `sprint close` **refuses** a batch carrying units no independent pass covered, and names them. The close asserts that coverage exists; it does not perform the review. ## The compulsory checklist [Section titled “The compulsory checklist”](#the-compulsory-checklist) The checklist is part of the sprint report, not a second document. It carries one row per **stage** of the cycle - the pre-plan reconcile, the goal’s seat review, the grooming gate, the run opening, the batch-boundary reviews, the closing review, the goal verdict, the retro, the lessons, the sign-off, the handoff - plus the figures a close otherwise re-derives by hand: planned against delivered, what was dropped or held or carried and why, scope creep as a count and a ratio, who reviewed what under which seat, and cost. **Every row but one is derived from the tree**, because a checklist that asks you to retype what the files already hold gets filled in from memory. The exception is a judgement, and it is the honest part: | Carried finding | Ruling | Ruled by | Date | | --------------- | ------------- | -------- | ---- | | BG0402 | not-stop-ship | you | … | | CR0510 | deferred | you | … | Every open finding takes a ruling - stop-ship, not-stop-ship, accepted-risk or deferred. An open finding with no row is reported **UNRULED**, because *“we carried it”* and *“nobody looked”* must never read the same. A stop-ship ruling holds the close. If an item genuinely does not apply, waive it on the record rather than fudging it. ## A finding at close is filed, never repaired inline [Section titled “A finding at close is filed, never repaired inline”](#a-finding-at-close-is-filed-never-repaired-inline) The close writes an account of the batch and then stamps the ledger saying the batch is accounted for. Anything reaching a terminal status after that stamp is, by construction, unaccounted for. So a finding surfaced during a close is **filed and deferred**. Repairing inline produces a close that appears never to finish: every mechanical check passes, the run reads closed, and the ledger still says a close is owed. One run hit that twice in a single close. ## Rolling cycles [Section titled “Rolling cycles”](#rolling-cycles) ```text /sdlc-studio sprint boundary --retro RETRO0001 # close this cycle, open the next from the live backlog /sdlc-studio sprint plan --cycles 3 --goal done # a standing policy: roll three cycles ``` Each cycle regenerates its plan against the backlog as it stands, rather than executing a plan drawn before the last two sprints changed it. ## Where to next [Section titled “Where to next”](#where-to-next) * [The retrospective](/concepts/retro/) - why it is checked on content and not existence. * [Lessons](/concepts/lessons/) - where a retro’s findings go, and how the next plan reads them. * [Two-role review](/concepts/two-role-review/) - the independence rule behind the sign-off. * [Charters](/sprint/charters/) - queueing the next run before this one closes. # Test specs, test code and test environments > Test specifications map every acceptance criterion to a named test case, test-automation writes the executable code from them, and test-env stands up the containers integration tests need. Coverage by construction, rather than reverse-engineered at the end. The [acceptance criteria](/concepts/executable-acceptance-criteria/) decide whether a story is done. This section is about the layer that makes them real tests rather than good intentions. ## Test specifications [Section titled “Test specifications”](#test-specifications) A test spec consolidates the plan, the suites, the cases and the fixtures into one document per epic. Its job is a mapping: **every acceptance criterion to a named test case**. ```text /sdlc-studio test-spec # from epics and stories - greenfield /sdlc-studio test-spec --epic EP0001 # one epic /sdlc-studio test-spec generate # reverse-engineer specs from tests you already have /sdlc-studio test-spec review # are the criteria still covered? ``` Tip Because the mapping exists up front, **coverage is by construction rather than reverse-engineered at the end**. “Which criteria have no test?” is a lookup, not an archaeology project. `test-spec review` is the one to run after a spec changes. Criteria drift; a spec that mapped cleanly three sprints ago may now be pointing at cases that no longer exist. ## Test code [Section titled “Test code”](#test-code) ```text /sdlc-studio test-automation # everything pending /sdlc-studio test-automation --spec TS0001 # one spec /sdlc-studio test-automation --type unit # or integration, or e2e /sdlc-studio test-automation --framework pytest # override the detected framework ``` It detects your language and framework and generates executable code from the specs. The generated tests are ordinary files in your repository under your test runner - not a proprietary format and not something only the tool can run. ### Name the mutant first [Section titled “Name the mutant first”](#name-the-mutant-first) The single most useful habit in this section, and it applies whether the test is generated or hand-written: > Before writing a test, state **the production change it must fail on**. Then break the code on purpose and check the test dies. A test that passes whatever you do to the code is a test of nothing. This project has found its own. [Mutation testing](/concepts/mutation-testing/) is the mechanical form of the same check. ## Test environments [Section titled “Test environments”](#test-environments) Integration and end-to-end tests usually need something running - a database, a queue, a fake payment endpoint. ```text /sdlc-studio test-env setup # generate docker-compose.test.yml, from the TRD /sdlc-studio test-env up # start it /sdlc-studio test-env status # are the services healthy? /sdlc-studio test-env down # stop and clean up ``` The environment is generated **from the TRD**, so the services the tests run against are the ones the architecture says exist. When the TRD changes, regenerate rather than patching a compose file by hand until it diverges from the design. ## Verification depth [Section titled “Verification depth”](#verification-depth) A fix records **how** it was verified, not merely that it was. The tiers are enforced at the status gate: a bug cannot reach Fixed below functional depth, and a production-affecting one cannot reach Closed below soak. That distinction translates directly: *“we fixed it”* and *“we fixed it and it survived a weekend in production”* are different claims, and the tooling makes you say which one you are making. ## Where to next [Section titled “Where to next”](#where-to-next) * [Executable acceptance criteria](/concepts/executable-acceptance-criteria/) - the criteria these tests prove. * [Mutation testing](/concepts/mutation-testing/) - proving a green suite was earned. * [The TSD](/specs/tsd/) - the strategy that sets the targets. * [Audit: the test profile](/audit/profiles/) - hunting for tests that cannot fail. # Upgrading from v1 / v4 > What changed since the human-driven era - the two-backlog workflow, sizing, the two-role gate - and how an existing project upgrades without disruption. If you have used SDLC Studio since the early, mostly human-driven days, the tool has grown a lot of discipline. The good news: **nothing changes in an existing project until you say so.** ## New in 5.1: it stops making you wait [Section titled “New in 5.1: it stops making you wait”](#new-in-51-it-stops-making-you-wait) If you have run SDLC Studio against a real backlog, two things grated. Both are gone. **`status` was taking about a minute, every time.** Measured on the same machine, over a backlog of 822 stories and 667 bugs: | | 5.0.1 | 5.1 | | ------------- | ----- | -------- | | `status` | 59.6s | **0.9s** | | `status hint` | 59.5s | **0.8s** | **Fixing one bug no longer invalidates other people’s evidence.** Mutation evidence used to be tied to a whole file, so editing anywhere in a file another unit had touched staled that unit’s evidence too - one line moving forced seven units’ checks to be re-run by hand before anyone could commit. Evidence is now tied to the exact spot a test covered, so an edit elsewhere in the same file leaves it alone. **The other direction, plainly:** the checks that run when you commit take *longer*, not less. There are 536 more tests than 5.0.1 and the full suite moved from 286s to 331s. That is the trade - more is checked, so more is caught. What got fast is what you run interactively. The rest of 5.1 is about trusting what the checks tell you: a new probe asks whether a criterion could ever **fail** before you build against it, `Done` refuses a unit whose own tests never ran a line it added, and the release gate asks the forge whether CI actually passed instead of believing a local file. One breaking change `mutation.py register` now requires `--anchor` - the exact text your mutant replaced. Existing calls exit 2 until you add it. Rows already in your ledger are untouched and need no backfill. ## The upgrade is opt-in [Section titled “The upgrade is opt-in”](#the-upgrade-is-opt-in) Re-run the installer (or `/sdlc-studio skill-update`). It is a drop-in: no project migration, and existing `sdlc-studio/` directories keep working exactly as they did. The v5 workflow changes - the two-backlog gates, sizing demands, terminal-status derivation - are **off by default**. An existing project upgrades with zero disruption and keeps its old flow until you turn enforcement on. ## What is new to learn [Section titled “What is new to learn”](#what-is-new-to-learn) * **[The two-backlog model](/concepts/two-backlog/).** The single biggest shift: a request (CR/RFC) is not work until `refine` sizes it into delivery units. This is new if you last drove the pipeline by hand. * **Sizing is compulsory.** Delivery units carry points (stories/bugs) or a T-shirt size (CRs/RFCs/epics). The planner refuses an un-sized unit. * **[Two-role review](/concepts/two-role-review/).** Past a configurable threshold, Done needs an independent, non-author sign-off. * **[The sprint](/sprint/overview/).** A deliberate batch driven to a goal, reviewed at its boundary and closed with a reconcile, a review and a retro that has to produce work. ## Turning enforcement on [Section titled “Turning enforcement on”](#turning-enforcement-on) Start with `/sdlc-studio migrate`. It reviews every artefact and upgrades what it safely can - conventions, version, sizing - applying the deterministic set and *reporting* the judgement calls with the command that fixes each. It is dry-run by default; `--apply` writes the safe set. Then three deliberate steps: 1. `/sdlc-studio migrate --apply` - convert existing requests and containers to a T-shirt size deterministically, and report the delivery units that need re-sizing. 2. `refine` the accepted requests into sized delivery work. 3. Set `two_backlog.enforce: true` in `.config.yaml`. The sizing migration only *adds* a `Size:` line and the workflow is one config line, so the upgrade is reversible. ## The numbering question [Section titled “The numbering question”](#the-numbering-question) New projects mint collision-free ULIDs (`US-01JQK3F8`) so parallel agents never fight over sequential ids. An existing project is asked the numbering question explicitly on upgrade, with three supported answers - it is never auto-flipped. Note The full, in-repo detail - what changed, the numbering question and its answers, and the honest breaking-change notes - lives in `docs/existing-users.md` in the repository. # A first change (quick taster) > One feature, start to finish - what you say in plain language, and what your team does. From a raw idea to a closed, independently reviewed sprint. The two-minute version. You drive the whole lifecycle in **plain language** - you say what you want, the agent works out what you mean, and the discipline holds underneath. Here is one feature - *adding the ability to delete a task* - from a raw idea to a closed, reviewed sprint, told the way you would actually experience it: what you say, and what your team does. Note This is the two-minute version, and it assumes a project already exists. For the full journey from nothing, see the [greenfield walkthrough](/walkthrough/greenfield/) (build a task-management app from an empty repo); to adopt code you already have, see the [brownfield walkthrough](/walkthrough/brownfield/). Tip You never have to memorise commands. Everything below also has an explicit command (shown as *the explicit form*) for when you prefer it - but the point is that you don’t need it. 1. **You say:** *“Add a delete function to the task list.”* The request is filed in the **discovery backlog** - an idea, not committed work yet. It is cheap and unsized. (For a bigger design question - *“should deletes be soft or permanent?”* - you’d say *“open an RFC”* to weigh the options first.) > *The explicit form:* `cr create` 2. **You say:** *“Refine that into work.”* `refine` breaks the request into an **epic and sized stories**, each with plain, checkable acceptance criteria - for example: ```text US: A user can delete their own task AC1 Given a signed-in user with a task, When they delete it, Then it is removed from their list AC2 Given a task they do not own, When they try to delete it, Then it is refused ``` Now it is delivery work. If the criteria are still rough, you say *“tidy up the acceptance criteria”* and the team makes each one concrete. > *The explicit form:* `refine --id CR0007` 3. **You say:** *“Plan a sprint over it.”* The **breakdown gate** checks the batch is ready - refined, sized, criteria written - and refuses if it isn’t. Then it opens the sprint and shows you the plan. > *The explicit form:* `sprint plan --goal done --write` 4. **You say:** *“Build the first story.”* **Dani** (your Engineering seat) writes the failing test first, implements the delete, and runs the story’s acceptance criteria. The story reaches Done only when they pass - so “done” is a fact the tool checked, not a claim. ```text verify_ac run --id US0012 -> ac=2 pass=2 fail=0 ``` > *The explicit form:* `verify_ac run --id US0012` 5. **You say:** *“Review it.”* A **fresh reviewer that did not write the code** runs an adversarial pass - does it really refuse deleting someone else’s task? - and files what it finds as evidence. You, or someone other than the author, ratify it. The author can never sign off their own work, so your AI isn’t marking its own homework. > *The explicit form:* `critic sprint-review` then your sign-off 6. **You say:** *“Close the sprint.”* The close records your sign-off, transitions the stories to **Done**, marks the epic and the request **Complete**, validates the **retro** and extracts its lessons, and runs the gate. One command, the whole ceremony. > *The explicit form:* `sprint close --apply-signoff --principal "you"` Note Want it hands-off? You say *“take this to done”* and the **goal-driven sprint** runs the batch to its goal - build, verify, review - and closes with a reconcile and review. You set the goal and the acceptance criteria; the team drives the proven lifecycle to it. ## What you are left with [Section titled “What you are left with”](#what-you-are-left-with) The delete feature, shipped: every story Done against passing criteria, a review record naming a reviewer who wasn’t the author, a retro with its lessons, and the request marked Complete - all as plain files under `sdlc-studio/`, true to the code that was actually built. You got there by talking. Next: the concepts behind each step - [the two-backlog model](/concepts/two-backlog/), [the sprint](/sprint/overview/), [two-role review](/concepts/two-role-review/), [executable acceptance criteria](/concepts/executable-acceptance-criteria/). # Brownfield walkthrough - adopt an existing app > A worked example of bringing a codebase you already have under the discipline. Guided init detects the stack and reverse-engineers the specs; the generated spec is a hypothesis until its tests pass against the real code. Most tools assume you are starting fresh. Real work usually is not - you inherit a codebase and have to make it safe to change. Here we adopt an existing **TaskFlow** app (say, an Express + React task manager with some tests and a CI file) and bring it under the full discipline, without rewriting a line to begin with. Tip **Try before you commit.** Before adopting anything, `/sdlc-studio audit --profile repo` runs a read-only, refute-panel-verified audit of the repo and files what it finds - zero setup, nothing written to your code. A good way to see what SDLC Studio notices about a codebase it has never seen. ## One command, forked for existing code [Section titled “One command, forked for existing code”](#one-command-forked-for-existing-code) In the existing `taskflow/` repo: ```text /sdlc-studio init guided ``` Guided init finds `package.json` (and friends), classifies the project **brownfield**, and forks every stage from *author* to *reverse-engineer* - you never choose `create` versus `generate`, it chooses for you. 1. **agents** - seeds `AGENTS.md` / `CLAUDE.md` (leaving anything you already have untouched). 2. **prd** - instead of interviewing you, it reads your routes, components, tests and config and **reverse-engineers** [`sdlc-studio/prd.md`](/specs/prd/), marking every inferred claim `[HIGH]`, `[MEDIUM]` or `[LOW]`. You see TaskFlow’s real feature inventory extracted from the code, with the guesses flagged as guesses. > *The explicit form:* `prd generate` 3. **trd** - it reverse-engineers [`sdlc-studio/trd.md`](/specs/trd/) from the code and runs an **architecture assessment**: pattern alignment, smells (Big Ball of Mud, Distributed Monolith), technology fit - reported with `[CRITICAL]` / `[REVIEW]` / `[INFO]`. This is the “document the code and tell me where it hurts” step. > *The explicit form:* `trd generate` 4. **tsd** - it reads your existing tests and CI, identifies the frameworks (Jest, Playwright, pytest…), and infers the [test strategy](/specs/tsd/) with `[INFERRED]` markers - what you cover today and where the gaps are. > *The explicit form:* `tsd generate` 5. **personas** - it grows the [team](/concepts/three-amigos/) and the design personas from the extracted PRD, so review has domain teeth from day one. 6. **decompose** and **7. plan** - the extracted spec becomes epics and stories, and you get a first sprint plan over the parts you want to change. ## The one rule that makes brownfield safe [Section titled “The one rule that makes brownfield safe”](#the-one-rule-that-makes-brownfield-safe) Caution A generated spec is a **migration blueprint, not documentation** - and it is worthless until proven. **Do not trust a generated specification until its tests pass against the existing code.** An unvalidated extraction is a guess dressed as a fact. So the brownfield loop has an extra beat the greenfield one does not. For the slice you are adopting, SDLC Studio writes tests from the extracted spec and runs them **against your real implementation**: ```text /sdlc-studio story generate --epic EP0001 # extract implementation-ready stories from the code /sdlc-studio code verify --story US0003 # do the extracted ACs actually hold against the code? ``` Acceptance criteria that pass are trusted; ones that fail are where your spec and your code disagree - which is exactly the list of things to fix or re-specify. Only once the extracted spec is green do you plan real change over it, from there following the same build → verify → review → close path as the [greenfield walkthrough](/walkthrough/greenfield/). ## What you have [Section titled “What you have”](#what-you-have) A codebase you inherited, now with a spec that is **proven against the code** rather than assumed, an architecture assessment that names the risks, a test strategy that reflects reality, and a team that reviews with your domain’s non-negotiables. From here, every change goes through the discipline - but the adoption cost was reading, not rewriting. ## Where to next [Section titled “Where to next”](#where-to-next) * [Greenfield walkthrough](/walkthrough/greenfield/) - the same lifecycle from an empty repo. * [The specification layer](/specs/overview/) - create vs generate, and the confidence markers, in detail. * [The two-backlog model](/concepts/two-backlog/) - how the extracted work becomes planned sprints. # Greenfield walkthrough - build a task-management app > A worked example from an empty repo to a shipped, reviewed increment. Guided init writes the specs, grows the team and plans the first sprint; then you build one increment under the full discipline. Let us build a real thing from nothing: **TaskFlow**, a small task-management web app where a signed-in user can create, list, complete and delete their own tasks. This page follows it from an empty repository to a first increment that is built, proven and independently reviewed. You will spend most of it in plain language. Every step has an explicit command shown as *the explicit form*, but you do not need to type them. ## Part 1 - from empty repo to a first plan, in one command [Section titled “Part 1 - from empty repo to a first plan, in one command”](#part-1---from-empty-repo-to-a-first-plan-in-one-command) In your empty `taskflow/` repo: ```text /sdlc-studio init guided ``` Guided init sees no code and classifies the project **greenfield**, then walks the seven stages. Review each draft, then say *“looks good, continue”* (the explicit form is `init guided --confirm`). 1. **agents** - it writes `AGENTS.md` and `CLAUDE.md` so every AI tool you point at TaskFlow follows the same rules. 2. **prd** - an interview: *what is TaskFlow, who is it for, what must it do?* You describe the features; it writes [`sdlc-studio/prd.md`](/specs/prd/) - a Feature Inventory (create / list / complete / delete a task, sign-in), functional and non-functional requirements (a task list loads in under 300ms), and the open questions. 3. **trd** - from that PRD it drafts [`sdlc-studio/trd.md`](/specs/trd/): project type *Web App*, a recommended stack with real rationale, the task and user data models, the REST endpoints, and any decision worth an ADR. 4. **tsd** - it drafts [`sdlc-studio/tsd.md`](/specs/tsd/): the [test strategy](/specs/tsd/) - unit ≥ 90%, the delete-a-task path 100% covered end to end, and the quality gates that will block a build. 5. **personas** - it grows your [team](/concepts/three-amigos/) and the people TaskFlow is *for*: ```text /sdlc-studio persona generate --team # Lena (Product), Dani (Eng), Sam (QA), grown from TaskFlow /sdlc-studio persona generate --from-prd # Priya, the busy team lead who lives in her task list ``` 6. **decompose** - the PRD becomes epics and sized stories, each naming the persona it serves: ```text /sdlc-studio epic /sdlc-studio story --epic EP0001 ``` 7. **plan** - it grooms the backlog and plans your first sprint. This is where guided init ends - you are standing exactly where delivery begins. ```text /sdlc-studio reconcile # recompute status and counts from the files /sdlc-studio status # a clean, drift-free backlog, and the next step /sdlc-studio sprint plan # a sized, sequenced first sprint ``` Everything so far is plain Markdown under `sdlc-studio/` that you read and edit - `prd.md`, `trd.md`, `tsd.md`, `epics/`, `stories/`, `personas/`. Caution **Cold-start reality.** A sprint’s Done gate runs your tests, and an empty repo has none yet. So you build the **foundation** epic (the app skeleton, the test harness, sign-in) by hand up to a green gate first. Only then do you hand the following epics to the sprint loop. The tool will not pretend an empty repo has a runnable gate. ## Part 2 - build one increment under the discipline [Section titled “Part 2 - build one increment under the discipline”](#part-2---build-one-increment-under-the-discipline) Now the foundation is green and *“a user can delete their own task”* is a Ready story (`US0007`). 1. **You say:** *“Build the delete-a-task story.”* **Dani**, your Engineering seat, writes the failing test first, implements the endpoint and the UI action, and runs the story’s acceptance criteria. The story reaches Done only when they pass. ```text verify_ac run --id US0007 -> ac=2 pass=2 fail=0 manual=0 ``` > *The explicit form:* `story implement --story US0007`, then `reconcile --verify --story US0007` 2. **You say:** *“Review it.”* A **fresh reviewer that did not write the code** - Sam’s review render - runs an adversarial pass: does it truly refuse deleting *someone else’s* task? It files what it finds as evidence. Then you, or a delegate who is not the author, sign it off. > *The explicit form:* `critic evidence …` then `critic signoff --principal "you"` 3. **You say:** *“Close the sprint.”* The close records the sign-off, transitions the stories to **Done**, derives the epic and any parent request to **Complete**, validates the **retro** and lifts its lessons, and runs the gate. > *The explicit form:* `sprint close --retro RETRO0001 --apply-signoff --principal "you"` Note Want it hands-off for the rest? You say *“take this epic to done”* and the goal-driven sprint drives the whole batch - build, verify, review - and closes with a reconcile and review. You set the goal and the acceptance criteria; the team drives the proven lifecycle to it. ## What you have [Section titled “What you have”](#what-you-have) TaskFlow’s delete feature, shipped: every story Done against **passing** criteria, a review record naming a reviewer who was not the author, a retro with its lessons, and the request marked Complete - all as plain files under `sdlc-studio/`, true to the code that actually exists. You got here by describing what you wanted; the discipline held underneath. ## Where to next [Section titled “Where to next”](#where-to-next) * [Brownfield walkthrough](/walkthrough/brownfield/) - the same journey starting from code you already have. * [The specification layer](/specs/overview/) - the PRD, TRD and TSD you just wrote, in detail. * [Sprint planning](/sprint/planning/) - how the plan and the delivery loop work.