config.yml
Every setting spec-driven development reads, in one file:
.local-workflows/config.yml.
- The file is optional
- The keys
stylespecRootsourcecheckpointsai:— what runs the AI phasesai.stages:— one phase, different settings- Every error the file can raise
The file is optional
Every key has a default. A fresh install writes nothing and works — a missing file, an empty file, and a file of comments all mean “the defaults”. You only create it to change something.
The file is committed, so the whole team runs the same process on the same settings.
It never reaches an AI. The extension reads it and hands each phase only the values that phase needs. Model choice, style id, and source settings stay in the engine.
For editor completion and hover docs on every key, put this on the first line:
# yaml-language-server: $schema=https://local-workflows/schemas/sdd-config.schema.json
The keys
style: kiro # which process runs
specRoot: .local-workflows/specs
source: ado # manual | ado | gh
checkpoints: required # required | optional | none
ai:
uses: ai@1 # what runs the AI phases
provider: ghcp # passed to the plugin, like every key below
model: auto
stages: # per-phase overrides, keyed by phase id
design:
model: claude-opus-5
thinking: high
| Key | Values | Default |
|---|---|---|
style |
kiro, spec-kit, or a style you wrote |
kiro |
specRoot |
a path inside the repository | .local-workflows/specs |
source |
manual | ado | gh |
unset — + New Spec asks each time |
checkpoints |
required | optional | none |
required |
ai.uses |
a plugin reference | ai@1 |
ai.<anything else> |
passed to the plugin as an arg | model: auto is the only default |
ai.stages.<id> |
the same keys, for one phase | — |
style
The process: its phases, its gates, its prompts, and the spec types in
the + New Spec menu. kiro and spec-kit ship;
your own works the same way.
specRoot
Where spec folders live, relative to the repository.
Two spellings are refused when the file is read:
- An absolute path —
D:\specsor/specs. Specs live in the repository because the whole point is that process state travels with git; a root outside it would put half the state somewhere no teammate clones. - A path with
..that climbs out of the repository — refused for the same reason.
Backslashes are accepted and read as /, so a Windows-style relative
path works.
In a
.code-workspace,specRoot:is ignored. One feature spanning five repositories is one spec, not five, so placement becomes the workspace’s decision —localWorkflows.specRootin the workspace file, which unlike this key may point anywhere, including outside the workspace. Every other key on this page still applies. See Workspaces.
source
Where the work item behind a spec comes from: written by hand
(manual), Azure DevOps (ado), or GitHub (gh).
This is the one key with no default on purpose. Unset means the file does not say, and + New Spec asks each time — which is the difference between a team that has standardised and one that has not. A default would answer a question nobody was asked, and make the setting impossible to leave open.
checkpoints
Whether the plan gets “run the tests and stop” barriers between groups of tasks. Read by the tasks prompt when the plan is written; nothing else branches on it.
ai: — what runs the AI phases
uses: names the plugin, ai@1 by default. Every other key in the
block is passed straight to that plugin as an arg — provider,
model, thinking, and whatever the provider adds next quarter. The
config file does not keep a list of allowed keys, so a switch the
plugin grows never waits for an extension release; the plugin validates
its own args.
Two defaults are worth knowing:
model: auto— the provider picks. A pinned model name goes stale, and a team that has not formed an opinion should not be made to hold one.providerhas no default here —ai@1’s own manifest defaults it toghcp. Writing it here again would leak it: a phase that overridesuses:to a different plugin inherits the file-level args, and would receive aproviderthat plugin never declared.
ai.stages: — one phase, different settings
Overrides keyed by phase id — the same ids format.house uses in a
style.
ai:
model: auto
stages:
design:
thinking: high
The merge is per key, not per block: design above gets
thinking: high and keeps model: auto. Naming one setting never
silently drops the others. A stage may also override uses: to run a
different plugin entirely.
Every error the file can raise
All of these are raised when the file is read, not in the middle of a run:
| The file says | The error |
|---|---|
| anything that is not valid YAML | config.yml is not valid YAML: ... |
| a list, or a bare value, at the top | config.yml must be a mapping of settings, e.g. 'style: kiro'. |
style: or ai.uses: that is not text |
'...' must be text. |
a source: or checkpoints: value not in its list |
expected one of ... |
an absolute specRoot: |
spec folders live in the repository. |
a specRoot: with .. climbing out |
climbs out of the repository. |
an ai: or ai.stages: entry that is not a mapping |
'...' must be a mapping. |
A key the file does not know is not an error here — unknown keys
under ai: are plugin args by design. The schema line at the top of
this page is what flags a genuinely misplaced key while you type.