A2UI protocol
The Agent-to-User Interface (A2UI) Protocol is an open specification that allows AI agents to stream safe, declarative user interfaces—such as cluster status cards, deployment progress bars, and interactive Human-in-the-Loop approval forms—without generating or executing raw HTML or JavaScript.
Agents emit schema-validated JSON component trees rather than executable HTML/JS, eliminating script injection risks.
Built-in primitives for cards, tables, progress indicators, status badges, and interactive approval forms.
Stream UI containers and live state updates incrementally over Server-Sent Events (SSE) as subagents complete tasks.
Map A2UI JSON payloads directly to your design system's native React, Vue, or Flutter components.
A2UI vs. raw HTML generation
| Dimension | Raw HTML / Markdown | A2UI Protocol |
|---|---|---|
| Wire Format | <button onclick="...">Deploy</button> | {"type": "button", "label": "Deploy", "action": "approve"} |
| Security Posture | Vulnerable to XSS and arbitrary script injection | Strictly schema-validated; zero arbitrary code execution |
| Streaming Behavior | Breaks layout until closing tags arrive | Streams incremental JSON component patches cleanly |
| Type Safety | Unvalidated strings | Validated against a registered component registry |
| Accessibility | Relies on LLM generating valid ARIA attributes | Inherits host design system's accessible primitives |
Protocol flow
When an agent responds to a request that benefits from structured visualization or interactive approval, it emits an A2UI component tree alongside its conversational response:
Component schema
Every A2UI payload follows a uniform recursive structure:
{
"type": "component_type",
"properties": {},
"children": []
}
Core primitives
Text and badges
{
"type": "text",
"content": "Infrastructure Status",
"style": "heading"
}
Action buttons
{
"type": "button",
"label": "Approve Rollout",
"action": "approve_rollout",
"variant": "primary",
"disabled": false
}
Layout containers and cards
{
"type": "card",
"title": "EKS Production Cluster",
"subtitle": "us-east-1 • v1.30",
"children": [
{
"type": "progress",
"value": 100,
"max": 100,
"label": "5 / 5 Nodes Ready"
}
]
}
Data tables
{
"type": "table",
"columns": ["Resource", "State", "Progress"],
"rows": [
["VPC (vpc-0a1b2c)", "Complete", "100%"],
["EKS Control Plane", "Running", "60%"]
]
}
Form inputs and selects
{
"type": "select",
"name": "region",
"label": "Target AWS Region",
"options": [
{"value": "us-east-1", "label": "US East (N. Virginia)"},
{"value": "eu-west-1", "label": "EU West (Ireland)"}
]
}
Production payload examples
Human-in-the-Loop approval card
When an agent reaches a mutating step (such as applying a Terraform plan or promoting a canary rollout), it emits an interactive approval card:
{
"type": "card",
"title": "Deployment Approval Required",
"children": [
{
"type": "text",
"content": "Review the proposed infrastructure changes before execution:",
"style": "body"
},
{
"type": "table",
"columns": ["Planned Change", "Estimated Cost Impact"],
"rows": [
["Add 3x m6i.xlarge worker nodes", "+$410/month"],
["Enable HorizontalPodAutoscaler", "Variable"],
["Update ingress security group rules", "$0/month"]
]
},
{
"type": "container",
"layout": "horizontal",
"gap": "medium",
"children": [
{
"type": "button",
"label": "Approve & Apply",
"action": "approve",
"variant": "primary"
},
{
"type": "button",
"label": "Reject",
"action": "reject",
"variant": "danger"
},
{
"type": "button",
"label": "Request Changes",
"action": "request_changes",
"variant": "secondary"
}
]
}
]
}
Multi-step rollout tracker
{
"type": "container",
"layout": "vertical",
"children": [
{
"type": "progress",
"value": 60,
"label": "Canary Rollout Progress"
},
{
"type": "list",
"items": [
{"text": "Render and lint Helm templates", "icon": "check", "status": "complete"},
{"text": "Deploy 20% canary replica set", "icon": "check", "status": "complete"},
{"text": "Evaluate Prometheus p99 latency SLO", "icon": "spinner", "status": "in_progress"},
{"text": "Promote rollout to 100% traffic", "icon": "circle", "status": "pending"}
]
}
]
}
Actions and events
Interactive components dispatch typed actions back to the agent's LangGraph thread:
{
"type": "button",
"label": "Deploy to Production",
"action": {
"type": "submit",
"endpoint": "resume_interrupt",
"params": {
"decision": "approve",
"environment": "production"
}
}
}
| Action Type | Behavior |
|---|---|
submit | Sends structured form values or approval decisions back to the active agent thread |
navigate | Opens a linked dashboard, trace view, or pull request URL |
dismiss | Collapses or dismisses a transient notification card |
confirm | Triggers a secondary client-side confirmation modal before submitting |
copy | Copies a generated command, PromQL query, or YAML snippet to the clipboard |
Streaming updates
A2UI supports path-based JSON patches over SSE so agents can update progress bars and checklist items in real time without re-transmitting the entire component tree:
{"type": "container", "children": [
{"type": "text", "content": "Running terraform plan..."},
{"type": "progress", "value": 15}
]}
Subsequent stream frames patch specific child nodes:
{"update": {"path": "children[0]", "value": {"type": "text", "content": "Validating 14 AWS resources..."}}}
{"update": {"path": "children[1]", "value": {"type": "progress", "value": 75}}}
React implementation
import { A2UIRenderer, registerComponent } from '@a2ui/react';
// Register custom domain components in your host application
registerComponent('deployment-status', DeploymentStatusCard);
export function AgentConsole({ agent }) {
const [a2uiTree, setA2uiTree] = useState(null);
useEffect(() => {
return agent.onA2UIMessage((payload) => setA2uiTree(payload));
}, [agent]);
return (
<A2UIRenderer
data={a2uiTree}
onAction={(action) => agent.sendAction(action)}
theme="dark"
/>
);
}
Security validation checklist
- Whitelist component types: Reject any
typenot explicitly registered inCOMPONENT_REGISTRY. - Disallow inline styles and scripts: Style variants must map to predefined design-system tokens (
primary,secondary,danger). - Validate external URLs: Restrict
navigateactions to HTTPS or approved internal domains. - Bind actions to thread IDs: Ensure every
submitaction includes the active LangGraph checkpointthread_idand user session token.