open-standards/joule-ui
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Transaction Science 9ffef885f0
All checks were successful
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 1m0s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 2m51s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m53s
standards workspaces build + test / aac-rs (pull_request) Successful in 3m4s
standards workspaces build + test / map-rs (pull_request) Successful in 1m0s
standards workspaces build + test / mesh-rs (pull_request) Successful in 56s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 2m0s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m1s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 2m3s
standards workspaces build + test / openpay (pull_request) Successful in 3m27s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 8m47s
WAI conformance / cargo-class corpora · macos (pull_request) Successful in 7m13s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 6m23s
WAI conformance / cross-arch byte-equality · macos (pull_request) Successful in 19s
WAI conformance / codec wrappers · fuzz smoke, text decode limits, C entry points (pull_request) Successful in 20s
WAI energy receipts / energy receipts · macos (pull_request) Successful in 1m38s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m3s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 4s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 5s
no-vanity-metrics / No new orphan source files (pull_request) Successful in 6s
spec citations resolve / Code cites no section its SPEC lacks (pull_request) Successful in 4s
lockfiles / every Cargo.lock is current (pull_request) Successful in 49s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m9s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m56s
standards workspaces build + test / jcp-rs (pull_request) Successful in 2m15s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m13s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m30s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m24s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m7s
WAI conformance / quantum core and corpus under wasm32-wasip2 (wasmtime) (pull_request) Successful in 2m14s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 14s
WAI conformance / cargo-class corpora · linux (pull_request) Successful in 8m51s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 9s
WAI conformance / cross-arch byte-equality · linux (pull_request) Successful in 25s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 48s
WAI energy receipts / energy receipts · linux (pull_request) Successful in 2m4s
WAI neural sink gates / model-free refusals of the neural sink (pull_request) Successful in 1m12s
wai-pack / wai-pack · does this change touch it (pull_request) Successful in 4s
wai-web reach builds / wai-web reach · does this change touch it (pull_request) Successful in 4s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 1m12s
wai-web wasm32 / wai-web wasm32 build · corpus, menu and writers (pull_request) Successful in 2m54s
wai-pack / wai-pack · macos (pull_request) Successful in 3m51s
wai-pack / wai-pack · linux (pull_request) Successful in 1m16s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 17m27s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 22s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 3m56s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 1m16s
wai-web reach builds / wai-web reach builds · the package of record, every output as recorded (pull_request) Successful in 2m45s
wai-web reach builds / wai-web reach builds · this tree's wai-web, every rung on its engine line (pull_request) Successful in 4m4s
clippy: no workspace reports an error, and the unsafe FFI states its contract
Three workspaces could not be linted at all: a deny-level clippy lint errored,
and clippy stops at the first erroring crate, so everything behind it went
unreported. None of the ten errors was a bug; each is fixed so it cannot mask
the next.

  jouleclaw-loader-gguf, jouleclaw-contract, jouleclaw-runtime: `0 * stride`
  spells the shared kv head (MQA) and the (row, col) cell address, mirroring
  the `hh * s` beside it. Kept, with the lint allowed and the reason written
  down, rather than dropping a term that documents which head is read.

  jouleclaw-backend-apple, jouleclaw-loader-gguf/ssm: a truncated SQRT_2 and
  LN_2 where the constant is what is meant -- `softplus(0) = ln2` is the
  assertion's whole point. Now `std::f32::consts`, which is also exact.

  jouleclaw-bounded, jouleclaw-outlier, jouleclaw-tools, joule-ui-core: 3.14
  as an arbitrary test value, which clippy reads as an attempt at pi. Given a
  value that is not near pi; in jouleclaw-tools the decimal is the subject of
  the format assertion, so expectation and input moved together.

  jouleclaw-policy-ipc: `parse_args` looped, but every arm returns or exits,
  so it could only ever run once. `if let` says what happens.

  smart-byte-edv: `s.sequence = cur` assigned the field to itself. `update`
  takes a document at its current sequence and bumps it, so the no-op was
  dead and the comment above it ("bump twice") described neither. Removed;
  the comment now states the mechanism the test relies on.

  jcp-schema: `Origins`'s `TryFrom<OriginsWire>` had `Error = Infallible`.
  Carried over to `From` with `#[serde(from = ...)]`, so the normalisation
  that keeps the top of the lattice single-encoded still runs on the wire --
  `origins_wire_normalizes_on_deserialize` pins it.

