- Docs
- Guides
- The Build Loop (core)
- How-to
- How to plan and execute non-trivial work
How to plan and execute non-trivial work
Turn an approved spec into a locked plan, checked implementation, independent review, and merge-ready change.
Use this when: You are about to start a feature, refactor, or multi-file change that goes beyond a one-line edit.
Prerequisites: core pack installed, a working directory with edit/commit/gate access, and familiarity with the four mandatory spec sections; see Prerequisites below.
Result: A spec and plan in docs/specs/<feature>/, a green-gates PR, and an adversarial-reviewer-clean diff ready to ship.
You have a feature to build, a refactor to drive, a migration to run — anything past a one-line edit. This guide walks the path from “I’m about to start” through “the PR is green and the reviewer is clean”, using the two skills that drive it: new-spec and work-loop.
Use the new spec skill to design webhook retries, then use work-loop to implement it.For the why behind this discipline, read the core pack as a system. This guide is task-oriented; it tells you what to type and what to expect back.
Prerequisites
Section titled “Prerequisites”- The
corepack installed in your target repo. - A working directory where you can edit, commit, and run gates (lint / typecheck / test).
- Familiarity with the four mandatory spec sections (Objective, Boundaries, Testing Strategy, Acceptance Criteria) — see
docs/CONVENTIONS.md.
Pick your entry point
Section titled “Pick your entry point”Two skills, one workflow:
| Situation | Skill to invoke |
|---|---|
| New feature or significant change — no spec yet | new-spec, then work-loop |
Spec already exists in docs/specs/<feature>/ | work-loop (it reads the spec) |
| Multi-file bug fix | bug-fix — see how to fix a bug |
| One-line edit, typo, single config tweak | Skip the loop — overhead isn’t worth it |
If you’re unsure whether the change is trivial, default to the loop. The cost of running it on a small task is one extra minute; the cost of vibe-coding a non-trivial task is a re-do.
Step 1 — Run new-spec (when no spec exists)
Section titled “Step 1 — Run new-spec (when no spec exists)”The skill writes docs/specs/<feature>/spec.md and plan.md, and gates body content on assumption sign-off.
Name the skill in your invocation. Two worked invocations — one backend, one frontend:
use the new-spec skill to design webhook retries with exponentialbackoff for the payment-events stream(retry logic is a state machine — Testing Strategy will pick TDD for this one.)
use the new-spec skill to spec the saved-filters chip on theproduct-search results page(the chip is a visible UI element — Testing Strategy will pair it with visual / manual QA, possibly automated.)
Natural phrasings (let's spec out X, new spec: Y, write a spec for Z) match the skill’s description and often trigger it, but description matching isn’t guaranteed. Lead with use the new-spec skill to … whenever you want the discipline to fire reliably.
What to put in front of it
Section titled “What to put in front of it”new-spec ingests whatever input you give it and surfaces what’s missing. Any of these shapes work:
- A one-line idea (“add 2FA for admin login”).
- A requirements doc or PRD pasted into the message.
- A linked ticket — Linear, Jira, GitHub issue. Reference the URL; the skill reads what’s there.
- An upstream brief from a portfolio team (Feature Intent, Component Brief, or whatever shape your org produces).
- A bug report that’s grown into a feature (“this thing should work differently”).
The skill doesn’t care which shape you brought. The assumption checkpoint is where missing information gets named, regardless of input shape — so an idea-shaped input surfaces more Unverified items, a brief-shaped input surfaces fewer. The output is the same: a spec and plan grounded in confirmed assumptions.
What to expect
Section titled “What to expect”- The skill scaffolds
docs/specs/<feature>/spec.mdandplan.mdfrom the bundled templates. - It drafts assumption candidates across Technical / Product / Process categories, runs one targeted check per candidate (a repo read, a web lookup, or a read-only probe), then stops and emits an
ASSUMPTIONS I'M MAKING:block split intoVerified(each with a one-line citation of the check) andUnverified(each needing your input). The check happens before the bullet gets filed, not after. - You read the Unverified list and confirm or revise. If the Unverified list is empty, the skill surfaces the Verified list with the highest-stakes item called out and asks you to confirm that one specifically — a vague “looks good” doesn’t count.
- Spec body fills in: Objective, Boundaries (including at least one structural
Never do), Testing Strategy with a verification mode per outcome, Acceptance Criteria. - Plan body fills in: tasks with
Tests:beforeApproach:, explicitDepends on:, verification mode per task. shaping-reviewerfirst reads the draft contract cold for scope and observability.adversarial-reviewerthen reads the complete spec and plan for construction risk;security-reviewerandquality-engineerremain later code-review lenses, each owning concerns the others do not repeat.- Every
adversarial-reviewerreport is persisted first, then classified from the persisted bytes. A report that is clean — by exact bytes, or by structure with nothing but blank lines around the clean sentence — closes the round without an adjudicator call. A report carrying findings, orsecurity-reviewer’s coverage-disclosure footer, goes throughfinding-adjudicatorbefore the author classifies it or edits either artifact. Only sustained findings can change the spec or plan; refuted findings stay in the audit, and an indeterminate result stops for your direction. - Before each repair, the author marks the finding
draft-originorprior-round-repair. If the review history cannot establish either one, unresolved origin stops for your direction. When a green gate supports a disposition, the author also states what that gate proves and one relevant blind spot; the spec-status lint’s own module contract remains the source for its scope. - Review iterates to direct or adjudicated clean — usually one to two passes. If it cannot reach clean in three, the skill stops and asks for human direction; the spec likely has a structural problem, not a wording one.
- The skill updates
docs/specs/README.mdand reminds you that spec drift is a bug — update the spec in the same PR when implementation diverges.
If you want to stop here (pure planning, no build yet), this is the natural exit point. The spec and plan are durable; come back to work-loop whenever you’re ready.
Step 2 — Run work-loop
Section titled “Step 2 — Run work-loop”With a spec in place, invoke the loop by name. Same two domains carried through:
use the work-loop skill to implement docs/specs/webhook-retries(TDD-mode tasks for retry logic; goal-based for wiring.)
use the work-loop skill to drive the saved-filters-chip spec(visual / manual QA on the chip; goal-based on the URL-state plumbing.)
Naming the skill is the reliable form. The work-loop description also matches phrasings like “implement the X spec” or “let’s work on Y”, but the explicit form fires the loop’s full discipline — gates, adversarial review, stasis detection, the state machine — even on edges where description matching wouldn’t pick it up automatically.
What it does
Section titled “What it does”The full procedure lives in the work-loop SKILL.md. The short version:
- PLAN — reads
spec.mdandplan.md, picks verification modes if not already set, and designs construction tests up front. For a TDD task, it stores the exact stub code inplan.mdand validates syntax plus the intended red from disposable scratch; it does not create a repository test file. Aspec-planrun can therefore stop after approval with clean gates. PLAN also asks you to name the declined-pattern register: one to three things you were tempted to add (a layer, a flag, a defensive wrapper) and explicitly declined. The register pairs with the spec’s Boundaries section so REVIEW can catch drift toward declined temptations as self-contradiction in the diff. Pre-EXECUTE adversarial review fires automatically on spec amendments or on any of the four structural triggers (new module, new dependency, new abstraction, new top-level directory). - EXECUTE — implements task by task. Once full mode enters
CODE-IMPLEMENTATION, a TDD task copies the approved plan block unchanged into the real test path, verifies byte identity, proves the intended red, and continues through green and refactor. Goal-based tasks run theDone when:one-liner; manual-QA tasks record the visual check. - GATES — lint, typecheck, tests. Mechanical, ordered, no editing the gate to make it pass.
- REVIEW —
adversarial-reviewerreads the diff cold againstAGENTS.md+CONVENTIONS.md+spec.md. Findings come back as Blockers / Concerns / Nits with one-sentence fixes. The loop records each pass’s finding fingerprints tostate.jsonvialoop-cohort review record, which is what enables stasis detection in the next phase. Pass--operation-id <run-id>:<transition-sequence>— read the sequence fromloop-engine statusafter the transition that opened the round — and the round is named on disk. Re-issuing the identical recording under that same id is then a no-op rather than a second round, so a session that dies before it knows whether the write landed can simply repeat it. A different payload under a used id is refused rather than silently accepted. Specialist reviewers (security-reviewer,quality-engineer) run when the diff warrants. - DECIDE — intent fit decides each finding: in-intent work that cannot share this unit becomes the next review unit in the same session; excluded work is acknowledged in the PR and captured only if its owner asks. Stasis detection fires if the same findings come back two iterations in a row — stop and surface to a human rather than spinning a third pass.
Two no-stub records are closed exceptions. Use no stub (mode) when the chosen
verification mode is not TDD. Use no stub (implementation-discovered) only
when the callable seam genuinely cannot be known before implementation, and
record both its discovery predicate and proof obligation. Neither record is a
reason to repeat the acceptance criterion as behavior prose.
For the end-to-end narrative with the parts in context, read core-pack.md § How they tie together.
Termination cues you’ll see
Section titled “Termination cues you’ll see”- Gates green and review clean → ship.
loop-cohort.py checkexits non-zero → the script tells you which cap fired (implementation retry cap or review retry cap). Read the message. A cap firing means the loop stopped converging, so the default answer is to reset and start a new run, not to push past it. The review cap alone has an escape hatch —--allow-retry-cap-override, which must be passed to bothloop-engine.py transition findings-remainand the matchingloop-cohort.py review record, since either half alone leaves the engine and the cohort a round apart. It is for a human who has looked at why the loop is not converging and decided to continue anyway; an agent running unattended should stop and surface the cap instead. The implementation cap has no override by design.- Diff is shrinking but findings aren’t → you’re spot-fixing without addressing root cause. Back to PLAN.
If any of these fire and the work isn’t done, the task is bigger than you thought. Re-plan rather than expanding scope silently.
What you have now
Section titled “What you have now”This how-to has two exits, and they end in different places.
If you stopped after PLAN — you have an approved spec and plan at
docs/specs/<feature>/, both carrying your explicit approval. Nothing has been
implemented. Start work-loop when you are ready, or return to the spec when
the intended outcome changes.
If you ran the loop through — you have the change implemented against that
spec, every mechanical gate green, the adversarial reviewer and any triggered
security or quality reviewer reporting clean, findings resolved or explicitly
dispositioned, the spec marked Shipped and the plan Done, and a
merge-ready PR. The merge decision is yours; the loop does not take it.
Variations
Section titled “Variations”Resume an in-flight spec
Section titled “Resume an in-flight spec”work-loop reads docs/specs/<feature>/ and picks up from both engine-state.json (FSM phase) and state.json (execution counters and wave progress). Phrase as “resume the X work” or “continue on docs/specs/X”. The Session Resumption protocol in the skill reads loop-engine status --json first, then loop-cohort status --json, and routes by last_event. On a review round it also compares last_review_record_operation_id against the id it would compute now: equal means the round was recorded and the loop moves on, and anything else means it was not.
Both files are gitignored session-scratch — on a fresh checkout (new machine, after git clean, a teammate’s box), the loop re-initializes with engine first: loop-engine init --json produces the run_id; loop-cohort init <spec-dir> --run-id <run_id> registers it. Any other init order causes the engine’s identity preflight to reject every subsequent transition.
Spec amendment mid-flight
Section titled “Spec amendment mid-flight”Once approve-plan runs (during the G-plan sequence after the plan approver fires plan-approved), plan check-current --require-schedule guards the subsequent plan-locked transition against the approved plan hash. A post-approval plan.md edit will cause the plan-locked transition to be rejected — the approved plan is immutable in substance. If EXECUTE discovers a fundamentally missing or wrong task, surface that to a human and start a new run rather than editing in place. Safe post-approval edits are the ones the loop itself mandates plus pure formatting: the preamble **Status:** token, checkbox bookkeeping ([ ] → [x]), trailing whitespace, and line endings are all normalized out of the hash. Anything else — task text, a Depends on: edge, re-indenting a criterion, or free text appended after the status token — invalidates it. Record an execution observation through the verification-ledger procedure.
Parallel implementers (supervisor mode)
Section titled “Parallel implementers (supervisor mode)”Parallel fan-out (dispatch-decision, worktree, auto-parallel) is disabled in Phase 1 — those verbs exit non-zero without touching state.json. The full parallel-dispatch design (opt-in, gated, wave-scheduled) is documented in references/supervisor-mode.md for future phases.
When an implementer subagent is installed, the controller dispatches each plan task sequentially, one implementer at a time, using the schedule order.
Pitfalls
Section titled “Pitfalls”When not to use this workflow
Section titled “When not to use this workflow”- Genuine one-line edits — typo, config tweak, copy-paste fix. The loop’s overhead exceeds the work.
- Spikes and throwaway exploration. If the output is going to be thrown away, the spec / plan / review machinery adds friction for no gain. Mark the work explicitly as a spike and skip the loop.
- Investigation before implementation. If you don’t yet know what to build, you’re not ready for
new-spec. Investigate first; come back with a question shaped like a feature.
For bug-shaped work that crosses multiple files, see how to fix a bug — the bug-fix skill is the right entry point.
Related
Section titled “Related”- The core pack as a system — why the loop exists and how the parts compose.
docs/CONVENTIONS.md§ How we do non-trivial work — the contributor-side rationale.new-specskill — authoritative procedure for the planning skill.work-loopskill — authoritative procedure for the loop itself.- How to fix a bug —
bug-fixis the entry point for bug-shaped work. - How to adapt the pack to your project — post-install setup; do this before your first feature.