Skip to content

Living specs

A feature spec describes one change, and a year later current behavior is the sum of thirty of them minus what later ones undid. A living spec describes a capability, a piece of behavior your code keeps having, and the runs that change that code keep it current. Living specs come with the Companion Spec Kit extension and stay off until you set them up.

A drawn diagram: the specs folder for a shipped feature greys out, and three capability specs lift out of it and settle next to the source files they describe, each carrying a coverage count or a drift flag, then the same three shown at a central capabilities root.
Specs for a shipped feature go quiet. Capability specs settle next to the source files they describe, each with a coverage count or a drift flag.

Open the Living Specs view in the sidebar and click Set up living specs. It asks one question, whether to keep the specs together in one folder or beside the code they describe, and writes living-specs.yml at the repo root.

Then pick the area you explain most often and run /speckit.companion.living-adopt on it. Your assistant reads the code’s surface and drafts a spec marked [DRAFT]. Reading that draft is the fastest way to learn whether you drew the boundary in the right place.

VS Code with the Living Specs tree in the sidebar: five capabilities grouped by folder, most with a coverage count, two flagged as drifted. Beside it the Photo Storage spec is open, with its counts, the paths it covers and its first requirement.
Each capability is a row. Open one to read its requirements.
On a row Meaning
7/9 covered Requirements with a test mapped in the coverage file. No file means no number, which isn’t the same as zero.
Warning icon, drift Source files changed after the spec was last committed

A living spec opens in the same viewer with its own header: the code it covers and the coverage count, where a feature spec shows a branch and a status. Requirements drafted from existing code carry an adopted badge until you approve them, and a drifted spec gets an Update button.

A living spec scrolled to one requirement marked Drifted, with a line saying the code it touches changed since the spec was last updated. The header counts 1 drifted.
Drift lands on the requirement that names the changed file.

In any source file a capability claims, the status bar reads 2 living specs. Click it to see which ones.

A Companion run adds a block to its own feature spec for each capability it changed:

## ADDED Requirements
<!-- capability: spec-viewer -->
- The viewer re-anchors a stored comment onto the freshly rendered page when its tab reopens.

The other headings are ## MODIFIED Requirements, ## REMOVED Requirements and ## RENAMED Requirements. A block without a capability comment goes to whichever capability the changed files matched. At mark-complete a script folds each block into its capability spec, so you review the result in the feature’s diff. Folding twice changes nothing.

A run with plain Spec Kit doesn’t do this, and neither does code you write by hand. Run /speckit.companion.living-sync afterwards. Commands lists all seven living-specs commands.

enabled: true
layout: central
exempt: ["*.config.*", "*.test.*", "**/migrations/**"]
capabilities:
- name: spec-viewer
match: ["src/features/spec-viewer/**"]
spec: src/features/spec-viewer/spec-viewer.spec.md
- name: workflows
match: ["src/features/workflows/**"]
rules:
spec:
- "Write every scenario as WHEN/THEN with exactly one observable outcome"
Key What it does
enabled The opt-in. Unset, or with no file, every living-specs command acts as if the feature were absent.
layout central or colocated: where adoption puts a spec you don’t place yourself. Defaults to central.
exempt Globs that never count as drift. The default is the list above.
name The capability id, and its folder name under capabilities/
match, exclude Globs for the files that belong to the capability, and the ones subtracted from it
spec Puts the spec beside the code, as <something>.spec.md. Omit it and the spec goes to capabilities/<name>/<name>.spec.md.
rules.spec, rules.plan Sentences handed to the specify step and the plan step on every run

You can mix both layouts, and /speckit.companion.living-move switches a capability later. A file that matches several capabilities goes to the one with the longest literal path prefix. A spec file no capability claims shows under Orphans. <stem>.coverage.md beside a spec maps requirements to tests, and you write it.

The Living specs chip in the Workflow Builder edits enabled and layout. It shows capabilities, exempt and rules read-only, because adoption and the capability commands write them. An older livingSpecs: block in .specify/companion.yml is still read, and living-specs.yml wins when both exist.

  • Nothing updates a spec on its own. It’s current only if a run folded its changes in or someone ran living-sync.
  • Drift and coverage never block anything. They always exit zero, so a CI job that should fail has to read their output. A run that loaded a capability and wrote no block for it gets a printed receipt, not a stop.
  • Drift reads committed history. A capability whose spec isn’t committed yet is skipped, and so is one in a CI checkout with too little history. The report names each one and why.