create-spec-driven-app v0.7.0

Zero runtime dependencies Any agent CLI MIT

Specifications that are
checked, not admired.

Requirements, Gherkin scenarios and a traceability matrix that your CI enforces — plus a harness that drives any coding agent through them, one requirement at a time, in its own git worktree. It never merges.

npx create-spec-driven-app@latest init

Get started Read the docs Worked example →

11
curated domain packs
24
commands, all JSON-capable
10
agent tools wired from one definition
0
runtime dependencies

A specification nobody checks is a wish

Most teams already write requirements. They live in a wiki, drift from the code within a sprint, and nothing fails when they disagree. Point a coding agent at that and you have automated the drift.

This tool makes the specification a thing that can be wrong: every requirement has a scenario, every scenario has a file, and csda validate fails when the link is broken. Then — and only then — an agent is worth pointing at it.

What makes it checkable

One row of the traceability matrix, read left to right, is a sentence about your system. Every link in it resolves to a real file, and the build fails when one does not.

  1. REQ-001requirement
  2. SCN-001scenario
  3. load_pack.featureGherkin
  4. UC-001use case
  5. CMD-001command
  6. AGG-001aggregate
  7. EVT-001event
  8. src/…code
  9. …steps.tstest
  10. Verifiedstatus
One row of the matrix, read as a sentence. Break any link and csda validate fails — which is what stops a specification from quietly becoming false.

This requirement is demonstrated by this scenario, in this feature file, realised by this use case, which dispatches this command against this aggregate, emitting this event, implemented here, proven by this test, currently in this state.

An event emitted by an aggregate nobody declared is a build failure, the same way an undefined symbol is. That is the whole idea, and everything else on this page exists to keep it true. How a matrix row is written →

The loop

Four commands. The same four whether a person or an agent is driving.

  1. 1

    csda init

    Scaffold a project: spec, scenarios, traceability matrix, and the execution contract an agent reads before it writes a line.

  2. 2

    csda plan

    What still needs a test, an implementation or a status change — ordered by dependency, with a fix on every blocker.

  3. 3

    csda harness run

    Hand one requirement to an agent in its own worktree, gate the result, and stop if the gate says no.

  4. 4

    csda validate

    The gate itself: structure, traceability, Gherkin that Cucumber can actually run, and TDD order. This is what CI runs.

Step three in detail. One requirement, one branch, one gate — and the branch is yours to merge or throw away.

One turn of the harness The harness picks the next pending requirement, creates a git worktree on a branch named after it, hands the agent a prompt, lets the agent write code and tests in the worktree, runs the gate, and commits only if the gate is green. It reports and never merges. harness git worktree your agent the gate plan → the next pending requirement create worktree on harness/REQ-001 the prompt — Gherkin, rules, boundaries writes code and tests validate --strict-tdd + the project's own tests green — and only then mark done, commit …and reports. It never merges — that stays yours.

What it actually prints

Not a mockup. This is stdout from a real run — scaffold, pack, plan, harness, gate — captured by npm run docs:terminal and committed to the repository. A test checks it was recorded from this version of the CLI.

smart-parking
~ $ cat smart-parking.yaml
PROJECT_NAME: Smart Parking
PROJECT_SLUG: smart-parking
PROJECT_TYPE: backend
DOMAIN: parking operations
STACK: Node 20, Express, PostgreSQL
API_STYLE: REST with DTO boundaries
TESTING: node:test

~ $ csda init --config ./smart-parking.yaml --out . --no-git
ℹ️ [INFO] 🧩 Rendering base template
ℹ️ [INFO] 🛠️ Applying project type template: backend
ℹ️ [INFO] 🧩 No optional modules selected. Generating base + project-type features only.
ℹ️ [INFO] 📋 Summary
ℹ️ [INFO] - Project: Smart Parking
ℹ️ [INFO] - Slug: smart-parking
ℹ️ [INFO] - Type: backend
ℹ️ [INFO] - Domain: parking operations
ℹ️ [INFO] - Output: ~/smart-parking
ℹ️ [INFO] - Dry-run: false
ℹ️ [INFO] - Git: skipped
ℹ️ [INFO] ✅ Generation completed

