Language design final — start modeling today

Turn your Event Models into Verified Contracts.

Stop translating sticky notes. Start compiling domain logic.

Eliminate the gap between business intent and software execution. Weltenwanderer compiles .ddd specifications into a formally verified domain kernel. No more implementation drift or AI-generated guesswork: your code is proof-checked against the model, not just unit-tested.

Open Source · Codeberg

shopping-cart.ddd
context Shopping {

  type CartId = String
  type ProductId = String
  type Quantity = Integer

  command AddItem {
    cartId: CartId
    productId: ProductId
    quantity: Quantity

    validate quantity > 0
      else "Quantity must be positive"
  }

  event ItemAdded {
    cartId: CartId
    productId: ProductId
  }

  decider ShoppingCart {
    commands: AddItem
    events:   ItemAdded
    state:    Empty | Active | CheckedOut

    decide(AddItem, Active) {
      require items.length < 50
        else reject "Cart is full"

      -> [ItemAdded { cartId, productId }]

      ensure items.length == old.items.length + 1
    }

    evolve(Active, ItemAdded)
      -> Active { items: items + item }
  }
}

"Domain language is specification. Everything else is infrastructure."

Tobias Brennecke
Creator of Weltenwanderer

You leave the EventStorming session with a wall of sticky notes and a shared understanding. Then the translation begins — and meaning gets lost.

You've seen it before: the model in code drifts from the model on the wall. Domain experts stop recognizing their own language. Developers build what they understood, not what was meant.

Teams that invest in collaborative design deserve a single source of truth — not a game of telephone between whiteboards, JSON schemas, and generated code.

The AI-assisted variant is faster but not better: paste a JSON schema into an LLM, review the output, fix the hallucinations, repeat. The RALPH loop burns tokens on translation that a compiler does deterministically in milliseconds.

Without a compiler, every team member maintains their own mental model. The models diverge. The system diverges. The bugs follow.

Why trust Weltenwanderer

We've been in that room

We've sat in those sessions. We've seen the gap between what the team designed and what got shipped.

Formal foundation

Built on proven computation theory (DynPROP, Schwentick). Not heuristics — theorems.

Deterministic compilation

No LLM in the loop. .ddd → verified TypeScript. Same input, same output, every time.

One file, every stakeholder

Domain experts read it. Developers compile it. The compiler enforces it.

How it works

Three steps from design to code

Model your domain

Write commands, events, and state machines in .ddd syntax that reads like the language from your design session.

Compile and verify

The compiler checks exhaustiveness, guard consistency, and postconditions. Structural bugs die here.

Generate and ship

Get typed TypeScript code, smart constructors, and framework wiring. Switch targets without rewriting your domain.

Your next EventStorming session could produce running, verified code

Not sticky notes that fade. Write your domain once, verify it at compile time, and generate code for any target platform.

Get notified when static verification ships.

No spam. One email when the feature lands.

What changes

After Weltenwanderer

Domain experts review .ddd files directly — no translation meetings

AI coding assistants use the .ddd file as context — no JSON schema, no RALPH loop, 10× fewer tokens

New team members read the domain model on day one — it’s the spec AND the program

Platform migration means changing a compiler flag, not rewriting the domain

See the language

One file. Domain experts and developers both read it.

This is what a domain expert and a developer both read. One file. The compiler does the rest.

Four constraint layers

Types, validations, business rules, and postconditions — each verified at the right scope.

Smart constructors

validate will generate private constructors with Result types. Invalid commands cannot be instantiated.

Atomic event sequences

Multiple events from one decision are folded left-to-right and committed atomically.
Why can a compiler verify this?

The evolve function is a catamorphism (left-fold). When the state type is a finite algebraic data type, the projection is a finite automaton. All properties — equivalence, minimality, reachability, confluence — are decidable.

This is not an approximation. Gelade, Marquardt, and Schwentick (2012) proved that dynamic maintenance with propositional updates captures exactly the regular languages.

ordering.ddd
context Ordering {

  type ItemList = Item[]
  type Reason = String

  command PlaceOrder {
    items: ItemList
  }

  command CancelOrder {
    reason: Reason
  }

  command ShipOrder {
    trackingId: String
  }

  event OrderPlaced {
    items: ItemList
    total: Number
  }

  event OrderCancelled {
    reason: Reason
  }

  event OrderShipped {
    trackingId: String
  }

  decider Order {
    commands: PlaceOrder, CancelOrder, ShipOrder
    events:   OrderPlaced, OrderCancelled, OrderShipped
    state:    Draft | Placed(items: ItemList) | Shipped | Cancelled
    initial:  Draft
    terminal: Shipped, Cancelled

    decide(PlaceOrder, Draft) {
      require items.length > 0
        else reject "Order must have items"
      require total >= 10.00
        else reject "Minimum order: 10 EUR"

      -> [OrderPlaced { items, total }]
    }

    decide(CancelOrder, Placed) {
      require not shipped
        else reject "Already shipped"

      -> [OrderCancelled { reason }]
    }

    decide(ShipOrder, Placed)
      -> [OrderShipped { trackingId }]

    evolve(Draft, OrderPlaced)      -> Placed { items: items }
    evolve(Placed, OrderCancelled)  -> Cancelled
    evolve(Placed, OrderShipped)    -> Shipped

  }
}

Comparison

Compiler vs. Runtime Frameworks

Weltenwanderer is not a replacement for runtime frameworks — it generates code that targets them. The comparison shows what static analysis adds.

Approach

Runtime Frameworks
Library you code against
Weltenwanderer
Compiler that generates code

Correctness

Runtime Frameworks
Discovered at runtime
Weltenwanderer
Proven at compile time

Domain model

Runtime Frameworks
Spread across code files
Weltenwanderer
Single .ddd source of truth

Platform lock-in

Runtime Frameworks
Tied to one framework
Weltenwanderer
Generates for any target

Documentation

Runtime Frameworks
Manual, drifts from code
Weltenwanderer
Generated from source

AI Coding

Runtime Frameworks
Paste JSON + fix hallucinations
Weltenwanderer
.ddd file IS the prompt — deterministic output

Your next EventStorming session could produce running, verified code

Not sticky notes that fade. Write your domain once, verify it at compile time, and generate code for any target platform.

Get notified when static verification ships.

No spam. One email when the feature lands.