Transaction Science · open standard · Apache-2.0 / CC-BY-4.0
joule-ui is a typed protocol for the moment a computation becomes something a human sees and acts on — and for making that moment accountable. An agent emits a typed widget tree against a registry the host published; the host renders. And when a human fires an action, the invocation is authorized against a capability, metered in joules, and sealed into a hash-chained receipt. A session stops being a stream of opaque callbacks and becomes a tamper-evident ledger of what the user did, what it computed, and what it cost.
The thesis
The first layer is the surface: a typed widget tree against a published registry, the shape the field converged on for agent-emitted UI. joule-ui pins it as a protocol — typed, validated, renderer-agnostic.
The second is the interaction: every fired action is an accountable event — authorized against a capability, metered in joules, sealed into a tamper-evident chain. The surface layer is renderer-agnostic UI. The interaction layer is the part you can audit: a UI whose every interaction is energy-accounted and signed, by construction.
The surface
An agent emits (name, props, children), recursively, against a registry the host published. Props are a closed set — text, number, list, object, and an opaque Action id the host binds at render time. No HTML over the wire, no code emission, no agent holding the renderer.
The registry is the host's contract; the renderer is the host's product surface. The protocol validates well-formedness exhaustively — every unknown widget, missing prop, mistyped prop, disallowed child — and stops there. Many renderers, one protocol.
A tree that validates against a registry is renderable by any conforming host of that registry. The check is pure and exhaustive: it returns every fault, not the first.
The interaction
When a human fires an action, it is checked against a capability before its handler executes. A denied action's handler never runs. The check is decided outside the model — a capability, not a prompt.
The handler is metered; the interaction records a two-part energy figure with an honest provenance — measured from a hardware interface, modelled, or estimated. The figure always says how it was obtained.
The measured cost is debited from the capability's remaining budget. The budget that stops a runaway UI is energy actually spent, settled after the action, not a token estimate guessed before it.
Each interaction seals as the next link of a hash-chained, signed log — allows and denies alike. Excise, reorder, or alter any interaction and the chain breaks at that point. A session is a tamper-evident ledger of what the user did, what it computed, and what it cost.
The receipt commits to the content address of what was supplied and what was produced — proof of the interaction without embedding its payload.
How you meter and how you gate are recognized edges the host wires — a hardware power meter, a budgeted grant — not parts of the protocol. joule-ui owns the receipt, the chain, and the lifecycle.
The receipt
Each interaction commits — in a fixed canonical core, signed with the host's key — to the surface shown, the action fired, the content addresses of the inputs and outputs, the verdict, the energy and its provenance, the budget left, and the previous link. Anyone holding the host's public key can verify the whole chain; removing or reordering one interaction breaks it at that point.
render #1: allow · 5751328 µJ [HwShunt] seq 0
render #2: allow · 7204884 µJ [HwShunt] seq 1
render #3: allow · 7224835 µJ [HwShunt] seq 2
sealed chain: 3 links verified, 20181047 µJ total
— measured on real hardware via the Sandbox PowerMeter edge Reference implementation
A Rust workspace, Apache-2.0. The surface and interaction layers, a reference renderer and host, and a conformance suite whose vectors reproduce from the published JSON alone. Measurement and capability are recognized edges: the sibling Sandbox meter supplies real hardware energy, the sibling JCP grant supplies the budgeted capability — joule-ui owns the receipt, the chain, and the lifecycle.
The surface: the typed Widget tree, the closed PropValue set with its Action variant, the host's WidgetSchema registry, and the exhaustive recursive validator. Streaming UiDelta primitives for token-by-token updates. Pure Rust, no IO, JSON-serialisable.
The interaction: run_interaction authorizes before running, meters the handler, charges the measured cost, content-addresses inputs and outputs. An InteractionLog seals each one as the next link of a hash-chained Ed25519 receipt — allows and denies both — and verify_chain rejects any excision, reorder, or mutation.
The reference renderer: a Widget tree to server-rendered HTML, no framework, no build step. Known widgets map to HTML, unknown widgets degrade visibly, text is escaped, and every Action wires to a single client function that posts the fire back to the host. A richer host swaps in a WASM/WebGPU renderer without touching the protocol.
The reference host: a pure (method, path, body) handler — serve the surface, run the metered interaction on each fired action, seal it, return the next surface plus the receipt fields, expose the hash-chained log — behind a dependency-free HTTP/1.1 driver.
Four conformance classes with a reproducible vector pack: exhaustive validation, interaction metering, authorize-before-run, and chain integrity. A third party reproduces the vectors from the published JSON alone — what makes joule-ui a standard, not one library's behaviour.