YAML first
Pages declare layout, components, bindings, actions, and stable component identifiers once on the backend.
A2UI
Democr.ai implements and extends Google's A2UI protocol, letting modules describe pages in YAML and publish effects while web, desktop, Tauri, React, and mobile-oriented clients render native interfaces. The backend remains the owner of business behavior.
Live example
The capture shows one backend-driven conversation surface being rendered by the client while the agent streams text, tools, and structured UI updates.
Authoring model
Democr.ai's A2UI layer builds on Google's A2UI protocol and extends it with YAML-first module pages, runtime effects, native desktop rendering, web renderers, and SDK-managed server actions.
Pages declare layout, components, bindings, actions, and stable component identifiers once on the backend.
A view loads the YAML, prepares minimal data, and seeds page data or stores through the SDK.
Actions can append, replace, open drawers, navigate, and publish stream updates without rebuilding the whole page on each client.
Screenshots
Static captures show the same conversation surface after structured A2UI components have been inserted into the timeline.
Dynamic surfaces
A2UI is designed for interactions where the final result is not the only useful UI update.
A message list can receive user turns, ephemeral agent steps, streamed text, components, and final persisted rows.
Long-running actions can publish state changes while background work continues.
Tools and agents can add tables, cards, lists, charts, or other structured UI blocks to the same conversation surface.
Client contract
The strongest test of a server-driven UI protocol is whether genuinely different clients can consume it. Democr.ai renders the same payloads through Qt/PySide, browser clients, Tauri, React variants, and a React Native client path.
Different renderers consume the same A2UI components and effects. Module authors do not rewrite feature UI for every client stack.
Effects address predictable targets — message lists, drawers, composers, collection-capable components — so the same update lands on every client.
Dynamic screens append or replace focused elements instead of forcing full-page rerenders, on every renderer.
Example
The example shows the contract shape without turning the page into implementation documentation.
- kind: Row
id: chat_page
children:
- kind: ThreadList
id: chat_thread_list
- kind: MessageList
id: chat_message_list
- kind: Composer
id: chat_composer
send_action:
name: chat.submit_message
Next
Use these pages to move from the concept to adjacent parts of the runtime.