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.
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 }
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.
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.
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.
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.
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.
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 |
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.
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.
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.
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.
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.
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.
// 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.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.
Modern, type-safe HTTP backend. Aggregates as classes with private state; repositories with master-detail persistence; domain events dispatched on save.
/openapi.jsonMediator-style controllers per aggregate; EF Core entity configurations; FluentValidation rules derived from your invariants; structured exception filter for clean 4xx errors.
Server-rendered HEEx pages over LiveView; Ash 3.x resources and actions per aggregate; Ecto migrations alongside. Same aggregates, idiomatic Elixir.
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.
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.
The polished React default — accessible primitives, batteries included, sensible defaults out of the box.
Tailwind-based components copied into your tree. Owned, not imported — styled the way your design team wants.
Material Design 3. The long-standing React UI standard, with deep theming and a vast component surface.
Composable React primitives with a focused theming system — ideal when you want consistency without ceremony.
Native HEEx components for the Phoenix LiveView backend. Server-rendered, real-time updated, no JS shipped.
Design packs are just templates against a small page contract. Write one for your in-house system; every deployable can use it.
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.
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-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.
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.
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.
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.
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.
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.
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.
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.
Private state, factories, invariant checks, derived properties, and emitted domain events — in every backend.
find-by-id, save, find-all, plus user-declared finds — with full master-detail load and event dispatch.
Every runtime serves the same request and response shapes. Your frontend targets any backend without changes — cross-runtime parity is structural, not coincidental.
List, detail, and create pages per aggregate; modal-form button per public operation; master-detail when aggregates contain parts — rendered through your design pack.
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.
docker-compose.yml with Postgres, every deployable, healthchecks, and a db-init SQL bootstrap — docker compose up -d and you're running.
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.
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.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.