Software Factory
Close every scope doubt first. Freeze the obligations. Delegate every heavy phase to a fresh subagent. Prove completion with an independent Verifier who did not write the code.
┌──────────┐ ┌──────┐ ┌────────┐ ┌───────┐ ┌────────┐
│ DISCOVER │ → │ PLAN │ → │ CHECKS │ → │ BUILD │ → │ VERIFY │
└──────────┘ └──────┘ └────────┘ └───────┘ └────────┘
0 doubts confirm obligations batches author != verifier
Five moves, three durable artifacts under .specs/features/<feature>/, and a Thin Orchestrator in the main chat that never bloats its context window.
- DISCOVER: A read-only
scoutsubagent scans the codebase and returns a compact (~30-line) ambiguity brief. The main chat interviews the user with concrete options and recommended defaults until zero unconfirmed assumptions remain (Confirmed? yfor every row). See discovery.md. - PLAN: A
plannersubagent writes.specs/features/<feature>/plan.md(Problem, Flow, Impact, Relations, Surface, Landing, Criteria, Out of scope, Assumptions, Observable, Sources) and runsvalidate_plan.py. The user gives a quick sign-off onplan.md. See plan.md. - CHECKS: After
plan.mdsign-off, the autonomous post-plan loop begins. Aspecifiersubagent derives.specs/features/<feature>/checks.md(claims + proofs, Coverage join, Test policy, Swept, Handoff arithmetic) and runsvalidate_checks.py. See checks.md. - BUILD: One
buildersubagent per slice/batch writes tests strictly from the checks, implements the code, runs proofs, updateschecks.md, and commits usingcheck_commit.py. See build.md. - VERIFY (and FIX loop): An independent
verifiersubagent (never the builder) audits<feature base>..HEADagainst every check, writes.specs/features/<feature>/verification.md, and runsvalidate_verification.py. If any check fails, afixersubagent resolves the ranked gaps and a freshverifierre-verifies (up to 3 rounds). See verify.md and orchestration.md.
Why this shape
Coding agents fail on complex features for two predictable reasons:
- Context window bloat: When a single chat session explores the repo, interviews the user, writes the plan, derives checks, writes tests and code, and verifies its own work, the context window fills up and triggers lossy compaction.
- Unconfirmed requirements & self-review blind spots: Silently guessing product behavior (
Confirmed? n) or letting the author self-certify completion ships the author's own blind spots.
software-factory solves both:
- Thin Orchestrator (<15k tokens in main chat): The main chat acts strictly as coordinator and user interviewer. All codebase reading, artifact authoring, coding, testing, and verification run inside isolated ephemeral subagents (
scout,planner,specifier,builder,verifier,fixer) that communicate exclusively via.specs/features/<feature>/files on disk and git commits. Full dispatch protocol: orchestration.md. - Small, frozen obligation set + independent Verifier: There is no granular task checklist or component catalogue (
Purpose/Location/Interfacesper class) to go stale. One-way doors get a literal shape inLanding; reversible placement is decided in the diff.
Critical rules
The pinned set. These hold at every profile:
- Zero unconfirmed assumptions (
Confirmed? y). Never guess product or scope behavior silently. Every gray area surfaced duringDISCOVERmust be asked with concrete options and a recommended default, or explicitly delegated by the user (Confirmed? y).validate_plan.pyrejects any row whereConfirmed?isnor blank. - Thin Orchestrator & Strict 1-Subagent-Per-Phase Boundary (
scout!=planner!=specifier!=builder!=verifier). Keep the main chat under ~15k tokens. Never merge two phases into a single subagent call:scoutONLY explores and returns the ~30-line ambiguity brief.plannerONLY writesplan.md+ runsvalidate_plan.py, then stops and exits.specifierONLY writeschecks.md+ runsvalidate_checks.py, then stops and exits (it MUST NEVER write test files or implementation code or continue intoBUILD).builderONLY runs afterspecifierhas returned. For multi-slice features (S1,S2, ...), dispatch one separatebuildersubagent per slice sequentially so each slice executes in a fresh context window and reports progress to the user.verifierONLY runs in a fresh subagent after the finalbuildercommits.
- Every check is one observable claim with a concrete value plus the proof — the exact test selector or command whose exit code settles it. No proof, no check.
- Tests assert what the checks say, never what the code happens to do. Never write a test by reading the implementation.
- Never weaken an assertion, delete a test, or skip one to make a suite pass. A genuinely wrong check is a stop-and-ask, not an edit.
- Checks and
Test policyrows are fixed once approved. Inplan.md,Landing,Relations, andSurfaceare additive — a door discovered while building gets a row before the code that closes it, and a row the user approved is never rewritten.FlowandImpactare kept true in the commit that changes the path. - The Verifier is a fresh subagent, never the author, never optional, never waiting to be asked. The Orchestrator dispatches it immediately after the last commit of the feature lands over
<feature base>..HEADwith every check. - The profile is a floor and is enforced by
validate_verification.py. - The completion gate is a script, not a feeling:
validate_verification.pymust exit 0. - Blast radius: an approved spec authorizes local edits and local commits.
git push, deploy, and production data changes need an explicit go-ahead for that action.
Profile
The project declares how much runs, in AGENTS.md or equivalent. Absent a declaration: light.
## software-factory
profile: light
budget: 150k
| Profile | Adds | Cannot catch |
|---|---|---|
light (default) | proofs run at HEAD with each named test shown to exist and run, one located assertion per check, level and sampling gaps, Swept existing re-read | a set member with no proof; a test that would pass under a wrong implementation |
standard | the Coverage join recomputed, Test policy rows with a verdict each, one fault per assertion surface | a check that contradicts a binding source; a screen nobody built |
ui | binding sources opened and compared, per-screen enumeration of copy and arrangement | only spacing, colour and type weight, enumerated per screen |
validate_verification.py fails a report whose profile differs from the one checks.md was approved under, fails a standard report with no fault rows or no recomputed coverage, and fails a ui report with no binding-sources section.
Artifacts
.specs/
├── STATE.md # Decisions log (AD-NNN) + Handoff snapshot
├── LESSONS.md # rendered by scripts/lessons.py - never hand-edit
├── lessons.json # machine-owned
└── features/<feature>/
├── plan.md # problem, flow, impact, relations, surface, landing, criteria, assumptions (all y), observable
├── checks.md # claims + proofs, coverage join, test policy, swept, handoff batches
└── verification.md # the independent Verifier's report
Create each file when its phase produces content. For a change under roughly three files with no one-way door and zero scope ambiguity, write only checks.md with an ## Intent paragraph and skip plan.md.
Five bounded design sections in plan.md
| Section | Reviews | Kept out |
|---|---|---|
Flow | the path, one line per hop | any module that neither exists nor is created by a door - that is placement |
Impact | what changes underneath: terms, and existing data | risk registers |
Relations | entities, cardinality, one-way constraints | columns and types |
Surface | route, in, out, statuses | request-body specification, and check ids - those do not exist yet |
Landing | the one-way doors, with the literal shape and the rejected alternative | anything a refactor reverses |
Flow
- Discover — Dispatch the read-only
scoutsubagent to inspect the repo,.specs/STATE.md, and.specs/LESSONS.mdand return a ~30-line ambiguity brief. Walk the user through genuine product and scope gray areas (at most 2 questions per turn, concrete options with recommended default) acrossObservablesurfaces and the 9 implicit dimensions until 0 doubts remain: discovery.md. - Plan — Dispatch the
plannersubagent with the confirmed discovery decisions to write.specs/features/<feature>/plan.mdand passvalidate_plan.py. Presentplan.mdto the user for quick sign-off: plan.md. - Checks — Once
plan.mdis approved, run autonomously. Dispatch a dedicatedspecifiersubagent to derive.specs/features/<feature>/checks.md(claims + proofs,Coveragejoin,Swept, and## Handoffbatch sizing) and passvalidate_checks.py, then terminate that subagent before any code or tests are written: checks.md. - Build — After
specifierfinishes, dispatch one freshbuildersubagent per slice (S1,S2, ...) sequentially. Each builder writes tests from the checks for its assigned slice, implements, runs proofs, recordsBoundaryinchecks.md, commits withcheck_commit.py, and exits: build.md. - Verify & Fix — Dispatch a fresh
verifiersubagent over<feature base>..HEADto writeverification.mdand runvalidate_verification.py. If FAIL, dispatch afixersubagent and re-verify (up to 3 rounds): verify.md. - Orchestration & Subagent Dispatch — Thin-Orchestrator rules, context-window budgets, and multi-agent mappings (
antigravity,claude,codex): orchestration.md. - Durable Memory — Project decisions (
STATE.md), session handoff, and verification-grounded lessons (lessons.py): memory.md.
Scripts
Resolve <skill-dir> as the directory containing this SKILL.md and invoke python3 <skill-dir>/scripts/<name>.py. Pass --root when cwd differs from the project root. A non-zero exit means STOP and fix.
| When | Command |
|---|---|
| Inspect pipeline phase & next subagent role | orchestrate.py status <feature> --root <dir> |
| Generate isolated subagent prompt | orchestrate.py prompt <feature> --role <scout|planner|specifier|builder|verifier|fixer> --root <dir> |
| Run phase gate via orchestrator | orchestrate.py gate <feature> --phase <plan|checks|verify> --root <dir> |
Dispatch subagent via CLI (or --dry-run) | orchestrate.py dispatch <feature> --role <role> --agent <antigravity|claude|codex> [--dry-run] |
Before presenting plan.md | validate_plan.py <feature> |
Before starting BUILD | validate_checks.py <feature> |
| Before each commit | check_commit.py --message "<msg>" |
| Before declaring done | validate_verification.py <feature> |
| At distillation | lessons.py add ... |
| After editing a validator, script, or template | selftest.py |
Subagents and handoff
Every phase is strictly isolated in its own subagent invocation (scout -> planner -> specifier -> builder [S1] -> builder [S2] -> ... -> verifier -> fixer). Never combine specifier (CHECKS) and builder (BUILD) in the same subagent. During BUILD, when a feature has multiple slices (S1, S2, ...), dispatch one separate builder subagent per slice sequentially so each builder starts with a clean context window, finishes quickly, commits its slice on green, and returns a progress update to the Thin Orchestrator.
When the final builder slice returns green, the Orchestrator immediately dispatches the independent verifier subagent in the same turn without asking the user.
Knowledge chain
In strict order: existing code and conventions, project docs, library documentation (Context7 where available), web search, then flag as uncertain. Never invent an API, a flag, a command, or a behaviour.
Output behaviour
Produce the artifact; do not narrate the phase. Lead with the verdict. State decisions definitively. Cut filler and mechanical hedging. Keep section headings in English (they are a schema verified by the gates).