~/smart-parking $ csda specops add --pack-root ~/packs --pack multi-tenant/backend --var "PROJECT_NAME=Smart Parking" --var PROJECT_SLUG=smart-parking --var "DOMAIN=parking operations"
ℹ  Adding multi-tenant/backend to ~/smart-parking
ℹ️ [INFO] Using pack: ~/packs/multi-tenant/backend/pack.yaml
ℹ️ [INFO] Generated 3 scenario file(s).
ℹ️ [INFO] Domain pack expansion completed.

~/smart-parking $ csda plan
  Needs Feature + Test + Code
    REQ-002   SCN-001
      ✓ feature: `features/multi-tenant/provisioning_a_tenant_emits_tenantprovisioned.feature`
    REQ-001   SCN-002
      ✓ feature: `features/multi-tenant/cross_tenant_read_attempts_are_rejected.feature`
    REQ-003   SCN-003
      ✓ feature: `features/multi-tenant/exceeding_a_quota_emits_quotaexceeded.feature`

  Needs Implementation
    REQ-000   SCN-000
      ✓ feature: `features/core/health.feature`
      · code:    `API /health`, smoke test

~/smart-parking $ cat harness.config.yaml
harness_version: 1
agent: 'csda-stub-agent {prompt_file}'
test_cmd: 'node --test test/*.test.js'
max_attempts: 1

~/smart-parking $ csda harness run --req REQ-000
ℹ️  [harness] Processing 1 requirement(s) from base HEAD.
⚠️  [harness] REQ-000: the row declares no test artifact, so the agent chooses where the test goes and the matrix will point somewhere else. [requirement_declares_no_test_artifact]
⚠️  [harness]   fix: csda req link REQ-000 --test <path>
ℹ️  [harness] REQ-000: attempt 1/1

