-
Notifications
You must be signed in to change notification settings - Fork 2
Hands On Walkthrough
One complete SDD cycle on a toy project, in about 45 minutes. Works in Claude Code and in GitHub Copilot — the commands are identical.
This is a workshop exercise: work in pairs. One person is the Product Owner (PO), one is the Developer (Dev). You sit at the same machine and take turns deliberately. In PO phases only the PO types; in Dev phases only the Dev types. That discipline is the lesson.
Doing it alone? Then switch hats consciously at each phase boundary and notice how different the two roles feel.
A tiny HTTP service that splits a restaurant bill fairly across several people. Inputs: bill amount, tip percentage, number of people. Outputs: the amount per person and the total tip. No database, no frontend, no login — just enough for the whole SDD cycle to run through visibly once.
Create an empty project from the template and open that folder in your tool — not a parent folder, or the slash commands will not appear.
git clone https://github.com/GregorBiswanger/featherspec.git tip-splitter
cd tip-splitter
rm -rf .git
git init(On Windows PowerShell: Remove-Item -Recurse -Force .git. With Node.js installed,
npx degit GregorBiswanger/featherspec tip-splitter replaces the clone and the two cleanup
lines.)
Claude Code: run claude in the folder. Type / and check that the sdd- commands appear.
GitHub Copilot: open the folder in VS Code, open Copilot Chat
(Ctrl/Cmd + Alt + I), switch to Agent mode, pick
the SpecDrivenAgent persona. Type / and check that sdd-setup, sdd-specify, sdd-plan,
sdd-compile and sdd-lifecycle appear. Missing? Restart VS Code completely — not just a
window reload.
Once per project. Creates the Memory Bank and fills the architecture snapshot.
/sdd-setup
Answer the language question with whatever your team documents in — English, Deutsch, … —
and then the short wizard.
Learning point: open
.memory-bank/. That is the long-term memory. Everything decided here survives closing the tool, switching to the other assistant, and next Monday. That is what separates SDD from a throwaway chat.
The PO writes the specification from the user's point of view. No tech stack. Not one word about Node.js.
/sdd-specify I want a small service that splits a restaurant bill fairly across several
people. A user gives three things: the bill amount, a tip percentage and the number of
people. The service returns what each person pays in total (including tip) and how large
the total tip is.
Goal: a group at the table knows within seconds what everyone owes, without doing mental
arithmetic.
Success criteria:
- The per-person result is always rounded to two decimal places.
- The individual amounts add back up to the total (no cents lost to rounding).
- A response arrives in under a second.
Out of scope: no login, no persistence, no currency conversion, no splitting by what each
person ordered.
The assistant now runs its interview — one question per message — about users, roles, edge cases and acceptance criteria. Answer as the PO. Short answers are fine.
Learning point: pause and notice what is not in there. No "build a REST API", no "use Express", no endpoint paths. Only the problem and what success means. The how comes from the Dev in a minute.
As a follow-up message in the same chat:
Add these rules to the spec:
- 0 or fewer people returns a clear error message, not a calculation.
- A negative tip percentage is not allowed and returns an error. 0 percent is allowed.
- A bill amount of 0 is allowed and yields 0 per person.
- Leftover rounding cents are added to the first person, so the sum comes out exactly.
Learning point: the rounding-cents rule is a genuine product decision. The AI cannot guess it and the Dev is not allowed to invent it. That is exactly why the PO is in the room.
The PO reads the generated spec in .specs/backlog/, checks it, and says out loud:
"Spec approved." Then hand the keyboard to the Dev.
You should now have:
.specs/backlog/0001-tip-splitter.md
with **Status:** Draft and a list of AC-001, AC-002, … criteria.
Now only the Dev types. The PO watches and does not intervene.
/sdd-plan We build this as a minimal HTTP service with Node.js and the built-in http module,
without external frameworks. A single POST endpoint /split takes JSON with the fields amount,
tipPercent and people, and returns JSON with perPerson and totalTip. Input validation happens
in the service. The calculation lives in its own testable module. We write unit tests with
the built-in node:test runner. No database, no build step.
This writes .specs/backlog/0001-tip-splitter.plan.md next to the spec: numbered baby steps
(T-001, T-002, …), each with a Verify: line, plus a research section, a traceability table
and a session-handoff block. Then it stops — planning does not touch code.
Read the plan before continuing. This is the cheapest moment to disagree with it.
Learning point: the Dev just made a dozen decisions the PO never saw — the
httpmodule instead of Express, a separate calculation module,node:test. The PO has no business in any of them. And conversely: the Dev should never have invented the rounding-cents rule.
Implement T-001.
Then T-002, and so on — or ask for the whole plan and review each focused change as it lands.
After every step the assistant ticks the checkbox, fills in Notes, writes the real file paths
into the traceability table, and moves Current step — in the same change set as the code.
Try this: close the session halfway through and start a new one with /sdd-plan. It reads the
plan, checks it against git status, and tells you in three lines what is done, what is next and
what blocks it.
In the terminal:
node --testnode server.jsAnd in a second terminal:
curl -X POST http://localhost:3000/split -H "Content-Type: application/json" -d "{\"amount\": 100, \"tipPercent\": 10, \"people\": 3}"Expect roughly 36.67 / 36.67 / 36.66 per person — the leftover cent goes to person one — and a
total tip of 10.
/sdd-compile
You get the readiness brief: every acceptance criterion marked satisfied or pending with evidence, open plan steps, docs-sync status, and the next three actions. The Dev says out loud: "Implementation done, tests green." Keyboard back to the PO.
The PO does not review the code. The PO checks every acceptance criterion they wrote themselves — with exactly the edge cases from Part 2.
Normal case:
curl -X POST http://localhost:3000/split -H "Content-Type: application/json" -d "{\"amount\": 50, \"tipPercent\": 0, \"people\": 2}"Edge case "0 people" — must return an error, not a calculation:
curl -X POST http://localhost:3000/split -H "Content-Type: application/json" -d "{\"amount\": 50, \"tipPercent\": 10, \"people\": 0}"Edge case "rounding adds up" — the three amounts must total exactly 100:
curl -X POST http://localhost:3000/split -H "Content-Type: application/json" -d "{\"amount\": 100, \"tipPercent\": 0, \"people\": 3}"The most important learning point of the day: you check against your own criteria from the spec, not against a gut feeling. If "actually I'd also like X" occurs to you now — that is not the Dev's mistake. It was not in the spec. That is the next iteration, a new
/sdd-specify.
/sdd-lifecycle
Spec and plan move together into .specs/done/, the spec status becomes Implemented, the plan
status becomes Done, and .memory-bank/activeContext.md is updated. The spec stays as a
versioned living document — the basis for the next iteration.
| Phase | Who | Command | What happens |
|---|---|---|---|
| Setup | PO + Dev | /sdd-setup |
Memory Bank and architecture snapshot |
| Specify | PO | /sdd-specify … |
what and why, success criteria, scope |
| Clarify | PO | follow-up message | edge cases and product rules |
| Sign off | PO | — | "Spec approved", swap seats |
| Plan | Dev | /sdd-plan … |
tech stack, module structure, baby steps |
| Implement | Dev | Implement T-001. |
code step by step, plan kept current |
| Verify | Dev | node --test |
tests green, app runs |
| Compact | Dev | /sdd-compile |
readiness brief, swap seats |
| Accept | PO |
curl against the criteria |
check against your own acceptance criteria |
| Close | PO | /sdd-lifecycle |
spec → done/, iteration finished |
The PO now also wants each person's amount rounded up to the next whole euro.
Run /sdd-specify again against the existing spec, then /sdd-plan. Watch what happens in
Mode C: before editing anything, the plan reads its traceability table in reverse and tells
you which steps and which files that one changed rule reaches.
The second lap is noticeably faster — the Memory Bank already knows the context, and the spec is the starting point rather than a blank page. That is the payoff of writing it down.
Adapted from the Spec-Driven Development hands-on workshop for Product Owners by Gregor Biswanger.
Start here
Reference
Design & interop
- Interop Matrix
- Design Decisions
- Specify Method
- Committing to One Tool
- Migrating from the predecessor
- Releasing
Help