@appswithlove/sdd
v0.7.0
Published
Spec-Driven Development for Apps with Love — Claude Code skills and hooks installer — one gate, four verbs.
Downloads
238
Readme
SDD — Spec-Driven Development
A Claude Code plugin that keeps a project's knowledge current and its requirements accepted before code is written. Built by Apps with Love AG.
SDD centres on one gate, four verbs, and a living knowledge base. It is not a process machine — how you design, split, and verify work stays your team's call. The system's job is that knowledge flows in (sales material, briefs, Confluence, people's heads) and out (decisions, lessons, finished work), and that a feature's requirements are accepted before it gets built.
Upgrading? 0.6.0 is a breaking release — see CHANGELOG.md and Migration from pre-0.6 below.
Install
Via npx (bare-name commands: /init, /req, …):
npx @appswithlove/sdd@latestOn a first install you are asked for the scope — global (~/.claude) or project (./.claude). Non-interactive:
npx @appswithlove/sdd@latest --global # or --project, or -y to auto-detect
npx @appswithlove/sdd@latest --dry-run # preview the writes, touch nothingThis installs the skills and hook scripts and merges the SDD hooks into settings.json (your own hooks are preserved). Nothing else lands on your machine — project conventions live per project in .project/steering/, seeded by /sdd:init.
Updating = re-run the same command. An existing install is detected: no scope question, it shows the version delta, asks one confirm (-y skips it), and mirrors the current source — files a previous version installed and this one no longer ships are removed. Your .project/ artifacts are never touched.
Via the Claude marketplace plugin (namespaced commands: /sdd:init, /sdd:req, …):
/plugin marketplace add appswithlove/sdd
/plugin install sdd@awl-sddThe plugin channel auto-loads the hooks; no settings.json merge happens. Both channels ship the same source tree — only the command prefix differs. This README uses the /sdd: prefix throughout; drop it if you installed via npx.
The four verbs
/sdd:init → create the structure (once per project)
/sdd:intake → knowledge IN: offer, brief, Confluence, interview → product/
/sdd:req → requirements + acceptance (the one gate)
...build... → free-form: your normal Claude Code work
/sdd:document → knowledge OUT: decisions, lessons, finished work → product//sdd:init creates .project/ with the four knowledge files and the steering seeds. On an existing codebase it derives the code-provable facts itself (stack, libraries, test command, module map) instead of asking you to type what the code already states. Run it once; re-running only fills in what is missing.
/sdd:intake brings knowledge from outside into the knowledge base — repo documents, Confluence/ClickUp pages (via the session's MCP tools), a pasted offer, or an interview when the knowledge only exists in someone's head. Non-repo sources are snapshotted into .project/intake/ with a provenance header. Run it whenever new material arrives, not just at project start.
/sdd:req captures a feature's requirements as behavioural REQs with acceptance criteria, and records their acceptance — the one gate. It ships no tracker integration: how requirements reach the client, and how their acceptance comes back, stays your project's own practice — you report the acceptance, /sdd:req records it.
...build... is deliberately not a skill — once req.md is accepted, work normally. A typical start:
/clear # fresh context for the build phase
Implement the accepted req.md for <feature>
# complex approach? plan mode first, then persist it:
# → .project/specs/<feature>/plan.md — reviewable, iterable, committed
# iterate however your team works — code, tests, review
/sdd:document # capture decisions/lessons when done/sdd:document routes what the work produced into its home: architecture decisions into product/adrs/, library and stack changes plus lessons into tech-stack.md, finished work into the Feature Log in overview.md, discovered non-functional requirements into constitution.md. It runs any time — after a design session, at the end of a work session, when a feature wraps up — and is idempotent, so a re-run extends or corrects instead of duplicating. On request it archives a finished feature's spec directory.
/sdd:learning is the one verb outside the product flow: when the workflow itself got in the way — a skill guessed wrong, a hook nagged falsely, a template had no home for something — it appends one observation (what happened, what it cost, no proposed fix) to .project/workflow-learnings.md. That log is the raw material for improving SDD itself; product knowledge still goes through /sdd:document.
/sdd:help shows the cheatsheet, per-skill detail, and /sdd:help status — where the project currently stands.
The knowledge base
A map plus references under .project/product/. README.md is the map — the one file every session loads (the SessionStart hook injects it) — and its Read when column says which reference to load for the task at hand. Everything else loads on demand:
| File | Answers | Read when |
|---|---|---|
| README.md | The map — one row per file, what it answers, when to read it | always (injected at session start) |
| constitution.md | Why — mission, goals, users, constraints, sales commitments, non-functional requirements | before any feature work |
| tech-stack.md | With what — platforms, repos, shared conventions and lessons; per code repo: tech-stack/<repo>.md | code or libraries are touched |
| adrs.md + adrs/NNN-<slug>.md | Why so — an index line per decision, one file per record | before a design decision |
| overview.md | What & where — description, module map, stakeholders & sources, Feature Log | a feature is picked up; onboarding |
| <name>.md | Project references — a data model, an external contract, a backend surface that outgrew a section | as its map row says |
A specs repo that governs several code repos splits repo-specific stack facts into tech-stack/<repo>.md — the repo the evidence came from decides the file, so nothing is filed by judgement.
Two supporting homes: .project/intake/ holds raw source material that has nowhere else to live (never auto-loaded — read once, re-read on demand), and .project/specs/<feature>/ holds the feature's req.md plus whatever free-form notes the team wants — design sketches, task lists. No required sections, no validation of their shape. The one optional exception is plan.md: when an approach is complex enough to review and iterate on, write the plan there instead of leaving it in a plan-mode session that nobody can diff.
Only two verbs ever write to product/: /sdd:intake (from outside in) and /sdd:document (from the work back). See docs/artifact-lifecycle.md.
New to a project? product/README.md names what to load for your task; read constitution.md before building and overview.md to orient. That is the onboarding path.
The one gate
.project/specs/<feature>/req.md exists
AND its YAML header carries status: acceptedThat is the only gate in SDD: a feature's requirements are accepted before its code is written. Questions, exploration, and discussion never require it, and an explicit instruction to bypass SDD wins — Claude says so and proceeds.
The acceptance axis lives in the req.md header and nowhere else: draft → in-review → accepted. In client work, accepted means the client accepted, not that we decided the requirements looked finished. Acceptance is a human fact that arrives on whatever channel the project uses — a tracker status, a meeting, a mail. You report it, /sdd:req records it; nothing sets it automatically. Solo projects self-accept directly. A meaning-changing edit to an accepted requirement revokes acceptance back to in-review; a typo fix does not.
Full model, including feature resolution: docs/gate-system.md.
Hooks
Three deterministic bash hooks (no LLM calls, jq required) back the behavioural rules up. All are warn-not-block — they nudge, they never deny a write, and they no-op outside an SDD project.
| Event | What it does |
|---|---|
| SessionStart | Injects the flow rules plus a live status report derived from the files: every feature and its acceptance state, the steering file list, a warning if a knowledge file is missing, and one if a committed settings.json points its SDD hooks at a script that does not exist here (an absolute path from another machine — otherwise a silent total hook failure). |
| PostToolUse (Write/Edit) | Warns when a req.md header carries a status outside the vocabulary, and once per session when source files are written while the active feature is not accepted. The active feature is only named when a deterministic signal identifies it — a spec written this session, the prompt, or the git branch; otherwise the nudge stays silent rather than accuse the wrong feature. |
| Stop | Asks once per session, when code was written but no spec or knowledge file was touched, whether /sdd:document should record what happened. |
Each warning class fires at most once per distinct state per session — a nudge that repeats on every edit teaches the model to ignore it.
Migration from pre-0.6
Nothing to run. Old artifacts in a project — the retired gate carrier and the previously mandatory design/task spec files, the retired state digest, the pre-0.6 extra product/ files — are inert leftovers: no skill, hook, or check reads or complains about them. /sdd:document archives spec leftovers along with their feature, and on request folds still-true content from the pre-0.6 product files into the current files. A project from before the map existed gets its product/README.md from the next /sdd:init or /sdd:document run. On the machine side, updating the npm install removes the skills and agents that 0.6.0 no longer ships.
Documentation
| Document | Contents | |---|---| | docs/gate-system.md | The one gate, the acceptance axis, feature resolution | | docs/artifact-lifecycle.md | Permanent vs ephemeral artifacts, the two-verb write rule, archival | | docs/artifact-header.md | The slim YAML header + status vocabularies | | docs/steering-system.md | Project conventions: the one steering home, loader mechanics | | docs/skill-manifest.md | SKILL.md format, description conventions, context budgets | | docs/context-engineering.md | Context-rot doctrine and the reading discipline it implies | | docs/troubleshooting.md | Common problems and fixes | | docs/decisions.md | Design decision log (historical record) | | docs/lessons-from-field.md | Field observations that shaped the tooling (historical record) |
Development
The repo is the plugin — no build step. Source tree:
plugins/sdd/
.claude-plugin/plugin.json ← plugin manifest
hooks/hooks.json ← wires the bash hooks into Claude Code events
scripts/ ← the three hook scripts + shared flow library
skills/<skill>/SKILL.md ← skill definition + instructions
skills/<skill>/references/ ← templates (incl. init's steering seeds)npm test # installer smoke, hook tests, manifest load, staleness lint
node bin/install.js --dry-run --project # preview an installContributor rules live in CLAUDE.md — including the mandatory staleness sweep after every change and the lockstep version bump across the three manifests. This README deliberately keeps no second copy of them.
Key design principles
- No runtime. Skills are system prompt injections. The gate is behavioural, backed by warn-not-block hooks; nothing programmatically denies a write.
- Adoption beats enforcement. 0.6.0 retired the multi-gate machinery because a process people route around documents nothing.
- Two verbs own the knowledge base. Everything that enters
product/comes through/sdd:intakeor/sdd:document, which keeps the write paths reviewable. - Specs are ephemeral, knowledge is permanent. Feature specs archive;
product/lives as long as the project.
License
Proprietary — Apps with Love AG.
