TypeScript-first specification validation framework — validate design consistency and external SSOT integrity with full traceability.
Requirements and design documents often drift from implementation. speckeeper treats specifications as code — type-safe, version-controlled, and continuously validated against your actual artifacts (tests, OpenAPI, DDL, IaC).
Mermaid flowchart ──► speckeeper scaffold ──► design/_models/
│
design/*.ts ─────────────────────────────► Validation & Consistency Checks
│
├─► speckeeper lint → Design integrity (IDs, references, phase gates)
├─► speckeeper check → External SSOT validation (test coverage, etc.)
└─► speckeeper impact → Change impact analysis with traceability
- TypeScript as SSOT — Define requirements, architecture, and design in type-safe TypeScript
- Design validation — Lint rules for ID uniqueness, reference integrity, circular dependencies, and phase gates
- External SSOT validation — Check consistency with test files, and custom checkers for OpenAPI, DDL, etc.
- Traceability — Track relationships across model levels (L0-L3) with impact analysis
- Scaffold from Mermaid — Generate
_models/skeletons from a mermaid flowchart with class-based artifact resolution - Custom models — Extend with domain-specific models (Runbooks, Policies, etc.)
- CI-ready — Built-in lint, drift detection, and coverage checks
npm install speckeeper
# Verify installation
npx speckeeper --helpCreate a Markdown file (e.g. requirements.md) containing a mermaid flowchart that describes the relationships between your specification entities:
flowchart TB
subgraph L0[Business]
UC[Use Cases]
TERM[Glossary]
end
subgraph L1[Requirements]
FR[Functional Requirements]
NFR[Non-Functional Requirements]
end
subgraph External[External Artifacts]
API[OpenAPI Spec]
DDL[Database Schema]
UT[Unit Tests]
end
FR -->|refines| UC
FR -->|implements| API
FR -->|verifiedBy| UT
FR -->|implements| DDL
class UC,TERM,FR,NFR speckeeper
class FR,NFR requirement
class UC usecase
class TERM term
class API openapi
class DDL sqlschema
class UT test
Key concepts:
class ... speckeepermarks nodes as managed by speckeeper- Additional
classlines assign artifact classes (determines model name/file and node grouping) - External node classes (
openapi,sqlschema,test) determine checker bindings subgraphdetermines model level (L0–L3)implementsedges trigger external SSOT validationverifiedByedges trigger test verification
npx speckeeper scaffold --source requirements.mdThis generates:
design/_models/— Model classes with base schema (id, name, description, relations) and core factory imports. Customise after generation.design/*.ts— Spec data files usingdefineSpecs()design/index.ts— Entry point viamergeSpecs()- Checker bindings from
implements/verifiedByedges are added as guidance comments
See Scaffold Mermaid Specification for the full input format.
Edit spec data files in design/ to add your actual specification data. Each file uses defineSpecs() to pair Model instances with data:
// design/requirements.ts
import { defineSpecs } from 'speckeeper';
import type { Requirement } from './_models/requirement';
import { FunctionalRequirementModel } from './_models/requirement';
const requirements: Requirement[] = [
{
id: 'FR-001',
name: 'User Authentication',
type: 'functional',
description: 'Users can authenticate using email and password',
priority: 'must',
acceptanceCriteria: [
{ id: 'FR-001-01', description: 'Valid credentials grant access', verificationMethod: 'test' },
{ id: 'FR-001-02', description: 'Invalid credentials show error', verificationMethod: 'test' },
],
},
];
export default defineSpecs(
[FunctionalRequirementModel.instance, requirements],
);design/index.ts aggregates all spec files, and speckeeper.config.ts imports the result — no manual wiring needed beyond adding your spec file to design/index.ts.
# Validate design integrity
npx speckeeper lint
# Check test coverage against requirements
npx speckeeper check test --coverage
# Analyze change impact
npx speckeeper impact FR-001Alternative:
npx speckeeper initcreates a minimal project with generic starter templates. Use this if you prefer to build models from scratch. See Model Definition Guide for details.
| Command | Description |
|---|---|
speckeeper init |
Initialize a new project with starter templates |
speckeeper lint |
Validate design integrity (ID uniqueness, references, phase gates) |
speckeeper check |
Verify consistency with external SSOT |
speckeeper check test --coverage |
Verify test coverage for requirements |
speckeeper scaffold |
Generate model skeletons from a mermaid flowchart |
speckeeper drift |
Detect manual edits to generated specs/ files |
speckeeper impact <id> |
Analyze change impact for a specific element |
Note: speckeeper build generates machine-readable specs/ output. For human-readable docs (docs/), use embedoc or similar tools with the model rendering API.
$ npx speckeeper lint
speckeeper lint
Design: design/
Loaded: 17 files
Running lint checks...
✓ No issues foundChecks include:
- ID uniqueness — No duplicate IDs within model types
- ID conventions — Enforce naming patterns (e.g.,
FR-001,COMP-AUTH) - Reference integrity — All referenced IDs must exist
- Circular dependency detection — Prevent reference loops
- Phase gates — Ensure TBD items are resolved by target phase
- Custom lint rules — Define model-specific validation
Validate your specifications against actual implementation artifacts. speckeeper provides built-in checker factories via speckeeper/dsl:
| Factory | Target | Validates |
|---|---|---|
testChecker() |
Test code | Test file existence + spec ID references in describe/it/test blocks |
externalOpenAPIChecker() |
OpenAPI spec | Spec ID existence (operationId, path, schema, x-spec-id), HTTP method, parameter/response property names and types |
externalSqlSchemaChecker() |
SQL schema | Table existence, column existence, type containment (DDL type must be equal or wider than spec type) |
relationCoverage() |
Cross-model | Coverage of a target model via relations |
Assign a checker to a model's externalChecker property. Scaffold emits guidance comments showing which factory to use based on your implements / verifiedBy edges.
// design/_models/requirement.ts
import { testChecker } from 'speckeeper/dsl';
class RequirementModel extends Model<typeof RequirementSchema> {
// ... schema, lintRules, etc.
protected externalChecker = testChecker<Requirement>();
}$ npx speckeeper check test --coverage
speckeeper check
Design: design/
Type: test
✓ All checks passed
Coverage: Requirement → UseCase
Coverage: 100% (7/7 use cases covered)You can also implement custom checkers for any external source by defining an ExternalChecker<T> directly. See Model Definition Guide for details.
speckeeper organizes models by abstraction level:
| Level | Focus | Examples |
|---|---|---|
| L0 | Business + Domain (Why) | UseCase, Actor, Term |
| L1 | Requirements (What) | Requirement, Constraint |
| L2 | Design (How) | Component, Entity, Layer |
| L3 | Implementation (Build) | Screen, APIRef, TableRef |
Relations between models enable impact analysis:
$ npx speckeeper impact FR-001
FR-001 (Requirement)
├── implements: COMP-AUTH (Component)
├── satisfies: UC-001 (UseCase)
└── verifiedBy: TEST-001 (TestRef)| Relation | Direction | Description |
|---|---|---|
implements |
spec→external | Spec is implemented as external artifact (OpenAPI, DDL) |
verifiedBy |
spec→test | Spec is verified by external test code |
satisfies |
L1→L0 | Satisfies a use case |
refines |
Same level or lower | Refinement |
verifies |
test→implementation | Test verifies implementation code (external, no checker) |
dependsOn |
None | Dependency |
relatedTo |
None | Association |
See Model Entity Catalog for full details on relation types and level constraints.
Scaffolded models provide a base schema (id, name, description, relations). You can customize them or add new domain-specific models using core factory functions from speckeeper/dsl:
import { z } from 'zod';
import { Model, RelationSchema } from 'speckeeper';
import type { LintRule, Exporter, ModelLevel } from 'speckeeper';
import { requireField, arrayMinLength } from 'speckeeper/dsl';
const RunbookSchema = z.object({
id: z.string(),
name: z.string().min(1),
description: z.string(),
severity: z.enum(['critical', 'high', 'medium', 'low']),
steps: z.array(z.object({
action: z.string(),
verification: z.string().optional(),
})).min(1),
relations: z.array(RelationSchema).optional(),
});
type Runbook = z.input<typeof RunbookSchema>;
class RunbookModel extends Model<typeof RunbookSchema> {
readonly id = 'runbook';
readonly name = 'Runbook';
readonly idPrefix = 'RB';
readonly schema = RunbookSchema;
readonly description = 'Incident runbooks';
protected modelLevel: ModelLevel = 'L3';
protected lintRules: LintRule<Runbook>[] = [
requireField<Runbook>('description', 'error'),
arrayMinLength<Runbook>('steps', 1),
];
protected exporters: Exporter<Runbook>[] = [];
}Core DSL factories (speckeeper/dsl) include requireField, arrayMinLength, idFormat, childIdFormat, markdownExporter, testChecker, externalOpenAPIChecker, externalSqlSchemaChecker, relationCoverage, and baseSpecSchema.
- Model Definition Guide — Start here for model customization and API reference
- Framework Requirements Specification — Detailed feature specifications
- Model Entity Catalog — Model hierarchy and relation types
- Node.js >= 20.0.0
- TypeScript >= 5.0
# Install dependencies
npm install
# Run tests
npm test
# Lint
npm run lint
npm run lint:design
# Full CI check
npm run ciMIT