~/groundwork

Walkthrough: a calculator app

A real build in OpenCode, recorded as it happened. Each chapter is a short clip of the actual session, and each caption quotes the transcript and links to the line.

Model: DeepSeek V4.1 Flash (max thinking) in OpenCode 2.0.18. Nothing is staged.

1. Writing the spec

no cards yet

/gw starts with the smallest useful version, not a blank prompt. It asks a few specific questions in small batches and offers choices; you pick one or type your own.

opencode — spec-questions
“First question, the scope one:” — the answer is “Four basic operations”, the recommended option.transcript L1371

When the answers are in, the agent writes .groundwork/SPEC.md and reads it back in plain words, including the calls it made where you didn't specify anything.

opencode — spec-written
“Pressing = when there’s no pending calculation — say, just the number 5 on screen — should do what?” — one of the last details, before the spec is written.transcript L2636

2. Planning the cards

six cards, all to do

gw-plan turns the spec into phases of small cards, each small enough for one session, with acceptance criteria you can check. Nothing is written until you say the plan looks right.

opencode — plan-confirm
“Does this plan look right?” — answered “Plan looks good”.transcript L4705

Then the card files land in .groundwork/cards/, and the next step is handed back to you.

opencode — plan-cards-written
“Planning is done:” — two phases, six cards, and card 1.1 next.transcript L5447

One more step before the loop: the planning files are committed on their own, so card 1.1's commit holds only card 1.1's work.

opencode — plan-committed
“Committed planning: 693fff8.” — then the runner lines up card 1.1.transcript L5614

3. Building the first card

being tested

/gw starts card 1.1 and hands it to the tester: a subagent with fresh context whose only job is tests that fail for the right reason. The runner doesn't write them, and the implementer won't be allowed to change them.

opencode — tester-launched
“Card started. Handing it to the tester now (a subagent, so its work stays separate from mine):”transcript L5828

When the tests come back failing for the right reason, the runner checks them itself, the card moves to being built, and the implementer gets it with the tester's evidence attached.

opencode — implementer-launched
“Failing state confirmed exactly as reported (MODULE_NOT_FOUND for ../src/calc.js, exit 1). Handing card 1.1 to the implementer:”transcript L6102

4. Approval and commit

waiting for you

The reviewer reran everything and passed the card, so the runner stops and shows you the same three-part summary every time: what changed, how to check it yourself, and the caveats.

opencode — approval-stop
“Card 1.1 — Number entry is built and waiting for your approval.” — with the reviewer’s caveats listed.transcript L6505

Only you can approve. /gw-approve checks the evidence first, marks the card done, commits it, and names the next card.

opencode — approved-commit
“Approved and committed:” — 78565bd, [1.1] Number entry. Next up is card 1.2, Operations and equals.transcript L6925

5. The finished calculator

six cards done

Six cards across two phases: arithmetic, clear and error states, 10-digit formatting, and a responsive keypad. The second phase ran in a new chat, which picked up from the handoff file. The app is live, and the whole project (spec, cards, decisions, evidence) is public.

calculator-groundwork
The finished calculator

Try it live → · Source and cards →

By the numbers

WhatMeasured
Building it$0.586 · 1.33M fresh tokens (41% of them reasoning)
Also in the chatsdeploying to GitHub Pages $0.020 · exporting the transcripts $0.061
Sessions20: 2 main chats, 18 role sessions
Work6 cards in 2 phases · 14 commits · 58 tests passing

Where the tokens went, why the cost per card stayed flat, and the one part that didn't: the proof. Every session, as it ran: the receipts.

On this page