Source-available · No-code altitude, real-code outcome

The speed of no-code.
The keys to the codebase.

Loom lets you describe complete systems at the altitude of a no-code platform — and walk away with real, owned source code across Hono, .NET, Phoenix LiveView, and React. No vendor lock-in. No scaling cliff. No drift between layers. Just the model, a visual builder, and full ownership of every line that's generated.

All the speed of no-code All the source you'd write by hand Zero vendor lock-in
orders.ddd
aggregate Order {
  customerId: string
  status: OrderStatus
  placedAt: datetime
  contains lines: OrderLine[]

  derived total: Money =
    Money(lines.sum(l => l.subtotal.amount), "USD")

  invariant lines.count > 0 when status == Confirmed

  operation confirm() {
    precondition isMutable()
    precondition lines.count > 0
    status := Confirmed
    emit OrderConfirmed { order: id, at: now() }
  }
}

// One model. Pick your runtime per deployable.
deployable api    { platform: dotnet, modules: Sales, port: 8080 }
deployable webApp { platform: react,  targets: api,    design: shadcn, port: 3001 }
The vision

The model is the system.

Most DDD codebases are aspirational: a tactical pattern in the docs, a CRUD service in the repo. Loom closes that gap. The .ddd source is the single source of truth — every line of running code, in every deployable, is derived from it. Refactor the model, regenerate the system.

Write what you mean

You write aggregates, invariants, operations, events, workflows — primitives from Domain-Driven Design, not from a web framework. The pages, the routes, the database, the page objects, the docker stack: generated. None of them yours to maintain.

Switch runtimes like you switch branches

Prototype on Hono. Ship on .NET. Evaluate Phoenix LiveView side-by-side. Each deployable picks its runtime in one line; the model doesn't change, the contracts don't drift, and the frontend doesn't notice which backend it's pointed at.

A guardrail for LLM-assisted development

The DSL is small, declarative, and validated before any code is emitted. The same source drives every layer, so an LLM can't hallucinate fields the model doesn't have, drift naming between files, or write a frontend that disagrees with its backend. Refactor the model; the model regenerates the rest.

Pick a design system, not just a framework

Five first-class design packs ship in-tree: Mantine, shadcn/ui, MUI, Chakra, and Phoenix HEEx. Swap packs to compare — no template edits, no UI rewrite. The page DSL is identical; only the rendering changes.

Versus the alternatives

Pick the trade-off you actually want.

Every shortcut to building a system comes with a hidden tax — lock-in, drift, framework jail, or a scaling cliff. Loom is the row where everything turns into a check mark.

Loom No-code / low-codeBubble · Retool · OutSystems · Mendix · Appsmith Starter kits / frameworksRails · Phoenix · Blitz · Wasp AI codegenCursor projects · v0 · Bolt · Lovable
Time to first prototypeFrom blank slate to a deployable backend + UI. Minutes Minutes Hours–days Minutes
You own every line of sourceReal files in your repo, not a managed model. Yes No (platform-managed) Yes Yes
Zero vendor lock-inWalk away anytime; generated code stays useful. Yes Existential dependency Yes Yes
Multiple runtimes from one sourceSame model on different stacks; pick per deployable. Hono · .NET · Phoenix · React Single platform Single framework Single framework per prompt
Scaling ceilingWill you hit a wall in performance or cost? None — native code Real (perf + cost cliffs) None None
Visual builder + textual editing on the same sourceSwitch views; round-trip every change back to source. Both, one model Visual only Textual only Textual + AI prompts
Built-in requirement → test → verdict traceDefinition-of-Done verdicts straight from test runs. First-class Separate tools Separate tools No native concept
Architectural drift across iterationsFrontend, backend, DB, tests stay aligned? Prevented by construction Hidden inside the platform Manual discipline High — drift after a few prompts
Production-grade tests generated end-to-endUnit + integration + e2e from the same source. Generated, runnable Visual recorders, limited You write them AI-generated, quality varies
Code review-able, debuggable outputIdiomatic per framework; team can read it. Idiomatic, owned Debug inside the platform UI Idiomatic, owned Idiomatic, owned
Visual + textual, one source

Three windows on the same model.

Loom ships a browser-based playground with a typed editor, a visual system builder, and a live preview of the generated app. Drag a deployable onto the canvas, type a workflow in the editor, or click through the generated UI in a sandboxed iframe — every view edits the same .ddd source. No round-trip to a server; no separate "design mode" with a different source of truth.

● Typed editor

Write the model with full LSP support

The browser editor speaks the same Loom language as the CLI: completion, hover, jump-to-definition, rename-refactor, inline diagnostics. Errors caught at type-time, not runtime.

● System builder

Drag deployables; wire UIs to APIs to storage

A graph view of your system: deployables, modules, UIs, APIs, storage. Edit visually — every drag, every wire, round-trips to the textual source. Designed for product folks; useful to anyone.

