Spec-Driven Development
Spec-driven development (SDD) is a way to agree on the behaviour of a change before building it, then use that agreement to guide implementation and verification. It works with or without an AI coding agent.
The spec is a living record, not a substitute for conversation, engineering judgment or code review. Start small and add detail where ambiguity or risk makes it useful.
The Workflow
- Choose an outcome. Identify the user, the problem and the smallest useful journey to deliver.
- Draft the spec. Describe observable behaviour, constraints, important failures and what is out of scope. Identify unresolved decisions instead of silently guessing.
- Agree on it. Have the people who understand the problem and the system review it. Resolve decisions needed to build the first increment.
- Plan verification. Decide which checks demonstrate each important behaviour. Automate deterministic checks where practical; identify any manual or qualitative evaluation.
- Implement. Give the spec and relevant repository context to an agent or developer. Work in a small increment and update the spec when an agreed requirement changes.
- Verify and review. Run the checks, inspect the changes and review security, operational impact and anything tests cannot establish. Record failures and unverified items.
- Learn and iterate. Deliver the increment, gather feedback and revise the spec and tests together for the next change.
There is no requirement to finish every future use case before writing code. A spec should be detailed enough to make this increment testable and prevent consequential misunderstandings.
Where Specs Live
Keep specs in the repository with the code they describe so they can be reviewed and versioned together. For example:
README.md
specs/
knowledge-assistant.md
This is a suggested layout, not a required framework. A small change can live in an issue or pull request; a larger feature may need a dedicated file. Link supporting API contracts, diagrams or architecture decisions instead of duplicating them. When behaviour changes, update the relevant spec and tests in the same change where practical.
Writing a Spec
Begin with the happy path. Write behaviours as outcomes that someone can check, not as vague qualities or a list of implementation steps. Add exceptional cases and constraints according to the risk of the change.
Use this template as a starting point:
# Spec: [Feature]
## Outcome
- [ ] [Who can do what, and why?]
## Behaviour
- [ ] Given [context], when [action], then [observable result].
- [ ] [Important failure or boundary behaviour.]
## Constraints
- [ ] [Security, privacy, compatibility or performance requirement.]
## Out of Scope
- [ ] [Explicitly excluded behaviour.]
## Verification
- [ ] [Test or other check that demonstrates the behaviour.]
## Open Questions
- [ ] [Decision needed, its owner if known, and when it must be resolved.]
Keep the first increment short: roughly 5 to 15 meaningful checklist items is a useful guideline, not a hard limit. Split an oversized feature into increments rather than omitting important risk. Do not mark an item complete merely because code exists; mark it complete when the agreed verification has passed.
For example, replace "the assistant should give good answers" with a checkable requirement such as "the answer includes a link for each internal source it uses." Answer quality still matters, but it needs an evaluation method rather than a vague promise.
Worked Example: Knowledge Assistant
This is an illustrative draft based on the discussion so far, not an approved or complete spec.
Outcome and Behaviour
- [ ] A user asks a question and receives an answer informed by an internal knowledge API.
- [ ] The answer cites the internal sources it uses, using links returned by the API to GitHub Wiki, Confluence or Jira.
- [ ] For a general question where internal results provide low confidence, the assistant suggests an internet search for wider industry insights.
- [ ] The user can allow one search, allow future searches, or deny the proposed search.
- [ ] A user's permission to allow future searches is saved as a preference and can be revoked.
- [ ] When search is allowed, the assistant uses relevant external results and distinguishes and cites external sources separately from internal sources.
- [ ] When search is denied, the assistant answers from available internal results and states uncertainty.
Constraints and Open Questions
- [ ] Sensitive information must not be sent to an external search provider. Define how sensitive content is identified and how search queries are constructed before enabling search.
- [ ] The internal API is under development. Agree its request, response, authentication and citation contract before integrating it; use a test double while the contract is being developed.
- [ ] Define how low confidence is determined and what happens when the knowledge API or search provider fails.
- [ ] Define how the user is identified, how consent is stored and how revocation takes effect.
- [ ] Decide whether and how the user can explicitly request a search when the assistant has not suggested one.
These questions matter because a requirement such as "never send sensitive information" is a goal, not an enforcement mechanism. The team must agree on controls and verify their limits before relying on them.
Working With an Agent
An agent can help draft a spec, find ambiguity, write tests and implement code. A person remains responsible for product decisions, approving trade-offs and reviewing the result. Agent instructions are not enforcement: use tests, access controls and review to enforce the requirements they can cover.
Start a spec discussion with a prompt such as:
Help me draft a small spec for [outcome]. Ask about missing requirements,
constraints and important risks. Do not implement until we agree on the spec.
Once the spec is agreed and ready for implementation, give the agent a bounded task:
Implement the first increment described in specs/knowledge-assistant.md.
Follow the repository conventions. Add or update tests for the agreed behaviour,
run the relevant checks, and report results and anything not verified. Do not
guess unresolved product or security decisions; surface blockers for review.
Adjust the path and scope to the actual project. Keep credentials and sensitive data out of prompts and test fixtures unless explicitly authorised and handled through approved mechanisms.
Verification and Review
Match each important requirement to evidence. For the assistant example, a test suite might use controlled API and search responses to check source links, permission choices, saved preferences, revocation and failure handling once those behaviours are defined. A search-provider test double can assert that no external request is made without permission and that the constructed query follows the agreed privacy rules.
LLM responses can vary. Prefer deterministic assertions for routing, permissions and citations; use representative question-and-answer examples, human review or an agreed evaluation set for answer quality. Passing a small evaluation set does not prove that every answer is correct or that all sensitive data will be detected.
Before merging, a reviewer should check:
- The change matches the agreed spec and does not quietly expand its scope.
- Relevant automated checks passed, and manual checks or missing coverage are reported.
- Security, privacy, accessibility and operational concerns appropriate to the change have been considered.
- API contracts, documentation and tests reflect any approved changes to behaviour.
Common Pitfalls
- Writing a novel before learning: start with a small useful outcome and expand where needed.
- Writing only the happy path for a risky feature: add the failures and safeguards that matter.
- Treating a prompt as a guarantee: verify observable behaviour and put controls in the system.
- Letting the agent decide product or security policy silently: record decisions and involve an accountable person.
- Treating green tests as proof of everything: inspect test coverage and report residual risks and unverified behaviour.
Top comments (0)