Claude Spec-Driven Development — as an executable contract.
csdd is a single Go binary that makes Spec-Driven Development (SDD) + Test-Driven Development (TDD) the native, enforced workflow inside a Claude Code repository. It turns the SDD lifecycle — requirements → design → tasks → implementation — from "good intentions in markdown" into a contract that is validated mechanically and gated by human approval at every phase, so neither a human nor an AI agent can skip a step, ship a requirement without a testable criterion, or mark a parallel task without declaring its boundary.
Around that spec core it adds two more layers: plan mode (docs/plans/), which decomposes a multi-feature initiative into feats that a runner drives to shipped code, and a knowledge base (docs/) — a graph "brain", an LLM-authored wiki, decision records, a glossary, and a tech contract — that keeps the why consultable instead of re-derived. There's no server and no database: the plain Markdown/JSON files under .claude/, specs/, and docs/ are the API, reviewable in any pull request.
Convention in this README: commands are written
csdd …. Zero install? The exact equivalent isnpx @protonspy/csdd …— or alias it:alias csdd='npx @protonspy/csdd'.
npx — zero install, always the latest. Fetches the right prebuilt binary for your OS/arch:
npx @protonspy/csdd --help # run instantly
npx @protonspy/csdd # no args → interactive TUIGlobal install — a short csdd on your PATH:
npm install -g @protonspy/csdd
csdd --helpOther ways in: grab a prebuilt archive from the releases page and put csdd on your PATH, or build from source with go install github.com/protonspy/csdd@latest.
# 1 · bootstrap this repo into a csdd workspace (no install)
npx @protonspy/csdd init --with-baselineThen, inside Claude Code, adapt the workspace to this project's stack in one step:
/csdd-setup-init # inspect the project → tailor steering, a specialized implementer agent, and skills
/csdd-setup-update # later: re-inspect and apply targeted adjustments, preserving your edits
Take your first feature from idea to ready-to-implement:
csdd spec init my-feature
csdd spec generate my-feature --artifact requirements # → validate → approve → design → tasks → implement| Command | What it does |
|---|---|
csdd init [--with-baseline] [--hooks] [--prepush] |
bootstrap the workspace (steering · skills · agents · commands · docs); the Claude Code hooks and the pre-push gate are opt-in via --hooks/--prepush (or --include hooks,pre-push) |
csdd update [--dry-run] · clean · destroy |
upgrade managed artifacts (keeping your edits as .old) · sweep .old backups · tear the workspace back down |
csdd copy <kind>/<name> |
cherry-pick one shipped artifact (skill · agent · rule · command · hook · template · steering) — the complement of init --exclude |
/csdd-setup-init · /csdd-setup-update |
adapt / refresh the workflow for your stack — Claude Code slash commands |
csdd spec init · generate · validate · approve · status · test-report |
the requirements → design → tasks gated lifecycle |
csdd plan init · validate · approve · status · next · brief · generate · run |
decompose an initiative into feats; drive each feat → spec → shipped code |
csdd sandbox init · doctor |
scaffold a default-deny-egress devcontainer and prove its isolation |
csdd graph build · query · path · explain · analyze · export |
the knowledge-base brain — a structured index over the whole workspace |
csdd wiki init · lint |
the LLM-authored knowledge base under docs/ |
csdd codewiki lint |
the repo-derived document under docs/raw/ — structure, slugs, and every citation resolved against the checkout |
csdd steering · skill · agent · mcp … |
author the governed resources (create · list · show · delete, plus validate) |
csdd web |
read-only live dashboard — spec progress, task board, file viewer |
/csdd-commit |
Conventional-Commit the reviewed slice, written from the diff + active spec |
New to the flow? Read on for the why. In a hurry? The three blocks above are the whole loop.
AI agents write code fast. Too fast to ship without a contract.
- Scope creep. Without an explicit, testable requirement, the agent "interprets" — and every run interprets differently. There is no baseline to review against.
- Zero traceability. Code with no link to a requirement. Nobody knows why a function exists, or what breaks if it changes.
- Human review too late. The human only sees the result in the PR — when reverting is expensive. The decision should be visible before the code.
The answer is SDD — Spec-Driven Development: a contract layer (requirements → design → tasks) with human approval at every gate. csdd is the tool that makes that contract impossible to break by accident.
A CLI + TUI + Web in a single Go binary — the only sanctioned author of the workflow's artifacts. You don't hand-edit frontmatter, spec.json, or task annotations — you generate from a template, edit the body, and validate.
Flag-driven, headless. Exposes 100% of the functionality so Claude Code, Cursor, Codex, or CI can drive the binary without reading the source.
csdd spec generate photo-albums --artifact requirementsInteractive interface (Bubble Tea). Running csdd with no arguments opens wizards and an artifact browser. Same operations, same rules.
csdd # no args → interactive TUIcsdd web serves a read-only dashboard in your browser: spec progress (phase, approvals, % of tasks done, validation status), navigable requirements / design / tasks (Markdown + Mermaid Boundary Maps), a live task board that updates as files change on disk, and a VS Code-style file viewer (Monaco) for the whole workspace.
csdd web # serve the dashboard and print its URL
csdd web --port 8080 # custom port
csdd web --tunnel # expose it publicly via a tunnel (forces auth)It's a view, not an author — the CLI stays the only thing that writes artifacts. And it's still a single binary: the React/Vite/Monaco UI is built ahead of time and embedded, so it runs offline with no extra runtime dependency. Binds to 127.0.0.1 by default.
🔑 Core principle: every surface calls the same operation helpers. A single source of truth — what a human does in the TUI, an agent does identically via the CLI.
The prebuilt binaries (npm / releases) embed the dashboard. Building from source? Run
make web-buildfirst to embed the UI — otherwisecsdd webserves a placeholder page (the API still works).
Four phases, three human gates:
Discovery → [gate] Requirements → [gate] Design → [gate] Tasks → Implementation
State lives in spec.json. Generating design while requirements is not approved fails — it's not a warning, it's exit code 2.
ready_for_implementationonly becomestrueafter all 3 approvals.--forcebreaks the gate — only with explicit human authorization, and it shows up in history.
csdd spec generate albums --artifact design
✗ phase gate: 'requirements' must be
approved before generating 'design'.
# the right path:
csdd spec approve albums --phase requirements
✓ requirements approved- 📜 Specification — the contract. The requirements, the File Structure Plan in the design, and the
_Boundary:_/_Depends:_annotations on the tasks. 👤 Humans review and approve this. - 🧩 Design — the implementation space. Components, internals, sequencing within each task. How the contract is fulfilled. 🤖 The agent is free here, after approval.
No phase is generated before the previous one is approved by a human — enforced mechanically, not by convention.
# 1 · create the feature workspace
csdd spec init photo-albums
# 2 · requirements → edit in EARS → validate → approve
csdd spec generate photo-albums --artifact requirements
csdd spec validate photo-albums # exit 2 = fix what it flags
csdd spec approve photo-albums --phase requirements
# 3 · design (blocked until step 2 passes) → 4 · tasks (same)
csdd spec generate photo-albums --artifact design # ... validate, approve
csdd spec generate photo-albums --artifact tasks # ... validate, approve
✓ spec.json: ready_for_implementation = true # implementation can begin💡
csdd spec status <feature>between any two steps: phase + approvals + validation issues on a single screen.
📝 Requirements in EARS. Fixed, testable syntax, one behavior per criterion. SHALL — never should. Unique N.M IDs.
### Requirement 1: Album Management
1. WHEN a user creates an album
THEN the system SHALL persist it <500ms.
2. IF the name is empty
THEN the system SHALL return 400.
✅ Annotated tasks (not a todo-list). Each leaf traces requirements; parallelism is declared and verified.
- [ ] 2. AlbumService _Boundary: AlbumService_
- [ ] 2.1 create / rename / delete
_Requirements: 1.1, 1.2_
- [ ] 3. PhotoService _Boundary: PhotoService_ (P)
- [ ] 3.1 upload S3
_Requirements: 2.1_
_Depends: 1.2_
_Requirements:_on every leaf ·_Boundary:_on every(P)·_Depends:_between boundaries.(P)= runs in parallel. Two(P)tasks cannot share a boundary — the validator rejects it, guaranteeing safe parallel execution by agents.
Once the gate is open, the agent implements in TDD:
RED (write the test) → GREEN (minimum to pass) → REFACTOR (clean under green) → widen the net (full suite + lint)
Drive it with the shipped implementer agent — a language-agnostic sub-agent that takes one task, drives it through the cycle the spec's development_flow declares, stays inside its design.md boundary, runs the gate, records evidence, marks the task done, and reports. Specialize it per stack (e.g. a go-developer) via steering and skills — /csdd-setup-init derives one for your project.
Each spec declares how its behaviors are delivered, and csdd spec validate enforces the shape it implies (exit 2, naming the task and line). Set it at creation: csdd spec init <feature> --flow unit|tdd|tdd-e2e, or workspace-wide via default_development_flow in steering.
| Flow | Cycle | Use it for |
|---|---|---|
tdd (default) |
tdd-cycle — RED → GREEN → REFACTOR |
money, auth, tenancy, anything irreversible |
unit |
unit-cycle — implement → cover → gate |
surfaces whose behaviors are render/CRUD states; halves the verification round-trips per behavior |
tdd-e2e |
tdd-cycle + an end-to-end pass |
flows that must be exercised whole |
- One leaf task per invocation. Takes the ID from
specs/<f>/tasks.md; doesn't batch tasks "to save time". - RED fails for the right reason. A compile error doesn't count — it cites the failure before moving on.
- Never weakens a test to make the suite pass. New behavior = new RED.
- Marks the task done. Once it's green, checks the task
[x]intasks.md— so progress (and the dashboard) reflect reality.
unit drops the RED-first ritual, not the test. It buys one fewer process invocation and one fewer round-trip per behavior; it costs the proof that the test could ever fail. So the cycle charges the cheap substitute: write the assertion from the acceptance criterion the task cites, never from the code you just wrote — a test written after the implementation drifts toward describing what the code does. It also names when to stop and escalate back to tdd.
Before reporting done: run the executable checks and produce real evidence — "compiles" and "looks right" are not done.
go test ./... ✓
lint ✓
typecheck ✓
build ✓
Each leaf traces _Requirements:_ → the test proves the requirement. Evidence beats assertion. Capture it into specs/<f>/test-report.json with csdd spec test-report (parses JUnit/coverage, or auto-discovers reports for go/python/typescript/java/rust).
code-reviewer → /csdd-commit → git push (pre-push gate) → Pull Request
code-reviewerruns on the diff; resolve every Blocker before moving on.security-reviewerif it touches auth / secrets / input — resolve Critical/High.- Reviewers don't write — you apply the fix and re-review until clean.
# Conventional Commits, generated from the diff + spec
feat(photo-albums): add album rename
Implements photo-albums; tasks 2.1, 2.2.
# git push → hook runs the suite; red BLOCKS
git push
✗ pre-push: test gate failed — push blocked
Never commit with an open Blocker; never git push --no-verify. The PR carries evidence: spec links · completed tasks · real check output · risks.
One spec is one feature. A real initiative spans several, with dependencies and a why. Plan mode is the layer above specs: a plan at docs/plans/<slug>/ decomposes an initiative into feats, where each feat becomes exactly one spec.
initiative ──▶ plan (docs/plans/<slug>/) ──▶ feats ──▶ one spec each ──▶ shipped code
A plan.md carries three machine-parsed sections that csdd plan validate checks:
| Section | What it declares |
|---|---|
## Feats |
one row per feat: Feat (kebab slug → spec dir) · Objective · Depends (feat slugs, no cycles) · Milestone · (P) · Refs |
## Quality Gates |
- <label>: <command> lines injected into each feat's brief as checks the session runs itself before declaring done; ≥1 required |
## Executor Notes |
opaque guidance inlined verbatim into every session brief |
The Refs column is how a feat cites its why: [[wiki-page]], stack:<name>, and adr:<slug> tokens — each must resolve, or validation breaks. Cited decision records are inlined in full into that feat's run brief.
csdd plan approve ──▶ you deliver, feat by feat ──▶ Pull Request
(human gate) (your Claude Code session) (human gate)
There is no runner. An approved plan is a queue with a dependency graph, and you work it in your own session, one feat at a time:
csdd plan status <slug> # milestones, delivered, what is ready
csdd plan next <slug> # the feat whose Depends are all satisfied
csdd plan brief <slug> --feat <feat> # that feat's context — the missionThe plan-dev skill is the method: create the spec, drive requirements → design → tasks with the spec-author sub-agent (you review, the human approves each phase),
delegate every leaf task to implementer under the spec's development_flow, run the
Tier-3 gate through quality-gate plus code-reviewer at feat exit, and
/csdd-commit the slices. One feat per pass — the next one is your call, not a loop's.
The phase gates stay human. csdd plan approve authorizes the plan — which feats
exist and under what constraints — not the specs you write from it.
Where the autonomous loop went.
csdd plan rundrove this headlessly — a session per feat, a verdict gate, worktrees, an attempt budget. Measured against the same work done in-session it cost an order of magnitude more and often delivered nothing: every session was rebuilt from zero per feat and per attempt, so all discovery was re-paid at orchestrator prices, and adonethe gate refused threw away a session already paid for. The command now refuses with a pointer here. The runner code stays in the tree — the idea may come back, and it should come back as a revert, not a rewrite.
Any bypass-mode work (--dangerously-skip-permissions) wants a proven sandbox rather than a trusted one: csdd sandbox doctor runs the checks and fails loudly when isolation cannot be proven.
csdd sandbox init --hardened # scaffold a default-deny-egress devcontainer (--feature, --allow-domain)
csdd sandbox doctor # prove the isolation holds before bypass mode is allowedPlans are authored by the
/prdskill (interview → research → stack → decompose into feats →csdd plan validate). A single feature stays on the lighterquick-prdon-ramp.
csdd init seeds a knowledge base under docs/. It exists so understanding comes from traversing relationships, not re-reading source; and so decisions and vocabulary are recorded once, not re-litigated.
csdd graph builds a deterministic index (docs/graph/graph.json.gz, a byte-stable gzip blob — commit it with the change; conflicts are resolved by rebuilding, not hand-merging) linking specs, tasks, .claude/ artifacts, docs/, and source. Consult it before you grep:
csdd graph build # rebuild the index (+ appends docs/graph/log.md)
csdd graph query "<terms>" # find nodes by label tier + their neighborhood
csdd graph path "<A>" "<B>" # shortest path between two nodes
csdd graph explain "<label>" # a node plus its connections, by neighbor degree
csdd graph analyze --strict # traceability gaps + tech/wiki lints (non-zero exit)
csdd graph export # a self-contained docs/graph/graph.html visualizationcsdd wiki init scaffolds docs/raw/ (a dropzone the CLI never edits) and docs/wiki/ (index, log, pages). When a source lands in docs/raw/, the wiki skill's Ingest workflow reads it and writes cross-linked pages under docs/wiki/pages/ with sources: provenance. csdd wiki lint reports broken wikilinks, orphan pages, index/log desync, and unprocessed sources.
Source code is a different kind of drop: a repository is not something to ingest page by page, it is something to read. Drop the checkout into docs/raw/<dir>/ (or a .zip unpacked beside itself) and run /csdd-codewiki — the codewiki skill compiles it into a single cited document, docs/raw/<owner>-<repo>.md: a Structure tree, <<< SECTION: >>>-delimited pages, mermaid for the moving parts, tables for every enum and flag, and a glossary. That document is the source you then ingest with /csdd-wiki-ingest.
The format is an interchange shape, not a private one — a document you compile locally and one produced by an external repo-wiki generator are the same artifact, linted by the same gate:
csdd codewiki lint # every repo-derived doc in docs/raw/
csdd codewiki lint <file> --repo <dir> # resolve citations against a checkoutcsdd codewiki lint is the deterministic half of the deal — the LLM writes the prose, the CLI proves the citations. It holds the Structure tree and the section delimiters to each other, checks slugs are unique and derived from their headings, fails a section that cites nothing, and resolves every [path:start-end]() against the checkout: a path that is not in the tree, a range past the end of the file, a citation climbing out of the repo with ... Run against externally generated documents it finds exactly that class of defect: a camelCase filename cited in snake_case, a name shortened to what it "should" be called, a 43-line manifest cited through line 60.
A checkout (a directory carrying .git/ or a dependency manifest) and an archive unpacked beside itself are material, not sources: the graph skips them, so a 200-file repo does not become 200 raw_source nodes and 200 unprocessed-source findings. The obligation moves to the one document derived from it — an archive nobody unpacked stays flagged.
| Artifact | Location | The rule |
|---|---|---|
| Decision records (ADR) | docs/adr/NNNN-<slug>.md |
A decision that passes the triple gate — hard to reverse · surprising without context · a real trade-off — becomes an append-only ADR. Feats cite it as adr:<slug>; a broken/superseded citation breaks csdd plan validate. Never edit a superseded record — mark it and write its successor. |
| Glossary | docs/glossary.md |
Each domain concept has one canonical term + an _Avoid_ list of banned synonyms. Slugs and page names are minted from canonical terms; using an avoided term as a whole token is a lint. Renaming a term appends the old name to the successor's _Avoid_ (a tombstone). |
| Tech contract | docs/stack.md |
Any technology not listed is an open decision — propose options and ask the human, never adopt a dependency silently. The stack skill refines each library against current docs before first use. |
Skills own the authoring:
graph,wiki,codewiki,glossary,stack(plus slash commands like/csdd-graph-query,/csdd-wiki-ingest,/csdd-codewiki,/csdd-stack-refine). The CLI is the only author ofdocs/graph/and.csdd/; nothing ever edits what is already underdocs/raw/—codewikionly ever adds one new document.
The contract above starts at requirements.md. Three skills bracket it upstream, all
landing in the same place: a normal, validated csdd spec or plan.
| Skill | For | Produces |
|---|---|---|
prd (/prd) |
a whole initiative — several features, with dependencies and a why | a docs/plans/<slug>/ plan whose feats each become one spec |
quick-prd |
a single feature | docs/product/prd-<feature>.md — stories + EARS-shaped FR-N, decision-ready in one pass |
spec-brainstorm |
an idea that needs requirements now | question-driven EARS requirements, straight into csdd spec |
🔑 An on-ramp never bypasses the contract. Whatever it produces still enters through
csdd spec generateand still passes the same mechanical gates.
csdd is the only sanctioned author of these artifacts, so their structure stays machine-checkable instead of drifting into free-form prose.
| Resource | What it is | Location |
|---|---|---|
| 🧭 steering | Project memory loaded into every agent interaction. Standards and the why behind decisions. | .claude/steering/*.md |
| 📐 spec | Per-feature contract: spec.json + requirements + design + tasks (+ research/bugfix). |
specs/<feature>/ |
| 🗺️ plan | Multi-feature initiative decomposed into feats, each feat → one spec. | docs/plans/<slug>/ |
| 🛠️ skill | Executable workflow bundle: SKILL.md + references + assets + scripts. |
.claude/skills/<name>/ |
| 🤖 agent | Custom sub-agent with a least-privilege tool scope (reviewer, debugger…). | .claude/agents/<name>.md |
| 🔌 mcp | Model Context Protocol servers the agent can connect to. stdio or remote, never both. | .mcp.json |
| 📚 knowledge base | Graph, wiki, decision records, glossary, tech contract. | docs/ |
Verbs per resource. Common base: create/init · list · show · delete. spec adds generate · approve · validate · status · test-report; plan adds validate · approve · status · next · brief · generate · run; mcp uses add · install · presets · remove · enable · disable · validate; skill adds add-reference/script/asset · validate; graph, wiki, and codewiki are CLI-only builders/linters.
A new csdd version ships new and improved managed artifacts. csdd update brings your workspace up to that version without ever losing your setup:
csdd update --dry-run # preview exactly what would change
csdd update # apply itIt tracks what it wrote in .csdd/manifest.json (a content-hash baseline) and, for each csdd-managed file, decides:
| On disk vs. shipped | What update does |
|---|---|
| missing | adds it (new in this version) |
| identical | leaves it (already current) |
| pristine but outdated | refreshes it in place — you never touched it |
| edited by you | writes the new version and keeps your copy as <file>-1.old (then -2.old, …) |
So nothing is silently overwritten: any file you customized is preserved as a numbered .old backup beside it to diff and fold in. --force overwrites in place without the backup. When you're done reconciling, csdd clean sweeps the *-N.old backups; csdd destroy tears the workspace back down (.claude/, CLAUDE.md, .mcp.json, the pre-push hook) for a fresh re-install — keeping your specs/.
🔒 Never touched by update: your
specs/, your filled.claude/steering/*.md, custom (non-shipped) skills/agents,.mcp.json,.claude/settings.json,docs/you authored, andCLAUDE.md. Update reconciles only the pure-csdd artifacts.
| Gate | Checks |
|---|---|
| spec · requirements | Every criterion starts with WHEN/WHILE/IF/WHERE/THE SYSTEM · none uses should · ### Requirement N: headers unique |
| spec · design | Boundary Map and File Structure Plan sections present · every requirement ID appears in the traceability table · design.md ≤ 1000 lines (else split the spec) |
| spec · tasks | Every leaf has _Requirements:_ with real IDs · every (P) has a _Boundary:_ that matches the design · no (P) pair shares a boundary · task shape matches the spec's development_flow (under tdd/tdd-e2e a GREEN step follows a RED and a RED is answered by a GREEN; under unit the RED/GREEN shape is a flow mismatch) |
| plan | Feats table well-formed · Depends resolve with no cycles · every Refs token ([[wiki]] · stack: · adr:) resolves · ≥1 quality gate · no avoided glossary terms |
| graph · analyze | Traceability gaps + tech lints (undeclared/phantom/unrefined) + wiki lints · --strict exits non-zero |
| wiki · lint | Broken wikilinks · orphan pages · index/log desync · unprocessed docs/raw/ sources |
| codewiki · lint | Provenance header · Structure ↔ sections in sync · unique, heading-derived slugs · every section cites something · every [path:start-end]() resolves in the checkout |
| skill · mcp · steering | SKILL.md ≤ 500 lines / ~5k tokens, refs cited · mcp: exactly 1 transport (stdio or url) · steering: valid inclusion, fileMatch has a pattern |
Exit codes: 0 ok · 1 usage error · 2 validation failure. Scriptable in CI.
cmd/csdd/main.go
(no args → TUI · with args → CLI)
│
┌────────────────────┴────────────────────┐
internal/cli · CLI internal/tui · TUI
dispatcher, 1 file/resource Bubble Tea · wizards + browser
└──── both call the SAME operation helpers ────┘
│
workspace · paths · validator · templater · plan · graph · frontmatter · render
│
artifacts on disk: .claude/ · specs/ · docs/ · CLAUDE.md · .mcp.json
(plain text, reviewable in a PR)
| Package | Responsibility | Why it matters |
|---|---|---|
internal/cli |
CLI surface. Dispatches resource action, flag parsing, 1 file per resource. Includes CLAUDE.md and .gitignore wiring. |
The public contract — 100% of functionality, headless. |
internal/tui |
Interactive front-end (Bubble Tea): menu, wizards, artifact browser. | Calls the same helpers as cli. No duplicated logic. |
internal/workspace |
Resolves the workspace root (the .csdd/ marker) by walking up the tree; validates kebab-case; enumerates phases and artifacts. |
Defines what a workspace is and the valid names. |
internal/paths |
Centralizes the on-disk layout: .claude/, .csdd/, docs/, specs/, CLAUDE.md, .mcp.json. |
The layout lives in exactly one place. |
internal/validator |
The mechanical checks: EARS, unique IDs, traceability, annotations, parallelism safety, skill structure. | The agent's "friend." Never asks for judgment — only true/false. Exit 2. |
internal/plan |
Plans, feats, the run loop, ADR parsing, and the sandbox scaffold. | Turns a multi-feature initiative into gated, runnable work. |
internal/graph |
Builds the deterministic knowledge graph and runs its analyses/lints. | The structured brain — consult over re-reading. |
internal/templater |
Renders templates embedded at compile time (go:embed). |
A fully self-contained binary — zero runtime dependencies. |
internal/frontmatter |
Parser for a minimal subset of YAML (scalars, bool, inline arrays). | Does only what's needed — small, predictable surface. |
internal/render |
Terminal output helpers with color (respects NO_COLOR/TTY). |
Consistent ✓ ✗ ! • messages in the CLI. |
- CLI = TUI, always. Both surfaces converge on the same helpers. There is no function only the TUI can do — which is why a headless agent has 100% of the power.
- Embedded templates.
go:embed all:templatescompiles the templates into the binary. You download one file and it works offline, with nothing to install. - Mechanical, not opinionated, validation. The validator never asks for judgment: either the criterion starts with
WHENor it doesn't. Deterministic → an agent can trust the exit code. - Artifacts are plain text. Everything becomes versionable markdown/JSON in
.claude/,specs/, anddocs/. Review happens in the PR, with the tools the team already uses.
The result: the CLI never stops you from doing the right thing — it stops you from doing the wrong thing without making the decision visible. Breaking a gate requires an explicit
--force, and that shows up in history.
The workspace csdd writes is the layout Claude Code expects. csdd init bootstraps it and handles the wiring:
CLAUDE.md # entry point + steering imports + knowledge-base workflow
.claude/steering/*.md # @-referenced from CLAUDE.md
.claude/agents/*.md # sub-agents (implementer, code-reviewer, …)
.claude/skills/<n>/ # skill bundles
.claude/commands/ # slash commands (/csdd-setup-init, /csdd-commit, /prd, /csdd-graph-query, …)
.claude/hooks/ # deterministic automation (format-after-edit, …) — opt-in via `init --hooks`
.csdd/ # csdd's operational state (the workspace marker + manifest.json) — the csdd analog of .git/
specs/<feature>/ # SDD contracts
docs/ # knowledge base: plans/ · adr/ · wiki/ · graph/ · raw/ · glossary.md · stack.md · product/
.mcp.json # MCP servers
Creating a steering automatically inserts @.claude/steering/<name> into a managed block of CLAUDE.md — idempotent, never clobbering manual edits.
What the team gains:
- Zero friction with Claude Code. Artifacts are read natively — no exporting or converting.
- Review where we already work. Specs, steering, and docs are text in a PR — diff, comment, approve.
- Least privilege by default. Sub-agents are born with
Read, Grep; MCP with a restricted scope. - CI validates the contract.
csdd spec validate(andplan validate/graph analyze --strict/wiki lint) in the pipeline blocks a broken contract before merge.
Prefer your agent to call tools over shelling out to a terminal? @protonspy/csdd-mcp is an MCP server (stdio) that exposes the csdd development flow as tools — csdd_spec_generate, csdd_steering_create, csdd_spec_approve, … 27 in total. It wraps the same CLI, so the contract is intact: phase gates still block, the validator still runs, and exit 2 surfaces as a distinct "validation failed" result the agent can branch on. Typed parameters (enums for artifact/phase/inclusion) mean the agent picks valid inputs and the server builds the argv — more precise than hand-written commands.
csdd init registers the server in .mcp.json for you (pass --no-mcp to skip):
# already wired by `csdd init`; to add it to an existing workspace:
claude mcp add csdd -- npx -y @protonspy/csdd-mcp- Dev-flow only, grouped by resource (steering · spec · skill · agent), plus
csdd_version. Setup and config management stay on the CLI —init,mcp, andexportare one-time human operations, not agent-loop tools. - Same binary, same rules. The server just builds the argv and runs
csddheadlessly (NO_COLOR, no TTY) — no logic of its own, so the CLI stays the single source of truth. - Zero-config binary via
npx(the matching prebuiltcsddis anoptionalDependency); override withCSDD_BIN.
Full tool reference and configuration: mcp-server/README.md.
csdd is Claude Code-native, but the SDD artifacts aren't locked in. csdd export converts the workspace to other agentic toolchains — a one-way, additive export that lives alongside .claude/ (nothing is overwritten in place):
csdd export kiro # → .kiro/steering/*.md + .kiro/specs/<feature>/{requirements,design,tasks}.md
csdd export codex # → AGENTS.md (CLAUDE.md + steering inlined) + .codex/config.toml (MCP)
csdd export kiro --out ./build --force- Kiro — steering frontmatter (
inclusion: always|fileMatch|manual|auto,fileMatchPattern) is already Kiro-compatible, so steering copies verbatim; specs copy their SDD markdown (spec.jsonis dropped — Kiro tracks phase state in-IDE). - Codex — Codex has no
@-import, so the managed steering block inCLAUDE.mdis replaced by the steering inlined intoAGENTS.md;.mcp.jsonbecomes[mcp_servers.*]tables in.codex/config.toml.
Takeaways: The validator is your friend. The gate makes the decision visible. Contract before code — requirements → design → tasks, each approved by a human before the next. Plan mode scales that from one feature to a whole initiative; the knowledge base keeps the why consultable. Always generate from a template; never hand-write frontmatter or spec.json. Least privilege everywhere.