── harness report ──
  ✅ REQ-000  pass (1 attempt)  → harness/REQ-000

  1 passed · 0 failed · 0 skipped
  Review and merge the harness/* branches you trust.
ℹ️  [harness] Run recorded in .harness/runs/2026-01-01T00-00-00-000Z.json — `csda harness report`

~/smart-parking $ git diff --stat main harness/REQ-000
 .../REQ-000-2026-01-01T00-00-00-000Z-attempt-1-agent.md | 83 +++++++++++++++++++++++++
 docs/specs/traceability.md                              |  2 +-
 src/health.js                                           |  9 +++
 test/health.test.js                                     | 10 +++
 4 files changed, 103 insertions(+), 1 deletion(-)

~/smart-parking $ git switch -q harness/REQ-000 && node --test test/*.test.js
✔ GET /health reports the service as UP (12ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1.234

~/smart-parking $ csda validate .
ℹ️ [INFO] ✅ Validation passed
ℹ️ [INFO] - Features detected: 4
ℹ️ [INFO] - Base SDD structure: complete
ℹ️ [INFO] - Traceability mode: rich

Recorded from v0.7.0. The same run, explained →

Bring your own agent

No agent runtime, no SDK dependency. The agent is any shell command containing {prompt_file} — the harness writes the prompt, substitutes the path, and reads the exit code plus the gate result.

csda harness run --agent "claude -p < {prompt_file}"
csda harness run --agent "aider --yes --message-file {prompt_file}"
csda harness run --agent "./my-wrapper.sh {prompt_file}"   # anything else

Commit the commands your team uses in .harness/profiles.yaml and pick one by name — or let a profile select itself per requirement, so an infrastructure task and a domain task get different tools and different allowances in the same run.

Wired from one definition: claudeclaude-plugincursorcopilotwindsurfaidergeminiclinecodexantigravity

Choosing your agent → How the harness works → Wiring agent tools →

What the gate actually checks

Every item here exists because the loop was caught approving work it had not checked. They are not features; they are scars.

  • 27 of 28 scenarios in the shipped domain packs executed nothing. Gherkin keywords are case-sensitive, so GIVEN parsed as prose — no error, no warning, and an empty scenario passes. The in-house linter matched case-insensitively and called all 28 fine.
  • An agent that could not pass a scenario rewrote the scenario as Given nothing / Then nothing is asserted and got 1 passed · 0 failed. The branch was published and the requirement closed.
  • 10 of 11 packs failed the JSON schema while all 11 passed pack lint --strict. A schema that declares authority it does not exercise is worse than none.

All three were found by running the tool against a real project and reading the output, not by reasoning about it. Each is now a test that fails when the guard is removed.

The scenario can fail

Gherkin keywords are case-sensitive, so GIVEN is prose and the scenario runs zero steps — and passes. The gate refuses a scenario Cucumber would see as empty.

The scenario actually ran

A filter that matches nothing exits 0. When the runner is Cucumber, the gate reads its message protocol instead of its exit code.

The agent did not edit the contract

An agent that cannot pass a scenario can relax the scenario. Touching spec.md, features/** or the rules fails the attempt, with the diff fed back.

The diff touched what was promised

The matrix names a test and a production artifact. A green diff that never goes near them is reported, and fails under --strict-artifacts.

The requirement was worth attempting

No feature file, unmet dependencies, or a status of Needs Clarification — checked before an agent is paid for, not after.

The run has a ceiling

--budget-seconds and --max-requirements. Running out is not an error: the run stops cleanly and still reports what it did.

How it compares

OpenSpec is the closest thing and the one worth reading first. The honest summary: it is smaller, and smaller is a feature.

 csdaOpenSpecSpec KitA wiki page
Change lifecycle: propose → review → archiveyesyes — their idea firstnono
Traceability matrix that CI enforcesyesnobasicno
Gherkin a real runner executesyesprose scenariosvia templatesno
Versioned, installable domain packsyesnonono
Unattended harness with a gateyesnonono
MCP server and language serverboth shippednonono
Concepts you have to learnmorefewerfewernone
Shortest path to a working loop todaynoyesyes

If you want the change loop and nothing else, or your specs are prose rather than a domain model, OpenSpec is the better tool and the table says so. We took the delta format and the audited agent contract from their design. The full comparison, including where we lose →

The parts a team asks about second

The specification layer is the interesting half. This is the other half — the answers that decide whether it survives contact with a real organisation.

It runs in your CI, not its own

csda ci init writes the workflow for GitHub Actions, GitLab, Azure Pipelines, CircleCI or Jenkins. The gate is one command with a JSON mode, so it fits whatever you already have.

Your issue tracker stays yours

csda alm sync pushes requirements to Jira, Azure Boards, GitHub or GitLab and csda alm pull brings status back. The board is a mirror; it never gets to define what a requirement is.

An audit surface of one package

Zero runtime dependencies. A CycloneDX SBOM is generated on every push and kept 90 days, the licence policy is a build gate, and every domain pack is pinned by content digest in .specops.lock.

In the editor, and in the agent

A language server and an MCP server ship in this repository, along with VS Code and IntelliJ extensions — built and installable from source, not yet on either marketplace.

CI and automation → Issue trackers → Supply chain →

Questions people actually ask

Do I have to use DDD, hexagonal architecture and CQRS?

No. Patterns are optional; principles are not (ADR-0022). Pick an architecture profile and you get only the vocabulary it declares — a static site is not handed six documents describing aggregates it does not have.

Does it work on a repository that already exists?

Yes — csda adopt installs the specification layer without touching your code. Checks that a legacy repository cannot pass yet are flags, and csda doctor reports them as advisories with a fix, so adoption is a door rather than a wall.

Which AI agent does it need?

None in particular, and none at all if you do not want one. Every command works by hand. The harness takes any shell command; there is no SDK and no vendor lock.

Will the harness merge things for me?

Never. It produces a branch per requirement and stops. Merging is a judgement, and a tool that merges its own work removes the only place a person was still reviewing it.

What does it cost to run?

Whatever your agent costs — the harness measures wall-clock, because an agent is any shell command and only the agent knows its token spend. A profile may declare a cost hint, and the report multiplies it out and says it is declared rather than measured.

How is this different from OpenSpec or Spec Kit?

Mostly in what happens after the specification is written. See the comparison, which is honest about where the others are the better choice.

Start with an empty folder

npx create-spec-driven-app@latest init
cd my-spec-driven-app
csda validate .

Getting started I was handed a repo