The build loop
One card goes through three roles, then stops at your door. This is the whole process.
- Testerwrites tests that fail for the right reason
- Implementermakes them pass, nothing more
- Reviewerfresh context, reruns everything
- Youapprove, or send back with a reason
- committed ✓
The runner is the main session — the one you type gw-next into. It hands the card to each
role in turn and never does their work itself.
The steps
- Pick. The lowest-numbered card whose status is
todoorrejectedand whosedepends_oncards are alldone. - Test. The tester writes failing tests — one per acceptance criterion — confirms they fail for the right reason, and saves the failing output as evidence.
- Implement. The implementer makes the tests pass with the smallest reasonable change, then runs the full suite, lint and build.
- Review. The reviewer re-runs everything itself, checks every criterion against the diff, and fills in the Evidence section — or sends the card back with specific problems.
- Approve. The runner stops and shows you what changed, how to check it yourself, and the
caveats. (In
per-phasemode this stop happens at the end of the phase instead.) - Commit. After approval, the runner commits the card and moves on.
The roles
| Role | Job | Must not |
|---|---|---|
| Planner | Interview you for the spec; write phases, cards and decision records | Write code; choose your stack |
| Tester | Turn acceptance criteria into failing tests | Write the implementation; weaken tests later |
| Implementer | Make the tests pass with the smallest reasonable change | Edit tests to make them pass; touch unrelated files |
| Reviewer | Check the work with fresh eyes, then pass it or send it back | Fix code itself — it sends the card back |
Each role reads only what it needs (its role file, the card, and the files they point to). In tools with subagents, each role runs as a separate agent with fresh context, so the reviewer really is seeing the work for the first time. The planner never picks a stack: options go to you.
What isn't in those files wasn't agreed. A role doesn't go searching chat logs or other folders for a decision; it makes a call and writes it on the card, where you'll see it.
The runner stays light
The runner is one long chat, and every step re-reads its whole history, so every extra step it takes costs more than the last. It keeps its own work small:
- Short hand-offs. Each role gets the card's path, its role file and facts the runner has checked, nothing else: no retelling what was agreed (it's on the card), no statuses to set (the role file says).
- No reruns between roles. The reviewer reruns every check; the runner doesn't repeat them.
- A fresh session each phase. When a phase closes,
/gw-approvesuggests starting the next phase in a new session. HANDOFF carries everything it needs.
Where these came from: the calculator's measurements →
Statuses
| From | To | Who | When |
|---|---|---|---|
todo | testing | runner | Starts the card |
testing | implementing | tester | Failing tests are written and saved |
implementing | review | implementer | Tests, lint and build all pass |
implementing | testing | implementer | A test looks wrong; the reason is written on the card |
review | implementing | reviewer | Problems found; listed under History |
review | awaiting-approval | reviewer | Passed, in per-card mode |
review | done | reviewer | Passed, in per-phase mode (the runner commits) |
awaiting-approval | done | human | Approved (the runner commits) |
awaiting-approval | rejected | human | Rejected, with a reason |
done | rejected | human | Rejected during a phase review |
rejected | implementing | runner | Picked up again; the reason is on the card |
No other changes are allowed, and every change gets one line under History.
After three reviewer send-backs on the same card, the loop stops and asks you rather than going round again.
The checks
The project's test, lint and build commands live in .groundwork/config.json. Normally all must
pass before a card reaches you. On a project with a saved baseline, the rule is no new
failures instead. Evidence and approval →
Commits
The runner commits — never a role, never before approval (or before review passes, in per-phase
mode). After approval it:
- marks the card
doneand adds a History line, - updates
HANDOFF.md, - commits the card's changes as
[<card-id>] <card title>, - moves to the next card, or stops if you asked it to.
Without subagents
Any tool that can't start separate agents still works: one session plays every role in turn. Before each role it reads that role's file and only the files it lists; it finishes the role completely before switching. As reviewer it re-reads the diff from scratch — and because fresh eyes aren't really possible, it re-runs every check itself.