Partial

UI files

A UI file sits beside a contract (order.ui.md beside order.dhl) and says what its records, actions and queries mean to the people and agents who use them: labels, money and dates, status badges, form steps, and a sentence for each refusal. The contract stays pure logic, and a UI file changes without upgrading any data.

Every field, argument, column, status value and validation line a UI file names is checked against the contract. If it does not match, it does not compile: a typo never silently disappears.

Example

---
contract: com.acme.orders.order
---

```ui
present Order
    label "Order" plural "Orders"
    title subject, placed_at
    status: states label "Status"
        0 Draft tone neutral
        1 Placed tone info
        2 Shipped tone success
    total_minor: money currency=currency minor label "Total"

present action Place
    label "Place order"
    tone primary
    confirm "Place order {subject} for the cart's buyer?"
    explain entries.len > 0 "Add at least one line."

form Place
    step "Cart" cart, buyer
    step "Lines" entries, total_minor
    buyer: prefill signer hidden
    entries: table columns line, product_id, quantity
```

Front matter has one key, contract: the contract's namespace. Indentation is four spaces; # and // start comments.

Blocks

BlockHolds
present <Aggregate>The record: label "X" [plural "Xs"], help, title <field>, …, and annotations per state field
present struct <Name>Labels and annotations for a struct's fields (sub-tables, rows)
present action <Name>label, help, tone neutral|primary|destructive, confirm "… {arg} … {subject}", annotations per argument, explain <validate line> "text"
present query <Name>label, help, columns a, b, …, annotations per column, arg <name>: …
form <Action>section "Title" a, b or step "Title" a, b (not both), and form annotations per argument

Each block appears at most once. record, browse, compose, view and relation are reserved Coming soon.

Field annotations

AnnotationForEffect
label "…", help "…", placeholder "…"anyHeader, form label, help line; also your accomplice's argument descriptions
money currency=<field> or money currency="EUR", minorInt, Decimal€4,250.00; input in major units
quantity [unit "kg"]Int, DecimalA number with its unit
percentInt, Decimal, Ratio12 %
date, datetime, relativeTimestampFormatting and a picker
email, phone, url, image, file, color, markdownTextRenderer and input
textarea [rows=N]TextMulti-line input
identityIdentityShown by display name
states + lines <value> <Name> [tone …] [label "…"]Int, Text, EnumStatus badges, filter chips, a status select
choice + lines <value> "Label"Enum, Text, IntA select with labels
refers <namespace>Identity, Ref, SubjectRefA link to that record
sensitiveanyMasked until revealed (display only)
hidden, priority N, align start|endanyColumn visibility, order, alignment
default <value>argumentsA starting value

One meaning annotation (money, quantity, states, choice, date…) per field.

explain

explain <validation line> "text" gives a refusal its words. The line must exist in the action (whitespace does not matter). When that rule refuses, the text is the error, shown on the fields the rule reads: in the form before submitting when it can tell, otherwise from the server.

Form annotations

AnnotationEffect
visible when <condition>Shown only while the condition holds (DHL syntax, this action's arguments)
table columns a, bA list argument as an editable sub-table
prefill signerThe acting identity's key
prefill subjectThe record id
prefill record.<field>The record's field, when the form opens from a row
hiddenNot shown; needs a prefill or a default
readonlyShown, not editable

Without a UI file

Every contract still gets a description derived from its rules: each validation line becomes a rule with its kind, and simple argument rules become input limits (x > 0 → minimum 1; name.len > 0 → required). Refusals then name the rule's source line.

Where to put it

Beside the contract, with the same stem, in MANDALA_CONTRACTS or the installed contracts directory. Mandala compiles descriptions at startup; a UI file that does not match its contract is logged and ignored, never stopping the node. dhl-engine describe <contract> <out> writes the description, the diagnostic module and the enriched OpenAPI.

Coming soon — UI files for the built-in standard contracts, record pages, server-side browse tables, compose forms, and the Workbench checking a UI file with its contract.