Spec-Driven Development

Spec-Driven Development (SDD) is a methodology for structured collaboration between developers and coding agents (Claude Code, Cursor, Gemini CLI, and others). Polycrate provides the infrastructure: a standard .specs/ layout, a machine-readable spec format with ID-based lifecycle management, and CLI commands for every phase. Teams can also keep a reference architecture in .specs/ARCHITECTURE.md (editable directly, not a spec document) — see Reference architecture.

After status=done comes the git-free release chain (workspace/block release, push, pull, action install): Develop and deploy. A Git tag and workspace sync are not the product process.

Why Spec-Driven Development?

Without SDD, AI-assisted workflows typically fail in these ways:

  • Coding agents write code without documented context — nobody remembers why it was implemented that way
  • Releases are hard to reconstruct — which changes belong to which version?
  • Agents edit files directly and corrupt structures that machines must read
  • There is no shared backlog between human and agent — work exists only in chat

SDD solves this with a defined process:

Question SDD answer
Why was this implemented? Spec as a permanent archive (context, analysis, solution)
What is the current state? Live scan of .specs/ — folder location and frontmatter define status
How does a change reach a release? Lifecycle draft ↔ done; assigning a release moves specs to .specs/<version>/
What is next? Backlog via .specs/.next/
What is the target architecture? Optional: .specs/ARCHITECTURE.md as a living, compact architecture document
What are the immutable project rules? .specs/.invariants.md — machine-readable core rules, embedded in agent rules

Concepts

Specs

A spec is a structured Markdown document that follows a change, bugfix, or feature from idea to implementation. Every spec has:

  • A unique ID (integer, never reused)
  • A status (draft, done, cancelled)
  • A type (Conventional Commits: feat, fix, breaking, …)
  • Structured sections: Context, Solution, Affected Files, Acceptance Criteria, Migration, Open Questions, Review, and more
  • Optional labels for filtering
  • Optional dependencies (needs) on other specs
  • Optional thematic links (relates-to) — non-blocking

Specs live in .specs/.next/ (backlog) or .specs/<version>/ (assigned to a release).

Live scan (no index.yml)

From CLI ≥ 0.45.0 there is no index.yml. Specs and releases are read live from diskfolder location is state:

Path Meaning
.specs/.next/<id>-<slug>.md Backlog — in progress, not assigned to a release
.specs/<version>/<id>-<slug>.md Spec assigned to release <version>

ID, status, type, labels, needs, and other metadata live in each spec's YAML frontmatter. polycrate spec list and related commands derive everything from that.

Reference architecture (.specs/ARCHITECTURE.md)

.specs/ARCHITECTURE.md is not a spec document and is not live-scanned. It is a recommended (should-have) reference architecture: modules, boundaries, data flows, pointers to code — kept incrementally.

Aspect Recommendation
Maintenance After larger implementations or releases, or when the team asks
Form Complete enough for planning, but token-conscious: headings, tables, bullets, pointers
Reading Include it before large planning or implementation when the file exists
Writing Normal editor / agent file tools — does not replace polycrate spec * for real specs

Two lifecycle phases

WORK PHASE                            RELEASE PHASE
polycrate spec *                      polycrate release *
draft ↔ done                          .specs/<version>/

Language

Write spec content in the project's primary language. Keep one language per spec.

Spec scope

One problem or feature per spec. If you write "and also…", create a separate spec.

Spec lifecycle

draft ↔ done
  → cancelled (any state, set cancellation_reason)

polycrate spec update <id> --set status=done works from any status. spec review / spec verify are informative. Open Questions should be empty before status=done — that is a conversation soft-stop, not a CLI gate.

polycrate spec create --name "Login timeout" --type fix
polycrate spec update 0 --section context="..."
polycrate spec update 0 --section solution="..."
polycrate spec update 0 --set status=done

Available sections: context, solution, affected-files, acceptance-criteria, migration, open-questions, review.

Acceptance criteria

Each criterion should be verifiable and carry a code anchor (@path:LINE) where the implementation lives. Self-review findings use [minor|major|blocker].

Spec types

fix | perf | feat | refactor | chore | docs | ci | build | style | test | breaking | analysis

Family A (fix, perf, analysis): Context + analysis. Family B (features): Context + solution. Family C (breaking): Migration is required.

