Spec-driven development
A workflow whose tasks are AI-drafted documents and human decisions: requirements, design, plan, then implementation. Each phase runs a fixed prompt in a clean session, and the whole process state is committed to git. This page walks your first spec end to end, then covers the rules underneath; the sub-pages hold the two shipped styles, their exact prompts, and writing your own.
This needs a GitHub Copilot sign-in. The document phases run on
the ai@1 plugin with its default ghcp provider, and the implement
phase launches Copilot Chat, so this is the one half of the extension
that does not work without it.
- What a spec is
- 1. New Spec
- 2. Argue about the requirements
- 3. Design — and notice there is no Approve button
- 4. The plan
- 5. Implement
- 6. The one thing that will stop you
- What you now have
- Existing specs are read, not just written
- Choosing a style
- Configuration
- The engine knows nothing about SDD
What a spec is
A folder of Markdown under .local-workflows/specs/, committed alongside
your code. That is the whole artefact — no database, no service, no
hidden state. Delete the extension and the documents are still there,
still readable, still in your history.
You need no configuration to start. With no
.local-workflows/settings.json at all you get the kiro style, specs
under .local-workflows/specs, checkpoints on, and whichever model
Copilot would have chosen. The walkthrough below assumes exactly that.
1. New Spec
Open the Specs view and click + New Spec. It asks at most two questions — what kind of spec, and where the work item comes from — then creates the folder.
The two kinds it offers come from the style, not from the engine:
| Phases | |
|---|---|
| Feature | requirements → design → tasks → implement |
| Bug fix | requirements → tasks → implement |
Pick Feature. A bug fix skips design, because a one-line fix does not need a design document and a process that demands one teaches people to write a paragraph of nothing to get past the gate.
2. Argue about the requirements
A Copilot chat opens and writes the first document with you. This one is a conversation rather than a form, deliberately: it is the document worth arguing about, and a chat gets more out of a person than a set of fields does.
The engine starts that session and does not wait on it. Nothing is pending, nothing is blocked — the pipeline picks up when the file lands.
The moment requirements.md appears, the spec shows up in the Specs view
and the panel offers the next phase.
3. Design — and notice there is no Approve button
The panel offers design. Click it.
Starting the next phase is the approval. There is no separate approve step anywhere in the process, because a second thing to click that changes nothing is a button people learn to press without reading — and a run recording “approved” against an unread document is worse than recording nothing.
So what you are actually deciding, when you click design, is
“requirements.md is good enough to build on”. That gate lives on the
phase that depends on the document rather than on the phase that wrote
it, because depending on it is when the judgement is real.
Two things about the session that runs:
- It is a fresh session, seeded only by
requirements.md. Not your intake chat, not the folder. - What crosses a phase boundary is a file on disk, never a conversation. That is what makes this portable: a teammate pulls the folder and carries on from exactly where you left off, because there was never any context living in your chat history for them to be missing.
Read design.md when it lands. If it is wrong, this is the cheap moment.
4. The plan
Click tasks. It writes tasks.md: a numbered plan (1, 1.1) with a
dependency graph between tasks expressed as ordered waves. Tasks in
one wave may run at the same time; a wave begins only when every task in
every earlier wave is finished and ticked.
The rule that decides where the boundaries fall is worth knowing before you read it, because it is not the obvious one:
Every task ends green. The repository builds and its tests pass at the end of each task, not just at the end of the plan. So an interface and its implementation are one task. A changed signature and every caller it breaks: one task. A behaviour and the test that proves it: one task. Splitting any of them would leave the tree red in between, and a plan you cannot stop half-way through is a script rather than a plan.
You will also see checkpoint tasks — a top-level task that runs the
full test suite and confirms it passes. A checkpoint verifies; it does
not ask. It never waits for a human, because whoever started the plan
already asked for it to be carried out. Turn them off with
"sdd": { "checkpoints": "none" } in
settings.json if you
must.
5. Implement
This phase is different in a way that matters: the engine does not wait here, and it never finishes. There are no artifacts to satisfy it.
Each task launches a native Copilot chat from the panel’s implement lens,
one at a time. The engine writes documents; it does not write your code.
Git is the record, and a ticked checkbox in tasks.md is the definition
of done.
There is no gate on this phase either — the plan was approved by starting its first task. Whether anybody watches the session is your choice.
6. The one thing that will stop you
An ## Open Questions section in any document blocks the next phase.
While it holds questions, the phase will not start, and the panel says so.
Answer them in the document, or delete the section.
It is the only hard block in the whole process, and it is there because every alternative is worse: a phase that proceeds anyway invents an answer, and one that merely warns gets clicked through.
What you now have
Look at git status. Three Markdown files under
.local-workflows/specs/<your-spec>/, and the process state alongside
them. All of it reviewable in a pull request.
That is the part that compounds. The judgement about what was required, what the design should be, and how the work was cut up stops living in one person’s chat history and becomes a file the team inherits.
Samples/HelloWorld/.local-workflows/specs/ has spec folders with their
requirements already written — read them without running anything, or
point the extension at one and it picks up at design.
Existing specs are read, not just written
Point the extension at a repository full of specs somebody else made and it works out which style wrote each folder from the documents in it, then picks up at the right phase. There is no import step.
This falls out of one rule: a stage whose artifacts already exist is
satisfied. A spec folder that already contains requirements.md starts
at design without visiting requirements — whether that file arrived from
an intake chat five minutes ago or from a colleague’s commit last month.
Choosing a style
A style is the process: which phases exist, what each writes, where the gates are, and the prompts behind them.
Two ship, and they are genuinely different shapes rather than the same one renamed:
| Phases | Shape | |
|---|---|---|
| Kiro | requirements → design → tasks → implement |
three documents, a gate between each; Bug fix skips design |
| Spec Kit | specify → plan → tasks → implement |
one phase writes several documents; a flat T001 task list |
Pick the one your team already writes. If neither, start with Kiro — three documents with a gate between each is the smaller idea, and switching later costs one line of config.
You are not limited to those two. Writing your own style is a YAML file and a folder of prompts; no code changes, and your style appears in the + New Spec menu beside the built-ins. The exact prompts the shipped styles run are published verbatim — Kiro’s and Spec Kit’s.
Configuration
Everything is optional. With no configuration at all, kiro runs on
whichever model Copilot would have chosen. Change that in
.local-workflows/settings.json:
{
"sdd": {
"style": "kiro",
"source": "ado",
"checkpoints": "required",
"stages": {
"design": { "model": "claude-opus-5", "thinking": "high" }
}
},
"ai": {
"ai@1": { "provider": "ghcp", "model": "auto" }
}
}
Every key, its default, and every error the file can raise:
settings.json.
The engine knows nothing about SDD
The runner walks a graph of tasks: resolve the args, run the task, record what happened, stop at the gates. SDD is a layer above that — a folder of prompts, a config file, and a purpose-built panel — expressed entirely in terms the engine already had.
That is not an implementation detail you can ignore. It is the reason a style is a YAML file you can replace, rather than a feature you have to wait for someone to build. Every phase of every process is a stage with a prompt and a gate, and nothing in the engine knows what “requirements” means.