Skip to content

Repository files navigation

Spec-Driven Development on RAG

Specs that stay authoritative, versioned, and machine-retrievable — decoupled from the code they describe.

Design intent lives in a dedicated spec repo, indexed by RAG (vector) + GraphRAG (relationships). Source code is deliberately not indexed: it churns on every commit, and an agent forced to reason about "what the code does" and "what the spec says it should do" at the same time does neither well.

npx @dependably/sdd init          # no install
# or
npm install -g @dependably/sdd && sdd init

Read METHODOLOGY.md for the model. This page is how you get running.


What it gives you

Commands — the mechanical work, scriptable and testable:

command what it does
sdd init configure a repo: project + developer config, agent skills, CLAUDE.md block, .sdd/ gitignore
sdd doctor prove the chain works — endpoint, auth, MCP registration, index
sdd validate check a spec repo's format; what CI runs on every MR
sdd validate --refs check the specs still describe real code; what the source repo's CI runs
sdd format write the generated ## Relationships blocks from edges:
sdd parse --json emit the parsed corpus (this is what the indexer consumes)
sdd update regenerate the generated agent files after upgrading

Skills — rendered into your project by sdd init, for the work that needs judgement about content rather than mechanics:

skill when
sdd-spec-advisor a work item opens, review comments land, or an issue closes
sdd-implement a validated work item has a spec and the code needs writing
sdd-spec-review reviewing an MR — does the change agree with the specs?
sdd-backfill seeding a corpus, or filling gaps, from SCM history
sdd-housekeeping daily — spec repo vs. index vs. closed issues
sdd-rag-init first-time index bootstrap, or a full rebuild

Setup is a command and not a skill on purpose: a health check written as prose can never be shown to go red, and one written as code can.


The workflow

How a work item moves through the loop, and what sdd reads and writes at each step. The spec written at the end is indexed and retrieved at the start of the next one — that closing edge is the whole point.

flowchart TB
    subgraph plan["1 · Planning"]
        ADV1["sdd-spec-advisor<br/>validate shape · retrieve<br/>draft .sdd/spec.md"]
    end
    subgraph build["2 · Implementing"]
        IMPL["sdd-implement<br/>branch · tests from<br/>acceptance criteria · code"]
    end
    subgraph peer["3 · Peer review"]
        REV["sdd-spec-review<br/>does the change agree<br/>with the specs?"]
    end
    subgraph close["4 · Completing"]
        ADV2["sdd-spec-advisor<br/>amend what changed<br/>write the spec back"]
    end

    WIT[("Work-item tracker<br/>issues · MRs/PRs")]
    SRC[("Source repo<br/>code")]
    SPEC[("Spec repo<br/>the source of truth")]
    RAG[("Spec RAG<br/>vectors + graph")]
    HK["sdd-housekeeping<br/>daily drift check"]

    ADV1 --> IMPL --> REV --> ADV2 --> HK

    WIT -. "issue opened" .-> ADV1
    RAG -. "prior decisions" .-> ADV1
    ADV1 -. "spec posted to the work item" .-> WIT
    IMPL -. "branch + commits" .-> SRC
    SRC -. "MR / PR opened" .-> REV
    RAG -. "standing specs + invariants" .-> REV
    ADV2 -. "spec rendered into the MR description" .-> WIT
    ADV2 == "commit the spec" ==> SPEC
    SPEC == "ingest when the revision moves" ==> RAG
    HK -. "index vs. specs vs. closed issues" .-> RAG
Loading

Two things the flow depends on, both enforced:

  • A work item that isn't spec-ready gets bounced, not guessed at — it needs a type, one testable objective, acceptance criteria as a checklist, a user statement, and for bugs, steps to reproduce.
  • A change touching a standing spec's source_refs either amends that spec or records why not. sdd-spec-review catches this before merge, while it is still a comment; sdd-housekeeping only catches it the next morning.

1. Adopt it in a source repo

cd your-repo
npx @dependably/sdd init

sdd init asks where your RAG is and for its token, then writes two config files, renders the skills, gitignores .sdd/, adds a marker-delimited block to CLAUDE.md, and runs the preflight.

Every prompt has a flag, so adopting the sixth repo costs a command rather than a conversation:

