A2UI Rendering
A2UI is a declarative JSON protocol for delivering rich UI from agents to client surfaces. UI is composed as a flat list of components where layout containers reference children by ID. The protocol enforces typed value wrappers and a fixed catalog of 18 primitives.
When to Compose A2UI
Compose A2UI only in response to a user message that needs rich visual output. Do not generate A2UI on session creation or proactively. Plain text remains the default for narrative responses.
Workflow
A2UI Render Progress:
- [ ] Decide what information to present
- [ ] Choose primitives (Text, Card, Column/Row, etc.)
- [ ] Compose the surfaceUpdate JSON with unique component IDs
- [ ] Call validate_and_emit_a2ui with the surfaceUpdate JSON
- [ ] If validation fails, fix the violations and re-validate
- [ ] Compose the beginRendering JSON pointing to the root component
- [ ] Call validate_and_emit_a2ui with the beginRendering JSON
- [ ] Wrap both validated payloads in ```a2ui markdown fences
validate_and_emit_a2ui MUST be called twice per surface: once
for surfaceUpdate and once for beginRendering. Without
beginRendering, the frontend will not render the surface.
Message Structure
surfaceUpdate (defines components)
{
"surfaceUpdate": {
"surfaceId": "my-surface",
"components": [
{"id": "unique-id", "component": {"TypeName": { ...props }}}
]
}
}
surfaceId: unique identifier for this UI surface.components: flat array of component definitions (NOT nested trees).- Each component has
id(unique string) andcomponent(object with exactly one key = the type name).
beginRendering (tells the frontend which component is root)
{
"beginRendering": {
"surfaceId": "my-surface",
"root": "root-component-id"
}
}
surfaceId: must match the surfaceUpdate's surfaceId.root: theidof the outermost component (usually a Card).
Typed Value Wrappers
CRITICAL: Never use raw JSON primitives. All values MUST be wrapped.
| Type | Wrapper | Example |
|---|---|---|
| String | {"literalString": "value"} |
"text": {"literalString": "Hello"} |
| Number | {"literalNumber": 42.0} |
"value": {"literalNumber": 3.14} |
| Boolean | {"literalBoolean": true} |
"autoplay": {"literalBoolean": true} |
| Binding | {"path": "some.data.path"} |
"text": {"path": "user.name"} |
Raw "value", raw 42, or raw true as property values will be
rejected by validate_and_emit_a2ui.
Container Children
Layout containers reference children by ID:
- Multiple children:
"children": {"explicitList": ["child-id-1", "child-id-2"]}(NEVER raw arrays) - Single child:
"child": "child-id"(used by Card, Button)
Component ID Rules
- IDs MUST be unique within a
surfaceUpdate. - Use descriptive names:
"title-heading","main-card","details-column". - All ID references (
child,children.explicitList,entryPointChild,contentChild,tabItems[].child) MUST resolve to IDs in the samecomponentsarray.
Component Catalog
For the full catalog of 18 primitives, with required and optional props plus per-type notes, see components.md.
Examples
For three complete surfaceUpdate + beginRendering payloads
(simple info card, data list card, dashboard with action button), see
examples.md.