wai-rs: 19 unsafe `extern "C"` entry points stated no safety contract, beside
neighbours that did. Each now names what its caller must guarantee, per
pointer, from its own signature.

Verified on the build host: all 17 workspaces lint with zero errors; the tests
of every crate whose values changed pass; wai-rs builds, lints and documents.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-13 09:56:05 -04:00
..
conformance joule-ui: a meter is an estimator until it opts in, and a charge carries its grade 2026-09-30 20:10:14 -04:00
joule-ui-rs clippy: no workspace reports an error, and the unsafe FFI states its contract 2026-10-13 09:56:05 -04:00
LICENSE joule-ui: typed declarative protocol for agent-emitted user interfaces 2026-05-30 09:43:56 -04:00
README.md licences: ship the Apache-2.0 text the code already declares 2026-10-09 17:22:32 -04:00
SPEC.md joule-ui: served and example interactions are metered by this process's own CPU energy 2026-09-30 23:01:05 -04:00

joule-ui

A typed declarative protocol for agent-emitted user interfaces.

joule-ui is the sibling to JouleClaw for the moment when an agent's resolution has to become something a human can see and interact with. The agent emits a widget tree — (name, props, children), recursively — against a widget registry the host has published. The host renders. No React in the spec, no HTML over the wire, no agent holding the renderer.

The shape the field has converged on for this is declarative components against a registry: agents are far more reliable emitting structured data than emitting code, and renderers are far easier to harden when they own their own widgets. joule-ui pins that shape as a protocol; the renderer is product surface, owned by the consumer.

What ships in v1

  • joule-ui-rs/crates/joule-ui-core/ — the protocol types (Widget, PropValue, WidgetSchema, Registry) and the recursive validator. Pure Rust, no IO, JSON-serialisable.

  • joule-ui-rs/crates/joule-ui-interaction/ (v0.2) — the layer no other UI protocol carries: when a human or an agent fires an Action, the invocation is an accountable event. Every fire names the principal that made it — a did:key, the same whether a person or an agent (the protocol draws no distinction; both are traced). run_interaction authorizes it against a capability before it runs (a denied action's handler never executes), meters it in joules, charges its cost (a reading or an estimate, and which), and an InteractionLog seals it as the next link of a hash-chained receipt. The actor is bound into the signed core, so an interaction cannot be re-attributed without breaking the chain. A joule-ui session becomes a tamper-evident ledger of who fired it, what it computed, and what it cost — verifiable by anyone holding the host's key. The metering (Sandbox PowerMeter) and the capability (JCP grant) are recognized edges; the receipt, the chain, and the lifecycle are joule-ui's. See SPEC.md §5–§7 and examples/metered_surface.rs for the full loop.

The surface layer makes joule-ui a peer of the declarative-UI protocols (A2UI, MCP Apps). The interaction layer makes it the only one you can hand to an auditor: a UI whose every interaction is energy-accounted and sealed, by construction.

What is not here:

  • A renderer. The renderer is owned by the host (browser app, native shell, terminal UI). joule-ui validates the surface and seals the interaction; it does not paint pixels.
  • A transport. The validated spec and the interaction stream ride MCP, REST, SSE, gRPC, Web MoQ — any bytes-out protocol. Transport-agnostic.
  • A "model emits React" path. The agent emits a declarative tree against the registry; arbitrary code emission is out of scope.

Why a sibling, not inside JouleClaw

The spec layer is protocol — small, stable, conformant. The renderer registry is product surface — many of them, evolving fast. Splitting them protects the tools for use line: JouleClaw stays the runtime substrate; joule-ui is the UI protocol; consumers ship their own widgets.

Licence

Specification text and protocol document: CC-BY-4.0 (see LICENSE). Reference implementation in joule-ui-rs/: Apache-2.0 (see joule-ui-rs/LICENSE).