Imported from noelserdna/sdd-pipeline (
skills/sdd-specifications-engineer/SKILL.md). Install upstream withnpx skills add noelserdna/sdd-pipeline --skill sdd-specifications-engineer. Copyright stays with the author.
Specifications Engineer (SWEBOK v4)
Professional specifications engineering skill that transforms software requirements into formal, structured specification documents following IEEE SWEBOK v4.
Critical Workflow
ALWAYS follow this sequence:
- Read and understand the existing requirements
- Analyze them for quality, gaps, and ambiguities
- Ask the user for decisions on every gap, ambiguity, or issue found
- If requirements are deficient, generate a modification proposal before proceeding
- Create the specification documents and folder structure — id ledger and shared domain first, then the per-requirement pass in parallel lanes above the threshold (§ Execution Strategy)
- Validate the resulting specifications
Modes of Operation
Determine which mode based on user intent:
Mode 1: Analyze Requirements for Specification Readiness
Use when the user provides requirements and wants to move toward specifications.
- Read references/gap-analysis-checklist.md for the full analysis framework
- Locate and read ALL requirement documents in the project
- For each requirement, evaluate specification readiness:
- Is it unambiguous enough to specify? If not, flag with options
- Is it testable enough to derive acceptance criteria? If not, flag
- Is it atomic enough to map to a single spec? If not, propose decomposition
- Is the scope clear enough to define boundaries? If not, ask
- Identify gaps in the requirements:
- Missing stakeholder perspectives
- Missing error/exception handling
- Missing security requirements
- Missing nonfunctional constraints (performance, scalability, availability)
- Missing boundary conditions
- Missing data lifecycle (CRUD + archiving)
- Missing integration/interface requirements
- Identify ambiguities:
- Terms used inconsistently
- Vague qualifiers ("fast", "easy", "user-friendly")
- Unstated assumptions
- Multiple valid interpretations
- Identify conflicts:
- Requirements that contradict each other
- Requirements that are infeasible together
- For EVERY issue found:
- Present the issue clearly to the user
- Provide 2-4 resolution options with a recommended option marked
- Use
AskUserQuestionto let the user decide - Record the decision for traceability
- Produce a Specification Readiness Report — one short table (console, or
requirements/READINESS-REPORT.mdonly if the user asks for a file; ≤ 2,500 chars):
# Specification Readiness Report — YYYY-MM-DD
Requirements: N · ready: N · need clarification: N · need modification: N · missing: N
| # | Severity | REQ | Issue (≤ 15 words) | Options (recommended first) | Decision |
|---|---|---|---|---|---|
| 1 | Critical | REQ-F-003 | "done" on an already completed task? | A no-op, exit 0 · B error, exit 3 | A → RN-010 |
Gaps: [category → what is missing → recommendation], one line each.
Decisions are recorded once, as RN rows in spec/CLARIFICATIONS.md (Template 16); the report cites the RN id and does not repeat options or rationale.
Mode 2: Create Specifications
Use when requirements are ready (after Mode 1 analysis or user indicates readiness).
-
Read references/specification-workflow.md for the full specification process
-
Read references/document-templates.md for available templates
-
Read references/template-checklist-alignment.md for the template↔auditor alignment matrix, and references/fanout-protocol.md for the id ledger, the lane split and the consolidation contract
-
Check previous audit feedback: If
pipeline-state.jsonexists and has a previousspec-auditorsummary withtopFindingCategoriesortemplateImprovements, read them and apply extra scrutiny to those areas during spec writing. This feedback loop prevents repeating the same defect patterns across projects. -
Ask the user which specification format(s) to use:
- SRS (IEEE 830-style): Formal specification document
- Use Case specifications: For complex workflows
- User Stories + BDD Scenarios: For agile teams
- Actor-Action specifications: For contractual/regulatory contexts
- Model-based: For architecturally complex systems
- Recommend the most appropriate based on project context
-
Ask the user about the project structure preferences:
- Monolithic document vs. modular documents per feature/module
- Naming conventions
- Output directory
-
Create the folder structure with one command:
mkdir -p spec/{domain,use-cases,workflows,contracts,adr,tests,nfr}(runbooks/only when a requirement asks for an operational procedure — see § Output Economy). -
Decide the execution mode before writing anything: count the functional requirements and apply § Execution Strategy /
references/fanout-protocol.md§1. More than 4 → fan-out lanes for phase C; otherwise one thread. Record the choice (and the reason, when it is a downgrade) for Persist Summary. -
Write the specifications following § Generation Order (id ledger → shared homes → one pass per requirement → cross-cutting → gate, no re-reading) and § Output Economy (cite ids, never copy requirement text). For each requirement — in the main thread in sequential mode, in its lane in fan-out mode:
- Map it to its UC / WF / contract operation ids from the id ledger (
.sdd/spec-id-plan.md); never invent an id that is not in it - Apply the Error Flow Forcing Function (step 6a) and Invariant Extraction (step 6b) while drafting, before the file is written
- Write the UC and its
tests/BDD-UC-NNN.mdback to back (the BDD file defines the AC-NNN-NN ids the UC cites) - Traceability = the UC's
Refsrow + one row inTRACEABILITY-MATRIX.md
Step 6a: Error Flow Forcing Function
For EVERY step in a UC's main flow, answer these 5 questions while planning the UC; each "yes" becomes one row of the
Exceptions & errorstable (Template 2):Question If yes, create... 1. What if this step fails (network, timeout, service down)? Exception course with error code + HTTP status 2. What if the input is invalid or missing? Exception course with VALIDATION_ERROR + 400 3. What if authorization is denied? Exception course with 403 + specific permission 4. What if there is a concurrent conflict? Exception course with 409 + conflict resolution 5. What if a precondition was met when checked but became false during execution? Exception course with race condition handling A "no" or "not applicable" answer produces no text: no N/A cells, no comments, no forcing-function matrix in the document. The goal is a non-empty exceptions table, not a record of the questions.
Each exception row also yields, in the same pass (never as a later patch to a written file):
- Its error code in the error catalog (
domain/03-VALUE-OBJECTS.md, the only place with message/class/HTTP) and one row in the contract's single Errors table — in fan-out mode the lane does not write either file: it returns the code inerrs(markingnew: truewhen the catalog does not already have it) and the main thread appends the catalog row and writes the contract in phase D - One scenario in
tests/BDD-UC-NNN.md, whose AC id the exception row cites - Exceptions shared by every UC (global error handler, storage failure) are described once — in the workflow or the contract — and cited by id from the UC
Tier Classification: For each exception course generated, classify its traceability tier:
Tier Condition Action Tier 2 The exception is a technical detail of a UC that already traces to a REQ (e.g., adding 404 to an existing endpoint) Register in spec/DERIVED-SPECS.mdas[Derived from REQ-X]— no REQ neededTier 1 The exception implies new user-visible behavior NOT covered by any REQ (e.g., a new retry workflow, a new notification to the user) STOP — present to user, ask if a new REQ should be created via sdd-req-changeTier 3 Structural/cosmetic (e.g., reordering error codes in a table) No registration needed Most error flows are Tier 2 — they are technical details derived from existing requirements. Only flag as Tier 1 if the error handling introduces user-visible behavior that no REQ anticipated.
The STOP belongs to the main thread. A lane never stops and never asks: it leaves the behaviour unspecified, returns the item in
tier1and marks the spot with anNCmarker from its block. The main thread raises every Tier 1 item once, in phase D, beforeDERIVED-SPECS.mdis written.Step 6b: Invariant Extraction
While drafting each UC (before its file is written), scan the requirement and the planned flow for constraint language and formalize as invariants:
- Search for: "must", "shall not", "always", "never", "at most", "at least", "between X and Y", "unique", "only if", "requires", "cannot exceed", "minimum", "maximum"
- For each constraint found:
- Check if a formal invariant already exists in
domain/05-INVARIANTS.md(written in Generation Order phase B) - If not: mint an
INV-{AREA}-{NNN}id from the block the id ledger reserved for this thread (main thread…-0NN, lane L…-{L}NN) with declarative rule and validation (Template 10 — one row, no prose). In sequential mode append the row to05-INVARIANTS.md; in fan-out mode the lane returns it ininv_newand never editsspec/domain/— the main thread appends the rows in phase D - Cite the INV-ID inline in the UC step or postcondition (e.g., "(INV-SRV-003)") — the rule text itself is never repeated in the UC
- Check if a formal invariant already exists in
- Present extracted invariants to the user for confirmation before finalizing (in fan-out mode, once in phase D over the consolidated
inv_newlist — a lane never asks)
Tier Classification: For each invariant extracted, classify:
Tier Condition Action Tier 2 The invariant formalizes a constraint already stated or implied by an existing REQ Register in spec/DERIVED-SPECS.mdas[Derived from REQ-X]Tier 1 The invariant introduces a NEW business rule not present in any REQ STOP — present to user, ask if a new REQ is needed Tier 3 The invariant already existed in 05-INVARIANTS.md(just back-annotated)No registration needed Step 6c: Register Derived Specifications
Keep a running list of derived items while writing; after the last UC, write
spec/DERIVED-SPECS.mdonce (Template 15). In fan-out mode a lane never writes this file: it returns its rows inderived/inv_new/tier1and the main thread writes the file in phase D from the union.- For every Tier 2 artifact created (exception courses, invariants, BDD scenarios, API error codes), add a row — grouped by pattern (one row per error family across UCs, one row per invariant range), never one row per UC per code
- For every Tier 1 artifact, add a row marked as
[PENDING REQ] - If >3 Tier 1 items exist without REQs, alert the user: "There are {N} specification artifacts that introduce new user-visible behavior without corresponding requirements. Consider running
/sdd-req-changeto create REQs before proceeding."
Research Questions: When specifying technical decisions that require evaluation of alternatives (e.g., REST vs GraphQL, encryption algorithm selection, database engine choice), document the open question instead of assuming an answer. Create
spec/RESEARCH-QUESTIONS.mdlisting each question with its context, the specification(s) it blocks, and candidate options identified so far. These questions are consumed bysdd-plan-architectPhase 3 (Research) for deeper investigation. This enables early identification of research needs during specification, avoiding costly rework downstream. - Map it to its UC / WF / contract operation ids from the id ledger (
-
Create
spec/TRACEABILITY-MATRIX.md(Template 5) from the id ledger (and, in fan-out mode, the lanes'ids_used/ids_ref): forward table only (REQ → UC/WF, API, INV, ADR, BDD/PROP, NFR, RN), a ≤ 6-word summary instead of the requirement description, one coverage line. No reverse table (every artifact carriesRefs), no per-acceptance-criterion table (BDD scenario titles carry the[REQ-X ACn]tag). Written from memory, without re-reading the generated files. -
At each decision point during specification writing, ask the user:
- When multiple design approaches exist
- When specification granularity is unclear
- When acceptance criteria could vary
- When interface boundaries are ambiguous
Only the main thread asks. In fan-out mode these questions must be raised in Mode 1 / phase A, before the lanes
start: a lane cannot use AskUserQuestion. A lane that meets an undecided ambiguity emits an NC-{L}NN marker from
its reserved block and returns it in gaps; the main thread resolves it in phase D (asking the user if the session
is interactive, appending the RN row and removing the marker) or leaves it in CLARIFICATIONS-PENDING.md.
Mode 3: Propose Requirements Modifications
Use when Mode 1 analysis reveals significant deficiencies in the requirements.
IMPORTANT: This mode activates AUTOMATICALLY when:
- More than 30% of requirements have critical issues
- Missing requirements exceed 20% of existing count
- Fundamental conflicts exist between requirements
- Core functionality is underspecified
- Create a Requirements Modification Proposal using Template 8 in
references/document-templates.md: one table of MOD/ADD/REM rows (REQ, issue, proposed text, one-clause rationale) and one impact line — no executive summary, no approval table. - Present the proposal to the user with clear explanation
- Ask the user whether to:
- Proceed with specifications despite issues (document risks)
- Go back to requirements phase (recommend using requirements-engineer skill)
- Address only critical issues and proceed
Mode 4: Validate Specifications
Use when the user has existing specification documents to review.
- Read all specification documents
- Check against references/gap-analysis-checklist.md Phase 3
- Verify each specification:
- Has clear acceptance criteria
- Is traceable to a requirement
- Uses consistent terminology
- Is implementation-ready (a developer could build from it)
- Has no ambiguity
- Verify the specification collection:
- Complete coverage of all requirements
- No orphan specifications (specs without requirements)
- No orphan requirements (requirements without specs)
- Consistent format and structure
- Produce a Specification Validation Report
Mode 5: Brownfield Specification
Use when the user has an existing codebase and wants to add specifications incrementally, rather than specifying everything from scratch.
When to activate:
- User mentions an existing project, legacy code, or working software
- There is source code but no
spec/directory (or a partial one) - User wants to formalize only specific modules or components
Process:
- Analyze existing codebase — Scan project structure, entry points, and dependencies to build a component map. Identify bounded contexts, modules, and integration boundaries.
- Identify and prioritize modules — Present the user a table of discovered modules with a recommended specification order based on: (a) business criticality, (b) change frequency, (c) dependency count, (d) risk level. Let the user reorder or exclude modules.
- Generate specs incrementally — For each prioritized module:
- Create only the relevant
spec/subdirectories (not all are required) - Derive specs from code behavior (contracts, state machines, invariants)
- Mark inferred specs with
[INFERRED]— user must confirm or correct - Ask the user for acceptance criteria that the code does not make explicit
- Create only the relevant
- Create
spec/COVERAGE.md— A living tracker of specification progress:
# Specification Coverage
| Module | Domain | Use Cases | Contracts | NFR | Tests | Status |
|--------|--------|-----------|-----------|-----|-------|--------|
| auth | done | done | done | — | done | SPECIFIED |
| billing| — | partial | — | — | — | IN PROGRESS |
| reports| — | — | — | — | — | PENDING |
Last updated: YYYY-MM-DD
- Integrate with other modes — Mode 1 (Analyze) and Mode 4 (Validate) can run on partial
spec/directories. Downstream skills (sdd-spec-auditor,sdd-plan-architect,sdd-task-generator) should scope their work to modules with statusSPECIFIEDinCOVERAGE.md.
Partial spec tolerance: Not all spec/ subdirectories need to exist. A brownfield project may have spec/contracts/ and spec/domain/ but no spec/workflows/ yet. This is valid — downstream skills must check COVERAGE.md to know which modules are ready.
Specification Folder Structure
CRITICAL: This is the canonical folder structure that ALL downstream skills expect. The folder is spec/ (singular, no 's').
spec/
├── README.md # Navigation table only (Template 18)
├── requirements/ # Do NOT copy REQUIREMENTS.md here: cite ../requirements/REQUIREMENTS.md
├── domain/
│ ├── 01-GLOSSARY.md # Ubiquitous language (terms, definitions)
│ ├── 02-ENTITIES.md # Domain entities with attributes and relationships
│ ├── 03-VALUE-OBJECTS.md # Value objects, enums, typed values
│ ├── 04-STATES.md # State machines for all stateful entities
│ └── 05-INVARIANTS.md # Business rules as formal invariants (INV-XXX-NNN)
├── use-cases/
│ └── UC-NNN-{slug}.md # One file per use case (UC-001, UC-002...)
├── workflows/
│ └── WF-NNN-{slug}.md # Multi-step processes spanning use cases
├── contracts/
│ ├── API-{module}.md # REST/GraphQL API contracts per module
│ ├── EVENTS-{module}.md # Domain events and async contracts
│ └── PERMISSIONS-MATRIX.md # Role-based access control matrix
├── adr/
│ └── ADR-NNN-{slug}.md # One per decision actually taken (Nygard short, Template 6)
├── tests/
│ ├── BDD-UC-NNN.md # BDD scenarios per use case — the only home of AC-NNN-NN
│ └── PROPERTY-TESTS.md # Property-based test specifications
├── nfr/
│ ├── PERFORMANCE.md # Performance targets (p99, throughput)
│ ├── LIMITS.md # Rate limits, quotas, thresholds
│ ├── SECURITY.md # Security requirements and controls
│ └── OBSERVABILITY.md # Logging, metrics, alerting specs
├── runbooks/ # ONLY when a REQ/NFR/ADR requires an operational procedure
│ └── RB-NNN-{slug}.md
├── CLARIFICATIONS.md # Business rules (RN-NNN) from user decisions — the decisions log
├── CLARIFICATIONS-PENDING.md # Open [NEEDS CLARIFICATION] markers (always present)
├── VALUE-REGISTRY.md # Canonical shared values (timeouts, limits, enums)
├── DERIVED-SPECS.md # Tier 1/2 artifacts not directly traced to REQs
├── TRACEABILITY-MATRIX.md # REQ → artifacts, forward table only
└── RESEARCH-QUESTIONS.md # Open technical questions for sdd-plan-architect (only if any)
Folder Structure Rules
- Always
spec/— neverspecs/,specifications/, or any variant - Numbered domain files —
01-GLOSSARY.mdthrough05-INVARIANTS.mdare mandatory - ID-prefixed files — Use cases (
UC-NNN), workflows (WF-NNN), ADRs (ADR-NNN) use sequential numbering - Module-scoped contracts — One API contract per bounded context/module
- CLARIFICATIONS.md at root — Collects all business rules (RN-NNN) from user decisions during specification
Input Requirements
This skill reads requirements/REQUIREMENTS.md (output of sdd-requirements-engineer) as its primary input. If this file does not exist:
- Brownfield path: Ask the user if they have an existing codebase to specify. If yes, activate Mode 5 to derive specs from code. No formal requirements file is needed — specs are inferred from the codebase and confirmed with the user.
- Greenfield path: Recommend running
sdd-requirements-engineerfirst to produce formal requirements before specifying.
When REQUIREMENTS.md exists but only covers part of the system (e.g., new features on an existing codebase), combine Mode 2 (for new requirements) with Mode 5 (for existing code without requirements).
Creating the Structure
mkdir -p spec/{domain,use-cases,workflows,contracts,adr,tests,nfr} — add runbooks/ only when required (§ Output Economy rule 5).
Key Principles (Always Apply)
Ask Before Assuming
NEVER make assumptions silently. Every decision point must be presented to the user with options. Use AskUserQuestion for every ambiguity, gap, or choice. Asking is the main thread's job: in fan-out mode the decisions are collected in Mode 1 / phase A, before the lanes start, and anything a lane discovers comes back as an NC marker in gaps for the main thread to raise in phase D. A lane that cannot ask must never decide instead.
Glossary-First Writing
The glossary (domain/01-GLOSSARY.md) is a controlled vocabulary. Once created, it governs ALL spec writing:
- Before using any domain term in any spec document, verify it exists in the glossary
- If a new term is needed, add it to the glossary FIRST, then use it in spec documents. A lane cannot: it returns the term in
gapsas{"term": "...", "def": "..."}and the main thread appends the glossary row in phase D. The glossary written in phase B must therefore cover all requirements, not just the first ones - Never use synonyms listed in the glossary's "Do not use" ("NO usar") column
- After completing all spec documents, run a final glossary compliance pass with
grep -rniwoverspec/: for each "Do not use" synonym, verify zero occurrences (no re-reading of files)
Value Registry
Before writing specifications, create spec/VALUE-REGISTRY.md (Template 14: one table) listing every shared value (timeouts, limits, rate limits, enum values, thresholds) with its canonical value and the ids that use it. During spec writing, every numeric value or enum used in more than one document MUST be registered and cited by name (TITLE_MAX_LENGTH) in the other documents. This prevents the #1 source of cross-document contradictions.
Traceability is Non-Negotiable
Every specification MUST trace back to one or more requirements. Every requirement MUST have at least one specification. Orphans in either direction must be flagged.
Iterative, Not Waterfall
If issues are found, stop and address them. Do not produce specifications over broken requirements. Better to go back than to build on a weak foundation.
Implementation-Ready, Not Verbose
Each specification must be detailed enough that a developer unfamiliar with the project could implement it correctly without additional clarification. Detail means precise ids, values, schemas and error rows — not prose, restated requirements or explanations of what does not apply.
Leverage Existing Skills
When requirements need modification, explicitly recommend sdd-requirements-engineer and explain how it can help.
Output Economy (Non-Redundancy)
Stage time is almost entirely output tokens (~5k tokens ≈ 1 min): every duplicated fact is paid for twice and later contradicts itself. Rules (per-template shapes in references/document-templates.md § 0):
- One home per fact, ids everywhere else. Requirement text stays in
requirements/REQUIREMENTS.md; UCs, contracts, ADRs, BDD files and matrices citeREQ-F-001(+ at most one clause), never the statement or its acceptance criteria. Same for terms (01-GLOSSARY.md), values (VALUE-REGISTRY.md), error code → message → class → HTTP/exit (error catalog in03-VALUE-OBJECTS.md), rules (INV in05-INVARIANTS.md, RN inCLARIFICATIONS.md), scenarios (tests/BDD-UC-NNN.md, where AC-NNN-NN ids are defined) and decisions (ADR / CLARIFICATIONS — there is no separate decisions log). - Empty =
None.A mandatory section with nothing to say is the single lineNone.; an optional section is omitted. No "not applicable because…" paragraphs, no N/A matrices, no absence justifications (the ADR id is the justification). - Tables, not prose. Never a table plus prose repeating it; a schema block instead of an attribute table; one
Refsrow per document instead of a trailing traceability section plus "business rules" and "invariants" lists; a UC has oneExceptions & errorstable, not exception subsections plus an errors table plus a forcing-function matrix. - Boilerplate once per file. Auth / rate limit / version once per contract, one Errors table per contract with an "Operations" column, no per-actor responsibility table in UCs; exceptions shared by every UC (global handler, storage failure) are described once and cited.
- Runbooks, events and permissions only when the requirements ask for them. Otherwise
runbooks/does not exist andEVENTS-*.md/PERMISSIONS-MATRIX.mdare a one-line absence declaration (Template 20). - Write each file once. Plan ids, invariants and exception rows first (§ Generation Order); never re-open a written file to add a cross-reference, and never re-read written files except through
grepin the Self-Validation Gate. The only sanctioned exceptions are the four phase-D appends (new INV rows, new error-catalog rows, missing glossary terms, resolved RN rows) and targetedEdits that fix a gate failure — both located withgrep -n, never by re-reading the file.
Output Budget
Indicative ceilings in characters (wc -c). Exceeding one by more than 20 % means the document repeats something that already has an id: cut, do not reflow.
| Artifact | Max chars |
|---|---|
use-cases/UC-NNN |
3,500 |
tests/BDD-UC-NNN |
2,500 |
workflows/WF-NNN |
4,000 |
contracts/API-{module} |
6,000 |
adr/ADR-NNN |
1,500 |
domain/ 01 GLOSSARY · 02 ENTITIES · 03 VALUE-OBJECTS · 04 STATES · 05 INVARIANTS |
4,000 · 4,000 · 5,000 · 3,500 · 6,000 |
nfr/*.md (each) |
2,500 |
CLARIFICATIONS.md |
6,000 (≤ 25 RN; +200 per extra RN) |
VALUE-REGISTRY.md · DERIVED-SPECS.md · TRACEABILITY-MATRIX.md |
3,000 · 4,000 · 3,000 |
README.md · RESEARCH-QUESTIONS.md · tests/PROPERTY-TESTS.md |
2,500 · 2,000 · 4,000 |
EVENTS-*.md · PERMISSIONS-MATRIX.md when not applicable |
300 each |
runbooks/RB-NNN (only when required) |
3,000 |
Total: ≤ 120,000 chars for ≤ 15 requirements. Above 15, add 5,000 chars per additional functional requirement (one UC, its BDD file and its share of contract rows). Measure at the end with find spec -name '*.md' -print0 | xargs -0 wc -c | tail -1 and report it as metrics.spec_chars (Persist Summary).
Execution Strategy (read first)
The full protocol is references/fanout-protocol.md. The rules that govern every run:
- Fan-out by default — it is part of this skill's contract, not an optional expansion of scope. Invoking
/sdd-specifications-engineeron more than 4 functional requirements is the explicit request for the requirement lanes: phase C is the bulk of the stage, it is per-requirement, and every id the lanes use was reserved in phase A. Never downgrade to sequential out of caution; downgrade only for the reasons inreferences/fanout-protocol.md§1 (≤ 4 functional REQs,--sequential, Modes 3/4/5, or theAgenttool not in the tool list) and record the reason inmetrics.modeandsummary.highlights. Flags:--fanoutforces the lanes regardless of size;--sequentialforces one thread. - Lanes. One R lane per group of 2–3 functional requirements (grouped by shared entity/module, not by number)
writing only its
use-cases/UC-0NN-*.md+tests/BDD-UC-0NN.md, plus at most one X lane writingnfr/*,adr/ADR-0NN-*.mdandtests/PROPERTY-TESTS.md. At most 4 agents at a time, never nested; more lanes run in waves of 4.subagent_type: general-purpose(neverfork),model: sonnetunlessCLAUDE_CODE_SUBAGENT_MODELis set (then omitmodel). Lanes readrequirements/and the already-written shared documents; they write only their own files, neverspec/contracts/,spec/domain/,spec/workflows/,pipeline-state.json, and they never ask the user, never run Persist Summary or Handoff, never launch subagents. - The id ledger is what makes it safe. Phase A allocates UC ids per requirement (
REQ-F-001 → UC-001..UC-002, andAC-NNN-NNfollows the UC number), everyAPI-{module}-NNoperation id to exactly one lane, the WF step skeletons and the ADR ids. Ids a lane mints carry its lane digit —INV-{AREA}-{L}NN,NC-{L}NN; phase A owns…-0NN— so collisions are impossible by construction and the three-digit grep shape is preserved. Lanes never mintRN-NNN(business rules need a user decision): an unresolved ambiguity becomes anNCmarker returned ingaps. - Cite by id, never copy. A lane references other lanes' artifacts only through ids from the ledger; it never opens another lane's file. This is what keeps cross-references intact, and the Self-Validation Gate verifies them.
- The main thread never re-reads what the lanes wrote. Consolidation, the traceability matrix and the gate run on
the returned JSON plus
grep/wc(budget ≤ ~30 k tokens of spec content). - Compact output. Same § Output Budget for every thread; each lane returns its per-file
wc -cso the main thread never measures by reading.
Generation Order
Shared context first, one pass per requirement, no re-reading of written files. Phases A + B are the shared contract, phase C is the per-requirement work (fanned out above the threshold — § Execution Strategy), phases D + E consolidate.
| Phase | Thread | Write (once) | Source |
|---|---|---|---|
| A. Plan | main, always sequential | Id ledger → .sdd/spec-id-plan.md (outside spec/): REQ → UC ids + titles, AC ranges, WF ids with their numbered step skeleton, contract modules and every API-NNN-NN operation id with its owner, INV areas, ADR ids, RN counter, and — in fanout mode — the lane table with each lane's reserved INV-{AREA}-{L}NN / NC-{L}NN blocks and write-set |
requirements/REQUIREMENTS.md read once + user decisions (Mode 1) |
| B. Shared homes | main, always sequential | domain/01..05 (glossary, entities, value objects + error catalog, states, invariants for all requirements — Step 6b), VALUE-REGISTRY.md, CLARIFICATIONS.md (the RN rows decided in Mode 1 — lanes must be able to cite them) |
Ledger A |
| C. Per module, per requirement | fan-out lanes (or main, sequential) | For each UC: Step 6a in memory → write UC-NNN then BDD-UC-NNN. Lane X writes nfr/* and adr/. Contract operations, new invariants, derived items, gaps and Tier 1 items are returned as JSON, not written. Sequential mode keeps the running lists in context instead |
Ledger A + B on disk — do not re-open written files |
| D. Cross-cutting | main | contracts/API-{module} (from the lanes' ops/errs), WF-NNN (skeleton + wf digests), adr/+nfr/* if there was no lane X, DERIVED-SPECS.md, RESEARCH-QUESTIONS.md, TRACEABILITY-MATRIX.md, README.md, CLARIFICATIONS-PENDING.md, EVENTS-* / PERMISSIONS-MATRIX (one line when N/A). Sanctioned appends (rows only, one Edit each): new INV rows to domain/05-INVARIANTS.md, new error codes to the catalog in domain/03-VALUE-OBJECTS.md, missing terms to domain/01-GLOSSARY.md, resolved gaps as RN rows to CLARIFICATIONS.md |
Returned JSON (fanout) or running lists from C (sequential) |
| E. Gate | main | Self-Validation Gate with grep / wc; fix only what fails; short console table |
spec/ via grep, never cat |
Needs Clarification Markers
When writing specifications, if a requirement is ambiguous and the user is unavailable or the session ends before resolution, embed a clarification marker directly in the spec text.
Marker Format
<!-- [NEEDS CLARIFICATION] NC-NNN: {concise question about the ambiguity} -->
- NC-NNN is three digits. The main thread uses the
NC-0NNblock (NC-001,NC-002, …); in fan-out mode each lane L uses only its reservedNC-{L}NNblock (lane 2 →NC-201,NC-202, …), so two lanes can never mint the same marker. - Place the marker immediately after the ambiguous spec text it refers to.
- Markers are HTML comments so they do not affect rendered output but survive across sessions.
- A marker is never a substitute for asking the user — always prefer
AskUserQuestionfirst. A lane cannot ask: it emits the marker and returns it ingaps, and the main thread asks in phase D.
When to Insert
- The requirement was ambiguous and the user did not provide a decision during the current session.
- A design choice has multiple valid interpretations and no ADR or
CLARIFICATIONS.mdentry covers it. - An external dependency or integration detail is unknown at specification time.
Tracking File: spec/CLARIFICATIONS-PENDING.md
Maintain a living index of all open markers:
# Pending Clarifications
| ID | Document | Question | Inserted | Resolved |
|--------|---------------------------------|-----------------------------------|----------|----------|
| NC-001 | use-cases/UC-005-upload-cv.md | Max file size: 10MB or 25MB? | YYYY-MM-DD | — |
| NC-002 | contracts/API-extraction.md | Retry policy: exponential or fixed? | YYYY-MM-DD | — |
When a marker is resolved in a future session, remove the HTML comment from the spec, move the row's Resolved column to the resolution date, and record the decision in spec/CLARIFICATIONS.md as a business rule (RN-NNN).
Always create this file, even if empty (no pending clarifications). This prevents downstream skills from having to check for file existence:
# Pending Clarifications
| ID | Document | Question | Inserted | Resolved |
|----|----------|----------|----------|----------|
(No pending clarifications)
Pipeline Integration
This skill is Step 2 of the SDD pipeline:
sdd-requirements-engineer → requirements/REQUIREMENTS.md
↓
sdd-specifications-engineer → spec/ (THIS SKILL)
↓
sdd-spec-auditor → audits/AUDIT-BASELINE.md (Mode Audit + Mode Fix)
↓
sdd-plan-architect → plan/
↓
sdd-task-generator → task/
↓
sdd-task-implementer → src/, tests/
Input: requirements/REQUIREMENTS.md (from sdd-requirements-engineer)
Output: Complete spec/ directory with all subdirectories populated
Next step: Run sdd-spec-auditor to validate the generated specifications
Self-Validation Gate
MANDATORY: Before declaring Mode 2 complete and updating pipeline-state.json, the specifications engineer MUST execute the following validation gate. This is NOT optional and NOT a separate mode invocation — it is the final step of Mode 2.
The gate runs on grep / wc output, not on re-reading the generated files (they are already in context from writing them).
Step 0: Fan-out Consolidation Checks (fan-out mode only)
Run before Step 1, on the lanes' JSON and ls / grep — never by opening a file a lane wrote
(references/fanout-protocol.md §7):
- Write set: every file the ledger promised exists and is non-empty;
wc -cwithin § Output Budget. A missing file means a lane failed → relaunch it once, then write it in the main thread and say so inhighlights. - No id collisions: no id appears in two lanes'
ids_used, and the definition-siteuniq -dchecks ofreferences/fanout-protocol.md§7.2 (UC/WF/ADR file names, INV/RN/API rows in their home document only, AC scenario titles, NC markers) all print nothing. A duplicate is a ledger bug: fix the ledger and rewrite the losing file. - No dangling references: the union of
ids_refminus (ids_used∪ phase A/B ids ∪ the ids phase D is about to create) must be empty. - Every id a lane used is inside its reserved block (
INV-{AREA}-{L}NN,NC-{L}NN, its UC / AC / API ranges); an out-of-block id means the lane improvised — verify it before it reaches the matrix.
Step 1: Structural Validation (Mode 4 Auto-Check)
- Extract every cited id once:
grep -rhoE '(UC|WF|ADR|RN|NC)-[0-9]{3}|INV-[A-Z]+-[0-9]{3}|API-[0-9]{3}-[0-9]{2}|AC-[0-9]{3}-[0-9]{2}' spec | sort -u— every id must have a definition (file name, heading or table row); every REQ id inrequirements/REQUIREMENTS.mdmust appear inTRACEABILITY-MATRIX.mdwith at least one artifact - No orphan specifications (every file has a
Refsrow with a REQ or aDERIVED-SPECS.mdrow) grep -rniE 'TBD|TODO|FIXME' spec→ empty; no heading followed directly by another heading (empty section) except sections marked[NEEDS CLARIFICATION], which must be listed inCLARIFICATIONS-PENDING.md
Step 2: Pre-Flight Defect Scan
Detection patterns reference: These checks are derived from
sdd-spec-auditor/references/detection-patterns.md. If available, also load the auditor's grep patterns for CAT-01 (ambiguity words), CAT-04 (glossary synonyms), and CAT-06 (TBD/empty sections) to augment the checks below.
Run these lightweight grep checks against ALL generated spec documents to catch the most common audit findings BEFORE handing off to sdd-spec-auditor:
- Glossary compliance: For every term in
domain/01-GLOSSARY.md"Do not use" column, verify zero occurrences in any spec document. Flag violations. - Value consistency: For every value in
VALUE-REGISTRY.md, grep the number acrossspec/; any document stating a different number for the same metric, or the number without the registry name, is a violation. - BDD coverage: For every UC, verify
tests/BDD-UC-NNN.mdexists with at least one happy-path and one error scenario, and that every AC id cited in the UC is defined there. - Error flow completeness: For every UC, verify the
Exceptions & errorstable has at least one row. Flag UCs with an empty table. - Invariant formalization: Scan all UC text for constraint language ("must", "shall not", "always", "never", "at least", "at most", "between X and Y", "unique", "only if", "requires") that does NOT have a corresponding INV-ID reference. Flag unformalized constraints.
- Cross-reference validity: Verify every
UC-NNN,WF-NNN,INV-XXX-NNN,ADR-NNN,RN-NNNreference resolves to an existing document or section. - API error responses: For every API contract endpoint, verify standard error responses are documented (401 for auth endpoints, 403 for protected endpoints, 404 for resource endpoints, 429 for rate-limited endpoints). Flag missing standard errors.
- Derived specs registration: Verify that ALL artifacts generated by Step 6a (Error Flow Forcing), Step 6b (Invariant Extraction), and Step 6c are registered in
spec/DERIVED-SPECS.mdwith correct Tier classification. Flag any Tier 1 items marked[PENDING REQ]— if >3 exist, alert the user before proceeding.
Step 3: Fix Pre-Flight Findings
If the pre-flight scan finds issues:
- Fix them immediately before completing Mode 2 (these are self-inflicted defects, not user decisions)
- Do NOT ask the user — these are mechanical completeness fixes
- After fixing, re-run only the checks that failed
- In fan-out mode a fix inside a lane's file is a targeted
Editlocated withgrep -n— never a re-read of the file, and never a relaunch of the lane
Step 4: Completion Gate
Mode 2 is complete ONLY when:
- All structural validations pass
- All pre-flight defect scans pass (or remaining issues are marked with
[NEEDS CLARIFICATION]) - The traceability matrix is complete
find spec -name '*.md' -print0 | xargs -0 wc -c | tail -1is within § Output Budget (or the excess is explained in onehighlightsline)
Report the gate to the console as one table (check | result | fixed), not as a document. Only then proceed to update pipeline-state.json.
Persist Summary
After generating all output artifacts, update pipeline-state.json:
- Read
pipeline-state.jsonfrom project root (create if absent with default stage structure) - Set
stages["specifications-engineer"].status="done" - Set
stages["specifications-engineer"].lastRun= current ISO-8601 - Set
stages["specifications-engineer"].summary:artifacts: list of files created inspec/with labels (e.g.,{"file": "spec/use-cases/UC-001.md", "label": "Extract PDF"})metrics:{ "use_cases": N, "workflows": N, "api_contracts": N, "bdd_scenarios": N, "invariants": N, "adrs": N, "spec_chars": N, "spec_budget_chars": N, "mode": "fanout" | "sequential", "spec_agents": N }—spec_charsfrom the finalwc -coverspec/**/*.md(or the sum of the lanes' reportedcharsplus the main thread's own files),spec_budget_charsfrom § Output Budget,modeandspec_agentsfrom § Execution Strategy (spec_agents= lanes actually launched, 0 in sequential mode)highlights: top 3-5 notable observations (e.g., "41 use cases across 8 domains", "55 invariants defined", "spec/ 98k chars, within the 120k budget"). Whenmodeissequentialabove the threshold, the first highlight is the reason for the downgrade (--sequential, noAgenttool, Mode 3/4/5, a lane that failed twice)nextStep:"Run /sdd-spec-auditor"generatedAt: current ISO-8601
- Write updated
pipeline-state.json - Display summary table to user (console output)
- Handoff: follow the plugin-root
references/handoff-protocol.md(only in station mode; never from a subagent).
Output Language
Respond in the same language the user uses. If the user writes in Spanish, respond in Spanish. If in English, respond in English.