Skip to content

A2UI — surfaces, catalogs, and actions

  • Protocol lesson
  • Intermediate
  • 15 min read
  • Checked 15 Aug 2026

A passenger-care agent could answer with a paragraph. Sometimes the user needs more: a status card, evidence links, a choice of remedies, and a button that requests human review.

A2UI lets the agent describe that interface without sending React, Swift, Flutter, or arbitrary JavaScript. A renderer on each platform turns the same abstract component description into trusted local components.1

As checked on 15 August 2026:

Version Status What to do
A2UI v0.9.1 Current production release Use this lesson’s message names and schemas
A2UI v1.0 Candidate Evaluate separately; do not assume candidate fields are production-stable
A2UI v0.8 Legacy Expect older names such as beginRendering and surfaceUpdate

The version field belongs in every v0.9.1 envelope. Do not mix examples across versions: v0.9 uses createSurface, updateComponents, and updateDataModel, while many older posts still use v0.8 names.

Object Plain meaning Passenger-care example
Surface One named UI area with its own components and data passenger_options card
Component An abstract widget with a stable ID Text, Column, or Button
Component catalog The schema and vocabulary the renderer agrees to support The v0.9.1 basic catalog or an airline-owned catalog
Renderer Trusted client code that validates and maps abstract components to native widgets Web, Android, iOS, or desktop application
Data model Surface state kept separately from component structure Case ID and eligibility status
Data binding A JSON Pointer or function that supplies a component value /care/status
Action A user interaction returned to the server or handled by an approved local function request_human_review

A catalog is both vocabulary and boundary. If the client supports Text, Card, and Button, the agent may compose those elements. It cannot invent RunShellCommand and expect the client to execute it.

  1. 01createSurface names the surface and catalog
  2. 02updateComponents adds or replaces component definitions
  3. 03updateDataModel supplies or changes bound data
  4. 04renderer validates and displays native widgets
  5. 05later updates change structure or data
  6. 06deleteSurface removes the UI area
Message Purpose Rule worth remembering
createSurface Create a surface and select a catalog Create before updating; catalog and surface ID stay fixed until deletion
updateComponents Add or replace components Components form a flat list linked by IDs; one component must be root
updateDataModel Replace all data or update one JSON Pointer path Data changes need not resend component structure
deleteSurface Remove the surface, components, and data Recreate it if the catalog must change

The first line creates the surface. The second supplies a flat component list. The third supplies the bound case data.

src/examples/protocols/a2ui_passenger_options.jsonl
{"version":"v0.9.1","createSurface":{"surfaceId":"passenger_options","catalogId":"https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"}}
{"version":"v0.9.1","updateComponents":{"surfaceId":"passenger_options","components":[{"id":"root","component":"Card","child":"content"},{"id":"content","component":"Column","children":["title","status","request_button"]},{"id":"title","component":"Text","text":"Passenger care","variant":"h2"},{"id":"status","component":"Text","text":{"path":"/care/status"}},{"id":"request_button_label","component":"Text","text":"Request human review"},{"id":"request_button","component":"Button","child":"request_button_label","action":{"event":{"name":"request_human_review","context":{"caseId":{"path":"/case/id"}}}}}]}}
{"version":"v0.9.1","updateDataModel":{"surfaceId":"passenger_options","value":{"case":{"id":"CASE-1047"},"care":{"status":"Hotel eligibility needs the delay cause and overnight-stay facts."}}}}

The renderer resolves /care/status when it draws the status component. Clicking the button sends an action event with the resolved case ID.

Client-to-server action
{
"version": "v0.9.1",
"action": {
"name": "request_human_review",
"surfaceId": "passenger_options",
"sourceComponentId": "request_button",
"timestamp": "2026-08-15T12:00:00Z",
"context": {
"caseId": "CASE-1047"
}
}
}

An action is an event, not authorization. The server must authenticate the caller, validate the case ID, check ownership and policy, and decide whether the requested operation is allowed.

A2UI uses an adjacency-list model: components live in one list and refer to children by ID. This supports progressive updates and avoids requiring one deeply nested UI tree in a single generated object.

root (Card)
└── content (Column)
├── title (Text)
├── status (Text bound to /care/status)
└── request_button (Button)

The client may receive a reference before its component or data arrives. A renderer should show an empty value or placeholder, then update when the missing message arrives. It should not crash or execute fallback code from the agent.

A2UI defines UI messages but does not require one transport. A2A, AG-UI, MCP, SSE, or WebSockets can carry the envelopes when they preserve message order and framing.2

Before generation, the server needs to know what the client can render. With the A2A extension, the client sends a2uiClientCapabilities, including supportedCatalogIds, in message metadata. A2UI envelopes travel inside A2A data parts identified with the application/a2ui+json media type.3

client supports: airline-basic-v3, a2ui-basic-v0.9.1
agent selects: airline-basic-v3
agent emits: only components and functions in airline-basic-v3
client validates → client renders

If no catalog matches, return an ordinary text or data response. Do not guess that an unsupported component will work.

  1. Allowlist catalogs. Load schemas from trusted build-time or administrative configuration, not an arbitrary URL supplied by the agent.
  2. Validate every envelope. Reject unknown versions, component types, invalid references, malformed data bindings, and oversized payloads.
  3. Render locally. Map catalog entries to maintained native components; never evaluate code, HTML, URLs, or styles as trusted merely because they arrived in A2UI.
  4. Constrain actions. Treat action names and context as untrusted input. Apply server-side authentication, authorization, validation, rate limits, and approval.
  5. Minimize synchronized state. sendDataModel can return an entire surface data model with later messages. Do not place secrets or unrelated personal data in that model.
  6. Keep origin ownership. Send a surface’s synchronized data only to the server that owns that surface.
  7. Trace the UI contract. Record protocol version, catalog ID, surface ID, message type, validation errors, action name, policy decision, and renderer version.

The agent chooses from components the client already knows how to render. The product team still owns accessibility, keyboard behavior, focus, localization, typography, responsive layout, destructive-action confirmation, and visual quality.

Use a normal frontend when the screen is known at build time. A2UI earns its cost when the useful interface depends on the agent’s result and must travel across renderer or system boundaries.

A2UI is the agent-to-renderer boundary. The agent streams declarative JSON envelopes that create a surface, define components from a negotiated catalog, update a separate data model, and eventually delete the surface. The client validates those messages and renders its own native widgets, so it does not execute arbitrary agent code. User interactions return as actions. Catalog negotiation, schema validation, data minimization, and server-side authorization are the real safety controls. A2UI 0.9.1 is the current production release; 1.0 is still a candidate, so I keep the version explicit.

Next: learn A2A discovery and task lifecycles or compare MCP, A2A, and A2UI.

  1. The A2UI v0.9.1 specification defines the current production surface, component, data-model, catalog, and action contracts.

  2. The A2UI specification requires ordered, framed delivery and describes A2A, AG-UI, MCP, and other possible transports.

  3. The A2UI A2A extension defines capability metadata and application/a2ui+json data parts for carrying A2UI messages over A2A.