Spec Driven Development + Test Driven Development in practice using AI
Prompt an AI for a short spec, then for one failing check and the smallest fix. A small calculator is only the practice case. You check the results. You do not write the spec or the tests yourself.
1 Two habits, used together
Spec-driven development and test-driven development answer different questions. They belong in one order: decide what you are building, then prove one small piece at a time.
Spec-driven development means a short plan exists first. That plan is the spec. It lists what the program should do, what it should not do, and how you will know you are finished. You do not type that file. You prompt an AI for it, then you read what came back before you invent extra features.
Test-driven development means a check exists before the code that should satisfy it. A test is a tiny automatic check, like “12 plus 3 must come back as 15.” The first time it runs, it fails, because the feature is not there yet. Then only enough code is added to make that one check pass.
You do not write the spec or those checks yourself. You prompt an AI, then you check the result. An AI here is a coding assistant you talk to in plain language. A prompt is the message you send it. First prompt for the spec and read it. Then name one line, prompt for a failing check only, wait until it fails, then prompt for the smallest fix.
| Spec-driven development | Test-driven development | |
|---|---|---|
| What you do first | Prompt the AI for a short list of goals and limits, then read it | Prompt the AI for one automatic check |
| Question it answers | What are we building, and what are we skipping? | Does this one piece still do what we said? |
| What goes wrong if you skip it | You add features nobody wanted | The code can be wrong and you notice late |
- SpecPrompt for what done looks like, then check it
- Fail promptPrompt for one check that is not satisfied yet
- Pass promptPrompt for only enough code for that check
- RepeatNext line from the spec
The order matters
If you are unsure what you are building, prompt for the spec first and read it. If a piece of code can quietly give the wrong answer, prompt the AI for a failing check next. Keep each prompt small. A prompt that says “write all the tests and the whole calculator” skips the method.
2 A small calculator as the practice case
I needed an example small enough to finish quickly. A calculator with add, subtract, multiply, divide, and a clear button is enough. Divide by zero should show the word Error. No memory keys. No extra science buttons. The calculator is only the practice case, so the prompts stay concrete. The finished calculator is at the end of this article.
- Small enough that a long planning process would be more than this job needs
- One known special case, already named: dividing by zero
The sequence I used prompt for the spec→prompt for a failing add check→prompt for the smallest add→repeat for the rest
3 Prompt for the spec before any calculator code
I did not type the spec. I prompted the AI to install Vitest and write specs/spec.md in the same message. Vitest is a program that runs the automatic checks. Then I stopped and read the file. Later prompts point at it.
- Prompt the AI to install Vitest and write the spec. Stop there.
- Read what came back: what we will build, what we will skip, and how we will know we are done. Prompt again only if the file is wrong.
- Do not prompt for the math functions yet. The spec already says they should live in their own file, away from the on-screen buttons.
Calculator spec
Rules (keep this small)
- Spec first. Do not invent features that are not listed here.
- Tests prove the engine. The UI only calls the engine.
- One failing test at a time. Write only enough code to pass that test.
- Out of scope is part of the contract. Ignore it on purpose.
Problem
A visitor can use a small calculator with the four basic operations on two numbers, then clear the display.
In scope
- Add, subtract, multiply, divide
- Clear
- Pattern: enter A, pick an operator, enter B, press =
- Divide by zero shows Error
Out of scope
- Memory keys (M+, MR)
- Percent
- Parentheses or operator precedence chains
- Scientific functions
- Keyboard support
Acceptance (EARS-style)
- When the user adds 12 and 3, the display shall show 15
- When the user subtracts 9 from 20, the display shall show 11
- When the user multiplies 6 by 7, the display shall show 42
- When the user divides 20 by 4, the display shall show 5
- When the user divides 10 by 0, the display shall show Error
- When the user presses Clear, the display shall reset to 0
Engine contract
Pure functions in calculator.js. No DOM.
- add(a, b) returns a number
- subtract(a, b) returns a number
- multiply(a, b) returns a number
- divide(a, b) returns a number, or the string Error when b is 0
Done when
- Spec written before production code
- Each operation has a failing test, then a passing test
- Divide-by-zero is covered
- UI uses the same engine
- Acceptance clicks match this file
# Calculator spec
## Rules (keep this small)
- Spec first. Do not invent features that are not listed here.
- Tests prove the engine. The UI only calls the engine.
- One failing test at a time. Write only enough code to pass that test.
- Out of scope is part of the contract. Ignore it on purpose.
## Problem
A visitor can use a small calculator with the four basic operations on two numbers, then clear the display.
## In scope
- Add, subtract, multiply, divide
- Clear
- Pattern: enter A, pick an operator, enter B, press `=`
- Divide by zero shows `Error`
## Out of scope
- Memory keys (M+, MR)
- Percent
- Parentheses or operator precedence chains
- Scientific functions
- Keyboard support
## Acceptance (EARS-style)
- When the user adds 12 and 3, the display shall show 15
- When the user subtracts 9 from 20, the display shall show 11
- When the user multiplies 6 by 7, the display shall show 42
- When the user divides 20 by 4, the display shall show 5
- When the user divides 10 by 0, the display shall show `Error`
- When the user presses Clear, the display shall reset to 0
## Engine contract
Pure functions in `calculator.js`. No DOM.
- `add(a, b)` returns a number
- `subtract(a, b)` returns a number
- `multiply(a, b)` returns a number
- `divide(a, b)` returns a number, or the string `Error` when `b` is 0
## Done when
- [ ] Spec written before production code
- [ ] Each operation has a failing test, then a passing test
- [ ] Divide-by-zero is covered
- [ ] UI uses the same engine
- [ ] Acceptance clicks match this file
That is the file the AI wrote. I read it before any calculator code. “EARS” is only a name for lines that say “when this happens, this should appear.” The “left out” list is part of the agreement. If it is not in the spec, I do not add it, even when it would be easy.
4 Prompt for a failing check, then the smallest fix
The spec already said that 12 plus 3 should become 15. I did not type a test. I prompted the AI for one automatic check of that line, and I told it to stop when the check failed. Add was missing, so the check received nothing useful. That failure is useful. It means the check is real, and the feature is not done yet.
- Prompt for one check only. Name the spec line. Do not prompt for the calculator code in the same message
- Stop when the check fails. A missing function name is a valid failure. Then send a second, smaller prompt
- The second prompt is only “make this one check pass.” Do not add subtract, multiply, divide, or buttons
Do not prompt for the whole calculator in one go
The spec already listed four operations. I still prompted only for add. If you tell the AI to write every check and every function at once, you skip the fail-then-pass habit.
5 Repeat the same prompts for the next operations
Subtract, multiply, and divide (when the second number is not zero) used the same two prompts as add. Name the next spec line. Prompt for one failing check. Wait. Then prompt for only enough code to pass it. Dividing by zero is a later prompt, because the spec already separated that case. I am showing the subtract fail prompt below. The pass prompt was the same shape as add: only enough code for that one check.
| What I prompted the AI to prove | Example numbers | Expected result |
|---|---|---|
| Subtract, one check only | 20 minus 9 | 11 |
| Multiply, one check only | 6 times 7 | 42 |
| Divide when the second number is not zero | 20 divided by 4 | 5 |
Each row is a pair of prompts: fail first, then the smallest fix. If I had prompted for a plain divide and stopped there, JavaScript would later return Infinity when someone divides by zero. Infinity means “this number has no end.” The spec called for the word Error, so that case waited for the next prompt.
6 Divide by zero was already in the spec
I did not discover this problem by clicking buttons. The spec already said that 10 divided by 0 should show Error. I prompted the AI to turn that sentence into one failing check. The current divide function returned Infinity. The check failed, which is what we want at this step.
I did not type the fix. The AI added a simple rule: if the second number is 0, return the word Error. My part was the two prompts, then reading the report.
7 Prompt for the on-screen buttons last
The automatic checks already proved add, subtract, multiply, divide, and the Error case. Only then did I prompt the AI for the calculator at the end of this article. The buttons should not redo the math. They should call the four functions that already passed.
This is the result
That is the last prompt in this walkthrough. The calculator below is what those prompts produced.
A warning: this is just a simple calculator. There is nothing special about the app. What matters here is the Spec-Driven Development and Test-Driven Development process.
8 References
These are the sources I used while writing this article. Some describe larger planning systems. Some describe the fail-then-pass habit. I ran that habit by prompting an AI, not by typing the spec or the checks.
| Source | What I used it for |
|---|---|
| Tekk, SDD vs TDD | How the two habits fit in one sequence |
| GitHub Spec Kit | A larger spec-driven toolkit for wider features |
| Spec-first, spec-anchored, spec-as-source | Names for how tightly the spec sits on the work |
| Kent Beck, Canon TDD | One test, then make it pass |
| Uncle Bob, Cycles of TDD | Short rules for how little code to write at each step |
| Martin Fowler, TDD | A public explanation of fail, pass, then clean up |
| Hacker News on Spec Kit | When extra planning files help, and when they waste time |