| name | implement |
| position | start |
| description | Build one ready epic to done — every spec passing — strictly inside the epic's box. Breaks the epic into a test-first plan (stories, tasks, tests, docs as a DAG), publishes that plan to the epic's tracked issue and keeps it current as the working spine, builds with spec separation (the implementer never sees tests or evals), and accepts done only from adversarial steelman verification. Opens the work; never closes it — the close belongs after /validate. Also the FIX ROUND: when /validate stamps an epic fix_required, implement re-enters lightweight — the fix report is the exact work list, revision pieces on the existing plan, no fresh breakdown — and the epic flips back to in_delivery. The /implement command in the ProductOS command model. Use when a grilled epic is ready to build, or a validated-rejected epic needs its fix. |
| user-invocable | true |
implement
Given one ready epic on a realized slice, build it to done — every spec passing —
strictly inside the epic's box: break it into stories, tasks, and tests test-first in
working memory, publish that plan to the epic's tracked issue and keep it current as the
working spine, build with verification walled off from the implementer, and accept "done"
only from adversarial steelman verification that tried to refute it. The play opens the
work; it never closes it — closing belongs after /validate accepts.
The play has a second entry: the fix round (C14). When /validate rejects the build it
stamps the epic fix_required and posts a fix report naming each failure by check and
location. Implement re-enters LIGHTWEIGHT: the report is the exact work list — its
findings become plan revision pieces on the existing plan, no fresh breakdown, no fresh
workspace — the epic flips back to in_delivery, and the same done bar applies.
Implement ↔ validate is expected to loop a few rounds; agents fix, validate finds.
Pipeline position: start. The D2 pipeline-position rule
(standards/rules/pipeline-position.md) prepends start-change (resolve/create the
epic's issue, cut the branch off fresh main, optional worktree, init STM). No end
sequence is injected: an epic may only merge — and be stamped delivered — after /validate accepts;
the close chain belongs to the validation side of the pipeline, never to this play. This
source never hand-rolls issue/branch steps — they come only via injection.
Compiled From
This play was compiled from the implement ICE (reference/ice.md) by play-creator
(edited via play-editor: crisp-spec approval gate + per-piece context scope; #466 Batch B:
Level 3 stop-condition formalization; #467 Batch D: spec-approval gate unpinned). Intent
defines constraints (C1–C20) and failure conditions (F1–F17); the expectation defines
success scenarios (S1–S8), a Done means (D1–D4, baked to stop-condition.yaml), and one
recovery entry per failure condition.
To modify this play, update reference/ice.md and recompile with play-creator.
Do NOT edit this file manually — it is a compiled artifact.
Supersedes the old garura:implement (the plan.yaml DAG executor) and absorbs the
breakdown work of the old garura:prepare — the stories/tasks/tests cut is now this
play's Plan phase, STM-only and regenerated on demand, per realignment decisions 9/10.
Role
You are the orchestrator. You own the workflow and the step order. You delegate domain
work to agents via JSON contracts over files on disk — never execute domain work directly.
The act is scripted: deterministic resolution, validation, gate-running, rendering, and
verdict assembly are bundled scripts the steps call; inference is spent only on planning,
authoring, building, and the steelman judgment.
Forbidden: direct git/gh commands in play prose (the two live reads pre-flight
needs — current branch, porcelain — are captured once and passed into scripts); any
closing action (commit/raise/review/merge of the work — C4); hand-rolled issue/branch
steps (those come via the injected start-change and project-orchestrator).
Agent boundaries:
| Agent | Type | Domain | Phases |
|---|
project-orchestrator | utility | Issue plan tracking: publish the rendered plan; keep piece states current; post the done summary (manage-issue over the platform CLI) | Plan; Build; Verify |
tech-designer | domain | Box context + harness capture; the build plan via author-build-plan; plan revisions (retry exhaustion, refutations) | Plan; Build (re-plan) |
test-engineer | domain | Author test pieces from the specs — never sees implementation output | Build |
code-builder | domain | Implement story/task/docs pieces from the piece's cut context slice (piece + deps + spec) — never the whole plan, tests, evals, or pass criteria | Build |
evals-engineer | domain | Steelman evals via author-steelman-evals — compartmentalized from the implementer | Plan |
quality-auditor | domain | The steelman verdict: judge captured gate results + evals against the build; try to refute "done" | Verify |
repo-orchestrator | utility | Self-commit the evidence files (evidence only — never the work) | Evidence & Close |
Domain agents: 5 (tech-designer, test-engineer, code-builder, evals-engineer,
quality-auditor) — at the ≤5 budget. Utility agents: 2 (project-orchestrator,
repo-orchestrator) — exempt. The injected start-change carries its own agents; not
counted here.
Isolation invariants (C6/C7/C17 — checked before every dispatch):
code-builder contracts carry the piece's CUT CONTEXT SLICE (the piece, its
transitive dependencies, and the approved spec — from cut_piece_context.py) plus box
paths only — NEVER the whole plan.yaml, a sibling piece, a free-repo directive, a test
piece's files, test content, the evals path, eval content, or pass criteria (C17/F13).
test-engineer contracts carry the piece's cut context slice + spec-side paths only
(epic, ICE, the spec) — NEVER the whole plan, a sibling piece, implementation piece
reports, or builder output.
evals-engineer contracts carry spec-side paths only; the evals_path it writes
appears in NO builder or test-author contract — only the play and quality-auditor
ever receive it.
Context discipline (C17/C18): no builder or test-author is ever handed the whole
plan — each works from its cut context slice (piece + transitive deps + spec), which is
what holds a long autonomous build faithful and bounded. The play may stand up a
temporary, single-use implementation skill at runtime to author a per-language build
prompt and removes it at run end (C18) — a context device, never a durable component.
Arguments
/implement [--epic <[domain/][slice-id/]epic-id>] [--slice <[domain/]slice-id>]
Examples:
/implement --epic e-1-login-lockout
/implement --slice checkout # auto-picks the earliest eligible ready epic
With --slice and no --epic, the readiness gate auto-picks the lowest-order ready
epic whose dependencies are all delivered. With neither, halt and ask for one.
Pre-flight
The play captures the two live reads once (git branch --show-current;
git status --porcelain into {stm_base}/_preflight/implement-porcelain.txt), then calls
the resolvers — facts from scripts, policy here:
python3 scripts/preflight.py --play implement --branch "<current branch>" \
--porcelain-file <captured porcelain>
python3 scripts/check_ready_epic.py --product-base <product_base from preflight> \
--config .garura/core/config.yaml (--epic <ref> | --slice <ref>) \
[--fix-report {stm_base}/{issue}/validate/report.yaml]
| Fact | Constraint | Action on Failure |
|---|
| config readable (preflight.py exit 0) | — | Hard halt — config is required |
stm_base, product_base resolved | — | Hard halt |
| epic/slice argument present | C1 | Hard halt — "Name an epic or a slice." |
check_ready_epic.py exit 0 (slice realized; epic ready, resuming in_delivery, or fix_required WITH its /validate fix report — the fix round; deps delivered; hub resolves; seven lens .md present) | C1, C14 | Hard halt (F1) — surface every error it printed |
mode (build | resume | fix, from check_ready_epic) | C14 | — recorded; fix → Step 4 runs in revision mode off the report |
--slice auto-pick found no eligible epic | C1 | Graceful exit — "No eligible ready epic; deliver dependencies or cut epics with /grill." |
plan_tracking (from check_ready_epic, implement.plan-tracking, default true) | C12 | — recorded; gates the publish/sync steps |
evidence_record (per-play → global → true) | — | — recorded; gates the evidence write |
Right after the resolvers, record the session identity stamp's start marker (#463 —
soft-fail, never a halt):
python3 scripts/session_stamp.py --phase start \
--marker "{stm_base}/{issue}/status/session-stamp-implement.json" \
--cwd "$(pwd)" --branch "<current branch>"
Resume check: if {stm_base}/{issue}/status/implement.json exists (issue from the
epic's issue_ref or the branch), resume — skip completed steps, reset any in-progress
step or plan piece to pending, re-anchor to the tracked plan (S5), and continue from the
first incomplete step. A fresh start creates the marker at Step 1.
Pre-flight Evals:
- SE-1 (F1/C1):
check_ready_epic.py exited 0 before any build step: the slice is
realized, the epic is ready (or in_delivery with a matching issue on resume, or
fix_required with its /validate fix report on a fix round), every depends_on epic
is delivered, every functionality ice_ref resolves, and all six lens files exist.
No build step ran when it exited non-zero.
Task DAG
Create ALL tasks via TaskCreate immediately after pre-flight resolves — before any
domain work. The play owns this DAG; agents must not edit its top-level tasks (they may
TaskCreate discovered sub-work with addBlockedBy).
[T1] start-change (injected — position: start, head) blockedBy: []
[T2] Anchor the Epic (in_delivery + issue_ref) blockedBy: [T1]
[T3] Box Context + Harness blockedBy: [T2]
[T4] Build Plan + Spec (breakdown + crisp ICE spec) blockedBy: [T3]
[T5] Publish Plan to Issue blockedBy: [T4]
[T6] Steelman Evals (compartmentalized) blockedBy: [T4]
[T7] Plan Checkpoint (spec approval — initial build) blockedBy: [T5, T6]
[T8] Build Loop (pieces along the DAG) blockedBy: [T7]
[T9] Run Gates (scripted) blockedBy: [T8]
[T10] Steelman Verdict blockedBy: [T9]
[T11] Done Assembly + Final Sync blockedBy: [T10]
[T12] Scenario Validation blockedBy: [T11]
[T13] Evidence & Close blockedBy: [T12]
The piece retry loop lives inside T8 (cap 2 per piece, then tech-designer re-plan). The
refutation loop wraps T8–T10 (a refuted verdict feeds new plan pieces and re-enters the
build loop; cap 2 refuted rounds, then human). Mark each task in-progress before its step
and completed right after its eval passes. No runtime reordering.
Workflow
Phase: Start (injected — D2 position: start)
Step 1 — start-change · Owner: start-change (sub-play) · Depends on: pre-flight
Run the start-of-pipeline member as a sub-play, dispatched with parent_run_id. When the
epic carries an issue_ref (resume), pass it so start-change resolves the existing issue;
otherwise pass the epic's title/outcome so it creates the issue this epic is delivered
under (decision 12: one issue per epic). start-change cuts the branch off fresh main, sets
up a worktree iff config calls for it, and initializes the STM workspace:
{
"play": "start-change",
"parent_run_id": "<this run id>",
"inputs": { "issue_number": "<epic.issue_ref if set, else omit>",
"title": "<epic title>", "body_hint": "<epic outcome + user_check>" },
"outputs": { "issue": "{stm_base}/{issue}/evidence/implement/start/issue.json",
"branch": "{stm_base}/{issue}/evidence/implement/start/branch.json" }
}
start-change owns its own evals (issue anchored, branch off latest main, worktree per
config, STM initialized); they are not re-checked here.
Step 2 — Anchor the Epic · Owner: play (script) · Depends on: Step 1
Execute the epic schema's /start fill rule (wiring decision #434 — start-change predates
epics): read the issue number from start/issue.json, then
python3 scripts/update_epic_status.py --product-base <product_base> --epic <epic_id> --issue <issue>
SE-2 (F1/C1, F11/C14): update_epic_status.py exited 0 — it refuses a delivered
epic or a foreign issue_ref, so an ineligible epic cannot slip past pre-flight into
the build (no build step ran after a refusal): the epic file now reads
status: in_delivery with issue_ref equal to the Step 1 issue (or was already exactly
that — idempotent resume). On a fix round this is the fix_required → in_delivery
re-admission (same issue only) — the epic never builds while still stamped
fix_required. A refusal (delivered epic, foreign issue_ref) is a hard halt.
Phase: Plan
Step 3 — Box Context + Harness · Owner: tech-designer · Depends on: Step 2
Dispatch a JSON contract. The agent reads the box only — the epic, its functionality ICE,
the six lenses, the repository — captures the repo context the plan needs, and invokes
detect-test-harness for the project's runnable commands. It invents nothing: every
entry in box-context.yaml cites its source (epic | ice | lens | repo path).
{
"task": "capture the epic's box context and the project's test harness",
"inputs": { "epic_file": "<epic_file>", "functionality_ices": ["<ice paths>"],
"lens_dir": "<lens_dir>", "repo_root": "." },
"outputs": { "box_context": "{stm_base}/{issue}/evidence/implement/box-context.yaml",
"harness": "{stm_base}/{issue}/evidence/implement/harness.yaml" }
}
SE-3 (C3): box-context.yaml and harness.yaml exist; harness.commands is
non-empty; every box-context entry carries a source that is an epic field, a resolved
ICE path, a lens file, or a repository path — nothing sourceless.
Step 4 — Build Plan · Owner: tech-designer → author-build-plan · Depends on: Step 3
Dispatch a JSON contract; the agent invokes the author-build-plan skill — it does NOT
author the plan inline. The skill cuts the epic test-first into grounded pieces (stories,
tasks, tests, docs) with dependency edges; anything ungroundable becomes an
open_questions entry, never invented work. Then the play validates mechanically:
{
"task": "break the epic into the test-first build plan",
"skill": "author-build-plan",
"inputs": { "epic_file": "<epic_file>", "functionality_ices": ["<ice paths>"],
"lens_dir": "<lens_dir>",
"box_context": ".../implement/box-context.yaml",
"harness": ".../implement/harness.yaml" },
"outputs": { "plan": "{stm_base}/{issue}/specs/implement/plan.yaml" }
}
Fix round (mode = fix, C14): Step 3 reuses the existing box-context.yaml +
harness.yaml (refresh only if missing), and this step runs author-build-plan in
revision mode: the inputs gain fix_report: {stm_base}/{issue}/validate/report.yaml,
and the directive is to derive revision pieces FROM THE REPORT'S FINDINGS ONLY — one or
more pieces per finding, each citing the finding's id as its grounding, onto the existing
plan (version bump). No second breakdown is cut; unfixed plan pieces keep their state.
SE-15 (F11/C14): on a fix round, every new plan piece's grounding cites a fix-report
finding id; the plan's piece count grew only by revision pieces (no second plan file, no
new STM workspace); the epic file read in_delivery before the first build dispatch.
python3 scripts/validate_plan.py --plan <plan.yaml> --product-base <product_base> --epic <epic_id>
SE-4 (F3/C3/C5/C11/C13): validate_plan.py exited 0: every piece carries a grounding
citation into the box; the pieces form an acyclic DAG with a dependency-free start; at
least one test piece exists and every epic acceptance criterion is covered by a test
piece authored from the spec (no test depends on the implementation it verifies); a docs
piece exists or a waiver reason is recorded.
SE-5 (F5/C5): the plan and every breakdown artifact live under {stm_base}/{issue}/;
zero breakdown files exist under {product_base}product-os/ (re-asserted by every
check_box.py run via its product-model guard).
Then author the spec — the crisp, human-readable, ICE-shaped boundary document the
human approves and the build treats as its north star (C16). Dispatch tech-designer to
distill it from the box context and the validated plan — Intent (what the build delivers),
Context (the rules, patterns, design decisions, and configuration — ports and the like —
the build must hold to, plus the existing-code map it touches), Expectation (acceptance +
the done bar) — stating boundaries and referencing the epic/ICE/lenses, never copying
code:
{
"task": "distill the approved-bound spec: a crisp ICE boundary doc (~1-2 pages) — rules, patterns, designs, config, existing-code map — referencing the epic/ICE/lenses, never copying code. STATE the spec's user-facing surface as a 'Surface: <type>' line carrying the epic's declared surface.type (surface-contract.md taxonomy) — the build holds that surface and never downgrades it",
"inputs": { "epic_file": "<epic_file>", "functionality_ices": ["<ice paths>"],
"lens_dir": "<lens_dir>", "plan": "<plan.yaml>",
"box_context": ".../implement/box-context.yaml" },
"outputs": { "spec": "{stm_base}/{issue}/specs/implement/spec.md" }
}
Gate it mechanically — the boundary doc must stay crisp and code-free, and its declared
surface must not downgrade the epic's (the epic's surface.type is read and compared by
the same script — C19/F15, surface-contract.md):
python3 scripts/check_spec.py --spec {stm_base}/{issue}/specs/implement/spec.md \
--product-base <product_base> --epic <epic_id>
SE-16 (F14/C16): check_spec.py exited 0 — the spec exists, is ICE-shaped
(Intent/Context/Expectation), carries a non-empty Context (the boundaries), holds no fenced
code block (it references code, never copies it), and is within the readable bound (~1-2
pages); a spec that copies code, balloons, or omits a needed boundary is re-authored before
the checkpoint (REC14).
SE-20 (F15/C19): check_spec.py --product-base --epic exited 0 on the surface gate — the epic
carries a declared surface_type on its spine entry (a legacy epic with none fails until it is declared,
REC15), the spec states a Surface: line, and the spec's surface is NOT below the epic's
declared surface by the surface-contract.md ordering (user-facing web_dashboard/server_api/cli
non-user-facing service_read_model/library). A downgrade fails the gate and halts the build
at the spec-approval checkpoint for explicit human approval of a recut (REC15); building the
same or a higher surface passes.
Step 5 — Publish Plan to Issue · Owner: play (script) + project-orchestrator ·
Depends on: Step 4 · Gated by plan_tracking (C12; when false, record
plan-publish skipped (plan-tracking=false) and continue)
The script composes; the agent fires the CLI verb — it writes no prose:
python3 scripts/render_plan.py --plan <plan.yaml> \
--output {stm_base}/{issue}/evidence/implement/plan-issue.md
{
"task": "post (or edit in place) the build-plan comment on the epic's issue",
"inputs": { "issue_number": "<issue>", "body_file": ".../implement/plan-issue.md" },
"outputs": { "publish_record": "{stm_base}/{issue}/evidence/implement/plan-publish.yaml" }
}
plan-publish.yaml records {plan_publish: {comment_ref, fingerprint, posted_at}} with
the fingerprint from render_plan.py. Every later state sync re-renders and edits the
SAME comment, then refreshes this record.
SE-6 (F9/C12): when plan_tracking is true, plan-publish.yaml exists with a
non-empty comment_ref and a fingerprint equal to the latest render_plan.py output
for the current plan state.
Step 6 — Steelman Evals · Owner: evals-engineer → author-steelman-evals ·
Depends on: Step 4 · CONTEXT-ISOLATED (C7)
Dispatch a JSON contract carrying spec-side paths only. The evals path lives under the
play's eval area and is never placed in any builder or test-author contract:
{
"task": "author the steelman refutation evals for this epic",
"skill": "author-steelman-evals",
"inputs": { "epic_file": "<epic_file>", "functionality_ices": ["<ice paths>"],
"quality_lens": "<lens_dir>/quality.md",
"plan_path": "<plan.yaml>" },
"outputs": { "evals": "{stm_base}/{issue}/evidence/implement/evals/steelman-evals.yaml" }
}
SE-7 (F6/C6/C7): the evals-engineer contract carries no implementer output and no
piece report; the evals path appears in no code-builder or test-engineer contract
this run; every code-builder contract carries zero test-piece file paths, test content,
eval content, or pass criteria; every test-engineer contract carries zero
implementation piece reports or builder output. Checked before each dispatch; a dirty
contract is rebuilt clean (REC6), never dispatched.
Phase: Checkpoint (spec approval on the initial build — Structure A; gate resolves per config)
Step 7 — Spec Checkpoint (class: standard) · Owner: play · Depends on: Steps 5 and 6
The spec-approval checkpoint resolves per standards/rules/gate-config.md (first match
wins: per-play gates.plays.implement, then class standard, then default). It is no
longer pinned — #467 Batch D unpinned it (an intent change to C15); the machine
preconditions below carry the spec alignment the human was checking, and an open question
stays a human halt.
- off (current config:
gates.plays.implement: off) → do NOT wait. Record gate skipped by config (gates.plays.implement) as a Checkpoint Decisions row, then verify the
machine wall before any build-loop dispatch: the plan lints clean (validate_plan.py
exit 0, Step 4 / SE-4), the spec passed check_spec.py including the surface gate
(SE-16 / SE-20), the steelman evals exist (steelman-evals.yaml, Step 6 / SE-7), and the
plan carries NO unresolved open_questions. All hold → start the build. Any of the first
three missing → hold the build and name what is missing (REC17). An open_questions entry
HALTS to a human regardless of the switch — present it one at a time, plainly, and dispatch
nothing until it is answered; an open question IS a genuine human need (REC3/REC17).
- on (config flipped back) → present the spec inline and wait for the typed approval,
exactly as below — no build piece is dispatched until a typed human approval is recorded.
Skip rule — fix round only: when mode == fix, skip the gate — the round is
report-bounded (C14), its revision pieces trace to /validate's findings and cannot widen
the already-approved box, so it re-enters without a fresh approval. Record checkpoint skipped (fix round — report-bounded) and proceed. On build and on a resume that has
not yet recorded an approval, the gate is presented.
Present the spec inline for approval, plus the plan shape and any open questions asked
one at a time, plainly, no option menus:
**Build spec: epic {epic_id} — {title}** — {n} pieces, {t} tests, published to #{issue}.
{the crisp ICE spec — Intent / Context (rules, patterns, designs, config, code map) /
Expectation — read it; this is what the autonomous build will hold to}
**Open question {i} of {q}** (if any)
{question — with its cited context from the plan}
Surface gate (C19/F15) — checked here, before any build dispatch. check_spec.py
(Step 4) already compared the spec's declared surface against the epic's surface.type.
If it flagged a DOWNGRADE (the spec promises a lower surface than the epic declared) or a
MISSING epic surface (a legacy epic), the build does not proceed silently: present the
downgrade — the spec's surface beside the epic's promised surface per surface-contract.md
— and either regenerate the spec preserving the declared surface, or build the lower
surface ONLY on explicit human approval of a recut. A missing surface is declared with the
human before building, never defaulted to service_read_model or any other value (REC15).
Wait for a typed response. Approve → record the approval in the status marker and start the
build. A typed answer to an open question, or any change asked for, becomes a revision
directive to tech-designer → author-build-plan (revision mode); the plan re-validates
(Step 4 gate), the spec is re-authored and re-gated (check_spec.py, including the surface
gate), and it is re-presented — the build never starts on an unapproved or surface-downgraded
spec. The box only widens where the human draws the wall (REC3).
SE-17 (F12/C15): on the initial build (mode != fix), before any build-loop dispatch,
EITHER the status marker records a typed human approval of the spec (gate on) OR the gate
resolved off with the gate skipped by config row recorded and the machine wall held
(plan lints clean, check_spec.py passed, steelman evals present, no unresolved
open_questions); an unresolved open question halted to a human regardless of the switch; a
fix round records the report-bounded skip and carries no approval (REC12).
SE-22 (F17/C15): with the gate resolved off, no build-loop dispatch occurred until the
machine wall held — the plan linted clean (validate_plan.py exit 0), the steelman evals
were present, and no unresolved open_questions remained; any of those missing held the
build (REC17), and an unresolved open question halted to a human.
Phase: Build (the loop — pieces along the DAG)
Step 8 — Build Loop · Owner: test-engineer / code-builder per piece ·
Depends on: Step 7
Walk the plan DAG (C13): repeatedly take the earliest piece whose depends_on are all
done. The plan is the spine — there is no other source of what to do next. Within a
piece, when to run tests and how to iterate is the executing agent's call (C8 —
structural: this play prescribes setup and the done bar, not the inner loop). For each
piece:
- Flip the piece
in_progress in plan.yaml (and sync the issue per Step 5's
render-and-edit when plan_tracking — batched per piece).
- Cut the piece's context slice — the builder gets its piece, that piece's transitive
dependencies, and the spec, NEVER the whole plan or a sibling piece (C17/F13):
python3 scripts/cut_piece_context.py --plan <plan.yaml> --piece-id <piece_id> \
--spec {stm_base}/{issue}/specs/implement/spec.md \
--out {stm_base}/{issue}/evidence/implement/pieces/<piece_id>.context.yaml
-
Optionally stand up a temporary, single-use implementation skill for the piece's
language to author its build prompt (C18) — registered for this run, removed at close;
it never widens the box beyond the spec.
-
Dispatch by kind — test → test-engineer; story/task/docs → code-builder —
carrying the cut slice + spec, not the plan:
{
"task": "deliver plan piece <piece_id> inside the epic's box",
"inputs": { "piece_context": ".../implement/pieces/<piece_id>.context.yaml",
"spec": "{stm_base}/{issue}/specs/implement/spec.md",
"box_context": ".../implement/box-context.yaml",
"harness": ".../implement/harness.yaml" },
"outputs": { "piece_report":
"{stm_base}/{issue}/evidence/implement/pieces/<piece_id>.yaml" }
}
The piece report records {piece_report: {piece_id, files_modified, summary}}. The
builder's pass/fail self-report is never a verdict (C9) — it is bookkeeping only.
-
Capture the changeset (git status --porcelain → file) and run the box gate:
python3 scripts/check_box.py --plan <plan.yaml> --porcelain-file <captured> \
--reports-dir .../implement/pieces/ --product-base <product_base> \
--stm-base <stm_base>
- Green → flip the piece
done, sync, continue the walk. Red → retry the piece (cap 2);
on exhaustion dispatch tech-designer with a revision directive (re-plan, plan
version bump), re-validate + re-publish, and continue — never halt blindly (REC7
direction at piece scale).
SE-8 (F10/C13): for every piece report, the piece exists in the plan and was
in_progress/done when its work ran — check_box.py's piece guard exited 0 every
loop; any plan deviation entered via a recorded revision (plan version bump), never
silently.
SE-9 (F2/C2): every check_box.py run exited 0 on mapping: zero changed files
unclaimed by a piece report, zero product-model writes beyond the anchored epic file.
SE-18 (F13/C17): every code-builder and test-engineer contract this run carried
its piece's cut context slice (cut_piece_context.py output: piece + transitive deps +
spec) — never the whole plan.yaml, a sibling piece, or a free-repo directive; a contract
carrying wider context is rebuilt to the slice and re-dispatched (REC13).
SE-19 (C18): any temporary implementation skill stood up for a piece this run is
removed by run end — none persists as a durable component, and none was used to build
outside the spec.
Phase: Verify
Step 9 — Run Gates · Owner: play (script) · Depends on: Step 8 (all pieces done)
python3 scripts/run_gates.py --harness .../implement/harness.yaml \
--quality-lens <lens_dir>/quality.md \
--output {stm_base}/{issue}/evidence/implement/gates-results.yaml
SE-10 (F7/C10): the final run_gates.py exited 0 and gates_results.pass is true —
every harness command (tests, lint, typecheck, build) green; lens gates mapped runnable
are covered by those results, the rest are handed to Step 10 as needs-judgment.
Step 10 — Steelman Verdict · Owner: quality-auditor · Depends on: Step 9
Dispatch a JSON contract. The verifier judges captured artifacts — it re-runs no
mechanics. Its posture is adversarial: execute every steelman eval's probe, hunt vacuous
tests, judge the needs-judgment lens gates, and try to refute "done":
{
"task": "attempt to refute that this build is done; record the verdict",
"inputs": { "evals": ".../implement/evals/steelman-evals.yaml",
"gates_results": ".../implement/gates-results.yaml",
"plan": "<plan.yaml>",
"piece_reports": ".../implement/pieces/",
"epic_file": "<epic_file>" },
"outputs": { "verdict": "{stm_base}/{issue}/evidence/implement/verdict.yaml" }
}
verdict.yaml: {verdict: {authored_by: quality-auditor, verdict: pass|refuted, refutations: [{claim, probe, finding, resolved}]}}. Refuted → the refutations go to
tech-designer as revision directives (new grounded pieces), the plan re-validates and
re-publishes, and the flow re-enters Step 8. Cap 2 refuted rounds; a third refutation
escalates to the human with the full record.
SE-11 (F8/C9): the verdict gating done is authored by quality-auditor (never the
implementer — a builder self-report is discarded, REC8); on the final round verdict is
pass and every refutation entry from earlier rounds carries resolved: true with the
fix recorded.
Step 11 — Done Assembly + Final Sync · Owner: play (scripts) + project-orchestrator
· Depends on: Step 10
python3 scripts/check_plan_sync.py --plan <plan.yaml> \
--publish-record .../implement/plan-publish.yaml [--tracking-off]
python3 scripts/check_done.py --plan <plan.yaml> --gates .../gates-results.yaml \
--verdict .../verdict.yaml --evidence-dir .../implement/ \
--output {stm_base}/{issue}/evidence/implement/done.yaml
Then (gated by plan_tracking) dispatch project-orchestrator to edit the plan comment
one last time (all pieces done) and post the done summary: built, specs passing, awaiting
/validate — the work is intentionally uncommitted.
SE-12 (F4/C4): check_done.py exited 0: done.yaml reads
specs-passing-awaiting-validation; zero end-sequence evidence (end/*.json) exists
under the play's evidence dir; the play recorded no commit/raise/review/merge of the
work. Full done is /validate's to declare, never this play's.
SE-13 (F9): check_plan_sync.py exited 0 at this step (and at any pause): the live
plan fingerprint equals the published one and no piece state violates its dependencies.
SE-14 (C11): the plan's docs piece(s) are done (or the recorded waiver stands) —
the deliverable included the documentation the change requires.
Phase: Scenario Validation
Step 12 — Scenario Evals · Owner: play · Depends on: Step 11
- SCE-1 (S1 — developer, end to end): the breakdown exists in STM; every epic
acceptance criterion maps to a passing test piece (validate_plan coverage + final
gates green);
verdict.yaml is authored by quality-auditor and reads pass;
the evidence records zero commit/raise/review/merge actions of the work.
- SCE-2 (S2 — project manager, the plan survives):
plan-publish.yaml carries the
issue comment ref; the final check_plan_sync.py exited 0 — every piece state on the
issue equals the STM record, zero divergence (or tracking was off by config and the
skip is recorded).
- SCE-3 (S3 — tech lead, box discipline): every
check_box.py run exited 0 — each
changed file claimed by a piece report, each piece grounded (validate_plan), zero
product-model writes beyond the anchored epic file.
- SCE-4 (S4 — QA engineer, honest verification): the evals-engineer contract carried
no implementer output; no builder/test-author contract carried the evals path; every
refutation in
verdict.yaml is recorded with its resolving fix; the verdict author is
quality-auditor.
- SCE-5 (S5 — developer, resumability): on any resume this run, no second plan was
cut (plan.yaml version history shows revisions only); the first post-resume action
targeted the earliest non-done piece; in-flight pieces were reset to pending and
re-run, not double-counted.
- SCE-6 (S6 — developer, the fix round): on a fix round, every revision piece's
grounding cites a fix-report finding id; no second plan file and no second workspace
exist; the epic file read
in_delivery from re-admission until done assembly; the
done bar re-ran unchanged (final gates green + a fresh quality-auditor verdict).
- SCE-7 (S7 — developer, the approval gate): on the initial build, no build-loop
dispatch occurred before the gate cleared — a recorded typed human approval of the spec
(gate on), or the recorded gate-off skip with the machine wall held (plan linted clean,
check_spec.py exited 0, steelman evals present, no unresolved open_questions) with any
open question halted to a human (gate off); check_spec.py exited 0 (the spec is
ICE-shaped and within the readable bound); a fix round recorded the report-bounded skip and
carried no approval gate.
- SCE-8 (S8 — developer, tight autonomous build): every
code-builder and
test-engineer contract carried its piece's cut context slice (piece + transitive deps
- spec) — zero carried the whole
plan.yaml, a sibling piece, or a free-repo directive;
the run carried from approval to done with no further human input; every temporary
implementation skill created was removed by run end.
Phase: Evidence & Close
Closes with the Standard Play Close — the canonical three-table delivery report (Run
Summary / Pipeline Steps / Artifacts), not prose. See standards/rules/play-close.md.
The close is stop-condition gated (C20/F16): the gate step below evaluates the baked
stop-condition.yaml and binds the verdict.
SE-21 (F16/C20): the close bound the stop-condition verdict — status: COMPLETED was
recorded only when the gate step's sc_exit == 0 (every Done means clause held: the plan
exists, the done verdict was assembled at specs-passing-awaiting-validation, the gates
pass); any other verdict closed HALTED with the unmet clauses named (REC16). COMPLETED
never stands without the Done means held.
evidence_template=$(cat "${ltm_project_target}standards/templates/evidence-file.md")
delivery_template=$(cat "${ltm_project_target}standards/templates/delivery-report.md")
ts=$(date -u +%Y%m%d-%H%M%S)
evidence_dest="${evidence_base}${ts}.md"
mkdir -p "$(dirname "$evidence_dest")"
session_stamp=$(python3 scripts/session_stamp.py --phase close \
--marker "${stm_base}/${issue}/status/session-stamp-implement.json")
python3 scripts/check_stop_condition.py \
--manifest "<play-dir>/stop-condition.yaml" \
--base "${stm_base}/${issue}/" \
--out "${stm_base}/${issue}/status/stop-condition-implement.yaml"
sc_exit=$?
Step C0 — bind the verdict. sc_exit == 0 (held) permits status: COMPLETED.
Anything else closes HALTED with exit_reason: stop_condition_unmet and the evidence's
Stop Condition section names every unmet clause. An unevaluable verdict is never a pass.
Step C1 — Write evidence file. Gated by the resolved evidence_record flag (per-play
evidence.plays.implement first, else global evidence.record, else record). When
false, skip the write and record evidence skipped (record=false) in the report's
pointer line. Otherwise fill the evidence-file.md slots (play implement, run_id
implement-${ts}, issue, started_at/completed_at, status per C0, exit_reason, artifacts:
plan/plan-publish/box-context/harness/evals/gates-results/verdict/done + piece reports;
step + scenario eval results; checkpoint decision or skip reason; epic anchor record;
the session identity stamp fields from $session_stamp (#463): session_id, ledger_file,
ledger_start_offset, ledger_end_offset (null when unresolved — never blocks the close);
and stop_condition per C0 with the Stop Condition section filled) and write to
$evidence_dest. Do NOT hand-author the body. Then dispatch repo-orchestrator
to self-commit only the listed evidence files with message
chore(stm): record implement evidence for #{issue} (non-blocking — a commit failure
logs a warning, never halts; the WORK stays uncommitted, C4).
Step C2 — Render delivery report. Also render the Next line: resolve this play in standards/rules/pipeline-next.md and emit **Next:** /<command> — <why>. Or run /next to see all recommended actions. (only /next pointer, or omit, when the mapped command is null), per play-close.md. Fill the delivery-report.md slots and output it:
## implement Built — #{issue} (built, not delivered — full done is /validate's), the
Run Summary table, the Pipeline Steps table from the task DAG (T1–T13, including the
injected start member), the Artifacts Produced table, Next Steps (run /validate on this
epic; the close chain follows acceptance), and a pointer to $evidence_dest. Always
emitted; never gated. When this play itself runs as a sub-play (parent_run_id
present), skip C2.
Scenario Validation
The success scenarios and their evals (run in Step 12):
| Scenario | Persona | Eval |
|---|
| S1 — end to end | developer | SCE-1 |
| S2 — the plan survives | project manager | SCE-2 |
| S3 — box discipline | tech lead | SCE-3 |
| S4 — honest verification | QA engineer | SCE-4 |
| S5 — resumability | developer | SCE-5 |
| S6 — the fix round | developer | SCE-6 |
| S7 — the approval gate | developer | SCE-7 |
| S8 — tight autonomous build | developer | SCE-8 |
Recovery
One entry per failure condition. The injected start-change owns its own recovery; the
entries below cover this play's build core.
| For | Trigger | Direction | Handoff |
|---|
| F1 | no epic resolvable, the epic isn't ready, or a dependency epic isn't delivered, yet build steps are starting | halt and name the failed precondition; a human supplies a valid ready epic or first delivers the dependency | human |
| F2 | a change or artifact maps to nothing in the epic's box (check_box.py mapping failure) | strip the out-of-box work from the change; if the work seems genuinely needed, surface it as a question for routing back to the owning play — never widen the box from inside implement | autonomous |
| F3 | a built behavior has no grounding in the epic, its ICE, a lens, or the repository (validate_plan.py grounding failure, or an open question) | halt that piece and present the ungrounded requirement to the human — where the box has no wall, only the human draws one | human |
| F4 | a closing action is attempted or recorded, or full done is declared without validation | stop the action, leave the change open, and end at "specs passing, awaiting validation" | autonomous |
| F5 | breakdown artifacts found under the product model | move them to STM and restore the product model to its prior state | autonomous |
| F6 | the implementer's input carries test or eval content, or the test author received implementation | rebuild the input clean — spec artifact paths only — and re-dispatch the piece | autonomous |
| F7 | done is about to be declared while a spec or quality gate fails | feed the failure back as work on the plan and re-verify; done only when everything passes | autonomous |
| F8 | the accepting verdict traces back to the implementer | discard the self-report and obtain the verdict from the independent steelman verifier | autonomous |
| F9 | the plan was never published to the issue, or issue states diverge from actual progress | publish or refresh the plan on the issue through the tracking role before any further build work | autonomous |
| F10 | work is detected that isn't a plan piece, or dependency order is violated | pause the work, update the plan first through the tracking role, then continue along the updated DAG | autonomous |
| F11 | fix-round work maps to no fix-report finding, a fresh breakdown or workspace appears, or the epic still reads fix_required after re-entry | drop the unreported work (or route it as a question per REC2), derive revision pieces only from the report, re-anchor to the existing plan and workspace, and flip the epic to in_delivery before building | autonomous |
| F12 | a build piece is about to dispatch on the initial build with no recorded human approval of the spec | hold all build work, present the spec, and dispatch nothing until the human approves; record the approval as the gate the run passed | human |
| F13 | a builder or test-author contract carries context beyond its piece — the whole plan, a sibling piece, or a free-repo directive | rebuild the contract to carry only the piece's cut context slice (piece + transitive deps + spec) and re-dispatch | autonomous |
| F14 | the spec copies code, exceeds the readable bound, or omits a boundary the build needs (check_spec.py non-zero) | re-author it as a crisp ICE boundary doc — trim code to references, cut to the bound, add the missing rule/pattern/design/config — then return it to the human for approval | human |
| F15 | the generated spec's surface is below the epic's declared surface_type (a downgrade), or the epic has no declared surface (check_spec.py --product-base --epic non-zero) | halt at the spec-approval gate and present the downgrade — the spec's surface beside the epic's promised surface per surface-contract.md; build the lower surface only on explicit human approval of a recut, else regenerate the spec preserving the declared surface; a missing surface is declared before building, never defaulted | human |
| F16 | the close is about to record COMPLETED while the stop-condition verdict is unmet or unevaluable | evaluate the stop condition, surface the unmet clauses in the evidence's Stop Condition section, and close HALTED with exit_reason: stop_condition_unmet — never COMPLETED | autonomous |
| F17 | a build-loop dispatch is about to start with the gate off while the plan is unlinted/ungrounded (validate_plan.py non-zero), the steelman evals are absent, or an open_questions entry is unresolved | an unresolved open question HALTS to a human (present it, dispatch nothing until answered); the rest is autonomous — hold the build, name what is missing, and clear it (re-lint/re-ground the plan, or author the evals) before any dispatch | mixed |
The piece retry loop (cap 2, then tech-designer re-plan) and the refutation loop (cap 2
rounds, then human escalation with the full record) are governed in Steps 8 and 10.
Pause and Resume
Steps run top to bottom. Resolve the epic and issue on entry (epic issue_ref, branch
name, or arguments), check the status marker at
{stm_base}/{issue}/status/implement.json, skip completed steps, reset any in-progress
step to pending, and continue from the first incomplete one. The plan is the spine on
resume too (S5): re-anchor to plan.yaml + the published issue state, reset in-flight
pieces to planned, never cut a second plan, and re-run check_plan_sync.py before the
first new piece. The injected start-change is itself resumable and never duplicates an
issue or branch on a re-run.
Compilation Metadata
| Field | Value |
|---|
| fingerprint | sha256:69654aa990e9517e1f446db00b3cb7f31ef277e9b63bcda7eb112278ec3aae88 (of reference/ice.md) |
| compiled_by | play-editor (#466 Batch B, Level 3 rollout per ADR 025; #467 Batch D — spec-approval gate unpinned; prior history: play-creator, crisp-spec gate + piece context via play-editor, surface gate #442, epic-lifecycle prose #439) |
| pipeline_position | start (start-change head; NO end sequence — the close belongs after /validate) |
| workflow_structure | A (spec-approval checkpoint on the initial build — class: standard, unpinned #467 Batch D, resolves per gate-config; when off the machine wall carries it — plan lints clean + every piece grounded + steelman evals exist — and an unresolved open_question still HALTS to a human; skipped on a report-bounded fix round; build loop + steelman verify) |
| stop_condition | stop-condition.yaml (D1–D4), gate live at Step C0 — the same bar check_done.py (Step 11) assembles |
| iteration_caps | piece retry 2 per piece (then tech-designer re-plan); refuted rounds 2 (then human escalation) — pre-existing loop caps, unchanged, governed in Steps 8 and 10 |
| domain_agents | 5 (tech-designer, test-engineer, code-builder, evals-engineer, quality-auditor) |
| utility_agents | 2 (project-orchestrator, repo-orchestrator) |
| skills_reused | manage-issue, detect-test-harness |
| skills_created | author-build-plan, author-steelman-evals |
| member_subplays | start-change |
| scripts | 13 (preflight.py, check_ready_epic.py, update_epic_status.py, validate_plan.py, check_spec.py, cut_piece_context.py, render_plan.py, run_gates.py, check_box.py, check_plan_sync.py, check_done.py, check_stop_condition.py, session_stamp.py) |
| step_evals | 22 (SE-1…SE-22; SE-20 covers the surface-downgrade gate C19/F15; SE-21 the stop-condition close gate F16/C20; SE-22 the gate-off machine wall F17/C15) |
| scenario_evals | 8 (SCE-1…SCE-8) |
| recovery_entries | 17 (one per failure condition; 11 autonomous / 5 human / 1 mixed) |
| structural_constraints | C8 (no fixed inner loop — enforced by the play's shape; the DAG orders pieces, the agent orders within a piece) |
| supersedes | garura:implement (+ absorbs garura:prepare's breakdown) |
Direct-edit deviation note (#434, six-lens ripple)
Non-intent edit: lens-count prose (three mentions) updated five → six when the measure
lens landed (decision 19/23/24); mirrors the already-patched check_ready_epic.py
LENS_TYPES constant. No constraint/failure/scenario/eval text changed; reference/ice.md
and the fingerprint are unchanged.
Direct-edit deviation note (#434, spine + grounding model)
Non-intent edit: the epic moved from a per-epic epic.yaml file to an entry in the spine
epics index (product-os/_spine.yaml) plus an epic.md grounding doc, and lens files
moved from .yaml to .md. The mechanism scripts were retargeted accordingly —
check_ready_epic.py (resolves the epic + slice + seven lens .md + functionality
groundings from the spine), update_epic_status.py (the ready → in_delivery status flip is
now a surgical write to the spine epics entry, --product-base --epic), check_spec.py and
validate_plan.py (read surface_type / acceptance from the spine entry + epic.md instead
of epic.yaml), and check_box.py (the one allowlisted product-model write is now the
spine, not a per-epic file). Prose invocations updated to match. No constraint/failure/
scenario/eval text changed — the lifecycle, the box discipline, and the surface gate are
identical; only the storage the scripts read/write moved. reference/ice.md and the
fingerprint are unchanged.
Follow-on (validate-readers-spine-migration): run_gates.py now reads the quality gate
list from quality.md's "## Gates" table (each gate = its dimension + how it is checked)
instead of a quality.yaml content.gates list; the harness-family mapping is unchanged.
The quality_lens input to author-steelman-evals and the run_gates.py invocation point
at quality.md. Mechanism only — reference/ice.md and the fingerprint are unchanged.