● Live preview

The generated app, booting in your browser

Every edit re-bundles your generated frontend (and a sandboxed backend) and serves it inside the playground. Click through pages, fire operations, watch state change — in seconds, no Docker, no localhost.

● In-browser test runner

Run the generated suite without leaving the page

The DSL's test and test e2e blocks compile to runnable tests. The playground executes them against the in-browser stack and surfaces the results — same wire format ddd verify consumes in CI.

Open the playground
Switch targets mid-project

Same model. Whatever stack you need today.

A deployable picks its runtime in one line. Prototype on Hono, ship on .NET, evaluate Phoenix LiveView side-by-side — identical contracts, idiomatic output, zero rewrites between platforms.

acme.ddd
// Same `Sales` module, three different runtimes.
deployable api    { platform: hono,            modules: Sales, port: 3000 }
deployable apiNet { platform: dotnet,          modules: Sales, port: 8080 }
deployable apiPhx { platform: phoenixLiveView, modules: Sales, port: 4000 }

// Frontend targets any of them.  Pick a design pack the same way.
deployable web {
  platform: react
  targets:  api          // switch to apiNet or apiPhx anytime
  design:   mantine      // or shadcn, mui, chakra, ashPhoenix
  port:     3001
}
Same request shapesEvery runtime serves identical JSON. Your frontend doesn't care which backend it's pointed at.
Same response shapesAggregates, parts, and value objects serialise identically across platforms.
Same invariantsValidated server-side; mirrored at the wire boundary as form-level errors when they fit.
Same migrationsSchema for the same module is generated for whichever backend owns it — never hand-maintained.
Same e2e suiteOne DSL test runs against whichever runtime you point it at — no test rewrite when you switch.
Four runtimes

Idiomatic output. Identical contracts.

Every backend produces the same aggregates, repositories, routes, and contracts — in the language and framework conventions your team would write by hand. Reviewable, debuggable, owned code — not framework lock-in.

● TypeScript backend

Hono

Modern, type-safe HTTP backend. Aggregates as classes with private state; repositories with master-detail persistence; domain events dispatched on save.

  • Type-validated routes for every operation and find
  • Drizzle-backed Postgres with generated migrations
  • OpenAPI spec served from /openapi.json
● .NET backend

ASP.NET Core

Mediator-style controllers per aggregate; EF Core entity configurations; FluentValidation rules derived from your invariants; structured exception filter for clean 4xx errors.

  • Commands and queries per public operation
  • EF migrations generated alongside the model
  • Swashbuckle OpenAPI, byte-compatible with Hono's
● Elixir backend

Phoenix LiveView & Ash

Server-rendered HEEx pages over LiveView; Ash 3.x resources and actions per aggregate; Ecto migrations alongside. Same aggregates, idiomatic Elixir.

  • One Ash resource per aggregate
  • Telemetry + structured logs out of the box
  • Compiled with warnings-as-errors in CI
● React frontend

React + your design pack

List / detail / create pages per aggregate, with master-detail when aggregates contain parts, and a modal-form button per public operation. Targets any of the backends above.

  • Typed API hooks that parse responses before returning
  • Generated forms with field-level validation
  • End-to-end tests against the live stack
Five design systems

Pick the look. Keep the model.

Pages, forms, tables, and modals are written once in the Loom page DSL — rendered through whichever design system you pick at generation time. Swap packs to compare, mix per deployable, or add your own. No template edits.

Mantine

The polished React default — accessible primitives, batteries included, sensible defaults out of the box.

shadcn/ui

Tailwind-based components copied into your tree. Owned, not imported — styled the way your design team wants.

MUI

Material Design 3. The long-standing React UI standard, with deep theming and a vast component surface.

Chakra UI

Composable React primitives with a focused theming system — ideal when you want consistency without ceremony.

Phoenix HEEx

Native HEEx components for the Phoenix LiveView backend. Server-rendered, real-time updated, no JS shipped.

Bring your own

Design packs are just templates against a small page contract. Write one for your in-house system; every deployable can use it.

Requirements → tests → verdict

The straightest line from a user story to a green check mark.

Most projects keep requirements in Jira, tests in CI, and code in git — and spend the whole quarter chasing the drift between them. Loom puts requirements alongside the domain, links them to test cases, and rolls test runs into a per-requirement Definition-of-Done verdict.

acme.ddd
requirement US-001 {
  type:     UserStory
  title:    "User can log in"
  status:   Approved
}

solution SOL-001 satisfies US-001 {
  entitles: Identity.Session.start
}

testCase TC-001 verifies US-001 {
  covers:   Identity.Session.start
}

