Skip to content

Hands On Walkthrough

Gregor Biswanger edited this page Aug 3, 2026 · 3 revisions

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.

The demo app: Tip Splitter

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.

Preparation · PO + Dev

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.

Part 1 · Setup — PO + Dev

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.

Part 2 · What and why — PO only

The PO writes the specification from the user's point of view. No tech stack. Not one word about Node.js.

2.1 · Specify

/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.

2.2 · Sharpen the edge cases

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.

2.3 · Attack the spec before signing it

/sdd-clarify

This reads the spec as a stranger — no memory of the conversation you just had — and comes back with four lists: contradictions, terms used in two senses, criteria nothing can decide, and failure modes nobody named. It does not fix them. It ends with one question.

Learning point: read the output together, then ask the room: how many of these could we have caught ourselves? Usually one or two. The rest were invisible from inside the conversation that produced them — which is the entire argument for a second pass. The context that created an ambiguity is structurally the worst placed to find it.

Decide per item: fix it in the spec now, or move it to Open points and accept the risk knowingly. Both are legitimate; silently ignoring it is not.

2.4 · Sign off

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.

Part 3 · The how — Dev only

Now only the Dev types. The PO watches and does not intervene.

3.1 · Plan

/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 and an empty Verified: field, plus a research section, a traceability table and a session-handoff block. Then it stops and hands the plan back — planning does not touch code.

Now actually read it. Both of you, out loud, for five minutes. This is the exercise most worth doing properly, and the one every team skips in real life.

You are not hunting for bugs. You are checking that you agree on the why and the ordering — does step three really need step two first, is the risky part early enough, is anything missing. A wrong step produces hundreds of wrong lines; a wrong line produces one. Two hundred lines of plan versus two thousand lines of diff is not a close call.

Say which steps look wrong before a single line is written.

Learning point: the Dev just made a dozen decisions the PO never saw — the http module 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.

3.2 · Implement

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 runs the Verify: command, writes what came back into Verified:, then ticks the checkbox, fills in Notes, writes the real file paths and the deciding test into the traceability table, and moves Current step — all in the same change set as the code.

Open the plan file and look at a finished step. Verified: should read something like 2026-08-03 · node --test · 7 passed. If it is empty and the box is ticked anyway, you have caught the failure mode this field exists for: an agent optimises for reporting completion, and a checkbox costs nothing to tick.

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.

3.3 · Verify

In the terminal:

node --test
node server.js

And 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.

3.4 · Secure the state

/sdd-compile

You get the readiness brief. It opens with a verdictREADY, NOT READY, or NOT READY — unverified — then every acceptance criterion marked satisfied or pending with evidence, open plan steps, docs-sync status, and the next three actions.

Look hard at the evidence column, because that word has a narrow definition here: a test name and its output, or a command and its output. Not a step ID. Not a sentence explaining what the code does — that is the code describing itself through the thing that wrote it. If a criterion shows prose instead of an artifact, it should say pending, and if it says satisfied anyway, you have found something worth discussing in the retro.

The Dev says out loud: "Implementation done, tests green." Keyboard back to the PO.

Part 4 · Acceptance — PO only

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.

4.2 · Close the lifecycle

/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.

The whole flow at a glance

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
Sharpen PO follow-up message edge cases and product rules
Clarify PO + Dev /sdd-clarify a cold second pass finds what the conversation hid
Sign off PO "Spec approved", swap seats
Plan Dev /sdd-plan … tech stack, module structure, baby steps
Read the plan PO + Dev the cheapest review in the cycle — do not skip it
Implement Dev Implement T-001. code step by step, Verified: filled, plan kept current
Verify Dev node --test tests green, app runs
Compile Dev /sdd-compile verdict + evidence per criterion, swap seats
Accept PO curl against the criteria check against your own acceptance criteria
Close PO /sdd-lifecycle spec → done/, iteration finished

Two rows are not commands. That is deliberate: the two moments with the highest leverage in this whole flow are a human reading something, not a tool producing something.

If there is time: a second iteration

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.

Clone this wiki locally