sdx: a toolchain for spec-driven development
sdx — published on npm as specdx — is a CLI toolchain for spec-driven development. It gives
specs a formal schema, validates and lints them deterministically — no LLM calls in the core
pipeline, no API keys — packs the relevant ones into token-budgeted context for an agent
session, and statically checks implementation drift afterwards. This page is its canonical
reference; the revision log below records how it changes.
It is alpha software, and this page says so plainly: twelve published versions since March 2026, all prereleases. The practice it tools up is documented separately in Spec-driven development; this page is about the tool.
What sdx is
The problem, as I keep meeting it: most AI-assisted development workflows are ad hoc. Specs — where they exist at all — are markdown files in inconsistent formats, pasted into context windows by hand, with no validation, no diffing, and no CI integration. The agent is asked to respect constraints that nothing enforces. sdx makes the spec a first-class, machine-checked artifact: a schema says what a spec must contain, a linter holds the line, a packer decides what an agent session actually needs to read, and two drift checks catch the places where documents and code have quietly stopped agreeing.
One naming wrinkle, stated once: the project is called sdx; the npm package and the
installed binary are both specdx. The shape underneath is a ten-package monorepo with
one-way data flow — a schema package at the bottom, a core parser above it, then lint, pack,
diff, and check as siblings, all bundled into a single CLI with sixteen subcommands.
The minimal loop looks like this:
npm install -g specdx
specdx init --name "my-app" --template lightweight
# → spec.config.yaml plus stub specs with their required sections scaffolded
specdx pack --task "implement user authentication" --copy
# → the relevant specs, token-budgeted, on your clipboard for the agent session
specdx check # after implementing: does the code still match the specs?
specdx lint # before committing: are the specs themselves still healthy?
Everything deterministic exits 0 or 1, which is the entire CI contract.
Why specs, not prompts
The argument for working spec-first is made in the methodology page and I won’t repeat it here. The argument for tooling is narrower: without enforcement, “we have specs” degrades into “we have markdown files someone hopes the agent reads.” Each command exists because I kept hitting a specific failure that hoping didn’t fix:
- A spec missing the section that mattered — acceptance criteria, non-goals — and nobody
noticing until an agent invented the missing part. →
validateandlint. - A PRD updated while the test plan that depends on it stayed put. →
diff, which walks the dependency graph and flags downstream specs as stale. - An implementation drifting from its API contract weeks after everyone stopped re-reading the
spec. →
check. - Pasting the same 30 KB of spec into every session, or worse, choosing by memory which parts
to paste. →
pack.
Prompts are ephemeral; specs are reviewable artifacts. The toolchain’s job is to keep the artifacts honest at machine speed.
The pieces
The schema. Nine spec types — PRD, technical design, user story, test plan, ADR, API
contract, epic, quick-spec, and project-context — each with named required sections (a PRD
must contain Problem Statement, Goals, Non-Goals, Features, and Success Criteria; an ADR must
contain Context, Decision, Status, Consequences). Seven required frontmatter fields per spec,
and typed cross-references between specs with five relationship kinds, from implemented-by
to supersedes. A spec.config.yaml at the repo root declares the suite: which specs exist,
their types, and what requires what.
The linter. Thirteen rules: five structural ones that default to error (valid
frontmatter, required sections, valid references, no circular dependencies, a single
project-context spec) and eight content rules that default to warn — staleness, vague
language, terminology consistency, story coverage, edge-case coverage among them. Three
presets: minimal is the five structural rules, recommended is all thirteen, strict is
all thirteen with every severity forced to error. Errors fail the build; warnings don’t.
The packer. Three stages: resolve, allocate, format. Relevance is scored from your task string against each spec — tag and title hits weighted ×3, section headings ×2, body ×1 — and specs adjacent in the dependency graph inherit half the score, so packing “implement auth” pulls in the design doc the auth story depends on. The budget defaults to 12,000 tokens. A project-context spec gets a reserved allocation (up to 2,000 tokens, uncompressed) before anything else competes, because the coding-rules spec is the one you never want evicted. Remaining specs fill greedily by relevance until the budget runs out. The token report prints to stderr so stdout stays pipeable.
The differ. Spec-to-spec drift between two git refs: which specs changed, and which downstream specs are now suspect, each with a staleness score. The default staleness threshold is 14 days.
The checker. Spec-to-implementation drift, fully static — an AST pass, not a model.
Routes extracted from Express, Hono, or Next.js App Router code are matched against API
contract specs; TypeScript interfaces, Zod schemas, and Prisma models against a technical
design’s data model; test titles against test-plan cases by word-set similarity. The output
is an implementation-coverage percentage. Code that exists but isn’t in any spec is reported
as extra and never penalised — the score only drops for what’s missing or mismatched,
because the specs constrain what must exist, not everything that may.
The gate. specdx ready runs five checks — required specs present, zero lint errors, no
broken references or cycles, nothing stale, every PRD feature covered by a story — and exits
1 if any fail. It’s the boundary between planning and building, and it’s what CI runs.
The agent surface. The package ships nine Claude Code skills (spec authoring, drift checking, pre-commit review, task kickoff among them) and an MCP server exposing seven tools, so agents can run the same checks the CLI does without shelling out blind.
Using sdx with an agent
The working loop on a real project: pack --task before the session, so the agent starts
from the specs that matter instead of the whole suite; the agent implements; check and
lint after; ready in CI as the gate. sdx’s own repository runs exactly this — its CI
workflow executes validate, lint, and status on every spec change, plus
diff --base origin/main to flag staleness on pull requests. The tool maintains a
fifteen-spec suite about itself and holds it at zero lint errors.
The design decision that shapes all of this: the core pipeline makes no LLM calls. The
reasoning engine in this loop is the agent already sitting in your editor; sdx’s job is to
hand it validated context going in and deterministic findings coming out. There is exactly
one exception, and it’s opt-in: check --ai sends the already-computed findings (not your
source code) to a model to classify likely false positives. It requires an API key, and
nothing in the workflow requires it.
Design decisions
Numbered and dated, mirroring the revision-log ethos of this site:
- 2026-03 — Skills-first, not API-first. The original design had sdx calling LLM APIs directly for intent analysis, ambiguity scoring, and drift detection — which meant provider abstraction, cost estimation, caching, confidence thresholds. Recognising that the developer’s coding tool already has a model in it cut roughly 40% of a phase’s scope and left the core deterministic and CI-safe.
- 2026-03 — No provider-specific packing formats. Pack emits XML, markdown, or JSON. Modern models handle all of them well enough that per-provider formatting is marginal complexity for marginal gain.
- 2026-03 —
js-tiktokenfor token counting. Accurate enough (the test target is within 5% of real tokenisation) with no native dependencies to break installs. - 2026-07 — Derive every spec-type enum from one source of truth. The config schema had
drifted from the sections registry: it accepted six of the nine spec types, making the
other three impossible to declare at all. The fix derives the enums from a single
SPEC_TYPESconstant and adds drift tests against the raw schema JSON, so the two can’t disagree again.
Decision 4 came from dogfooding. Setting sdx up on this website is what surfaced the bug — and the root cause was its own small horror story: the schema package’s incremental build didn’t track JSON files, so a correct fix could land in source one minute before a publish and still ship a stale artifact. As of this revision the fix is committed but the latest published version, 0.4.0-alpha.2, still carries the bug. Reference pages should say things like that out loud.
Roadmap
What’s deliberately not built yet, and what each item is waiting on:
- Confidence-scored findings.
checkcurrently reports ~59 spurious “add a test matching…” warnings against sdx’s own suite, because word-set similarity can’t reliably map prose test-plan bullets to real test titles. Findings need a confidence score so CI can block on high-confidence errors and downgrade the rest — until then, the checker is honest but noisy. - Workflow enforcement hooks — detecting when a session skipped the spec steps entirely, rather than trusting that it didn’t.
- Spec-aware commits — commit messages that reference the spec IDs they implement.
- Methodology modules as npm packages — pluggable spec methodologies beyond the built-in templates. Deferred until the core templates have survived more real projects.
- Cross-repo spec federation. The tool is monorepo-first by decision; federation waits for a real multi-repo consumer, not a hypothetical one.
The constraint carried across all of it, from the roadmap’s own risk notes: AI-assisted features stay opt-in and are never required for the core workflow. The deterministic pipeline is the product; everything else negotiates for a place around it.
Revisions
- Created as a living reference page; outline only.
- Wrote the full reference body from the sdx repo, its spec suite, roadmap, and the npm registry.