A2UI is built on three interlocking ideas that together allow AI agents to produce rich, interactive UIs safely and portably. This page explains those ideas from the ground up: how the architecture is layered, what message types agents send, how components are structured, how data flows reactively through a surface, what catalogs are and why they matter for security, and how A2UI messages travel over different transports. Understanding these concepts will make every other part of the documentation click into place.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/a2ui-project/a2ui/llms.txt
Use this file to discover all available pages before exploring further.
The Three-Layer Architecture
Every A2UI interaction is organized into three distinct layers:Message Types
All A2UI communication is a sequence of self-contained JSON messages (streamed as JSON Lines / JSONL). The set of message types differs slightly between protocol versions:- v0.9 (Stable)
- v1.0 (Candidate)
- v0.8 (Legacy)
| Message | Purpose |
|---|---|
createSurface | Create a new surface and declare which catalog the agent will use |
updateComponents | Add or update UI components in a surface |
updateDataModel | Update application state at a specific JSON Pointer path |
deleteSurface | Remove a surface and release its resources |
version field. createSurface replaces the old beginRendering — surface creation and render initiation are now a single, explicit step.For complete field-level documentation of every message type, see the Message Reference.
Surfaces
A surface is a named, isolated area of UI that an agent creates and manages. Think of it as a canvas: a dialog, a sidebar panel, a main content area, or a card embedded in a chat stream. Each surface has its own:surfaceId— a string that uniquely identifies the surface; every message that affects a surface must include this ID.- Component tree — the flat list of components that make up the surface.
- Data model — an independent JSON object holding that surface’s application state.
surfaceId, without any risk of state collision.
When the agent sends
deleteSurface, the client removes the surface and its data model from memory. This is the canonical signal that a workflow step is complete.Components: The Adjacency List Model
A2UI represents component hierarchies as a flat list of nodes with ID references — an adjacency list — rather than a nested JSON tree. This is a deliberate design choice.Why flat lists beat nested trees
| Nested tree | Adjacency list (A2UI) | |
|---|---|---|
| LLM generation | Must track indentation depth across the whole response | Each component is an independent, flat object |
| Streaming | Hard to render partial output; tree isn’t valid until closed | Any individual component can be rendered as soon as it arrives |
| Incremental update | Replacing one node requires resending its entire subtree | Update any node by id; the rest is untouched |
| Error correction | Malformed nesting can break the entire payload | A malformed component doesn’t affect its siblings |
Component anatomy
Every component has three required fields:id— a unique string identifier within the surface (use descriptive names like"user-profile-card", not"c1").component— the component type string, matching a name in the active catalog ("Text","Button","DateTimeInput", etc.).- Properties — zero or more type-specific fields, either as literal values or reactive data-binding paths.
- v0.9 (Stable)
- v0.8 (Legacy)
A flat component list using the v0.9 format. Parent–child relationships are expressed as arrays of child IDs:
Static vs. dynamic children
Children can be a fixed list ("children": ["a", "b"]) or a template that generates one child instance per item in a data array:
- v0.9 (Stable)
- v0.8 (Legacy)
/products array, the renderer instantiates product-card with that item’s data in scope. Adding or removing items from /products automatically adds or removes rendered cards.For the full component catalog with properties and live examples, see the Component Reference.
Data Binding
A2UI separates UI structure (what the interface looks like) from application state (what data it displays). Components connect to state via JSON Pointer paths (RFC 6901).The data model
Each surface maintains an independent JSON object as its data model:| Path | Resolves to |
|---|---|
/user/name | "Alice" |
/reservation/guests | 2 |
/cart/items/0/name | "Widget" |
Reactive binding
When a component’s property references a path, it updates automatically whenever that path changes — no component update message is needed:- v0.9 (Stable)
- v0.8 (Legacy)
status-text component re-renders with “Shipped” — automatically, without any updateComponents message.Bidirectional binding for inputs
Input components (TextField, CheckBox, ChoicePicker, DateTimeInput) write user interactions back to the data model automatically. The agent can read the current value of any bound path when the user triggers an action:| Component (v0.9) | Binding example | User action | Data model update |
|---|---|---|---|
TextField | "value": { "path": "/form/name" } | Types “Alice” | /form/name → "Alice" |
CheckBox | "value": { "path": "/form/agreed" } | Checks box | /form/agreed → true |
ChoicePicker | "value": { "path": "/form/country" } | Selects “Canada” | /form/country → ["ca"] |
For full data binding syntax and advanced patterns (scoped template paths, nested objects), see the Data Binding Reference.
Catalogs
A catalog is a JSON Schema file that defines exactly which component types, properties, functions, and theme values the agent is permitted to use on a given surface. It is the primary security boundary in A2UI.Why catalogs matter
Without a catalog, an agent could request arbitrary components — including ones the client doesn’t implement, ones that conflict with the host app’s design system, or ones that expose unintended behaviors. With a catalog:- The client is in control. The agent can only request what the client has pre-approved and implemented.
- Payloads are validated. Both the agent (pre-send) and client (on-receive) validate every A2UI message against the catalog schema.
- Design consistency is enforced. A production catalog mirrors the host app’s design system —
PrimaryButton,HeroCard,DataGrid— not generic primitives.
The Basic Catalog
For getting started quickly, the A2UI team maintains a Basic Catalog — a pre-defined schema with general-purpose primitives (Button, TextField, Card, Column, Row, Text, DateTimeInput, etc.). It has open-source renderers for Lit, Angular, and React. Reference it increateSurface to use the Basic Catalog:
Catalog negotiation
Because clients and agents may support different catalogs, A2UI defines a negotiation handshake:Client advertises supported catalogs
The client sends a prioritized list of
supportedCatalogIds in the metadata of every message it sends to the agent:Agent selects the best match
When creating a surface, the agent picks the highest-priority catalog from the client’s list that it is capable of generating. This choice is locked for the lifetime of that surface. If no compatible catalog is found, the agent sends no UI.
Custom catalogs
Most production applications define their own catalog that matches their design system. A minimal custom catalog looks like this:For catalog versioning, graceful degradation, and the full linking workflow, see the Catalogs Reference.
Transports
A2UI is transport-agnostic. Any mechanism that can carry JSON messages from agent to client works. The protocol defines the message format; the transport is the pipe.| Transport | Best for |
|---|---|
| A2A Protocol | Multi-agent systems and remote agents; standardized agent-to-agent communication |
| AG-UI (CopilotKit) | Bidirectional real-time agent–UI communication with state sync; use AG-UI as the pipe, A2UI as the payload |
| Server-Sent Events (SSE) | One-way streaming over HTTP; simple and broadly supported |
| WebSocket | Persistent bidirectional connections; ideal when the client also needs to send frequent updates |
| REST / HTTP | Simple request-response for non-streaming use cases |
| Custom | gRPC, message queues, in-process — if it carries JSON, it works |
The restaurant finder demo uses the A2A Protocol: the Python agent exposes an A2A endpoint and the Lit client connects to it. For CopilotKit-based setups, AG-UI carries the A2UI messages transparently.
For implementation details on each transport adapter, see the Transports Reference.
Putting It All Together
Here is a complete lifecycle for a restaurant booking request, showing all three layers working together:- Agent creates the surface (
createSurface) — declares the catalog; client allocates a new surface context. - Agent defines the UI (
updateComponents) — streams a flat list of component records; client renders them progressively. - Agent populates state (
updateDataModel) — sends initial field values; bound components update automatically. - User edits a field — the TextField writes the new value back to the data model; no agent message needed.
- User clicks Submit — the Button fires an
actionevent with the current data model snapshot; the agent receives it. - Agent confirms — either updates the surface to show a confirmation state or sends
deleteSurfaceto close it.
Concept Reference Cards
Message Reference
Full field-level specification for all message types across v0.8 and v0.9.
Component Reference
Every component in the Basic Catalog with properties, examples, and rendering notes.
Data Binding Reference
JSON Pointer path syntax, reactive binding patterns, input bindings, and dynamic lists.
Catalogs Reference
Catalog schema, negotiation protocol, versioning strategy, and custom catalog guide.
Transports Reference
A2A, AG-UI, SSE, WebSocket, and custom transport integration details.
Glossary
Short definitions for all A2UI protocol terms: surface, catalog, data model, renderer, agent turn, and more.