uidl-runtime
v0.1.14
Published
A schema-driven React runtime that renders validated JSON UIDL documents into lists, forms, reports and dashboards.
Maintainers
Readme
uidl-runtime
A schema-driven React runtime that renders validated JSON documents into real application surfaces — lists, forms, reports, dashboards and settings — without putting business workflows inside page components.
A UIDL document is JSON describing layout, state, queries, bindings, events and actions.
uidl-runtime validates it against a Zod schema and renders it through a component registry.
Nothing in a document names a data source, an HTTP client or a database: reads go through a
single DataAdapter seam and writes go through a host-supplied mutation handler, so the same
document runs in memory, against a mock API, or against a real backend.
It was built for three callers: AI agents that generate interfaces from structured instructions, ERP-style products whose screens are defined by metadata rather than code, and low-code systems that need a validated document model instead of generated page files.
Screenshots
Every screen below is generated UIDL, rendered by the same UIDocumentRenderer — none of it
is hand-built page markup.
| | |
|---|---|
|
Reference gallery — 11 industry consoles plus Meridian |
Meridian — cashflow, P&L and expenses derived from postings |
|
Point of sale, generated from the same document model |
Hospital reference console — one of eleven industry verticals |
Install
npm install uidl-runtimeFlutter (pub.dev):
dependencies:
uidl_flutter: ^0.1.4https://pub.dev/packages/uidl_flutter
import { DocumentSchema, UIDocumentRenderer, meridianLightTheme } from "uidl-runtime";
import "uidl-runtime/style.css";
const document = DocumentSchema.parse(rawDocument);
export function App() {
return (
<UIDocumentRenderer
document={document}
theme={meridianLightTheme}
onRouteChange={(path) => navigate(path)}
/>
);
}Status
The runtime and its reference suite are functional, extensively tested, and automated across multi-platform CI gates. The reference applications are executable blueprints, not certified systems — read the maturity table below before treating any of them as finished.
- Web / TypeScript: 143 test files, 1,312 tests, one typecheck, one lint pass
- Android Native (Kotlin 2.1 / Java 21): 69 tests covering parser, expression evaluator, binding resolver, and Compose widget abstractions
- Flutter Native (Dart 3.7 / Flutter 3.29): 73 tests covering widget rendering, expression evaluator, and native widget tree
- Server Generator & REST API (Java 21 / Quarkus): 43 tests across model generators and REST endpoints
- Multi-Platform Conformance Suite: 55 / 55 active fixtures passing across all 4 runtimes (100% pass rate)
- Interactive Conformance Explorer: In-browser test evaluator and multi-runtime showcase at
/conformance - Workspace Control Companion: Real-time bidirectional synchronization with
ws_web.pyfor Kanban boards, backlogs, and activity clocks - Benchmarked Compiler Throughput: >350,000 ops/sec across canonical page recipes with sub-millisecond p50/p95 latency
- Automated Multi-Platform CI Matrix: GitHub Actions pipeline executing TypeScript, Java/Quarkus, Android Kotlin, and Flutter Dart suites
- 11 industry reference consoles plus a full double-entry accounting reference
- Every financial posting satisfies
sum(debit) === sum(credit), checked by an audit gate
Multi-Platform Runtime Ecosystem
UIDL provides native runtimes across web, mobile, and server platforms sharing the same JSON document specification:
| Platform | Directory | Language / Tooling | Package / Artifact |
|---|---|---|---|
| Web / React | packages/core | TypeScript 5.8, React 18/19 | npm install uidl-runtime |
| Android Native | runtime-android/ | Kotlin 2.1, Java 21, Maven | dev.uidl:uidl-android:1.0.0-SNAPSHOT |
| Flutter Native | runtime-flutter/ | Dart 3.7, Flutter 3.29 | uidl_flutter ^0.1.4 on pub.dev |
| Server Generator | server/uidl-generator/ | Java 21, Jackson, Maven | dev.uidl:uidl-generator:1.0.0-SNAPSHOT |
| Quarkus Server | server/uidl-server/ | Java 21, Quarkus 3.x, RESTEasy | Microservice executable |
| Companion App | apps/workspace-control/ | React 19, Vite, Tailwind v4 | Live workspace control desk |
| CLI Compiler | bin/ | Node.js 22+ | npx uidl-compile, npx uidl-validate |
See the complete specification compliance breakdown in docs/conformance-matrix.md.
Multi-Platform Quickstart
1. Web (React / TypeScript)
npm install uidl-runtimeimport { DocumentSchema, UIDocumentRenderer, meridianLightTheme } from "uidl-runtime";
import "uidl-runtime/style.css";
const document = DocumentSchema.parse(rawDocument);
export function App() {
return (
<UIDocumentRenderer
document={document}
theme={meridianLightTheme}
onRouteChange={(path) => navigate(path)}
/>
);
}Page recipes without React
The page recipes (list, form, report, dashboard, settings, tree, wizard) are
pure functions from metadata to a UIDL document. uidl-runtime/recipes exports them with
nothing else: no React, no zod, no package at all. A compiler, a server, or a CLI can then
build pages and hand them to any runtime.
import { compilePage } from "uidl-runtime/recipes";
const page = compilePage({
recipe: "list",
meta: {
name: "invoices",
label: { id: "Faktur", en: "Invoices" },
titleField: "number",
fields: [{ key: "number", label: { id: "Nomor", en: "Number" }, widget: "TextField" }],
columns: [{ field: "number" }],
defaultSort: { field: "number", dir: "asc" },
},
hostCapabilities: { collections: ["invoices"], commands: [] },
});pnpm run smoke:package loads this entry from the packed tarball in a folder where nothing
else is installed, so a recipe that started importing React would fail the release check.
Three presets sit beside the seven recipes (ADR-0010). compileAuthPage builds sign-in,
sign-up, forgot-password, and reset-password pages that send their values to one host
command. wrapInShell puts any page inside a sidebar and top bar whose items are gated by
session.permissions. compileLandingPage assembles a marketing page from sections (hero,
features, pricing, testimonials, faq, cta, signup). Every command they emit must be
in hostCapabilities.commands.
import { compileAuthPage, wrapInShell } from "uidl-runtime/recipes";
const caps = { collections: [], commands: ["auth.signIn", "auth.signOut"] };
const signIn = compileAuthPage(
{ name: "sign-in", mode: "sign-in", command: "auth.signIn", successRoute: "/" },
{ hostCapabilities: caps, uiPolicy: { lang: "en" } },
);
const page = wrapInShell(
invoicesPage,
{
name: "app",
title: { id: "Konsol", en: "Console" },
items: [{ id: "invoices", label: { id: "Faktur", en: "Invoices" }, route: "/invoices", permission: "invoices.read" }],
signOutCommand: "auth.signOut",
signOutRoute: "/sign-in",
},
{ hostCapabilities: caps, currentRoute: "/invoices" },
);Gallery catalog
Ready-made documents for a gallery UI (industry consoles, dashboards, forms) ship as data:
uidl-runtime/catalog/gallery.json holds every entry's metadata and its documents per locale,
and uidl-runtime/catalog/<id>.<lang>.json holds one document. The manifest lives in
packages/templates/src/catalog/gallery/; the build validates every document and refuses to
publish one that fails. UIDL-Builder reads this instead of keeping copies of its own.
import gallery from "uidl-runtime/catalog/gallery.json";
const consoles = gallery.entries.filter((entry) => entry.category === "industry");
const document = consoles[0].documents.en;Presentation preset catalog
Presentation presets are owned by the runtime and referenced by version from a document. Hosts may discover a preset, apply its selected theme, and preserve the reference without copying the preset definition into application code.
import {
applyPresentationPreset,
presentationPresetCatalog,
} from "uidl-runtime";
const preset = presentationPresetCatalog.get("dense-business");
if (!preset) throw new Error("Presentation preset is unavailable");
const themedDocument = applyPresentationPreset(document, preset, "light");
// themedDocument.presentationPreset is { id: "dense-business", version: "0.1.0" }2. Android Native (Kotlin)
import dev.uidl.runtime.model.UidlParser
import dev.uidl.runtime.evaluator.ExpressionEvaluator
import dev.uidl.runtime.binding.BindingResolver
val parser = UidlParser()
val document = parser.parse(jsonString)
val context = mapOf("state" to mapOf("user" to mapOf("name" to "Ada Lovelace")))
// Dot-notation reactive binding resolution
val userName = BindingResolver.resolve("state.user.name", context)
// Evaluates declarative AST expressions
val result = ExpressionEvaluator.evaluate(document.root.props["visible"], context)3. Flutter Native (Dart)
dependencies:
uidl_flutter: ^0.1.4import 'package:flutter/material.dart';
import 'package:uidl_flutter/uidl_flutter.dart';
class UidlScreen extends StatelessWidget {
const UidlScreen({super.key, required this.rawDocument});
final Map<String, dynamic> rawDocument;
@override
Widget build(BuildContext context) {
final document = UidlParser.parse(rawDocument);
return UidlRenderer(document: document);
}
}4. Server Document Generation (Java 21)
import dev.uidl.generator.builder.UIDLDocumentBuilder;
import dev.uidl.generator.model.UIDLDocument;
UIDLDocument doc = UIDLDocumentBuilder.create("invoice-form")
.version("1.0.0")
.title("Faktur Penjualan")
.addState("status", "draft")
.build();
String jsonOutput = doc.toJson();5. Workspace Control Companion Desk
The companion application pairs directly with the local Agent Workspace daemon (ws_web.py) for live Kanban boards, backlog grooming, and activity tracking:
# Start local workspace backend with the UIDL runtime
python3 .agents/bin/ws_web.py --runtime uidl --port 8765
# Or start the companion app in standalone development mode
pnpm run dev:workspace-controlDevelopment Setup
The rest of this document is for working on uidl-runtime itself — the runtime, the
reference suite, and the build. If you only want to consume the library, corepack pnpm install --frozen-lockfile
uidl-runtime above is all you need.
Prerequisites
- Node.js LTS (>= 20.11) and npm
- Java 21 JDK (for server generator and Quarkus server)
- Flutter SDK (for mobile runtime development)
git clone https://github.com/hi-donwi/UIDL-Runtime.git
cd UIDL-Runtime
corepack pnpm install --frozen-lockfile
pnpm run devTo exercise the HTTP adapter instead of the in-memory one, run two terminals:
pnpm run mock:api # mock API on port 8787
pnpm run dev:reference:httpRelease Automation
The public npm package is published from .github/workflows/publish-npm.yml using npm
Trusted Publishing with GitHub Actions OIDC. Configure the uidl-runtime package on
npmjs.com with this trusted publisher before cutting the next release:
Publisher: GitHub Actions
Organization or user: hi-donwi
Repository: UIDL-Runtime
Workflow filename: publish-npm.yml
Allowed action: npm publishNo NPM_TOKEN repository secret is required for the public npm publish path. The workflow
uses Node.js 24, disables package-manager cache in the release job, requires manual publish
dispatches to run from the default branch, validates the requested version against
package.json, and refuses to publish a version that already exists on npm.
Distribution is npm-only. After a release, run the manual Verify npm package workflow with
the released version.
Commands
| Command | Purpose |
|---|---|
| pnpm run dev | Start the reference application suite in memory |
| pnpm run dev:reference:http | Start the suite with VITE_DATA_MODE=http |
| pnpm run dev:workspace-control | Start the companion workspace control desk (port 5174) |
| pnpm run mock:api | Start the local mock API on port 8787 |
| pnpm run typecheck | Type-check all workspaces |
| pnpm run lint | Run ESLint |
| pnpm test | Run Vitest unit and integration tests |
| pnpm run build | Build the public library and JSON schemas |
| pnpm run build:reference | Build the reference application suite |
| pnpm run build:workspace-control | Build the companion app production bundle |
| pnpm run bench:compilers | Benchmark compiler throughput across all 7 canonical recipes |
| pnpm run audit:reference | Architecture, maturity and balanced-GL gates |
| pnpm run test:reference | Playwright acceptance tests, in memory |
| pnpm run test:reference:visual | Playwright visual baseline tests |
| pnpm run test:reference:update | Regenerate reviewed visual baselines |
| pnpm run test:reference:http | Playwright acceptance tests over HTTP |
| pnpm run smoke:package | Pack and consume the public npm artifact |
| pnpm run validate:examples | Validate the example UIDL documents |
| pnpm run validate:spec | Validate the UIDL specification schemas |
How it works
Reads flow one way, from metadata to rendered surface:
DoctypeMeta / ModuleSpec
-> page generator
-> UIDLDocument (validated by DocumentSchema)
-> UIDocumentRenderer
-> DataAdapterWrites never take that path. They cross an explicit boundary instead:
UIDL mutate action
-> host mutationHandler
-> document or domain service
-> DataAdapterThe data mode is chosen in exactly one file, packages/templates/src/config/data.config.ts.
Documents and generators must not import a concrete adapter.
Core concepts
$bindreads reactive state or query results.$querydelegates a read to theDataAdapter.$exprevaluates the supported declarative expressions, including aggregates.mutatedelegates a write to the host and fails closed when no permitted handler exists.- Generic list, form, workspace, settings, dashboard and report surfaces are generated UIDL.
- A composite transaction may use a thin React component when UIDL cannot express the interaction — but the business rules stay in services.
Repository structure
uidl-runtime/
├── packages/
│ ├── core/ # Web runtime, schemas, renderer, expressions, telemetry
│ └── templates/ # Reference generators, 11 verticals, domain services
├── runtime-android/ # Android Native Kotlin 2.1 runtime & Compose abstractions
├── runtime-flutter/ # Flutter Native Dart runtime & widget tree renderer
├── server/
│ ├── uidl-generator/ # Java 21 fluent AST document builder & JSON serializer
│ └── uidl-server/ # Quarkus 3.x REST server backend
├── apps/
│ ├── reference/ # Reference suite, gallery, playground, and consoles
│ └── workspace-control/ # Companion desk for runs, tasks, and telemetry
├── conformance/ # 55 cross-platform test fixtures across 7 domains
├── e2e/ # Browser acceptance and visual-regression tests
├── scripts/ # Compiler benchmarks, packaging, and validation tools
└── docs/ # Architecture, ADRs, and cross-platform conformance matrixpackages/core, packages/templates, apps/reference, and apps/workspace-control are npm workspaces. The
published npm artifact is uidl-runtime (with style.css). The
Flutter runtime is published separately as uidl_flutter 0.1.4 on
pub.dev. Android and Java artifacts remain SNAPSHOT libraries in this repository.
Visual regression tests are intentionally separate from the default reference command.
The committed baselines are generated on the canonical Linux CI environment. Run
pnpm run test:reference:visual locally only on an environment with matching platform
baselines, and use pnpm run test:reference:update only for a reviewed visual change.
Reference suite
Meridian is the core reference: a complete double-entry accounting desk — chart of accounts, sales and purchase cycles, journal entries, payments, stock ledger, POS shifts, General Ledger, Trial Balance, Profit and Loss and Balance Sheet. Every report is derived from postings rather than hand-written, so the books balance by construction.
Eleven industry consoles sit beside it: shoe retail POS, school finance, manufacturing, food roasting, EPC contracting, CRM, cooperative/BMT, hospital, medical device, omnichannel distribution and helpdesk. Several model Indonesian business documents directly — Faktur Pajak, e-Faktur DJP, Surat Jalan, Akad Murabahah — and the interface runs bilingually in Indonesian and English.
Maturity is stated per reference rather than claimed for the suite:
| Level | Meaning | |---|---| | Concept Reference | Architecture or workflow direction, no complete user journey | | UI Reference | Reusable interface pattern, no complete business execution | | Functional Reference | Executable workflow with deterministic data and acceptance evidence | | Domain-Verified Reference | Functional, plus proven domain invariants and reconciliation | | Production-Ready | Operations, security, accessibility, performance and support proven |
Most verticals are Functional References. School dunning, koperasi murabahah collectibility, hospital claim reconciliation and helpdesk SLA are Domain-Verified. None is Production-Ready. A workflow counts as proven only when a browser test drives its UI; calling a service directly counts as setup, not evidence.
Implementation rules
- Presentation in components, reusable behaviour in hooks, pure functions in utilities, workflows and integrations in services.
- Validate every generated document with
DocumentSchemabefore rendering. - Keep one
DataAdapterseam; never import a concrete adapter from a document, generator or UI component. - Require
sum(debit) === sum(credit)for every financial posting. - Keep API-backed actions fail-closed and explicitly allowlisted.
- Use the shared design tokens and vector icons; respect
prefers-reduced-motion. - Do not introduce a second primary runtime model alongside
UIDLDocument.
Credits
Outline icons are from Heroicons (MIT). The interface type is Inter (SIL Open Font License).
License
MIT — see LICENSE.
Administration layouts
For bounded forms, meaningful sections, wrapping actions, and stable pagination,
see Administration layout compositions. These
helpers are additive in unreleased source after 0.1.8. Validate a host with the
matching stylesheet and run npm run test:layout for shared geometry regressions.
