open-standards/joule-ui/README.md
Transaction Science 9206e7c18a joule-ui: README — actor is part of the accountable event
Reflect the mandatory actor in the headline description: a fire is made by
a human or an agent (one did:key scheme either way), the principal is bound
into the signed core, and the ledger records who fired it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-12 22:22:27 -04:00

67 lines
3.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 the measured cost, 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.