A language-agnostic CLI tool that enforces traceability from requirements through specifications to tests, with 18 machine-verified invariants.
go install github.com/mafron/tdm/cmd/tdm@latestOr build from source:
git clone https://github.com/mafron/tdm.git
cd tdm
go build -o tdm ./cmd/tdm/Initialize TDM in your project:
tdm init --level 2This creates .tdm.yaml, ADR template, and spec ledgers. Levels 0–4 control how much structure to scaffold (see Adoption Levels).
Add requirements and specs to the YAML ledgers, then add Verifies: directives to your tests:
// Verifies: SPEC-001
func TestUserCreation(t *testing.T) { ... }Run checks:
tdm check # Traceability invariants
tdm lint-adr # ADR format validationtdm Dashboard (project health summary)
tdm check [--strict] Run traceability invariant checks
tdm lint-adr Validate ADR format
tdm req [ID] List/filter requirements or show detail
tdm spec [ID] List specs or show detail
tdm des [ID] List designs or show detail
tdm adr [N] [--graph] List ADRs, show detail, or dependency graph
tdm matrix [--phase N] Traceability matrix (REQ x SPEC x Test)
tdm work [NAME] Work package list or detail
tdm impact FILE Change impact analysis (file -> SPEC -> REQ)
tdm snapshot Save metrics snapshot to JSONL
tdm lint-work [NAME] Validate work package structure
tdm lint-commits Validate commit trailers (--range REV..REV)
tdm lint-docs Validate CLI reference docs against commands
tdm mutation-diff Diff gremlins report against accepted-mutant baseline
tdm coverage Coverage per package (--gate) or per ledger entry (--by-design)
tdm serve [--port N] Start web dashboard (127.0.0.1:8080; --host to expose)
tdm json Dump all data as JSON
tdm init [--level N] Initialize TDM in a project
tdm version Show version
tdm serve --port 8080Opens a local web UI with nine views: dashboard, requirements, specs, designs, ADRs (with SVG dependency graph), traceability matrix, work packages, impact analysis, and metrics (with SVG trend chart). All views support ?format=json for programmatic access.
Requirement, spec, and design detail pages render the entry's description and the prose behind each source / design_ref reference, and link to the source of every test and implementation file. A file is viewable only if TDM already derived it — a ledger reference target, or a file the scanner linked via Verifies: / Implements: (ADR-0019).
The dashboard binds 127.0.0.1 and has no authentication. --host 0.0.0.0 exposes it — every requirement, spec, ADR, and linked source file — to anyone who can reach the port.
Requirements (REQ-F/N-NNN)
|
| requirements[] (N:M)
v
Specifications (SPEC-NNN)
|
| "Verifies: SPEC-NNN" directive
v
Tests
tdm check enforces 18 rules, grouped by domain:
- Chain (REQ → SPEC → Test) — orphan-spec, uncovered-req, untested-spec, dangling-test-ref, duplicate-id, bad-id-format, manual-without-procedure
- Bidirectional (code → SPEC) — unimplemented-spec, dangling-impl-ref, unlinked-source
- Design layer (DES) — orphan-design, untested-design, unimplemented-design, granularity-gap, design-bypass
- References & work packages — broken-design-ref, adr-dangling-enforces, planned-without-work
--strict additionally applies untested-* to planned entries (unless an in-progress work package claims them) and upgrades design-bypass / planned-without-work from warning to error.
A ledger entry records why it exists, not just that it does. Requirements, specs, and designs each take an optional description — the irreducible rationale, in your words, held next to the entry it explains. Rationale that outgrows a sentence lives in a document, and the entry points at it:
- id: REQ-F-001
title: Traceability chain enforcement
description: >
Why this requirement exists, in prose.
source: [docs/methodology.md#Traceability] # long-form rationaletdm req <ID>, tdm spec <ID>, tdm des <ID> and the dashboard render both: the inline prose, and the section under the referenced heading — the reference is a way to read the document, not merely an assertion that it exists.
The ledger loader is strict (ADR-0019): a key the model cannot represent is a load error naming the file and the key, not a silent drop. A misspelled descriptoin: fails loudly rather than vanishing.
Place immediately before the test function in any supported language:
| Language | Syntax |
|---|---|
| Go | // Verifies: SPEC-001 |
| Python | # Verifies: SPEC-001 |
| TypeScript/JS | // Verifies: SPEC-001 |
| Rust | // Verifies: SPEC-001 |
| Ruby | # Verifies: SPEC-001 |
Multiple SPECs: // Verifies: SPEC-001, SPEC-002
| Level | Name | What You Get |
|---|---|---|
| L0 | Foundation | .tdm.yaml config |
| L1 | Decisions | ADR directory + template |
| L2 | Specifications | YAML ledgers + Verifies: directives |
| L3 | Work Packages | docs/work/ + work.yaml manifest guide + progress tracking |
| L4 | Full Process | Agent workflow assets (tdm-work / tdd-workflow skills, CLAUDE.md) |
A work package is a single data manifest (ADR-0010): specifications live in the ledger, decisions in ADRs, and the package only bundles references plus task progress.
# docs/work/<name>/work.yaml
id: <name> # equals the directory name
branch: feature/<name>
status: in-progress # planned | in-progress | completed
specs: [SPEC-001] # registered as 'planned' at work start
designs: [DES-001]
adrs: [ADR-0001]
tasks:
- {id: T-1, title: First task, status: todo} # todo | done
notes: |
Irreducible background only.tdm lint-work validates manifests against the ledger (unknown references, status consistency, task ID uniqueness). Planned entries claimed by an in-progress package pass tdm check --strict; completion flips everything in one batch. Directories without work.yaml are legacy archives (spec.md / plan.md / status.yaml) linted under the old rules.
.tdm.yaml at project root:
# Core: where traceability data lives
ledger_dir: docs/ledger
adr_dir: docs/adr
# Scanner: where and how to find test links
source_dirs: [internal, cmd, src, lib]
test_patterns:
- "*_test.go"
- "test_*.py"
- "*.test.ts"
# Extensions (omit to disable)
work_dir: docs/work
# commit_trailer_pattern: "\\[spec:(\\S+)\\s+task:(\\S+)\\]"- Methodology Guide — Full conceptual model, processes, and adoption guide
- Templates in
cmd/tdm/templates/— embedded intotdm init(ADR-0011): CLAUDE.md, ADR template, tdm-work / tdd-workflow skills
MIT