Labels

polycrate spec update 15 --add-label sdd --add-label agent
polycrate spec list --label sdd
polycrate spec list --blocked

Quickstart

polycrate spec init
polycrate spec create --name "Login Timeout Fix" --type fix
polycrate spec note "S3 upload fails silently on 403" --type fix --label s3
polycrate spec update 0 --section context="..."
polycrate spec update 0 --section solution="..."
polycrate spec inspect 0
polycrate spec lint 0
polycrate spec review 0
polycrate spec verify 0
polycrate spec update 0 --set status=done
polycrate spec list --format json

Code references in comments

The stable reference is the spec ID, not the file path:

// Spec: polycrate spec inspect 5     ← CORRECT (stable after release)
// Spec: .specs/.next/5-feature.md    ← WRONG (path changes on release)

Release lifecycle

polycrate release diff 1.0.0
polycrate release create 1.0.0 --spec 0 --spec 1
polycrate release create 1.0.1
polycrate release update 1.0.0 --set type=feat --set message="..."
polycrate release update 1.0.0 --note-section highlights="..."
polycrate release status 1.0.0
polycrate release finalize 1.0.0
polycrate block push <block>
polycrate block pull <registry/org/name:version>
polycrate run <block> install

--workspace / -w must be an absolute path. workspace sync is not a release step. Canonical chain: Develop and deploy.

Release notes (RELEASENOTE.md)

Each release has a structured RELEASENOTE.md in .specs/<version>/. highlights is required for finalize.

Guard Behavior
Assigned specs not done (or cancelled) Error
RELEASENOTE.md missing or highlights empty Error
No specs assigned Allowed — version bump with a release note alone is valid
Empty message Warning
Missing docs_url Warning

Validation

polycrate spec validate

Checks paths, frontmatter, sections, and dependencies. .specs/ARCHITECTURE.md is not a spec. Errors always include the fix command.

Agent integration

polycrate spec init and polycrate spec rules generate write instruction files:

File Target agent
CLAUDE.md Claude Code
AGENTS.md OpenAI Codex, Gemini CLI, others
.cursor/rules/sdd.mdc Cursor IDE
polycrate spec manual --no-pager -w /path/to/workspace
polycrate spec rules show --no-pager -w /path/to/workspace
polycrate spec list --format json -w /path/to/workspace
polycrate spec rules generate --force

Existing CLAUDE.md / AGENTS.md with user content are not overwritten, even with --force.

Recovery

polycrate spec validate
polycrate spec lint <id>
polycrate spec format <id>

Legacy repos with index.yml:

polycrate spec index migrate
polycrate spec lifecycle migrate-v2

Sandbox and runtime directory

SDD commands start no full workspace — no Docker, no container.

polycrate spec list --runtime-dir /tmp/polycrate-run -w /path/to/project

CLI reference — runtime directory

Typical workflow

Developer: spec initspec create → fill Context/Solution/Review → implement → spec verifystatus=donerelease create / update / finalize → block push / pull / install.

Multi-agent workflow

Role Job CLI entry
Grounding agent Analyze codebase, set anchors spec update <id> --section affected-files=...
Spec author Write Context + Solution spec update <id> --section solution=...
Reviewer Check self-review spec lint <id>spec review <id>
Verifier Check acceptance criteria spec verify <id> --with-agent

Each session works on exactly one spec. Parallelize only when specs have no needs links and disjoint code areas.

All commands

polycrate spec

Command Description
spec init Initialize .specs/ + agent rules
spec create --name <name> Create a spec (--type for scaffolding)
spec note "<text>" Quick-capture a minimal spec
spec list Compact table (--label, --type, --blocked, --format json)
spec inspect <id> Show spec content
spec update <id> Frontmatter, sections, labels, needs, relates-to
spec lint / spec format Report or fix structural drift
spec review / spec verify Informative review and acceptance checks
spec validate Consistency of the whole tree
spec manual / spec rules generate LLM manual and agent rule files

polycrate release

Command Description
release create <version> Create a release, optionally assign specs
release update <version> Changelog, release notes, more specs
release finalize <version> Guards, set version, pre/post actions
release block-finalize Finish a block release and push the image
release status / release list / release diff Inspect

See also