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 initRead METHODOLOGY.md for the model. This page is how you get running.
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.
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
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_refseither amends that spec or records why not.sdd-spec-reviewcatches this before merge, while it is still a comment;sdd-housekeepingonly catches it the next morning.
cd your-repo
npx @dependably/sdd initsdd 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 --yessdd 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.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.
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.
One per source repo, named for it with a .spec suffix:
sdd init --spec-repo-scaffold ../your-repo.specThat 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.
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.
npm install -g @dependably/sdd@latest
cd your-repo && sdd update # regenerate skills and the CLAUDE.md blockRun 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.
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.
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