← Back to home

The .loom/ artifact directory

Every ddd generate system run emits, alongside the per-deployable project trees, a .loom/ directory at the output root containing derived artefacts — JSON / Markdown / Mermaid / C4 files the generator produces for tooling and review, not for runtime consumption.

<outdir>/
├── docker-compose.yml
├── docker-compose.obs.yml   # opt-in observability overlay (see docs/observability.md)
├── monitoring/prometheus.yml
├── db-init/
├── <deployable-1>/
├── <deployable-2>/
├── ...
└── .loom/
    ├── manifest.json            # what this run emitted — the next run prunes against it
    ├── wire-spec.json
    ├── messages.en.json
    ├── domain.mmd
    ├── workflows.mmd
    ├── er.mmd
    ├── sequence.mmd
    ├── deployment.mmd
    ├── architecture.c4
    ├── datasources.md
    ├── traceability.md
    ├── traceability-matrix.md
    ├── traceability.mmd
    ├── traceability.json
    ├── coverage.md
    ├── gaps.md
    ├── verification.json        # written by `ddd verify`
    ├── verification.md          # written by `ddd verify`
    ├── sourcemap.json           # opt-in, only under `generate system --sourcemap`
    └── snapshots/
        └── <ts>-<guid>.loomsnap.json               # provenance rule captures

None of the files in .loom/ ship to runtime; they are review and tooling output. Check them into the project alongside the generated code if you want pull-request-time diff visibility on wire contracts, traceability coverage, or migration baselines.

Regeneration bookkeeping

File Producer What it is
manifest.json src/system/manifest.ts, written by the CLI write phase (src/cli/main.ts, phase ⑩) Every path this run emitted, sorted, with a scaffoldOnce flag on the files the user takes ownership of. This is how regeneration deletes. On the next run, a path the previous manifest lists and the current run does not emit is stale and is removed — so renaming an operation or a page no longer leaves a dead CommentHandler.cs / board.tsx behind to break the build. The prune is deliberately narrow: a file with no manifest entry (every hand-written file) is structurally unreachable, and .loomignored paths, scaffold-once files, migration files, and .loom/snapshots/ are all spared. An absent or unreadable manifest degrades to "prune nothing". Check it in — that is what makes the prune work on a teammate's clone.

Wire contract

File Producer What it is
wire-spec.json src/system/wire-spec.ts (phase ⑨) JSON-Schema-shaped derivation from every aggregate / part / value object's wireShape. Language-agnostic; the canonical source of truth for what the JSON over the wire looks like. Diffable — wire-contract drift between regens shows up as a clean JSON diff. Carries the CONSTRAINTS the drift check needs, not just carrier types: an enum field publishes its declared members ({"type":"string","enum":["New","Qualified"]}, in declaration order, resolved in the referring context), so removing an enum value — a breaking change — moves the file instead of leaving it byte-identical.

i18n catalog

File Producer What it is
messages.en.json src/system/i18n-catalog.ts (phase ⑨) Source-language (English) message catalog — every user-visible string extracted from the system's UIs, as a flat, key-sorted { key: message } object. Keys are content-hashed (page.<Page>.<role>.<hash> / component.<Comp>.<role>.<hash> / menu.<role>.<hash>, D-I18N-KEY) so the catalog is reorder-invariant and a rephrase re-keys cleanly (delete-old + add-new). The diff surface a future ddd i18n sync merges each locale against (M-T1.11, docs/old/proposals/i18n.md). This slice extracts plain string literals only — interpolated strings ("Order ${o.id}") await the template→ICU lowering slice. Extraction: src/generator/_walker/i18n-extract.ts.

Storage routing

File Producer What it is
datasources.md src/system/datasources.ts → renderDataSourcesMd Per-system Markdown view of how resource declarations route domain contexts to physical storage. Two sections: per-deployable routing (context → kind → storage with effective schema / table-prefix), and per-storage usage roll-up. Catches accidental "primary" sharing and unused bindings at PR-review time.

Diagrams