sdd init --rag-endpoint http://rag.internal:8080/mcp --rag-token "$TOKEN" \
         --mcp-server spec-rag --scm-type gitlab \
         --scm-project group/project \
         --spec-repo https://scm.example.com/group/project.spec.git --yes

sdd init --check verifies without writing, giving CI a way to assert a repo is still configured.

Pinning matters more than convenience. The format rules — frontmatter validation, the H2 chunk boundary, the character cap — are versioned, and both the ingest image and the spec-repo CI job pin the CLI. A global sdd is the one link in that chain that floats. Every rendered skill carries the version that rendered it, so sdd doctor fails when what is on disk differs from what your CLI would write now (sdd update regenerates it; sdd update --check shows the drift). It compares the artefacts rather than a recorded number, so it catches a stale render for any reason. Pin explicitly to guarantee it rather than merely detect it:

npx @dependably/sdd@0.6.2 init

Two files, split by who owns the setting

.sddconfig ~/.config/sdd/config
holds SCM, spec repo, pinned CLI version your endpoint, MCP server, token, clone URL
true for the project this machine
committed yes — reviewed, shared, safe to mirror never
mode normal 0600, in a 0700 directory
keyed by repos.<scm.project>

The split is by ownership, not sensitivity. An endpoint like http://localhost:8180/mcp is not a secret, but it is a fact about one laptop — commit it and everyone else edits that line and then has to remember never to commit the edit. Keying on the SCM identity rather than the path means your settings follow the repo into a second checkout, a worktree, or a new machine.

No credential ever reaches .sddconfig. It is committed and sometimes mirrored publicly, so a token there is a published token. sdd never collects, stores, or repairs an SCM credential either: it reports what is missing and points at claude mcp.

Keeping specs honest about the code

sdd validate --refs is the other direction: it checks that every source_refs path and enforced_by name a spec claims still exists. It needs a source checkout, so it runs in the source repo's pipeline:

git clone --depth 1 "$SPEC_REPO_URL" .spec-checkout
sdd validate .spec-checkout --refs --source .
finding result
source_refs path gone error — the spec describes a file or directory that is not there
path#Symbol symbol gone warning — a legitimate rename looks identical
enforced_by name gone warning — an invariant claims a gate that was deleted

--strict promotes the warnings. Only standing specs still claiming to be current are checked: a superseded spec describes the past on purpose, and a work item records one moment, so holding either to today's tree produces findings nobody can clear.

2. Create a spec repo

One per source repo, named for it with a .spec suffix:

sdd init --spec-repo-scaffold ../your-repo.spec

That writes CONVENTIONS.md (the format contract), taxonomy.yml, a validate-on-MR pipeline, and the four kind directories under specs/.

Edit taxonomy.yml before writing your first spec. It ships as a prompt rather than a default: the vocabulary is enforced at index time, so a generic term set gets baked into the components: of every spec written before anyone notices it was wrong.

An empty corpus is a legitimate state. Nothing seeds an example spec, because invented content in a spec corpus is the exact failure this methodology exists to prevent.

3. Stand up the RAG (once per team)

Skip this if a teammate already runs one — get the endpoint and token from them.

A Docker Compose bundle: Qdrant (vectors), Neo4j (spec edges), an ingest job, a scheduler, and a query API exposed over MCP. Full walkthrough in deploy/README.md, or ask an agent to run sdd-rag-init.

Ingest verifies before declaring success — file count == vector count == graph count, plus a smoke retrieval — and exits non-zero if they disagree. It re-polls hourly at a random minute and re-indexes only when the revision moved, so a poll costs one git ls-remote when nothing changed.

Upgrading

npm install -g @dependably/sdd@latest
cd your-repo && sdd update      # regenerate skills and the CLAUDE.md block

Run sdd update in each project after upgrading. Generated files are either marker-delimited or live in their own directory, so regenerating never touches hand-written content.

Privacy

No telemetry. sdd phones home to nothing, collects no usage data, and makes no network calls except to the RAG endpoint and SCM you configure.

Layout

src/                 the CLI — spec/format.ts is the single definition of the format
templates/           skills and the spec-repo scaffold, rendered by sdd init
deploy/              the RAG stack (Docker Compose)
METHODOLOGY.md       the model these tools enforce

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages