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 disk — folder 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 init → spec create → fill Context/Solution/Review → implement → spec verify → status=done → release 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 |