π§ Trivia App Case A
Build a Kahoot-style trivia game a host can run in a meeting: people join from their phones with a code, answer questions, and watch their score climb. You'll build it spec-first β the plan gets settled before a single line of code.
The seven steps you'll follow
Every case runs the same seven steps, in two phases. The first four happen before a single line of code exists β that's the whole point. How far you push the build is up to you.
- 1Intentwhat problem
- 2Specwhat & why
- 3Plan+ sign-off
- 4Tasksunits of work
- 5Implementagent writes
- 6Verifya check gates it
- 7Reviewa human reads
Guided happy path everyone starts here
Follow the steps in order. Each one ends with a checkpoint β don't move on until you see it.
You decide
Steps 1β4 all happen before a single line of code exists. This is where the thinking lives.
Intent β what problem, is it even worth a spec?
In your workshop folder, start opencode. Ask yourself the facilitator's question: "Could I one-shot this with a single prompt?" Joining + categories + scoring has enough moving parts that the answer is no. Start by creating agents.md (example) at repo root so your defaults are explicit: PHP-first, PSR-aligned, minimal JS, and DDEV as the dev/test loop.
/agents.md exists with project rules.Spec β what & why, as a file
Create spec.md (example) in /.specification/changes/feature-name/. This is a file the agent reads every session, not a chat message that vanishes. Fill in the skeleton β paste it to your agent and ask it to help you sharpen it, but you own the decisions.
# spec.md β Trivia
## Problem
A host needs a low-friction quiz for a meeting or video call.
## Why
Existing tools need accounts or installs; we want "join with a code".
## Boundaries
- 5β10 seeded categories, provided up front
- Host can add custom questions
- Players join with a short code, answer, and see their score
## Done means
A joiner submits an answer and their score updates on screen.spec.md exists in /.specification/changes/feature-name/ and has no implementation detail in it β only what and why.Plan β how, grounded, then signed off
Switch OpenCode to Plan mode (press Tab). Ask it to write plan.md (example) in /.specification/changes/feature-name/: which files change, in what order, and the check that proves each part works. Keep it grounded and aligned with agents.md: PHP-first structure, JS only where it adds clear value, and checks you run via DDEV.
We're building the app in spec.md. Stay in plan mode.
Write plan.md: the files to create, in order, and for each step
the command or check that proves it works (run checks through DDEV).
Keep it small β a PHP entry point plus a questions store is fine.
Use JS only where it clearly improves UX. Do NOT write code yet.plan.md to a facilitator or the person next to you. "Is this plan right?" Changing your mind here costs a paragraph. Changing it after 200 lines of code costs a rewrite. This is where review moved to β the moment the whole method is about.plan.md is reviewed, every step names a check, and the DDEV run path is explicit.Tasks β units of work, still no code
The last thing before code exists: turn the signed-off plan into tasks.md (example) in that same /.specification/changes/feature-name/ folder β small, ordered units the agent can execute and you can tick off. Stay in Plan mode.
Still in plan mode β no code yet. Break plan.md into tasks.md
of small tasks, in order, each one something you can verify on its
own. For example:
- [ ] questions store loads the seeded JSON
- [ ] host can start a session and get a join code
- [ ] a joiner submits an answer and their score updates
- [ ] checks run in DDEV and passAgent writes Β· a check gates it Β· a human reads it
Only now does code appear. You already made every decision β the rest is execution and checking.
Implement β the agent writes
Press Tab back to Build mode and let the agent work tasks.md one by one. Keep it consistent with agents.md: PHP-first for backend/domain work, JS only where it helps UX, and run the dev loop in DDEV. Grab the seeded questions so nobody stalls on content:
trivia-questions.json β 8 categories, ready to import.
When you specify behaviour, give the agent the acceptance scenario (the "oracle"), not a lecture on testing:
Add a check for this behaviour:
WHEN a joiner submits the correct answer
THEN their score increases by the question's points.
Write it as a runnable test, then implement until it passes.Verify β a check gates it, prose doesn't
Pick one rule that matters and make it a deterministic check, not a polite sentence in the spec. This is the gate the agent has to get past. Run it in DDEV so your check matches the team environment.
Review β a human reads it
You already agreed the plan, so this read is quick β you're checking the agent honoured it, not meeting the design for the first time. Also confirm consistency with your artifacts: agents.md rules followed, spec.md intent preserved, tasks.md executed, and DDEV checks green. This is where you'll often notice the plan was wrong. That's not failure β it's the point, and because you're at review (not release) the fix is a paragraph. A classic one for this case:
plan.mdAmend plan.md and let the agent redo that step. Then record what you couldn't finish β a plan that names its own gaps is one a reviewer can trust:
## Done
- join-by-code, scoring, 6 seeded categories
## Not done, and why
- live presenter view β needs websockets, out of scope todayplan.md shows the corrected step and a Done / Not-done block."Waterfall's flaw was never having a plan. It was waiting months to find out the plan was wrong."
Stretch goals finished early? go deeper
All optional. Add each as a new spec requirement + plan step first β keep practising the loop.
- Stop-gate β a check so the agent can't declare itself "done" while any test is red.
- Timed rounds & leaderboard β countdown per question, ranked results at the end.
- Import questions from CSV β with a validator that rejects malformed rows.
- Custom category β let the host add a category, enforced by a test for its rules.
- Live presenter view β the "not done" item from the Review step, via websockets/SSE.
Reflect
You wrote about a page of markdown before any code. Was it worth it here? Would it be worth it for a one-line CSS fix?
Simple tasks need a prompt. Complex ones need a spec. Writing the decision down turns a six-month bet into an experiment you can fail in an afternoon.
Level up β see it as a tool Optional Β· if time permits
Everything you just did by hand, there's a tool for: OpenSpec. Your facilitator may demo this on the beamer β and if the clock beat us to it, no problem, the take-home page below has the whole thing.
/agents.md at root + change files in /.specification/changes/feature-name/ (include the path in session chat)agents.md rules (PHP-first, minimal JS, DDEV)βcarried into proposal.md + design.mdspec.md β what & whyβopenspec propose#### Scenariosplan.md (files, order, checks)βdesign.md implementation plantasks.md checklistβtasks.md in change folder (- [ ] β - [x])openspec applyopenspec archiveopenspec/specs/