All checks were successful
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
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 4s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m13s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m58s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m30s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m11s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m13s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m19s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m50s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 28m1s
standards workspaces build + test / aac-rs (pull_request) Successful in 5m42s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 10m13s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 5m35s
standards workspaces build + test / map-rs (pull_request) Successful in 7m25s
standards workspaces build + test / mesh-rs (pull_request) Successful in 4m18s
standards workspaces build + test / openpay (pull_request) Successful in 16m8s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 3m15s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m53s
arl-rs, eoc-rs, smart-byte-rs and joule-ui-rs declare license = "Apache-2.0" in every crate, but each standard carried only its CC-BY-4.0 LICENSE for the specification text. Each Rust workspace now carries the Apache-2.0 text, and each README names both licences and where they live. jouleclaw's README pointed spec text at a spec/LICENSE that does not exist; it now points at LICENSE-SPEC. No licence changes: every file already declared these terms. Co-Authored-By: Claude Opus 5.5 <[email protected]>
68 lines
3.3 KiB
Markdown
68 lines
3.3 KiB
Markdown
# joule-ui
|
||
|
||
A typed declarative protocol for **agent-emitted user interfaces**.
|
||
|
||
joule-ui is the sibling to [JouleClaw](../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`](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`](LICENSE)).
|
||
Reference implementation in `joule-ui-rs/`: Apache-2.0 (see [`joule-ui-rs/LICENSE`](joule-ui-rs/LICENSE)).
|