// Inside the aggregate:
aggregate Session {
  operation start(email: string, password: string) { /* ... */ }

  test "successful login" verifies TC-001 {
    let s := Session.start("u@x.com", "correct")
    expect s.active.toBe(true)
  }
}
ddd verifyRuns the generated test suites against the running system; joins results back to the requirements that asked for them.
.loom/verification.mdPer-requirement Definition-of-Done verdict in human-readable form: which requirements are actually done against running code.
.loom/verification.jsonMachine-readable for CI gates, status dashboards, release checklists, traceability matrices.
.loom/coverage.mdWhich requirements have no verifying test case; which test cases have no executable backing. The gap report.
.loom/gaps.mdRequirements without solutions; solutions citing missing code symbols. Surface fiction before it ships.
LLM-safe by construction

An anchor against hallucination and architectural drift.

LLM-assisted development is fast — and dangerous. Hand-written code drifts between layers; LLMs hallucinate fields, invent operations, and forget the conventions three files away. Loom is a small declarative DSL that keeps every layer agreeing with the same source — on purpose.

One source of truth

The .ddd describes domain, contracts, and pages once. Frontend, backend, database, and tests regenerate together. No hand-maintained mirrors to drift apart between commits, between teams, or between LLM sessions.

Validated before emission

Types, references, invariants, and scope are checked end-to-end before a line of code is generated. An LLM can't sneak in a field the model doesn't have, a state the workflow doesn't allow, or a reference that crosses an aggregate boundary.

Small surface, large reach

The DSL fits in a prompt. An LLM holds the whole language in context — no rambling through hundreds of generated files to find the conventions; no divergent code coming out at the other end.

Refactor the model, regenerate the system

Rename an aggregate, add a containment, remove a derived field — one source change, one ddd generate system, your whole stack updates in lockstep. No half-updated codebases waiting for the next LLM round.

Diff the contract, not the implementation

Every regen writes a language-agnostic contract spec. Wire contract changed? Clean JSON diff. Migration needed? Snapshot diff. The generator surfaces drift you'd otherwise discover at runtime — or in production.

Owned, idiomatic output

Generated code looks like code your team would write by hand — not a framework's opaque internals. Review it, debug it, edit it. If you ever leave Loom, the generated tree is yours to keep.

What you get

One generate. A full deployable stack.

From a single source, ddd generate system emits a runnable multi-deployable system with database init, healthchecks, OpenAPI specs, and end-to-end tests.

Aggregate roots, faithfully

Private state, factories, invariant checks, derived properties, and emitted domain events — in every backend.

Repositories with finds

find-by-id, save, find-all, plus user-declared finds — with full master-detail load and event dispatch.

Identical API contracts

Every runtime serves the same request and response shapes. Your frontend targets any backend without changes — cross-runtime parity is structural, not coincidental.

Generated pages, ready to use

List, detail, and create pages per aggregate; modal-form button per public operation; master-detail when aggregates contain parts — rendered through your design pack.

End-to-end tests, top-down

One page object per generated page; write expect(order.total).toBe(...), not selectors. The same DSL test runs against whichever runtime you point it at.

Wired stack out of the box

docker-compose.yml with Postgres, every deployable, healthchecks, and a db-init SQL bootstrap — docker compose up -d and you're running.

CLI

One model. Whatever shape you need.

Generate a single deployable for a focused service, or the full system for an integrated stack. Capture a provenance snapshot when shipping a release; run verify to roll test results up against the traceability graph. Watch mode re-runs on save; --dry-run prints the plan with write / skip annotations.

~/acme
$ ddd generate system acme.ddd -o ./out
parse acme.ddd ............................. ok
validate ................................... ok (0 errors, 0 warnings)
emit api/ (.NET · Sales, Catalog) .. write 84
emit catalog_web/ (Hono · Catalog) ......... write 41
emit ops_phx/ (Phoenix · Ops) .......... write 38
emit web_app/ (React · shadcn → api) ... write 67
emit e2e/ (DSL e2e) ................ write 9
emit docker-compose.yml + db-init/ ......... write 2
contracts identical across runtimes ........ match

$ docker compose -f out/docker-compose.yml up -d
✔ postgres healthy
✔ api healthy (:8080)
✔ catalog_web healthy (:3000)
✔ ops_phx healthy (:4000)
✔ web_app healthy (:3001)
ddd parseParse + validate. Exits non-zero on errors.
ddd generate tsEmit a single Hono + Drizzle project.
ddd generate dotnetEmit a single ASP.NET + EF + Mediator project.
ddd generate systemEmit every deployable + docker-compose.yml.
ddd snapshotCapture an immutable .loom/snapshots/<ts>-<guid>.loomsnap.json for provenance.
ddd verifyJoin test-execution results onto the traceability graph; write .loom/verification.{json,md}.
-w, --watchRe-run on every save of the .ddd source.
--dry-runPrint the plan; touch nothing.

Ready to weave?

Loom is source-available under the FSL-1.1-Apache-2.0 license — free for any non-competing use, with an Apache 2.0 future license two years after publication.