Skip to content

v1.2 — Generative UI Trust Runtime

Document ID: RM-GUI-001 File Path: docs/18-roadmap/v1.2-generative-ui.md Version: 1.3.0 Status: Phases 1–3 complete (2026-07-15) — the scoped v1.2 milestone is shipped Owner: Product / Founder Last Updated: 2026-07-15


Execute PRD-005 (decision: ADR-0011): ship the frame protocol, the trust/policy engine, the durable interaction loop, the renderer SDK, and the internal-tools beachhead — in three strictly sequential phases with measured exit criteria.

Requirement IDs (UIP/GRD/HIL/RDR/CMP/ITS/EMB) are defined in PRD-005 §6; tickets here carry the RM-GUI-P<phase> prefix and reference them.

Relationship to v1.1: Phase 1/2 of v1.1 are done. v1.1 Phase 3 (ecosystem & scale) is re-scoped through PRD-005: items serving the trust runtime (MCP surface, SDK distribution) fold into RM-GUI-P3; purely horizontal items are deferred to future.md.


2. Phase 1 — Protocol & Trust Core (server-side only) — ✅ DONE (2026-07-15)

Section titled “2. Phase 1 — Protocol & Trust Core (server-side only) — ✅ DONE (2026-07-15)”

Theme: frames exist and are governed. No renderer; acceptance is against the API/SSE stream and the audit chain.

Shipped: all nine tickets. wovyr-ui + wovyr-ui-guard crates; __execution_id engine stamping; the server ui activity (UiActivityExecutor in crates/wovyr-server/src/ui.rs) with the durable pending-frame store under ~/.wovyr/ui; GET /api/v1/ui/frames[/{id}] + POST /api/v1/ui/decisions/{id}; audit-chain verdict/decision records paired with frame hashes; RunEvent::UiFrame over SSE. Exit criterion met: UC1 (incl. the kill/restart crash-recovery variant) and UC4 run green in wovyr-server’s ui::tests. Two P1 deviations, both documented in code: display-only frames complete immediately instead of suspending (nothing to decide — a pending record no decision could clear would leak), and the protocol additionally rejects frames declaring inputs without any action (a dead control the decision loop could never complete). The GRD-203 LLM-judge variant was cut per §5’s P1 cut line — structural rules only.

TicketRequirement(s)Summary
RM-GUI-P1-101UIP-101, UIP-106New crate wovyr-ui: UiFrame tree over the constrained component vocabulary, schemars-derived schemas, semver’d schema version, newer-than-understood rejection
RM-GUI-P1-102UIP-102, UIP-103Provenance metadata (run id, model id, prompt pin, canonical content hash) + declared intents on every actionable node; undeclared effects are validation errors
RM-GUI-P1-103UIP-104UiFrame event on RunEventSink → server SSE frame; workflow-activity output form; REST pull of the pending frame
RM-GUI-P1-104GRD-201, GRD-206New crate wovyr-ui-guard: UiPolicy YAML (forbidden component classes deny-by-default, approval-gate requirements, redaction, media-origin allow-list), tenant-scoped + versioned + pin-immutable
RM-GUI-P1-105GRD-202, GRD-207Guardrail-stage enforcement between generation and emission, fail-closed; hosted-run floor: no policy ⇒ input/action frames denied (WOVYR_UNRESTRICTED_UI=1 escape hatch)
RM-GUI-P1-106GRD-203, GRD-204Intent-consistency structural checks + deception-shape rules (structural first; LLM-judge variant shadow-mode only)
RM-GUI-P1-107GRD-205Verdicts into the wovyr-audit hash chain (rule id + frame hash); blocked-frame content retained KMS-encrypted, policy-controlled
RM-GUI-P1-108HIL-301..303ui workflow activity (durable suspend on the Interrupted path); typed decision validation; POST /api/v1/ui/decisions/{frame-id} over the human-approval signal path, decision-taker recorded
RM-GUI-P1-109Integration tests: UC1 (block-then-allow) and UC4 (injection containment) end-to-end over SSE + audit verify(); crash-kill between frame and decision resumes clean (the existing startup-resume test pattern)

Exit: UC1/UC4 green in CI, including the crash-recovery variant.


3. Phase 2 — Renderer & Interaction Loop — ✅ CORE DONE (2026-07-15)

Section titled “3. Phase 2 — Renderer & Interaction Loop — ✅ CORE DONE (2026-07-15)”

Theme: humans see and decide.