File Producer What it is
domain.mmd src/system/mermaid.ts → renderDomainDiagram Mermaid class diagram of every aggregate, value object, enum, and event in the system, with containments and X id references drawn as relationships.
er.mmd src/system/mermaid.ts → renderErDiagram Mermaid entity-relationship diagram of every persisted aggregate + part — schema-shaped (PK / FK / columns), not class-shaped.
workflows.mmd src/system/mermaid.ts → renderWorkflowDiagram One Mermaid flowchart per workflow, showing the create / load / mutate / emit steps.
sequence.mmd src/system/mermaid.ts → renderSequenceDiagram Mermaid sequence diagram of an operation lifecycle (client → route → repository → DB → events).
deployment.mmd src/system/mermaid.ts → renderDeploymentDiagram Mermaid deployment diagram of the system's deployables, their target backends, and their shared storage.
architecture.c4 src/system/likec4.ts → renderC4Model LikeC4 model of the system at C4 levels 1–3 (context, container, component). Renderable in the LikeC4 viewer / VS Code extension.

Traceability

File Producer What it is
traceability.md src/system/traceability.ts → renderTraceabilityDoc Per-requirement Markdown index: each requirement block with its linked solutions, testCases, and the runnable test / test e2e that verifies each test case.
traceability-matrix.md src/system/traceability.ts → renderMatrix Two-axis matrix view (requirement × test case).
traceability.mmd src/system/traceability.ts → renderTraceabilityDiagram Mermaid graph of the requirement → solution → testCase → test graph.
traceability.json src/system/traceability.ts → renderTraceabilityJson Machine-readable form of the same graph (for CI gating, custom reports).
coverage.md src/system/traceability.ts → renderCoverageReport Per-solution and per-requirement coverage roll-up.
gaps.md src/system/traceability.ts → renderGapsReport Inverse of coverage — requirements with no solution, solutions with no test case, test cases with no test.
verification.json ddd verify (src/cli/main.ts) Join of the requirements graph with a JSON of test results — every requirement gets a VERIFIED / FAILING / UNVERIFIED / UNTESTED verdict.
verification.md ddd verify Human-readable companion to verification.json.

See traceability.md for the surface that populates these.

Snapshots

snapshots/ carries the immutable provenance captures:

Pattern Producer What it is
<ts>-<guid>.loomsnap.json ddd snapshot (src/system/loomsnap.ts) Provenance rule snapshot. One immutable timestamped+GUID file per system; captures the rule snapshots for every provenanced field. The latest such file is the one the generated runtime loads at startup. See provenance.md.

They are only written by the explicit ddd snapshot sub-command — never by generate.

Migration state is not under -o

.loom/ holds no migration state. The migration history is the committed migrations/ directory beside the .ddd — recorded by ddd migrate add, rendered by every generate system — so an output tree can be deleted and regenerated anywhere. See migrations.md § The migration chain.

Source map (opt-in)

sourcemap.json is the one artifact not written by default — it lands only when generate system is passed --sourcemap. Emitted by src/system/sourcemap.ts from an Origin spine that all five backends thread through their emitters, it maps each generated line back to the .ddd construct — and, for operation bodies, the .ddd statement — it came from, at both construct and statement granularity.

Its consumer is ddd trace <logfile>: given a runtime stack-trace from a generated backend, it rewrites each frame to point at the originating .ddd source line, so a failure in the generated code reads against the model the author actually wrote. See tools.md for the CLI.

Note that "opt-in" is about the artifact, not the recorder. The web playground records the map on every system generate and reads it in memory — that is what powers its source ↔ output correspondence (playground.md) — while still passing the flag off, so the emitted tree it shows and downloads stays byte-identical. The distinction is possible because the Source Map v3 / JSR-45 sidecars (and the trailing sourceMappingURL directives they add to the emitted .ts) are gated on sourceTexts, not on the recorder: with a recorder and no sourceTexts, the only addition to the emission is sourcemap.json itself.

What .loom/ is NOT

Cross-references