- name
- a2ui-rendering
- description
- Use when an agent renders rich UI back to a client surface (cards, dashboards, forms, modals) using the A2UI v0.8.0 declarative protocol. Required whenever the response should display structured components rather than plain text, or whenever the validate_and_emit_a2ui tool is in scope.
- license
- Apache-2.0
# 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.
<!-- [START a2ui_skill_message_structure] -->
## Message Structure
### surfaceUpdate (defines components)
```json
{
"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) and **`component`**
(object with exactly one key = the type name).
### beginRendering (tells the frontend which component is root)
```json
{
"beginRendering": {
"surfaceId": "my-surface",
"root": "root-component-id"
}
}
```
- **`surfaceId`**: must match the surfaceUpdate's surfaceId.
- **`root`**: the `id` of the outermost component (usually a Card).
<!-- [END a2ui_skill_message_structure] -->
<!-- [START a2ui_skill_wrappers] -->
## 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`.
<!-- [END a2ui_skill_wrappers] -->
## 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 same `components` array.
## Component Catalog
For the full catalog of 18 primitives, with required and optional
props plus per-type notes, see [components.md](components.md).
## Examples
For three complete `surfaceUpdate` + `beginRendering` payloads
(simple info card, data list card, dashboard with action button), see
[examples.md](examples.md).
View on GitHub