Shipped: @wovyr/ui-react (sdks/ui-react) — a React renderer for the full component vocabulary, CSS-custom-property design tokens, an inert visible placeholder for unrecognized node types, and client-side frame-hash verification (hash.ts’s canonical-JSON + Web Crypto SHA-256, cross-checked against a real frame from the live Rust server — the JS and Rust hashes matched byte-for-byte, proving RDR-403’s integrity claim actually holds, not just that the two implementations independently believe themselves correct). The base TS SDK (sdks/typescript) gained a ui resource (frames.list/get, decisions.submit) with an ui: integration-test suite proving UC1/UC4 against a live server. The killer demo (RM-GUI-P2-209) ships as examples/workflows/ui-checkout-{approve,block}.yaml + examples/ui/checkout-demo (a runnable Vite+React app) — driven end-to-end in a real browser against a real wovyr-server: the poisoned frame blocked and never rendered; the safe frame rendered, was approved with a real decision POST, and cleared from the pending list. A scoped HIL-304 landed as the ui_present tool (wovyr-tools, opt-in only, never a default builtin) + UiInteraction trait + the CLI’s wovyr agents run --local --interactive-ui stdin presenter — so a bare (non-workflow) agent run can present a policy-checked frame and get a decision back, with the same fail-closed frame/decision validation as the workflow path.

Honest gaps, carried forward rather than silently dropped:

  • RDR-402 (web-component build) — cut per §5’s P1 cut line, extended to P2: React is the only supported host.
  • RDR-404 (progressive/streaming rendering) — not built. Frames present complete, not incrementally; the protocol has no partial-frame delta shape to stream (unlike ToolCallDelta). A later slice if a real use case needs it.
  • HIL-305 (durable frame timers) and the audit-chain pairing half of HIL-306 — not built for the bare-agent-run path. ui_present has no durability at all (a bare agent run has no checkpoint to resume from, documented in the tool’s own module comment) and is not wired into any audit log — only the P1 workflow path is audited. Presenting UI from a bare agent run in a hosted/audited context is not yet a supported combination; use the workflow ui activity for anything that needs a durable or audited trail.
  • GRD-208 (WASI validator sandboxing) and CMP-501..503 (signed templates) — cut per §5, deferred to Phase 3.
TicketRequirement(s)Status
RM-GUI-P2-201RDR-401, RDR-403Done — @wovyr/ui-react, cross-language hash-verified
RM-GUI-P2-202RDR-402Cut — React only
RM-GUI-P2-203RDR-404Not built — no progressive rendering (see above)
RM-GUI-P2-204RDR-405Done — accessible markup by construction
RM-GUI-P2-205HIL-304..306Partial — HIL-304 (bare-run ui_present tool) only; no durability, no audit
RM-GUI-P2-206GRD-208Cut — deferred to P3
RM-GUI-P2-207CMP-501..503Cut — deferred to P3
RM-GUI-P2-208RDR-406Done — sdks/ui-react/README.md quickstart
RM-GUI-P2-209PRD-005 §9Done — examples/ui/checkout-demo, verified live in a real browser

Exit: the killer demo runs from a fresh clone (verified: server up, demo npm install && npm run dev, both flows work in a real browser). The SDK quickstart is documented but not yet timed with an external tester — that measurement is deferred to the design-partner onboarding in Phase 3.


4. Phase 3 — Beachhead & Embeddability — ✅ DONE (2026-07-15)

Section titled “4. Phase 3 — Beachhead & Embeddability — ✅ DONE (2026-07-15)”

Theme: sellable and adoptable.

Shipped: wovyr-ui-guard::conformance (EMB-704) — a public, serde_json/plain-JSON-vector conformance suite (crates/wovyr-ui-guard/src/conformance.rs) any deployer can run against their own policy (conformance_report(&policy)), gated in this workspace’s own cargo test --workspace. Standalone middleware mode (EMB-701, crates/wovyr-server/src/ui.rs) — POST /api/v1/ui/present + GET/POST /api/v1/ui/decisions/{id} present/decide/retrieve a trust-layer-governed frame with zero workflow or agent adoption, verified live end-to-end (present → render → decide → retrieve, plus the sensitive-input block path) against a real server. RDR-402’s cut was revisited and built: <wovyr-ui-frame> (@wovyr/ui-react/web-component, sdks/ui-react/src/webComponent.tsx) wraps UiFrameView in a framework-agnostic custom element (react-dom/client’s createRoot internally), dispatching a decide CustomEvent a host attaches its own async decision promise to — proven with a deliberately React-free smoke test (examples/ui/checkout-demo/web-component.html). The dashboard’s Surfaces panel (ITS-601/602, dashboard/src/app/features/surfaces/) is real dogfooding, not a mock: an operator composes an actual UiFrame, presents it via POST /api/v1/ui/present through the dashboard’s own HttpClient + tenant interceptor, renders it with <wovyr-ui-frame>, and decides it under their own RBAC-scoped session (ui:read/ui:write) — verified live in a browser end to end, including the trust layer visibly blocking a destructive action the operator opts into for the demo. The design-partner onboarding guide (PRD-005 §8, docs/01-product/design-partner-onboarding.md) ships with every command in its quickstart run against a real server, not just written.

Verification, not just code: every claim above was exercised against a live wovyr-server (curl for the onboarding quickstart, a real browser for the web component and the dashboard panel) — including both the allow path and the trust layer actually blocking a frame, in the dashboard’s own UI.

