Single Source of Truth
One .moment file drives your types, tests, documentation, and visualizations. No more scattered domain knowledge.
Moment is the first toolchain that lets you model, simulate, and validate
domain flows before writing a single line of implementation.
Write a .moment specification, generate simulation scenarios,
and visualize them with Facet — then generate typed TypeScript, tests,
docs, and API contracts from the same source of truth.
In every other engineering discipline, you validate the design before building. In DDD and Event Sourcing, you go from whiteboard directly to implementation. There is no way to simulate event flows, validate crossing contracts, or test saga orchestration before writing code. Until now.
Your model lives in the wiki, the types, the tests, the docs, the API spec, and someone's head. Six representations that diverged on day two. No tool connects them.
You test individual commands. You test queries. But the temporal flows between bounded contexts — where events cross boundaries, contracts break, and sagas fail — are never tested.
One specification replaces seven manually maintained artifacts.
order.types.ts — hand-written interfacesmanualorder.aggregate.ts — manual aggregate classmanualorder.spec.ts — test stubs from scratchmanualorder.feature — Gherkin written by handmanualorder-spec.md — docs that driftdriftsorder-api.yaml — maintained separatelydriftsfacet.json — simulation scenariosn/aorder.moment You write this — the single source of truth $ moment generate --all $ moment simulate order.types.ts — typed interfacesgeneratedorder.aggregate.ts — aggregate contractsgeneratedorder.spec.ts — crossing assertionsgeneratedorder.feature — BDD with flowsgeneratedorder-spec.md — Mermaid diagramsgeneratedorder-api.yaml — AsyncAPI 3.0generatedfacet.json — simulation scenariosgeneratedFrom specification to production-ready artifacts in four deterministic stages.
Write your domain specification with flows and crossings. Moment generates typed code, tests, docs, and API contracts.
context "Ordering" [Core]
aggregate "Order"
identity orderId: UUID
command PlaceOrder
input customerId: UUID, items: OrderItem[]
precondition orderNotPlaced: "Order has not already been placed"
emits OrderPlaced
command CancelOrder
input orderId: UUID, reason: string
precondition orderNotShipped: "Order must not have been shipped"
emits OrderCancelled
event OrderPlaced
orderId: UUID
customerId: UUID
items: OrderItem[]
placedAt: DateTime
event OrderCancelled
orderId: UUID
reason: string
cancelledAt: DateTime
value-object OrderItem
productId: UUID
quantity: number
unitPrice: Money
invariant ORD-01 "Order must contain at least one item"
scope Order
context "Fulfillment" [Supporting]
aggregate "FulfillmentRequest"
identity fulfillmentId: UUID
command InitiateFulfillment
input orderId: UUID, items: OrderItem[]
emits FulfillmentInitiated
event FulfillmentInitiated
fulfillmentId: UUID
orderId: UUID
items: OrderItem[]
initiatedAt: DateTime
value-object OrderItem
productId: UUID
quantity: number
unitPrice: Money
flow "order-placed"
description "Order submission triggers fulfillment"
lane ordering "Ordering" [Core]
lane fulfillment "Fulfillment" [Supporting]
moment "Order submission"
ordering: PlaceOrder
ordering: OrderPlaced crosses-to fulfillment via CustomerSupplier
contract
orderId: UUID [required]
items: OrderItem[] [required]
moment "Fulfillment initiation"
fulfillment: InitiateFulfillment
triggered-by OrderPlaced
fulfillment: FulfillmentInitiated// Generated by @mmmnt/emit-ts
// ── Ordering Context ──
export type OrderEvent =
| OrderPlaced
| OrderCancelled;
export interface OrderPlaced {
readonly _tag: 'OrderPlaced';
readonly orderId: UUID;
readonly customerId: UUID;
readonly items: readonly OrderItem[];
readonly placedAt: DateTime;
}
export interface OrderCancelled {
readonly _tag: 'OrderCancelled';
readonly orderId: UUID;
readonly reason: string;
readonly cancelledAt: DateTime;
}
export interface OrderItem {
readonly productId: UUID;
readonly quantity: number;
readonly unitPrice: Money;
}
export interface PlaceOrderInput {
readonly customerId: UUID;
readonly items: readonly OrderItem[];
}
/** @precondition orderNotPlaced — Order has not already been placed */
export interface OrderAggregate {
placeOrder(input: PlaceOrderInput): OrderPlaced;
cancelOrder(input: CancelOrderInput): OrderCancelled;
}
// ── Fulfillment Context ──
export type FulfillmentRequestEvent =
| FulfillmentInitiated;
export interface FulfillmentInitiated {
readonly _tag: 'FulfillmentInitiated';
readonly fulfillmentId: UUID;
readonly orderId: UUID;
readonly items: readonly OrderItem[];
readonly initiatedAt: DateTime;
}// Generated by @mmmnt/emit-ts — Test Scaffold
import { describe, it, beforeEach } from 'vitest';
describe('Flow: order-placed', () => {
describe('Order submission', () => {
it('should execute PlaceOrder in Ordering', () => {
// Setup: precondition "orderNotPlaced" must hold
// Assert: OrderPlaced is emitted
// TODO: implement command execution
});
it('should verify OrderPlaced crosses from Ordering to Fulfillment', () => {
// Crossing: Ordering → Fulfillment via CustomerSupplier
// Contract fields:
// orderId: UUID (required)
// items: OrderItem[] (required)
// TODO: assert contract compliance
});
});
describe('Fulfillment initiation', () => {
beforeEach(() => {
// triggered-by: OrderPlaced
// Ensure OrderPlaced has been emitted
});
it('should execute InitiateFulfillment triggered by OrderPlaced', () => {
// Assert: FulfillmentInitiated is emitted
// TODO: implement command execution
});
});
});
describe('Ordering / Order aggregate', () => {
it('should enforce invariant ORD-01: Order must contain at least one item', () => {
// Reject PlaceOrder when items is empty
// TODO: implement invariant assertion
});
});# Generated by @mmmnt/generate
@flow:order-placed
Feature: Order submission triggers fulfillment
@context:Ordering @classification:Core
Rule: Ordering [Core]
Background:
Given precondition "orderNotPlaced" holds:
| Order has not already been placed |
@happy-path
Scenario: Order submission
When Ordering executes PlaceOrder with:
| customerId | <UUID> |
| items | <OrderItem[]> |
Then Ordering emits OrderPlaced
@crossing
Scenario: OrderPlaced crosses to Fulfillment
Given Ordering has emitted OrderPlaced
Then OrderPlaced crosses to Fulfillment via CustomerSupplier
And the crossing contract contains:
| orderId | UUID | required |
| items | OrderItem[] | required |
@context:Fulfillment @classification:Supporting
Rule: Fulfillment [Supporting]
Scenario: Fulfillment initiation
Given OrderPlaced has been received
When Fulfillment executes InitiateFulfillment
triggered-by OrderPlaced
Then Fulfillment emits FulfillmentInitiated
@invariant
Scenario: Invariant ORD-01 — Order must contain at least one item
When Ordering executes PlaceOrder with:
| items | [] |
Then the command is rejected
And invariant ORD-01 is violatedGenerated by @mmmnt/generate
| Context | Classification | Aggregates | Commands | Events |
|---|---|---|---|---|
| Ordering | Core | 1 | 2 | 2 |
| Fulfillment | Supporting | 1 | 1 | 1 |
graph LR
Ordering["Ordering\n[Core]"]
Fulfillment["Fulfillment\n[Supporting]"]
Ordering -->|CustomerSupplier| Fulfillment
Order submission triggers fulfillment
sequenceDiagram
participant O as Ordering [Core]
participant F as Fulfillment [Supporting]
Note over O: Order submission
O->>O: PlaceOrder
O->>F: OrderPlaced (CustomerSupplier)
Note over O,F: contract: orderId, items
Note over F: Fulfillment initiation
F->>F: InitiateFulfillment (triggered-by OrderPlaced)
F->>F: FulfillmentInitiated
| Source | Target | Event | Relationship | Required Fields |
|---|---|---|---|---|
| Ordering | Fulfillment | OrderPlaced | CustomerSupplier | orderId, items |
Order (identity: orderId)
FulfillmentRequest (identity: fulfillmentId)
# Generated by @mmmnt/generate
asyncapi: '3.0.0'
info:
title: Order Placement
version: '1.0.0'
description: >-
Event-driven contract for the order-placed flow.
Ordering emits OrderPlaced; Fulfillment consumes it.
channels:
order-placed:
address: ordering.order-placed
messages:
OrderPlaced:
$ref: ' 1
operations:
publishOrderPlaced:
action: send
channel:
$ref: '#/channels/order-placed'
summary: Ordering publishes OrderPlaced on order submission
components:
messages:
OrderPlaced:
name: OrderPlaced
title: Order Placed Event
summary: Emitted when a new order is placed
payload:
type: object
required:
- orderId
- items
properties:
orderId:
type: string
format: uuid
customerId:
type: string
format: uuid
items:
type: array
items:
$ref: '#/components/schemas/OrderItem'
placedAt:
type: string
format: date-time
schemas:
OrderItem:
type: object
properties:
productId:
type: string
format: uuid
quantity:
type: number
unitPrice:
type: number// Generated by @mmmnt/derive — Facet Simulation Scenario
{
"scenarioId": "order-placed-happy-path",
"scenarioLabel": "Order Placement — Happy Path",
"description": "Order submission triggers fulfillment",
"given": "An order is ready to be placed",
"when": "PlaceOrder is executed in Ordering",
"then": "OrderPlaced crosses to Fulfillment and InitiateFulfillment is triggered",
"expectedPath": [
"moment:order-submission",
"moment:fulfillment-initiation"
],
"activeBranches": [],
"events": [
{
"eventId": "evt-001",
"eventType": "OrderPlaced",
"productSource": "moment",
"causationEventIds": [],
"correlationId": "corr-order-placed-001",
"timestamp": "2026-01-15T10:00:00.000Z",
"version": "1.0.0",
"payload": {
"orderId": "ord-abc-123",
"customerId": "cust-def-456",
"items": [
{ "productId": "prod-001", "quantity": 2, "unitPrice": 29.99 }
],
"placedAt": "2026-01-15T10:00:00.000Z"
}
},
{
"eventId": "evt-002",
"eventType": "FulfillmentInitiated",
"productSource": "moment",
"causationEventIds": ["evt-001"],
"correlationId": "corr-order-placed-001",
"timestamp": "2026-01-15T10:00:01.000Z",
"version": "1.0.0",
"payload": {
"fulfillmentId": "ful-ghi-789",
"orderId": "ord-abc-123",
"items": [
{ "productId": "prod-001", "quantity": 2, "unitPrice": 29.99 }
],
"initiatedAt": "2026-01-15T10:00:01.000Z"
}
}
]
}
Moment is the first tool that bridges specification and implementation with
a simulation layer. Generate Facet-compatible scenarios from your .moment
file, then visualize event flows, causation chains, and branch paths —
all before you write a single aggregate class.
Write your .moment file with contexts, aggregates,
flows, crossings, and branches.
.moment
Run moment simulate to generate scenarios
with synthetic events, causation chains, and branch paths.
facet.json See your domain flows rendered as interactive timelines. Validate event causation, crossing contracts, and saga states — before any implementation exists.
Facet Now generate typed code, tests, and docs. Your implementation conforms to a domain model that's already been validated.
.ts .spec.ts .feature .md No tool in the DDD or Event Sourcing ecosystem lets you simulate and visually validate event flows, crossing contracts, and saga orchestration from a specification — before you write implementation code. Moment + Facet is the first.
Every feature exists to close the gap between domain knowledge and running code.
One .moment file drives your types, tests, documentation, and visualizations. No more scattered domain knowledge.
Derive test topologies, simulation scenarios, and negative test cases directly from your specification — no manual test writing.
AST-level diffing detects when your implementation diverges from the specification. Catch drift before it becomes a bug.
Four-phase schema lifecycle — Active, Deprecated, End-of-Life, Removed — with consumption tracking and deprecation rules.
Model Context Protocol server exposes all Moment capabilities as structured tools for Claude, Copilot, and Cursor.
Auto-regenerate artifacts on specification changes. Deterministic output means clean git diffs every time.
Moment stands on the shoulders of the DDD community — Evans, Young, Brandolini, Vernon, Tune, Khononov — and encodes their patterns into a toolchain that enforces what books can only recommend.
Moment works alongside Sift and Forge to provide a complete domain-driven workflow — from discovery to deployment.
Domain Discovery
Upstream domain modeling that captures bounded contexts, aggregates, commands, and events.
Temporal DDD Modeling
Transforms specifications into typed code, tests, and living documentation.
Domain Flow Simulation
Visualize and test event flows, causation chains, and branch paths before coding.
Project System
Gets your project into motion from Moment's typed artifacts and simulation scenarios.
Coming soon
No. Generated artifacts are standard TypeScript, Gherkin, Markdown, and AsyncAPI.
If you stop using Moment, your generated code still works. The .moment file
is the only Moment-specific artifact.
Moment includes drift detection (moment drift) that catches when your
implementation diverges from the spec. Fix the spec or reconcile the implementation
— either direction works.
Yes. Start with one bounded context. Moment generates artifacts alongside your existing code. You can adopt context by context, aggregate by aggregate.
Moment is at milestone 3 (derivation + generation pipeline). The parser, type emitter, Gherkin generator, test scaffold emitter, and spec doc generator are all functional. Schema governance, viz, and MCP server are in active development.
Basic familiarity with aggregates, commands, and events helps. But the .moment
DSL is designed to be readable without DDD expertise — it reads like a domain
description, not an academic paper.
FSL-1.1-Apache-2.0: source-available now with full read/use rights. Two years after each release, it converts to Apache 2.0 (fully permissive). The only restriction during the FSL period is competing commercial use.
Moment is built in the open. Every feature, decision, and bug fix happens on GitHub.