Skip to content

UI Engine

Arun Soman edited this page Sep 2, 2026 · 3 revisions

The UI Engine

Nirdosha ships a declarative UI DSL plus a UI generator that derives a full CRUD + dashboard web application from a program's struct declarations and its function-naming conventions — no UI syntax needed for the common case.

Zero-syntax inference

compiler/src/ui_gen.rs looks for list_<struct>, create_<struct>, update_<struct>, delete_<struct>, get_<struct>, and stat_<name>/chart_<name> functions and generates a complete HTML/JS CRUD app + dashboard from them alone.

Optional screen / dashboard blocks

For what a naming convention can't express (a friendlier title, a relabeled field, a custom action), there is an additive DSL:

struct Product {
    id: i64,
    name: str,
    price_cents: i64,
    stock: i64,
}

fn list_product() -> Result(json, str) { ... }
fn create_product(p: Product) -> Result(i64, str) requires(role: "admin") { ... }
fn restock_product(id: i64) -> Result(i64, str) requires(role: "admin") { ... }

screen Product {
    title: "Catalog"
    field name { label: "Product Name" pattern: "^[A-Za-z0-9 ]+$" }
    field stock { min: 0 }
    action "Restock +10" -> restock_product {
        style: "outlined"
        confirm: "Restock this product by 10 units?"
    }
}

dashboard {
    tile "Products" -> stat_product_count
    chart "By Price" -> chart_products_by_price
}
  • screen/dashboard are real reserved keywords (top-level items like struct/fn); field/action/tile/chart are contextual keywords.
  • Typechecked: screen <Name> must name a real struct; field/action targets must resolve; view/edit must be role(...)/claim(...); pattern must compile as a regex and only apply to a str field; format must be one of "email"/"phone"/"date"/"url"/"uuid"; min/max must only apply to a numeric field.
  • Inert to native codegennirdosha build compiles a program containing screen/dashboard cleanly (codegen never inspects them). They're consumed only by nirdosha emit-ui/nirdosha serve.
  • view/edit (role/claim visibility) and pattern/format/min/max (format validation) are enforced for real, both client- and server-side — serve.rs is the actual security/validation boundary (redact_gated_fields, check_edit_gates, check_field_validations); the client-side version is cosmetic convenience only.
  • Tracked-but-not-wired (see compiler/UI_DSL_TODO.md): paginate, searchable/sortable as DSL keysnirdosha serve --db already provides real sorting/search/pagination unconditionally per struct via its own table route, independent of these two keys.
  • Deliberately closed, not gaps: one chart type (inline-SVG bar chart, no line/scatter/heatmap/treemap/geo/3D, no Recharts/D3/Victory dependency), four fixed built-in animations (fade-in/slide-up/scale-in/pop, no custom transitions or Framer-Motion-style gesture/physics motion), and a fixed seven-kind form-control set (text/number/checkbox/select/ struct/readonly/date — no rich text editor, color picker, drag-drop upload preview, autocomplete, calendar/scheduler, or signature pad). See compiler/UI_DSL_TODO.md's "Deliberate non-goals" section for the full rationale.

Design tokens: --theme

nirdosha emit-ui/serve --theme theme.json layers a full design system on the baked-in Material Design 3 defaults — brand/neutral color ramps, fonts, radius, shadow, density, real entrance/hover/press animations, three dark-mode strategies, and CSS-only layout shell variants (LANGUAGE.md §11b). Every section is optional; a program with no --theme renders exactly as before this existed. nirdosha serve re-reads the file on a TTL, so a redeployed theme takes effect without restarting the server.

Serving

nirdosha serve <file.nir> runs a tiny_http server exposing the inferred functions as a JSON API (POST /api/<fn>), with optional OIDC JWKS/issuer/audience gating — the same identity primitives as Language Features, applied to HTTP.

Why this matters for an agent

The zero-syntax path means an LLM asked for "a CRUD app over Product" doesn't need to also generate any UI code, HTML, or client-side validation logic — it writes struct Product and five naming-convention functions, and a working, role-gated, themeable web app falls out. The demo referenced in the README (examples/vendor_ops.nir, 334 lines, zero UI code) is the concrete proof: a themed dashboard, a sortable/searchable table, and a role-gated approval action, all derived, all enforced server-side — not generated client JS that a curious user could bypass by reading the page source.

Clone this wiki locally