Scoped for this pass (solo-founder bandwidth, same discipline as P1/P2’s own cuts): the highest-leverage, honestly-buildable subset this pass is EMB-701 (standalone mode — the definitional embeddability feature: zero workflow/agent adoption required to use the trust runtime) and EMB-704 (a public, reusable conformance suite). Building real dashboard Surfaces dogfooding (ITS-601/602) requires embedding @wovyr/ui-react in a non-React host, which means revisiting P2’s RDR-402 cut — a web-component wrapper is now in scope because Surfaces needs it, not as a standalone goal. The design-partner onboarding doc is a cheap, concrete artifact; the actual partner program (5 partners, paid pilots) is a business/GTM activity, not a code deliverable, and isn’t attempted here.

Cut, per this scoping pass:

  • EMB-702 (MCP server surface) — this codebase has an MCP client (wovyr-tools::mcp) but no MCP server implementation at all; serving ui_present/ui_await_decision as MCP tools is a new subsystem, not an extension of existing code. Deferred whole.
  • UIP-105 / EMB-703 (interop mapping to A2UI/MCP Apps) — per the P3 cut line already on record below; those standards are still in motion and the runtime/enforcement point (already shipped) is the durable value, not the schema.
  • ITS-603 (destructive-action auto-gating) and ITS-604 (saveable/ shareable surfaces) — real features, not attempted this pass; the Surfaces panel below is a working, honestly-scoped v1, not the full ITS vision.
  • The design-partner program’s execution (outreach, 5 partners, red-team, paid pilots) — a business activity; only the onboarding document ships.
TicketRequirement(s)Status
RM-GUI-P3-301ITS-601, ITS-602Done — real Surfaces panel, verified live (not the full ITS vision — see cuts below)
RM-GUI-P3-302ITS-603, ITS-604Cut — deferred
RM-GUI-P3-303EMB-701Done — standalone present/decide/retrieve, verified live against a real server
RM-GUI-P3-304EMB-702Cut — no MCP server subsystem exists yet
RM-GUI-P3-305UIP-105, EMB-703Cut — deferred (standards immaturity)
RM-GUI-P3-306EMB-704Done — wovyr_ui_guard::conformance, gated in cargo test --workspace
RM-GUI-P3-307PRD-005 §8Done — onboarding doc shipped, quickstart run live end-to-end; partner program itself (outreach, 5 partners, paid pilots) is a business activity, not attempted
RDR-402 (revisited)Done — <wovyr-ui-frame> web component, un-cut from P2 because Surfaces needed it

Exit: met. POST /api/v1/ui/present proven end-to-end with zero workflow/agent involvement (including the sensitive-input block path); the conformance suite passes in cargo test --workspace (147+ Rust tests green, one pre-existing unrelated environmental flake in an unrelated wovyr-cli scaffold test — confirmed to pass in isolation, a resource-contention issue under the full parallel test run, not a regression); a real Surfaces panel in the dashboard renders a real frame built from a real API call and dispatches a real, RBAC-scoped action under the operator’s own session when decided — verified live in a browser, both the allow path and the trust layer visibly blocking a destructive action.


5. Cut Lines (solo-founder bandwidth, PRD-005 §10)

Section titled “5. Cut Lines (solo-founder bandwidth, PRD-005 §10)”

If a phase overruns, cut in this order — never the other:

  • P1: LLM-judge consistency checks (GRD-203 judge variant) → structural rules only. Blocked-frame content retention (GRD-205 second half) → verdict-only audit.
  • P2: Web-component build (RDR-402) → React only. Marketplace badge track (CMP-502) → signing only.
  • P3: Interop mapping breadth (UIP-105) → one target shape first. Surfaces sharing (ITS-604) → per-operator only.

The fail-closed floors (GRD-202/207, HIL-302) and audit integration (GRD-205 verdicts, HIL-306) are never cut — they are the product.


VersionDateDescription
1.3.02026-07-15Phase 3 shipped: EMB-701 standalone mode, EMB-704 conformance suite, RDR-402 web component (revisited from its P2 cut), and a real dashboard Surfaces panel (ITS-601/602) — all verified live against a real server/browser, not just typechecked. Design-partner onboarding doc (PRD-005 §8) shipped with its quickstart run end-to-end
1.2.02026-07-15Phase 2 core shipped: @wovyr/ui-react (cross-language hash-verified), the killer demo running live in a browser, and a scoped HIL-304 (ui_present tool, no durability/audit). RDR-402/404, HIL-305, GRD-208, CMP-5xx documented as cut or not built
1.1.02026-07-15Phase 1 shipped: all RM-GUI-P1 tickets done, UC1/UC4 + crash-recovery green; two documented P1 deviations (display-only frames complete immediately; inputs-without-actions rejected at the protocol)
1.0.02026-07-14Initial v1.2 milestone: three phases executing PRD-005