# Technical Documentation: a2ui-project/a2ui

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/a2ui-project/a2ui)

### Overview (README.md)

# A2UI: Agent-to-User Interface

A2UI is an open-source project, complete with a format
optimized for representing updatable agent-generated
UIs and an initial set of renderers, that allows agents
to generate or populate rich user interfaces.

<img src="docs/public/assets/a2ui_gallery_examples.png" alt="Gallery of A2UI components" height="400">

_A gallery of A2UI rendered cards, showing a variety of UI compositions that A2UI can achieve._

## ⚠️ Status: Early stage public preview

> **Note:** A2UI's current production release is **v0.9.1**, a patch release in
> the stable v0.9 protocol family. The v1.0 specification is a release
> candidate, while v0.8 is legacy. The specification and implementations are
> functional but are still evolving. We are opening the project to foster
> collaboration, gather feedback, and solicit contributions (e.g., on client
> renderers). Expect changes.

## Summary

Generative AI excels at creating text and code, but agents can struggle to
present rich, interactive interfaces to users, especially when those agents
are remote or running across trust boundaries.

**A2UI** is an open standard and set of libraries that allows agents to
"speak UI." Agents send a declarative JSON format describing the _intent_ of
the UI. The client application then renders this using its own native
component library (Flutter, Angular, Lit, etc.).

This approach ensures that agent-generated UIs are
**safe like data, but expressive like code**.

## High-level philosophy

A2UI was designed to address the specific challenges of interoperable,
cross-platform, generative or template-based UI responses from agents.

The project's core philosophies:

- **Security first**: Running arbitrary code generated by an LLM may present a
  security risk. A2UI is a declarative data format, not executable
  code. Your client application maintains a "catalog" of trusted, pre-approved
  UI components (e.g., Card, Button, TextField), and the agent can only request
  to render components from that catalog.
- **LLM-friendly and incrementally updatable**: The UI is represented as a flat
  list of components with ID references which is easy for LLMs to generate
  incrementally, allowing for progressive rendering and a responsive user
  experience. An agent can efficiently make incremental changes to the UI based
  on new user requests as the conversation progresses.
- **Framework-agnostic and portable**: A2UI separates the UI structure from
  the UI implementation. The agent sends a description of the component tree
  and its associated data model. Your client application is responsible for
  mapping these abstract descriptions to its native widgets—be it web components,
  Flutter widgets, React components, SwiftUI views or something else entirely.
  The same A2UI JSON payload from an agent can be rendered on multiple different
  clients built on top of different frameworks.
- **Flexibility**: A2UI also features an open registry pattern that allows
  developers to map server-side types to custom client implementations, from
  native mobile widgets to React components. By registering a "Smart Wrapper,"
  you can connect any existing UI component—including secure iframe containers
  for legacy content—to A2UI's data binding and event system. Crucially, this
  places security firmly in the developer's hands, enabling them to enforce
  strict sandboxing policies and "trust ladders" directly within their custom
  component logic rather than relying solely on the core system.

## Use cases

Some of the use cases include:

- **Dynamic Data Collection:** An agent generates a bespoke form (date pickers,
  sliders, inputs) based on the specific context of a conversation (e.g.,
  booking a specialized reservation).
- **Remote Sub-Agents:** An orchestrator agent delegates a task to a
  remote specialized agent (e.g., a travel booking agent) which returns a
  UI payload to be rendered inside the main chat window.
- **Adaptive Workflows:** Enterprise agents that generate approval
  dashboards or data visualizations on the fly based on the user's query.

## Architecture

The A2UI flow disconnects the generation of UI from the execution of UI:

1. **Generation:** An Agent (using Gemini or another LLM) generates or uses
   a pre-generated `A2UI Response`, a JSON payload describing the composition
   of UI components and their properties.
2. **Transport:** This message is sent to the client application
   (via A2A, AG-UI, etc.).
3. **Resolution:** The Client's **A2UI Renderer** parses the JSON.
4. **Rendering:** The Renderer maps the abstract components
   (e.g., `type: 'text-field'`) to the concrete implementation in the client's codebase.

## Dependencies

A2UI is designed to be a lightweight format, but it fits into a larger ecosystem:

- **Transports:** Compatible with **A2A Protocol** and **AG-UI**.
- **LLMs:** Can be generated by any model capable of generating JSON output.
- **Host Frameworks:** Requires a host application built in a supported framework
  (currently: Web or Flutter).

## Getting started

Pick the path that matches where you want to start:

| Path                                                                                                      | What you get                                                                                                                            | Time   |
| --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| 🍜 **[Quickstart Restaurant Finder Demo](https://a2ui.org/quickstart/)**                                  | Full-stack A2UI running locally with a Gemini powered ADK agent and Lit renderer. Learn A2UI end-to-end and customize to your use case. | ~5 min |
| ⚛️ **[Use A2UI with Any Agent Framework & Harness](docs/public/guides/a2ui-with-any-agent-framework.md)** | Scaffold an AG-UI app or harness for your framework of choice, then enable A2UI rendering over AG-UI.                                   | ~5 min |
| 🎨 **[A2UI Composer](https://a2ui-project.github.io/composer/)**                                          | Generate A2UI JSON from a visual editor and paste it into any agent prompt — no install required.                                       | ~1 min |
| 🎬 **[A2UI Theater](https://a2ui-composer.ag-ui.com/theater)**                                            | Step through pre-built A2UI streaming scenarios across Lit, React, and Angular renderers — no install required.                         | ~1 min |

### Restaurant Finder demo — Summary

Prerequisites: Node.js 18+ (with [Corepack](https://nodejs.org/api/corepack.html) enabled), [uv](https://docs.astral.sh/uv/), and a [Gemini API key](https://aistudio.google.com/apikey).

```bash
git clone https://github.com/a2ui-project/a2ui.git
cd a2ui
export GEMINI_API_KEY="your_gemini_api_key"

# Enable Corepack (macOS Homebrew users: see tip below)
corepack enable

yarn install
cd samples/client/lit
yarn demo:restaurant
```

> [!TIP]
> **macOS Homebrew Users:** If you previously installed standalone package managers, unlink conflicts before installing Corepack so Corepack can manage versions per-project:
>
> ```bash
> brew unlink yarn pnpm
> brew install corepack
> corepack enable
> ```

These commands install dependencies across workspaces, build the renderers, start the Python agent, and open the client at `http://localhost:5173`. For step-by-step instructions, alternative demos, and troubleshooting see the **[full Quickstart](docs/public/quickstart.md)**.

### Use A2UI with Any Agent Framework & Harness — Summary

```bash
npx create-ag-ui-app@latest
```

Use the AG-UI CLI with your framework or harness of choice (Google Chat, ADK, LangGraph, CrewAI, Mastra, Strands, Slack, Teams, etc.), then follow the **[AG-UI guide](docs/public/guides/a2ui-with-any-agent-framework.md)** to enable A2UI rendering. Some scaffold paths use [CopilotKit's A2UI runtime](https://docs.copilotkit.ai/generative-ui/a2ui) with Next.js under the hood, but the setup surface is AG-UI-first.

### Other renderers

For Flutter, check out the [GenUI SDK](https://github.com/flutter/genui), which uses A2UI under the hood. See [docs/public/reference/renderers.md](docs/public/reference/renderers.md) for the full list of client implementations.

## Roadmap

We hope to work with the community on the following:

- **Spec stabilization:** Moving towards a v1.0 specification.
- **More renderers:** Adding official support for React, Jetpack Compose, iOS (SwiftUI), and more.
- **Additional transports:** Support for REST and more.
- **Additional Agent frameworks:** Genkit, LangGraph, and more.

## Contribute

A2UI is an **Apache 2.0** licensed project. We believe the future of UI is agentic,
and we want to work with you to help build it.

See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to get started.

---

### Public Index (`docs/public/index.md`)

---
hide:
  - toc
---



<div style="text-align: center; margin: 2rem 0 3rem 0;" markdown>


<img src="assets/A2UI_dark.svg" alt="A2UI Logo" width="120" class="light-mode-only" style="margin-bottom: 1rem;">

<img src="assets/A2UI_light.svg" alt="A2UI Logo" width="120" class="dark-mode-only" style="margin-bottom: 1rem;">

# A Protocol for Agent-Driven Interfaces

<p style="font-size: 1.2rem; max-width: 800px; margin: 0 auto 1rem auto; opacity: 0.9; line-height: 1.6;">
A2UI enables AI agents to generate rich, interactive user interfaces that render natively across web, mobile, and desktop—without executing arbitrary code.
</p>

</div>

## Specification Versions

| Version                                    | Status        | Description                                                                                                                                                                                                                                           |
| ------------------------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[v1.0](specification/v1.0-a2ui.md)**     | **Candidate** | Release candidate. Adds client-to-server RPC (`actionResponse`), action IDs, and renames theme to surfaceProperties. (Previously designated as v0.10 when in draft). [Evolution guide →](specification/v1.0-evolution-guide.md)                       |
| **[v0.9.1](specification/v0.9.1-a2ui.md)** | **Current**   | Current production release. Minor refinements to v0.9, standardizing on the `application/a2ui+json` MIME type and relaxing surfaceId constraints. [Evolution guide →](specification/v0.9.1-evolution-guide.md)                                        |
| **[v0.9](specification/v0.9-a2ui.md)**     | **Stable**    | Previous stable version. Philosophical shift to Prompt-First. Introduces `createSurface`, client-side functions, custom catalogs, modular schemas, and validation failed error formatting. [Evolution guide →](specification/v0.9-evolution-guide.md) |
| **[v0.8](specification/v0.8-a2ui.md)**     | **Legacy**    | Legacy version. Structured Output first. Baseline surfaces, components, data binding, and adjacency list model.                                                                                                                                       |

A2UI is Apache 2.0 licensed,
created by Google with contributions from
[CopilotKit](https://docs.copilotkit.ai/generative-ui/a2ui) and the open source community,
and is in active development [on GitHub](https://github.com/a2ui-project/a2ui).

A2UI solves the following problem: **how can AI agents safely send rich UIs across trust boundaries?**

Instead of text-only responses or risky code execution, A2UI lets agents send **declarative component descriptions** that clients render using their own native widgets. It's like having agents speak a universal UI language.

This repository contains:

- **[A2UI specifications](specification/v0.9.1-a2ui.md)** (v0.9.1 current, v1.0 candidate).
- **Implementations for [renderers](reference/renderers.md)** (Angular, Flutter, Lit, Markdown, etc.) on the client side.
- **Transports like [A2A](concepts/transports.md)** which communicate A2UI messages between agents and clients.

<div class="grid cards" markdown>

- :material-shield-check: **Secure by Design**

    ***

    Declarative data format, not executable code. Agents can only use pre-approved components from your catalog—no UI injection attacks.

- :material-rocket-launch: **LLM-Friendly**

    ***

    Flat, streaming JSON structure designed for easy generation. LLMs can build UIs incrementally without perfect JSON in one shot.

- :material-devices: **Framework-Agnostic**

    ***

    One agent response works everywhere. Render the same UI on Angular, Flutter, React, or native mobile with your own styled components.

- :material-chart-timeline: **Progressive Rendering**

    ***

    Stream UI updates as they're generated. Users see the interface building in real-time instead of waiting for complete responses.

</div>

## Get Started in 5 Minutes

<div class="grid cards" markdown>

- :material-clock-fast:{ .lg .middle } **[Quickstart Restaurant Finder Demo](quickstart.md)**

    ***

    Run the full-stack demo locally with a Gemini powered ADK agent and Lit renderer. Learn A2UI end-to-end and customize to your use case.

    [:octicons-arrow-right-24: Run the demo](quickstart.md)

- :material-react:{ .lg .middle } **[Use A2UI with Any Agent Framework & Harness](guides/a2ui-with-any-agent-framework.md)**

    ***

    Scaffold an AG-UI app or harness for your agent framework, then enable A2UI rendering in the client surface.

    [:octicons-arrow-right-24: Use with any agent](guides/a2ui-with-any-agent-framework.md)

- :material-palette-outline:{ .lg .middle } **[A2UI Composer](https://a2ui-project.github.io/composer/)**

    ***

    Generate A2UI JSON from a visual editor — no install required. Paste the output into any agent prompt.

    [:octicons-arrow-right-24: Open the composer](https://a2ui-project.github.io/composer/)

- :material-book-open-variant:{ .lg .middle } **[Core Concepts](concepts/overview.md)**

    ***

    Understand surfaces, components, data binding, and the adjacency list model.

    [:octicons-arrow-right-24: Learn concepts](concepts/overview.md)

- :material-code-braces:{ .lg .middle } **[Developer Guides](guides/client-setup.md)**

    ***

    Integrate A2UI renderers into your app or build agents that generate UIs.

    [:octicons-arrow-right-24: Start building](guides/client-setup.md)

- :material-file-document:{ .lg .middle } **Protocol Specifications**

    ***

    Dive into the complete technical specs: [v0.8 (legacy)](specification/v0.8-a2ui.md) · [v0.9 (stable)](specification/v0.9-a2ui.md) · [v0.9.1 (current)](specification/v0.9.1-a2ui.md) · [v1.0 (candidate)](specification/v1.0-a2ui.md)

    [:octicons-arrow-right-24: Read the v0.9.1 spec](specification/v0.9.1-a2ui.md)

</div>

## How It Works

The typical interaction flow consists of these steps:

1. **User sends a message** to an AI agent
2. **Agent generates A2UI messages** describing the UI (structure + data)
3. **Messages stream** to the client application
4. **Client renders** using native components (Angular, Flutter, React, etc.)
5. **User interacts** with the UI, sending actions back to the agent
6. **Agent responds** with updated A2UI messages



## A2UI in Action

### Landscape Architect Demo

<div style="margin: 2rem 0;">
  <div style="border-radius: .8rem; overflow: hidden; box-shadow: var(--md-shadow-z2);">
    <video width="100%" height="auto" controls playsinline style="display: block; aspect-ratio: 16/9; object-fit: cover;">
      <source src="assets/landscape-architect-demo.mp4" type="video/mp4">
      Your browser does not support the video tag.
    </video>
  </div>
  <p style="text-align: center; margin-top: 1rem; opacity: 0.8;">
    Watch an agent generate all of the interfaces for a landscape architect application. The user uploads a photo; the agent uses Gemini to understand it and generate a custom form for landscaping needs.
  </p>
</div>

### Custom Components: Interactive Charts & Maps

<div style="margin: 2rem 0;">
  <div style="border-radius: .8rem; overflow: hidden; box-shadow: var(--md-shadow-z2);">
    <video width="100%" height="auto" controls playsinline style="display: block; aspect-ratio: 16/9; object-fit: cover;">
      <source src="assets/a2ui-custom-component.mp4" type="video/mp4">
      Your browser does not support the video tag.
    </video>
  </div>
  <p style="text-align: center; margin-top: 1rem; opacity: 0.8;">
    Watch an agent chose to respond with a chart component to answer a numerical summary question.  Then the agent chooses a Google Map component to answer a location question.  Both are custom components offered by the client.
  </p>
</div>

### A2UI Composer

We have a public [A2UI Composer](https://a2ui-project.github.io/composer/).

[Documentation for the A2UI Composer](./composer/index.md)

---

### Public Quickstart (`docs/public/quickstart.md`)

# Quickstart: Run A2UI in 5 Minutes

Get hands-on with A2UI by running the restaurant finder demo. This guide will have you experiencing agent-generated UI in less than 5 minutes.

## What You'll Build

By the end of this quickstart, you'll have:

- A running app with an A2UI renderer (Lit or Flutter).
- A Gemini-powered agent that generates dynamic UIs.
- An interactive restaurant finder with form generation, time selection, and confirmation flows.
- Understanding of how A2UI messages flow from agent to UI.

## Prerequisites

Before you begin, choose your client framework:

=== "Lit"

    - **Node.js** (v18 or later with [Corepack](https://nodejs.org/api/corepack.html) enabled) — [Download here](https://nodejs.org/)

=== "Flutter"

    - **Flutter SDK** — [Install here](https://docs.flutter.dev/install)

**Common Prerequisites:**

- **uv** (Python package manager) — [Install here](https://docs.astral.sh/uv/getting-started/installation/) (used to run the Python agent backend)
- **A Gemini API key** — [Get one free from Google AI Studio](https://aistudio.google.com/apikey)

> [!WARNING]
> **Security Notice**
>
> This demo runs an A2A agent that uses Gemini to generate A2UI responses. The agent has access to your API key and will make requests to Google's Gemini API. Always review agent code before running it in production environments.

## Step 1: Clone the Repository

```bash
git clone https://github.com/a2ui-project/a2ui.git
cd a2ui
```

## Step 2: Set Your API Key

Export your Gemini API key as an environment variable:

```bash
export GEMINI_API_KEY="your_gemini_api_key_here"
```

## Step 3: Run the Agent and Client

=== "Lit"

    The client application source code is located in `samples/client/lit/shell`. Navigate to the parent samples directory to run the demo:

    ```bash
    cd samples/client/lit

    # Enable Corepack (macOS Homebrew users: see tip below)
    corepack enable

    yarn install
    yarn demo:restaurant
    ```

    ??? note "Running the agent and client separately"
        The `demo:restaurant` command runs both the A2A agent and the web client
        automatically. It is equivalent to:

        **1. Run the Agent:**

        ```bash
        cd samples/agent/adk/restaurant_finder
        uv run .
        ```

        **2. Run the Client:**

        ```bash
        cd samples/client/lit/shell
        yarn dev
        ```

    > [!INFO]
    > **About Package Managers:**
    >
    > The A2UI repository uses `yarn` for its development, but `yarn` is not
    > required to **use** A2UI. You may use the package manager of your choice
    > on your projects (e.g. `npm` or `pnpm`).

=== "Flutter"

    **1. Run the Agent:**

    In your first terminal, start the Python agent backend:

    ```bash
    cd samples/agent/adk/restaurant_finder
    uv run .
    ```

    **2. Run the Client:**

    In a second terminal, launch the Flutter web application:

    ```bash
    cd samples/client/flutter/restaurant_finder/app
    flutter run -d chrome
    ```

> [!TIP]
> **Demo Running**
>
> If everything worked, you should see the demo app. The agent is now ready to
> generate UI!

## Step 4: Try It Out

In the web app, try these prompts:

1. **"Book a table for 2"** - Watch the agent generate a reservation form
2. **"Find Italian restaurants near me"** - See dynamic search results
3. **"What are your hours?"** - Experience different UI layouts for different intents

The demo application should update after each response from the agent, with UI
completely generated by the Gemini LLM. **The resulting screens (list of restaurants,
reservation flow, reservation confirmation...) are not hardcoded in the source
of the app.**

---

## How does it work?

Let's dive deeper into how this demo app is put together, and how you can build similar applications with A2UI.

### Interaction sequence diagram

```mermaid
sequenceDiagram
    actor User
    box Front-end
    participant App@{"alias":"App (A2UI renderer)"}
    end
    box Back-end
    participant Agent@{"alias":"A2A agent (Python)"}
    participant LLM@{"alias":"Gemini API (LLM)"}
    end

    User->>App: Interacts
    App->>Agent: ClientToServerMessage
    activate Agent
    Agent->>LLM: Query LLM
    activate LLM
    LLM-->>Agent: Generate A2UI JSON payload
    deactivate LLM
    Agent-->>App: (Streaming) JSONL messages
    deactivate Agent
    App-->>User: Updated UI
```

1. **User interacts** with your app (sends a message, clicks a button, etc.)
2. **The A2A agent** receives it and sends the conversation to Gemini
3. **Gemini generates A2UI JSON** messages describing the UI
4. **The A2A agent** streams these messages back to the app
5. **The A2UI renderer** converts them into UI components
6. **Your app UI updates**

### The A2UI JSON payloads

Let's peek at what the agent is returning. Here's a simplified example of the JSON messages:

=== "v0.9"

    **Creating the surface:**

    ```json
    { "version": "v0.9.1",
      "createSurface": {
        "surfaceId": "main",
        "catalogId": "https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"
      }}
    ```

    **Defining the UI:**

    ```json
    { "version": "v0.9.1",
      "updateComponents": {
        "surfaceId": "main",
        "components": [
          {"id": "header", "component": "Text", "text": "# Book Your Table", "variant": "h1"},
          {"id": "date-picker", "component": "DateTimeInput", "label": "Select Date", "value": {"path": "/reservation/date"}, "enableDate": true},
          {"id": "submit-text", "component": "Text", "text": "Confirm Reservation"},
          {"id": "submit-btn", "component": "Button", "child": "submit-text", "variant": "primary", "action": {"event": {"name": "confirm_booking"}}}
        ]
      }}
    ```

    **Populating data:**

    ```json
    { "version": "v0.9.1",
      "updateDataModel": {
        "surfaceId": "main",
        "path": "/reservation",
        "value": {"date": "2025-12-15", "time": "19:00", "guests": 2}
      }}
    ```

=== "Legacy (v0.8)"

    **Defining the UI:**

    ```json
    {"surfaceUpdate": {"surfaceId": "main", "components": [
      {"id": "header", "component": {"Text": {"text": {"literalString": "Book Your Table"}, "usageHint": "h1"}}},
      {"id": "date-picker", "component": {"DateTimeInput": {"label": {"literalString": "Select Date"}, "value": {"path": "/reservation/date"}, "enableDate": true}}},
      {"id": "submit-text", "component": {"Text": {"text": {"literalString": "Confirm Reservation"}}}},
      {"id": "submit-btn", "component": {"Button": {"child": "submit-text", "action": {"name": "confirm_booking"}}}}
    ]}}
    ```

    **Populating data:**

    ```json
    {"dataModelUpdate": {"surfaceId": "main", "contents": [
      {"key": "reservation", "valueMap": [
        {"key": "date", "valueString": "2025-12-15"},
        {"key": "time", "valueString": "19:00"},
        {"key": "guests", "valueInt": 2}
      ]}
    ]}}
    ```

    **Signaling render:**

    ```json
    {"beginRendering": {"surfaceId": "main", "root": "header"}}
    ```

    Note: In v0.8, `createSurface` was `beginRendering`, components were nested
    in the response, and the data model used an adjacency list instead of
    flat JSON.

> [!TIP]
> **It's Just JSON**
>
> Notice how readable and structured this is? LLMs can generate this easily, and it's safe to transmit and render—**no code execution required.**

### Peek at the source code

Want to see what the code looks like? Check out:

- **Agent Code**: `samples/agent/adk/restaurant_finder/` — The Python A2A agent

=== "Lit"

    - **Client Code**: `samples/client/lit/` — The Lit web client with A2UI renderer
    - **A2UI Renderers**: `typescript/renderers/lit/` (Lit) and `typescript/core/web_core/` (framework-agnostic core)

=== "Flutter"

    - **Client Code**: `samples/client/flutter/` — The Flutter web client with A2UI renderer
    - **A2UI Renderer**: `dart/a2ui_flutter/` (Flutter)

Each directory has its own README with detailed documentation.

---

## Troubleshooting

=== "Lit"

    ### Port Already in Use

    If port 5173 is already in use, the dev server will automatically try the next available port. Check the terminal output for the actual URL.

    ### Corepack and Homebrew issues

    If you have standalone package managers installed, try to unlink conflicts before installing Corepack so Corepack can manage versions per-project:

    > ```bash
    > $ brew unlink yarn pnpm
    > $ brew install corepack
    > $ corepack enable
    > ```

=== "Flutter"

    

### API Key Issues

If you see errors about missing API keys:

1. Verify the key is exported: `echo $GEMINI_API_KEY`
2. Make sure it's a valid Gemini API key from [Google AI Studio](https://aistudio.google.com/apikey)
3. Try re-exporting: `export GEMINI_API_KEY="your_key"`

### Connection Errors on Startup

If you see `ERR_CONNECTION_REFUSED` errors when the browser opens, **don't worry** — this is a known race condition. The web app may start faster than the Python agent backend. Just wait a few seconds and refresh the page.

### Python / uv Issues

The demo agents require [uv](https://docs.astral.sh/uv/) to run. If you see `uv: command not found`:

```bash
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh

# Verify
uv --version
```

If you encounter other Python errors:

```bash
# Make sure Python 3.10+ is available
python3 --version

# Try running the agent manually
cd samples/agent/adk/restaurant_finder
uv run .
```

### Still Having Issues?

- Check the [GitHub Issues](https://github.com/a2ui-project/a2ui/issues)
- Review the sample README.md ([Lit](../../samples/client/lit) or [Flutter](../../samples/client/flutter))
- Join the community discussions

---

## Exploring more demos

=== "Lit"

    ### Lit Component Gallery (No Agent Required)

    See all the provided Basic Catalog components:

    If you're running the gallery from a fresh checkout, build the gallery and its workspace dependencies first:

    ```bash
    cd typescript/renderers/lit/a2ui_explorer
    yarn build
    ```

    Start the gallery:

    ```bash
    yarn dev
    ```

    This runs a client-only demo showcasing every standard component (Card, Button, TextField, Timeline, etc.) with live examples and code samples.

=== "Flutter"

    

### Other Languages and Frameworks

A2UI provides samples for other popular frameworks in the `samples/client` directory:

- **Angular**: `samples/client/angular`
- **Flutter**: `samples/client/flutter`
- **Lit**: `samples/client/lit`
- **React**: `samples/client/react`

Explore the [samples/client](../../samples/client) directory to see all available client implementations.

---

## What's Next?

**Congratulations!** You've successfully run your first A2UI application. You've seen how an AI agent can generate rich, interactive UIs that render natively in a web application—all through safe, declarative JSON messages.

Check out the following links to learn more:

- **[Learn Core Concepts](concepts/overview.md)**: Understand surfaces, components, and data binding
- **[Build an Agent](guides/agent-development.md)**: Create agents that generate A2UI responses
- **[Set Up Your Own Client](guides/client-setup.md)**: Integrate A2UI into your own app
- **[Define Your Own Catalog](guides/defining-your-own-catalog.md)**: Move past the Basic Catalog, and control the UI elements used to generate your app
- **[Use an Existing Agent App](guides/a2ui-with-any-agent-framework.md)**: Add A2UI through CopilotKit + AG-UI for ADK, LangGraph, CrewAI, Mastra, or a custom service
- **[Explore the Protocol](reference/messages.md)**: Dive into the technical specification

---

### Scripts README (`docs/scripts/README.md`)

# Documentation Transformation Scripts

This directory contains utility scripts to prepare our documentation for the **MkDocs** build process.

## Purpose

To ensure a great reading experience both on GitHub and the hosted site, the project uses **GitHub-flavored Markdown** as the primary source of truth. This script transforms GitHub's native syntax into **MkDocs-compatible syntax** (specifically for the `pymdown-extensions`) during the build pipeline.

## Supported Conversions (Uni-directional)

The script performs a uni-directional transformation: **GitHub Markdown → MkDocs Syntax**.

### Alert/Admonition Conversion

The script handles the following conversions:

- GitHub uses a blockquote-based syntax for alerts.
- MkDocs requires the `!!!` or `???` syntax to render colored callout boxes.

## Running the Conversion

The conversion is run as part of the build pipeline. No additional steps are required. If you need to run the conversion manually, you can run the `convert_docs.py` script in the repository root.

```bash
python docs/scripts/convert_docs.py
```

### Example

- **Source (GitHub-flavored Markdown):**

    ```markdown
    > ⚠️ **Attention**
    >
    > This is an alert.
    ```

- **Target (MkDocs Syntax):**

    ```markdown
    !!! warning "Attention"
    This is an alert.
    ```

---

### Public Composer Index (`docs/public/composer/index.md`)

# A2UI Composer

Try building A2UI widgets interactively with the **A2UI Composer**.


1. Navigate to the [A2UI Composer](https://a2ui-project.github.io/composer/)

2. By default, you'll be using the Basic catalog provided by an Angular-based
   renderer

3. Use the Gemini chat to start building an A2UI interface! (**Note**: This
   requires a Gemini API key. See [below](#gemini-api-key))

## Using the Composer UI

The Composer workspace is split into several interactive panels to assist in
developing and debugging A2UI surfaces:

- **Gemini Assistant:** A chat interface powered by Gemini. You can use
  natural language prompts to ask Gemini to generate new layouts, refine the
  existing JSON, or modify visual attributes.
- You can **upload an attachment** (a mock, for example) by clicking the
  paper clip icon
  {style="width:30px;height:30px;display:inline;vertical-align:middle;"}.
- You can **include a screenshot** of the
  current A2UI interface by clicking the camera icon
  {style="width:30px;height:30px;display:inline;vertical-align:middle;"}.

- **Rendered A2UI Preview:** Displays the live visual preview of the active
  component.

- **A2UI JSON Editor:** Displays the raw JSON payload defining the UI
  structure and component hierarchy. You can edit this directly to instantly
  update the rendered preview.
- The editor has **[tooltips on hover](../assets/composer_editor_tooltip.png)**,
  showing the description of the A2UI element.
- If you have A2UI JSON from another source, you can paste it into this
  panel. You can right-click to format the JSON if you want.

- **Debug & Inspection Tabs (Bottom):**
    - **Data Model:** Inspects and modifies the runtime state/data values
      bound to the UI components. Changes here propagate to the preview, and
      user inputs in the preview update this model.
    - **Events:** Logs user-interaction events (e.g., clicks, inputs, or
      selections) dispatched by the rendered components.
    - **Errors:** Displays errors from rendering, JSON parsing, or API
      failures.
    - **Raw Messages:** Shows the communication between the Composer and the
      renderer, as well as interactions with Gemini. (See more [below](#raw-messages).)

## Components Gallery



The Components gallery allows you to browse through all the components which
are provided in the current A2UI catalog. Each component has an example
rendered, along with the A2UI JSON to produce that rendering. Use the copy icon
{style="width:30px;height:30px;display:inline;vertical-align:middle;"}
at the top of the Usage panel to copy the full A2UI JSON for this component.

At the bottom of the page is a table listing all the properties of the
component with descriptions, type, and indicating whether the property is
required or not.

## Settings

### Renderer Application

The settings page allows you to change the renderer application being used.
At this time, there are three preloaded renderer applications:

- Angular Basic Catalog
- Lit Basic Catalog
- React Basic Catalog

If you are building another renderer app, you can select "Custom" from the
dropdown, and put the URL in the text box. (For instructions on building a
renderer app, see [A2UI Composer Integration](./composer_renderer_integration.md)).

### Gemini API Key

This is also where you can enter a Gemini API key, enabling use of the Gemini
chat feature.

To obtain an API key:

1. Go to [Google AI Studio](https://aistudio.google.com/api-keys) and sign in
   with your Google account.
2. Click Create API key.
3. Select or create a Google Cloud project when prompted, then click Create key.
4. Save your key in a secure location!

Note that the A2UI Composer encrypts your key and stores it locally in your
browser's secure database using the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API).
Neither Google nor anyone else has access to this key.

## Work in Progress

The A2UI team is actively working on the following improvements:

- **Latency reduction:** Improving latency within Gemini-assisted workflows.
- **Visual understanding:** Updating Gemini-assisted workflows to improve
  visual understanding of already rendered surfaces.

## Raw Messages

The messages which flow between the Composer and the renderer can help with
troubleshooting and to gain a better understanding of what's going on. These
messages include:

- **RENDERER_READY**: Sent by the renderer once it has fully bootstrapped.
- **A2UI_CATALOG**: Sent by the renderer (upon request from the Composer).
  Contains the full A2UI catalog supported by the renderer.
- **COMPONENT_USAGES**: Sent by the renderer (upon request from the Composer),
  containing the data to support the Component Gallery page.

Whenever there is a change to the A2UI component's data model, the
**DATA_MODEL_CHANGE** message is captured, showing the `updateDataModel`
message which would be sent back to the agent.

Additionally, when using the Gemini chat feature:

- **LLM_REQUEST**: Shows the full request (including the system prompt) sent
  to the LLM.
- **LLM_RESPONSE**: Shows the full response received from the LLM.

---

### Public Concepts Overview (`docs/public/concepts/overview.md`)

# Core Concepts

This section explains the fundamental architecture of A2UI. Understanding these concepts will help you build effective agent-driven interfaces.

See [Glossary](glossary.md) for short definitions of key terms.

## The Big Picture

A2UI is built around three core ideas:

1. **Streaming Messages**: UI updates flow as a sequence of JSON messages from agent to client
2. **Declarative Components**: UIs are described as data, not programmed as code
3. **Data Binding**: UI structure is separate from application state, enabling reactive updates

## Key Topics

### [Data Flow](data-flow.md)

How messages travel from agents to rendered UI. Includes a complete lifecycle example of a restaurant booking flow, transport options (SSE, WebSockets, A2A), progressive rendering, and error handling.

### [Component Structure](components.md)

A2UI's **adjacency list model** for representing component hierarchies. Learn why flat lists are better than nested trees, how to use static vs. dynamic children, and best practices for incremental updates.

### [Data Binding](data-binding.md)

How components connect to application state using JSON Pointer paths. Covers reactive components, dynamic lists, input bindings, and the separation of structure from state that makes A2UI powerful.

## Message Types

=== "v0.9 (Stable)"

    Version 0.9 uses the following message types:

    - **`createSurface`**: Create a new surface and specify its catalog
    - **`updateComponents`**: Add or update UI components in a surface
    - **`updateDataModel`**: Update application state
    - **`deleteSurface`**: Remove a UI surface

    v0.9 separates surface creation from rendering — `createSurface` replaces both `beginRendering` and the implicit surface creation in `surfaceUpdate`. All messages include a `version` field.

=== "v1.0 (Candidate)"

    Version 1.0 uses the following message types:

    - **`createSurface`**: Create a new surface and specify its catalog
    - **`updateComponents`**: Add or update UI components in a surface
    - **`updateDataModel`**: Update application state
    - **`deleteSurface`**: Remove a UI surface
    - **`actionResponse`**: Respond to client-initiated actions

    v1.0 introduces the `actionResponse` message type, enabling robust client-to-server synchronous RPC capabilities.

=== "v0.8 (Legacy)"

    Version 0.8 uses the following message types:

    - **`surfaceUpdate`**: Define or update UI components
    - **`dataModelUpdate`**: Update application state
    - **`beginRendering`**: Signal the client to render
    - **`deleteSurface`**: Remove a UI surface

For complete technical details, see [Message Reference](../reference/messages.md).

---

### Contributing Release Pub Dev (`docs/contributing/release-pub-dev.md`)

# Maintenance information for publishing to pub.dev

This page contains maintenance information for publishing to pub.dev.
It is needed when main steps stop working or something needs to be changed.

For main publishing steps, see [release.md](release.md#pubdev-publishing-steps).

## Versioning

We use [Semver] for package versioning, although before 1.0.0, we will be
incrementing only the minor number for breaking changes and the patch number for
non-breaking changes.



[Semver]: https://semver.org/

Depending on the package category, the process of publishing to pub.dev follows different rules:

### The package is not published, and is not planned to be published

`pubspec.yaml` has `publish_to: none`.

### The package is planned to be published as production-ready (but wasn't published as such before)

The package should be published to pub.dev with a `-wip<three digit number>` suffix to reserve the name and maybe to try the package for development purposes.

### The package is published as production-ready

1. The package's `version:` in `pubspec.yaml` doesn't contain any suffix.
2. It is recommended to publish the changes after every pull requests.
3. If your feature is partially implemented, hide the feature's code behind a false-by-default flag, and make sure the version at `main` is still ready for production.

## CI

The following CI workflows support publishing, making sure the packages are always publish-ready:

In this repo:

- [pub_health.yaml](../../.github/workflows/pub_health.yml)

In genui repo:

- [pub_health.yaml](https://github.com/flutter/genui/blob/main/.github/workflows/pub_health.yaml)
- [pub_post_summaries.yaml](https://github.com/flutter/genui/blob/main/.github/workflows/pub_post_summaries.yaml)

## How to enable the workflows

For these workflows to function, the GitHub org needs to be configured.

This section instructs how to do that, in case some future reorg will require re-enabling them
(The permissions cover more than needed, because we may want to do more automation in future).

In https://github.com/organizations/a2ui-project/settings/actions:

1. Find the section "General actions permissions"
2. Either select "Allow all actions and reusable workflows" or choose "Allow enterprise, and select non-enterprise, actions and reusable workflows" and add these values (if they are already here, they will be de-dupped automatically):

    ```
    peter-evans/create-or-update-comment@*,
    peter-evans/create-pull-request@*,
    peter-evans/repository-dispatch@*,
    dart-lang/ecosystem/.github/workflows/health.yaml@*,
    dart-lang/ecosystem/.github/workflows/post_summaries.yaml@*,
    dart-lang/ecosystem/.github/workflows/publish.yaml@*,
    ```

---

### Contributing Release (`docs/contributing/release.md`)

# Release process

## How to publish packages

Release cadence: every 1-2 weeks.

### Pub.dev publishing steps

Between releases, each Dart package in this repository collects the notes of
merged pull requests under `## Unreleased` at the top of its `CHANGELOG.md`.
`version:` in its `pubspec.yaml` stays at the last released version, and only a
release pull request changes it.

**1. Find the packages to release**

A package has something to release when its `CHANGELOG.md` has notes under
`## Unreleased`:

- [a2ui_core CHANGELOG.md](../../dart/a2ui_core/CHANGELOG.md)
- [a2ui_agent CHANGELOG.md](../../dart/a2ui_agent/CHANGELOG.md)

**2. Open a release pull request**

In one pull request, for each package to release:

- Choose the next version, as described in
  [Versioning](release-pub-dev.md#versioning).
- Rename `## Unreleased` in `CHANGELOG.md` to `## <version>`.
- Set `version:` in `pubspec.yaml` to the same version.

Change nothing else, and merge the pull request.

**3. Publish the packages**

For each package in the release pull request:

- Check out the commit that merged the release pull request, not the latest
  `main`, which may already have unreleased changes.
- Run `flutter pub publish` in the package directory, making sure the console
  shows no warnings.
- Verify that the correct version was uploaded to pub.dev.

If any step fails, file a GitHub issue and inform the team.

For troubleshooting and maintenance, see [release-pub-dev.md](release-pub-dev.md).

### Packages in the genui repository

In these changelogs, find the packages whose top version is not `-wip...` and
is not published yet (follow the link in the CHANGELOG.md header to verify),
then publish them from the latest `main` of that repository:

- [genui CHANGELOG.md](https://github.com/flutter/genui/blob/main/packages/genui/CHANGELOG.md)
- [genui_a2a CHANGELOG.md](https://github.com/flutter/genui/blob/main/packages/genui_a2a/CHANGELOG.md)
- [genai_primitives CHANGELOG.md](https://github.com/flutter/genui/blob/main/packages/genai_primitives/CHANGELOG.md)
- [json_schema_builder CHANGELOG.md](https://github.com/flutter/genui/blob/main/packages/json_schema_builder/CHANGELOG.md)

### NPM

See [web_publishing.md](web_publishing.md).

### PyPI

The Python packages are `a2ui-core`, `a2ui-agent-sdk`, and the agent framework integrations `a2ui-a2a` and `a2ui-adk`. Releasing one or more of them is performed by providing a prompt to an AI assistant within the `a2ui` project directory.

```text
Release <package names, or all> with a <major|minor|patch> bump
```

Name the packages to release, for example `a2ui-agent-sdk` or `a2ui-a2a and a2ui-adk`, or ask for `all` to release all four.

The assistant uses the [`a2ui-release-python`](../../.agents/skills/a2ui-release-python/SKILL.md) skill to inspect changelogs, run local preflight checks, execute a dry run, confirm with you, trigger publishing via the GitHub Actions workflow, and open the changelog pull request. Once publication finishes, you only need to find a reviewer to approve and merge the pull request to update the changelog. Released packages appear on PyPI ([a2ui-core](https://pypi.org/project/a2ui-core/), [a2ui-agent-sdk](https://pypi.org/project/a2ui-agent-sdk/), [a2ui-a2a](https://pypi.org/project/a2ui-a2a/) and [a2ui-adk](https://pypi.org/project/a2ui-adk/)) as well as under corresponding [Git tags](https://github.com/a2ui-project/a2ui/tags) and [GitHub releases](https://github.com/a2ui-project/a2ui/releases) that link to them.

#### How it works behind the scenes

Publishing is handled by the [Release Python SDKs](../../.github/workflows/release-pypi.yml) workflow on `main`. There is no version file to edit and no package build or upload to run locally.

The workflow works out the new version from the latest release tag, tags the
release, builds, stages the artifacts in the OSS Exit Gate Artifact Registry,
and uploads the manifest that triggers publishing. The Exit Gate emails
`a2ui-core-working-group@google.com` when publishing starts and again when it
finishes. The GitHub release is updated with a link to the published version
once it appears on PyPI, either by the release run itself or by the hourly
[Confirm PyPI publication](../../.github/workflows/release-verify-pypi.yml)
workflow.

If an assistant is unavailable, maintainers can dispatch the workflow manually from the Actions tab on `main`. Always run with `dry_run: true` first to verify the plan and artifact staging before running with `dry_run: false`.

#### The release only pushes tags

`main` is covered by a ruleset that requires a pull request and allows no bypass
actors, so the workflow cannot push to it. Being refused mid-run would leave
artifacts staged in the Artifact Registry, so the workflow does not try: it
pushes only tags, which no ruleset covers, and raises the changelog edit as a
pull request afterwards.

Tags therefore point at the commit that was the tip of `main` when the run
started, not at the changelog commit. That is deliberate. The repository
requires linear history, so a tag created on a branch commit would be left
unreachable once the pull request is squashed, and the `git describe` check in
[python_ci.yml](../../.github/workflows/python_ci.yml) would start failing.

#### Why the workflow does not open the changelog pull request directly

The release workflow prepares the changelog edit on a `release/changelog-*` branch and
stops there. It could open the pull request, but that pull request could never
be merged: GitHub does not start workflow runs for events caused by the
built-in `GITHUB_TOKEN`, so none of the required checks would ever report, and
the ruleset allows no bypass. Opening it yourself from the link in the job
summary (or having an AI assistant open it using user credentials) allows
the required CI checks to run.

#### Versions come from git tags

Each package has its own tag series (`python/a2ui-core/v*`,
`python/a2ui-agent-sdk/v*`, `python/a2ui-a2a/v*` and `python/a2ui-adk/v*`), and
hatch-vcs derives the package version from it at build time. Do not hand-edit a version anywhere; the `version.py` in each
package only reads the version back out of the installed distribution metadata.

A checkout without tags falls back to the version pinned as `fallback-version`
in `pyproject.toml`, which keeps shallow CI clones working. The release workflow
reads the version back out of every built artifact and fails if it does not
match the version it planned, so a release cannot go out on a fallback version.

#### Things that will stop a release

The preflight checks in
[release_version.py](../../.github/scripts/release_version.py) fail the run when
the Unreleased section is empty, when the target version already has a tag,
when a proposed version falls outside the range that another package pins it
to, and when a package depends on another package of this repository that no
released version satisfies.

The pins form a chain: `a2ui-agent-sdk` pins `a2ui-core`, `a2ui-a2a` and
`a2ui-adk` pin `a2ui-agent-sdk`, and `a2ui-adk` pins `a2ui-a2a` in its `a2a`
extra. A minor `a2ui-core` bump, for example, needs the pin in
[a2ui_agent/pyproject.toml](../../python/a2ui_agent/pyproject.toml)
widened in a pull request that is merged to `main` before the release is
dispatched. The workflow releases `main` as it is and cannot change the pin
during the run.

A dependency can be released in the same run: a release of several packages
publishes them in dependency order, `a2ui-core`, `a2ui-agent-sdk`,
`a2ui-a2a`, `a2ui-adk`, so each package's new dependencies are on PyPI first.
Releasing `a2ui-a2a` or `a2ui-adk` on its own requires a released version of
each dependency that satisfies its pins.

`a2ui-a2a` and `a2ui-adk` start from `0.0.0`, so their first release uses a
`minor` bump to publish `0.1.0`. Both require an `a2ui-agent-sdk` release newer
than `0.8.0`, the last one that shipped `a2ui.a2a` and `a2ui.adk` itself. For
their first release, release `a2ui-agent-sdk`, `a2ui-a2a` and `a2ui-adk`
together with a `minor` bump, or release `a2ui-agent-sdk` first, merge its
changelog pull request, then release `a2ui-a2a` and `a2ui-adk` with a `minor`
bump.

#### If authentication fails

The Exit Gate authorizes this repository through Workload Identity Federation,
matching the workflow file path and branch exactly against an allowlist entry in
Google's internal project config:

```
builders: "github_workflow:a2ui-project/a2ui/.github/workflows/release-pypi.yml@refs/heads/main"
```

Two consequences worth knowing. Renaming `release-pypi.yml` breaks releases
until the internal config is updated. And the workflow cannot be triggered by
pushing a tag, because the matched claim includes the triggering ref, which is
why the release is dispatched from `main` and creates its own tag rather than
being started by one.

To test access and artifact staging without publishing anything, run the
[Release Python SDKs](../../.github/workflows/release-pypi.yml) workflow with
`dry_run: true`. See go/oss-exit-gate-builders and go/oss-exit-gate-onduty.

### Documentation website

[MkDocs](https://www.mkdocs.org/), configured in [.github/workflows/docs.yml](../../.github/workflows/docs.yml), updates https://a2ui.org/ whenever the content of [docs/public](../public) changes.

## Internal troubleshooting and notes

See go/a2ui-release for internal information.

---

### Contributing Triage Templates (`docs/contributing/triage-templates.md`)

# A2UI Standard Triage Replies

Canonical replies for recurring triage cases.

## Issues

### Weekly A2UI Compliance Report

**Case**: AI-generated compliance report issues, such as
[Weekly A2UI Compliance Report](https://github.com/a2ui-project/a2ui/issues/2025).

**Triage**: priority `P3`, action `backlog` (keeps the issue open).

As agreed, this has been assigned a P3 priority: we need better workflow to make it easier to follow up on the findings.

### Assigned issue without a priority

**Case**: The issue already has an assignee but no priority label, so it sits in the triage
queue with nothing else to decide.

**Triage**: priority `P2`, action `assign_and_fix`, keeping the existing assignee.

I assigned a P2 priority to move this out of the triage queue. Please adjust the priority
if needed to better reflect the issue's status.

### Stale P2 issue

**Case**: The issue is P2 but stale.

**Triage**: add comment.

This issue should be considered for a P1 priority together with other P2 issues in the next planning cycle after we burn through the triage queue.

### Stale assigned P1 issue

**Case**: The issue is P1 and has an assignee, but has been stale for a while.

**Triage**: add comment.

Ping from triage process: is this issue still on your radar?

### Out of Scope / Roadmap Conflict

**Case**: The user suggests a feature or change that is outside the current scope of the A2UI protocol roadmap.

**Triage**: priority `P4`, action `backlog` (keeps the issue open).

Thanks for the suggestion. This falls outside the current scope of the A2UI protocol roadmap.

Marked as `P4`: we do not plan to invest in it, and PRs against it will not be reviewed. Leaving it open as a record of the request — comment here if you have new arguments to share.

## Pull requests

These cases are handled by the gardener directly. The dashboard and apply script
cover issues only, so the actions below are performed by hand.

### Superseded PR

**Case**: A valid contribution that has gone stale and was replaced by a newer PR carrying
the original commit.

**Triage**: close the PR, linking the superseding one.

Thank you for your contribution! We apologize that this PR has become outdated. To
expedite the process, I created a superseding PR based on your analysis and changes. Your
original commit is included to ensure your contribution is properly recorded.
`<link to new PR>`

### Complex PR without an associated issue

**Case**: A complex PR that does not address an issue. Straightforward and minor PRs are exempt.

**Triage**: close the PR.

Thank you for your contribution. Unfortunately, we must decline this PR at this time.  
Our team resources are limited, and our policy is to prioritize the review of PRs that address an existing issue prioritized issues. Consider opening issue  
and link your PR in the issue description as one of the options for resolution.

### PR outside the project's scope

**Case**: The change targets functionality the maintenance team cannot support long-term.

**Triage**: close the PR.

Thank you for your contribution to the A2UI ecosystem! Unfortunately, we must decline this PR as the scope of this repository is restricted to features the maintenance team can support long-term. We encourage you to find a more suitable repository for this code or to consider launching your own repository to support this segment of the A2UI ecosystem.

### Complex PR towards existing issue but not assigned to the author

**Case**: Complex PR that is not assigned to the author.  
It might be a good contribution, but we do not have enough bandwidth to review it at this time.

**Triage**: close the PR.

Thank you for your contribution to the A2UI ecosystem! Unfortunately, we must decline this PR at this time: we review PRs against an issue only from the contributor the issue is assigned to, and this one is not assigned to you. Issues are assigned in priority order, so we cannot say yet when this one will be picked up.

We will link this PR to the issue, so whoever takes it on can see your approach. They may reopen this PR and build on it rather than start from scratch.

### Meaningful stale PR with conflicts

**Case**: The PR is meaningful, but has conflicts with the main branch.

**Triage**: assign `status: waiting-for-user-response`.

Thank you for your contribution. I am sorry it took so long for our team to review your PR. Unfortunately the branch has conflicts with the main branch. If you believe the issue is not resolved yet, can you, please, resolve the conflicts? We will review it again after you resolve conflicts.

### PR that closes already closed issue

**Case**: The PR closes an issue that has already been closed.

**Triage**: close the PR.

Thank you for your contribution. I am closing this PR as the linked issue has already been resolved.

---

### Contributing Triage (`docs/contributing/triage.md`)

# Triage for PRs and issues

See go/a2ui-triage-internal for internal information.

## Goals

Continuously make sure that on [a2ui](https://github.com/a2ui-project/a2ui):

1. External PRs are addressed
2. Issues are prioritized and addressed
3. Number of branches is observable

## Invariant we want to keep

This section describes goals at a high level. See concrete steps in the section [Triage responsibilities](#triage-responsibilities).

1. **Issues** priority (aligned with other teams in Dash):
    - **P0**: very urgent, and it should be assigned
    - **P1**: actively being worked on, and it should be assigned
    - **P2**: is expected to be converted to P1 within three months, as part of regular planning process
    - **P3**: not planned, but may become a priority
    - **P4**: we do not plan to invest in this issue

2. **PRs**: We will review PRs from external contributors if at least one of the following is true:
    - the PR contributes to a **P0-P3** issue (PRs for P4 issues will not be reviewed)
    - the issue is assigned to a contributor by the A2UI team (as assignee or in the first line of issue description) or has label `type: contributions-welcome`
    - the change is, in the opinion of the A2UI team, absolutely clear and obviously needed

The relevant issue should be linked in the the PR description.

3. **Branches**: [list of stale branches](https://github.com/a2ui-project/a2ui/branches/stale) should fit on one screen and should not have a button ‘Next’.

## GitHub labels used in triage

1. Priority labels: [P0][p0], [P1][p1], [P2][p2], [P3][p3], [P4][p4]
2. [status: needs-team-input][needs-team-input]
3. [status: needs-triage][needs-triage-label]
4. [status: first-line-handled][first-line-handled]
5. [size: small][size-small]
6. [type: contributions-welcome][contributions-welcome]
7. [status: waiting-for-author-response][waiting-for-author-response]

See [all github labels](https://github.com/a2ui-project/a2ui/labels).

[p0]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3AP0
[p1]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3AP1
[p2]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3AP2
[p3]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3AP3
[p4]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3AP4
[needs-team-input]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22status%3A%20needs-team-input%22
[needs-triage-label]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22status%3A%20needs-triage%22
[first-line-handled]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22status%3A%20first-line-handled%22
[size-small]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22size%3A%20small%22
[contributions-welcome]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22type%3A%20contributions-welcome%22
[waiting-for-author-response]: https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22status%3A%20waiting-for-author-response%22

Two of these labels are automated: `status: needs-triage` is managed entirely by the bot, and `status: waiting-for-author-response` is applied manually and automatically cleared once the author replies.

### How the automated triage bot works

The [triage.mjs](../../scripts/triage.mjs) script runs via the [`Flag/Unflag issues and PRs`](https://github.com/a2ui-project/a2ui/blob/main/.github/workflows/triage.yml) GitHub Actions workflow. It reconciles `status: needs-triage` across all open items according to the following rules:

1. **Skipped items**: The automation skips the following items:
    - **Items waiting on author**: If an item has `status: waiting-for-author-response`, it is skipped. The automation removes this label once an external contributor posts a comment, review or review comment after the label was added.
    - **Assigned issues**: When an issue is assigned, it is assumed that a team member is looking into it.
2. **Issues**: Flagged with `status: needs-triage` if any of the following apply:
    - **No priority**: The issue lacks a priority label (`P0`–`P4`).
    - **Unassigned high priority**: Labeled `P0` or `P1` without an assignee.
    - **Stale**: Inactive beyond the priority threshold:
        - `P0`: stale for > 1 day
        - `P1`: stale for > 30 days
        - `P2`: stale for > 90 days
        - (`P3` and `P4` issues are never flagged for staleness)
    - **Unanswered external comment**: The latest human comment is from an external contributor.
3. **Pull Requests**: Flagged with `status: needs-triage` if opened by an external contributor and no maintainer has responded to the author's latest contribution. (Maintainer-authored PRs are not flagged).
4. **Transparency**: The automation prints to the console what items are flagged or unflagged and why. This can be used to track triage progress.

Staleness is calculated from the last human contribution (comment, review, or issue/PR creation) rather than `updated_at` to avoid bot edits resetting the timer.

The workflow runs daily on a schedule (15:00 UTC / 07:00 PST), on manual dispatch, and automatically on issue events (opened, edited, labeled, unlabeled, assigned, unassigned, reopened), new issue comments, and submitted PR reviews or review comments.

## Triage responsibilities

### First line triage (daily)

For each issue that is [not first-line-handled](https://github.com/a2ui-project/a2ui/issues?q=is%3Aissue%20state%3Aopen%20-label%3AP0%20-label%3AP1%20-label%3AP2%20-label%3AP3%20-label%3AP4%20-label%3A%22status%3A%20first-line-handled%22%20sort%3Acreated-asc):

- If it is P0, add label `P0` and notify team chat
- Add label `status: first-line-handled`

### Second line triage (weekly)

Update [items with label `status: needs-triage`][needs-triage], so that the label, managed by [the triage bot](#how-the-automated-triage-bot-works), disappears. Do at least one of the following:

- Set priority (P0-P4)
    - Be sure to assign P0/P1 issues to someone.
- Answer external comments
- Add `status: waiting-for-author-response` when you need more information from the author

You can remove the `needs-triage` label manually to speed up the process, but if the item still matches a rule, the label will come back because the label will be re-applied by the triage bot.

For items where you need input from the team, follow this process (passing any remaining follow-up to the next gardener if still in progress):

1. add the `status: needs-team-input` label
2. post a message to the team chat, suggesting options and/or asking for input
3. drive the discussion to resolution
4. remove the label `status: needs-team-input`

Use [standard replies](triage-templates.md) that are provided for standard cases.

Lastly, check for [issues which are still unlabeled/unprioritized][unlabeled] (without P0-P4 label and _haven't_ had `status: needs-triage`, `status: needs-team-input` or `status: waiting-for-author-response` added to them). If you find such issues, follow the `status: needs-triage` workflow above (This is just to check for issues which somehow fall through the cracks).

When weekly triage is complete, the [`needs-triage`][needs-triage] list should ideally be empty.

[needs-triage]: https://github.com/a2ui-project/a2ui/issues?q=state%3Aopen%20sort%3Aupdated-asc%20repo%3Aa2ui-project%2Fa2ui%20label%3A%22status%3A%20needs-triage%22%20-label%3A%22status%3A%20needs-team-input%22%20-label%3A%22status%3A%20waiting-for-author-response%22
[unlabeled]: https://github.com/a2ui-project/a2ui/issues?q=sort%3Aupdated-desc%20is%3Aissue%20state%3Aopen%20-label%3AP0%20-label%3AP1%20-label%3AP2%20-label%3AP3%20-label%3AP4%20-label%3A%22status%3A%20needs-team-input%22%20-label%3A%22status%3A%20needs-triage%22%20-label%3A%22status%3A%20waiting-for-author-response%22

## AI assistance

Use [.agents/skills/a2ui-issue-triage](../../.agents/skills/a2ui-issue-triage/SKILL.md) to get agent help with triage.

It forks multiple subagents (one for each issue) to try and reproduce the issue if it is something that can be easily reproduced. It won't attempt to repro something that takes a lot of setup.

It will then display a web UI in a local browser with the list of issues to triage, suggested responses (which you can edit) and a UI to apply suggestions to GitHub.

## Frequently asked questions

### Why do we allow branches on the repo and thus create work for maintainers?

Eval and e2e tests cannot be executed on pre-submit for PRs from forks, because they require an API key that is visible only on the original repo.

We want evals and e2e's to run on pre-submit at least for team members.

Watching branches is not big extra toil for triage process, because:

1. If we forbid branches, the work will not disappear, it will just move to the fork
2. It is easy to cleanup branches because ownership is clear
3. As team members know it is part of triage to clean them up, they are more careful managing their branches

### Why do we need P4? Why not just close the issue?

We need the label P4, because:

1. Just closing the issue will not give a clear searchable sign why it is closed
2. External developers can reopen issue, but cannot change label

It is better not to close P4, because:

1. As we have label P4 anyway, closing the issue is an extra step.
2. If P4 is open, it is a sign that this feature request is still:
    1. not implemented
    2. seems to be valuable
    3. considered P4

    which adds clarity and makes it harder to push for prioritization.

---

### Contributing Web Publishing (`docs/contributing/web_publishing.md`)

# Publishing Guide for A2UI Web Packages

This guide outlines the workflow for project maintainers publishing web packages
(`@a2ui/*`) to npm through Google's internal Artifact Registry.

## Prerequisites: Authentication

Publishing requires access to Google's internal Artifact Registry. Google Cloud
CLI must be authenticated before starting:

```sh
gcloud auth login
```

The release scripts retrieve this authentication token using
`gcloud auth print-access-token` when needed.

---

## Release Workflow

All scripts should be executed from the repository root. The workflow consists
of a pull request bumping the versions of the packages to release, followed by
publishing from the `main` branch.

### 1. Increment Versions (in a Pull Request)

`increment_version.mjs` can be run on a local branch to bump package versions
and synchronize locks:

```sh
# Increment patch version automatically (e.g., 0.9.5 -> 0.9.6)
./typescript/scripts/increment_version.mjs web_core

# Set an explicit version
./typescript/scripts/increment_version.mjs lit 0.10.0-beta.1
```

This branch should be merged into `main` through a PR as with any other change
to the repo.

**CLI parameters for `increment_version.mjs`:**

- `<package-name>`: The name of the package to update (e.g., `web_core` or `@a2ui/web_core`).
- `[new-version]`: The specific new version to set (e.g., `1.0.1`). If omitted, increments the patch version automatically.
- `--skip-sync`: Skip synchronizing dependent packages (running `yarn install` in dependents). **Not recommended.**

### 2. Publish to Staging (from `main`)

Once the new versions land in `main` and it is checked out locally,
`publish_npm.mjs` can be used to build, test, and upload the packages to
Google's internal Artifact Registry:

```sh
./typescript/scripts/publish_npm.mjs --package=lit --package=web_core
```

This script publishes requested packages in the correct dependency order (e.g.,
ensuring `web_core` is published before `lit`), runs unit tests, and verifies
that required core packages exist on the registry.

By default, the script runs in dry-run mode to prevent accidental uploads; the
`--no-dry-run` flag can be passed to actually upload the packages:

```sh
./typescript/scripts/publish_npm.mjs --package=lit --package=web_core --no-dry-run
```

Artifacts are uploaded to: [go/a2ui-oss-exit-gate-artifacts](https://go/a2ui-oss-exit-gate-artifacts).
This URL points to a web app that allows verifying that the packages have been uploaded correctly.

For each package it should be checked:

- That it has been uploaded at the expected version
- That its size is non-zero in the "Files" tab of the details of the version.

**CLI parameters for `publish_npm.mjs`:**

- `-p, --package=<name>`: Package(s) to publish. Can be specified multiple times. Accepts short names (e.g., `web_core`) or scoped names (e.g., `@a2ui/web_core`).
- `--no-dry-run`: Actually publish the packages. By default, the script runs in dry-run mode.
- `--skip-tests`: Skip building and testing packages before publishing. **Not recommended.**

### 3. Trigger Public Release (from `main`)

Once packages are verified in staging, a release manifest must be uploaded to
trigger the internal Exit Gate pipeline, which publishes them to npm:

```sh
./typescript/scripts/upload_manifest.mjs --package=web_core --package=lit
```

Similarly to `publish_npm.mjs`, this script runs in dry-run by default, so the
`--no-dry-run` flag must be passed to actually trigger the release:

```sh
./typescript/scripts/upload_manifest.mjs --package=web_core --package=lit --no-dry-run
```

Confirmation emails from Exit Gate and npm reporting on the progress of the
actual publishing will be sent automatically. Publishing normally takes around
5 minutes.

**CLI parameters for `upload_manifest.mjs`:**

- `-p, --package=<name>`: Package(s) to trigger release for (e.g., `--package=lit`). Can be specified multiple times.
- `--no-dry-run`: Actually trigger the public release via Exit Gate. By default, the script runs in dry-run mode.

---

## What is the `publish:package` yarn script doing?

A2UI web packages depend on each other via `workspace:*` links during development. When `publish_npm.mjs` invokes a package's `publish:package` target, the following preparation steps occur:

1. **Build & Metadata Transformation**: `prepare-publish.mjs` copies build output into `dist/`, replaces internal `workspace:` protocols with absolute semantic version ranges (e.g., `^0.10.3`), and strips development scripts/dependencies.
2. **Boundary Isolation**: Because the root workspace config excludes `dist/` (`!**/dist`), an empty `yarn.lock` is initialized inside `dist/` to establish it as an independent package boundary.
3. **Clean Upload**: `yarn npm publish --access public` executes strictly inside `dist/`, ensuring only clean production assets are uploaded.

---

## What are valid values for the `--package` argument?

The `increment_version.mjs`, `publish_npm.mjs` and `upload_manifest.mjs` scripts
work with all publishable web packages in the `typescript` directory of the monorepo:

- `web_core`
- `markdown-it`
- `angular`
- `lit`
- `react`

The scripts also support the full package names, e.g. `@a2ui/web_core`, but the
`@a2ui/` prefix is not required.

---

## Troubleshooting

- **Dirty Working Tree Warnings**: If build artifacts or temporary files
  persist, `yarn clean:all` can be run from the monorepo root before trying again.

---

### Proposals Eval Suite Expansion (`docs/proposals/eval_suite_expansion.md`)

# Evaluation dataset expansion and agentic data points design

_Status: Draft_

_Author: A2UI Team_

_Created: 2026-07-23_

## Background

The A2UI evaluation framework located in [eval/](../../eval) tests whether Large Language Models generate valid and contextually appropriate A2UI JSON payloads. The current framework runs Inspect AI tasks ([eval/tasks.py](../../eval/tasks.py)) against prompt datasets stored in YAML format. Datasets are encrypted at rest using Transcrypt to prevent data contamination from web crawlers.

While the existing system tests basic generation well, real-world agentic applications present scenarios that the current setup cannot evaluate:

1. **Monolithic dataset files**: All evaluation samples reside in monolithic YAML files. There is no mechanism to isolate data points into separate modular datasets (such as `core_v0_9_1`, `customer_a_data`, or `banking_app`), execute only a specific dataset, or view separate reporting tables per dataset.
2. **Disconnected single-string prompts**: The existing schema ([eval/datasets/dataset_schema.json](../../eval/datasets/dataset_schema.json)) uses a standalone `promptText` string. Real agentic applications pass a structured `messages` list containing prior user queries, assistant responses, and tool calls with execution outputs before the model generates UI.
3. **Domain system prompts and custom catalogs**: In production applications, models receive domain-specific system prompts (such as customer support rules, flight booking domain logic, or medical guidelines) that are separate from A2UI protocol instructions. Applications also define custom component catalogs with specialized UI elements. The current eval engine only injects A2UI protocol instructions without merging custom domain system prompts or supporting multi-turn chat history.
4. **Contributor onboarding**: Contributors and external teams creating new data points need a clear, step-by-step workflow covering decryption, schema verification, local evaluation execution, and safe encrypted commits.

This proposal outlines the technical design for expanding the evaluation framework to support separate modular datasets, standard LLM chat completion message formats (`messages`), custom catalogs with merged domain system prompts, and a contributor guide. All existing data points are cleanly migrated into modular dataset files under `eval/datasets/`, eliminating legacy monolithic files and obsolete field aliases.

---

## Architecture overview

The expanded evaluation pipeline adds dataset discovery, standard LLM `messages` array parsing, system prompt merging, and dataset-aware reporting to Inspect AI.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

## 1. Separate datasets of data points

### Directory organization

Dataset files will be organized under [eval/datasets/](../../eval/datasets) as separate modular YAML files. The legacy monolithic files (`prompts_v0_9_1.yaml` and `prompts_v1_0.yaml`) are migrated directly into named dataset files:

```
eval/datasets/
├── .gitattributes                  # Transcrypt filter rules
├── dataset_schema.json             # Updated JSON schema for data points
├── defaults.py                     # Default prompt templates and catalog paths
├── core_v0_9_1.yaml                # Migrated core dataset for v0.9.1 protocol
├── core_v1_0.yaml                  # Migrated core dataset for v1.0 protocol
├── customer_a_data.yaml            # Customer A specific agentic scenarios
└── flight_booking.yaml             # Domain-specific multi-turn dataset
```

Each YAML file in `eval/datasets/` represents a distinct evaluation dataset named after its filename (e.g. `customer_a_data.yaml` defines the `customer_a_data` dataset, and `core_v0_9_1.yaml` defines the `core_v0_9_1` dataset). Alternatively, a sample can specify an explicit `dataset` property in its metadata.

### Dataset resolution and CLI execution

The CLI runner in [eval/main.py](../../eval/main.py) and the CI runner in [eval/bin/run_ci_evals.py](../../eval/bin/run_ci_evals.py) will support filtering by dataset:

```bash
# Run all datasets (default)
uv run main.py

# Run only a specific dataset
uv run main.py --dataset customer_a_data

# Run multiple specific datasets
uv run main.py --datasets customer_a_data,core_v0_9_1

# Run a quick sanity check on a specific dataset
uv run main.py --dataset customer_a_data --sanity
```

#### CLI argument specifications

- `--dataset <name>`: Evaluates only samples belonging to the named dataset.
- `--datasets <name1,name2>`: Evaluates samples belonging to any of the listed datasets (comma-separated).
- When no dataset flag is supplied, the framework defaults to evaluating all active datasets or the default core datasets.

### Dataset-aware reporting and summary tables

The evaluation reporting tools in [eval/bin/report_evals.py](../../eval/bin/report_evals.py) will group and calculate metrics per dataset:

#### Console output format

```text
=== Evaluation Results Summary ===

--- Dataset: customer_a_data (Pass Rate: 100.00%) ---
customer_a_flight_select  | Algorithmic: PASS | Judging: C  | Inference Time: 3.20s
customer_a_seat_picker    | Algorithmic: PASS | Judging: C  | Inference Time: 2.80s

--- Dataset: core_v0_9_1 (Pass Rate: 90.00%) ---
contact_form              | Algorithmic: PASS | Judging: C  | Inference Time: 1.90s
data_binding_list         | Algorithmic: PASS | Judging: P  | Inference Time: 2.10s
  [Judging Failure Reason (Grade P)]:
    Minor cosmetic variation in column label.

==================================
Dataset Summary:
  customer_a_data : 2/2 passed (100.00%)
  core_v0_9_1     : 9/10 passed (90.00%)
Overall Pass Rate: 91.67% (Threshold: 90.00%)
Inference Time - Average: 2.50s | Median: 2.45s
==================================
```

#### Markdown summary format (`eval_summary.md`)

The generated markdown summary file will include a top-level dataset summary table followed by detailed per-dataset breakdowns:

```markdown
### Evaluation Summary: a2ui_v0_9_1_eval

- **Status**: PASS
- **Model**: `google/gemini-3.6-flash`
- **Overall Pass Percentage**: `91.67%` (Threshold: `90.00%`)

#### Dataset Performance Summary

| Dataset Name      | Total Samples | Algorithmic Pass Rate | Judging Pass Rate | Dataset Pass Rate |
| :---------------- | :-----------: | :-------------------: | :---------------: | :---------------: |
| `customer_a_data` |       2       |        100.0%         |      100.0%       |      100.0%       |
| `core_v0_9_1`     |      10       |        100.0%         |       90.0%       |       90.0%       |

#### Detailed Dataset Results: customer_a_data

| Sample / Task            | Algorithmic | Judging | Inference Time | Status |
| :----------------------- | :---------: | :-----: | :------------: | :----: |
| customer_a_flight_select |    PASS     |    C    |     3.20s      |  PASS  |
| customer_a_seat_picker   |    PASS     |    C    |     2.80s      |  PASS  |
```

---

## 2. Standard LLM chat schema and field reference guide

To align the evaluation format with industry-standard LLM chat completion APIs (such as OpenAI Chat Completions, Anthropic Messages API, and Inspect AI's internal `state.messages`), conversational turns and user prompts are consolidated under the familiar **`messages`** array. Every data point explicitly declares its required **`catalog`** path.

### Standalone field reference

| Field Name                | Type                     | Required? | Clear Explanation & Purpose                                                                                                                                                                                                                                                                                           |
| :------------------------ | :----------------------- | :-------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`**                | string                   | **Yes**   | Unique identifier for this evaluation sample (e.g. `customer_a_login_form`). Used in logs and result tables.                                                                                                                                                                                                          |
| **`description`**         | string                   | **Yes**   | Human-readable explanation of what this test case verifies.                                                                                                                                                                                                                                                           |
| **`catalog`**             | string                   | **Yes**   | **Path to the component catalog JSON file** defining available UI widgets and validation functions. Supports the `{version}` placeholder (e.g. `specification/{version}/catalogs/basic/catalog.json`). Required on every data point so solvers and scorers explicitly know which component schema and rules apply.    |
| **`messages`**            | array of message objects | **Yes**   | **The conversation messages.** An ordered list of chat turns preceding and including the final UI request. Each item specifies a `role` (`user`, `assistant`, `system`, or `tool`), `content`, and optional `tool_calls` or `tool_call_id`.                                                                           |
| **`target`**              | string                   | No        | **The primary grading criteria and expected UI outcome.** Used by the LLM-as-a-judge (`measured_model_graded_qa`) to evaluate whether the generated output meets requirements. If omitted, defaults to the value of `description`.                                                                                    |
| **`dataset`**             | string                   | No        | The name of the dataset module this sample belongs to. If omitted, the loader infers it from the YAML filename.                                                                                                                                                                                                       |
| **`system_prompt`**       | string                   | No        | **Domain-specific system instructions** representing the host application (e.g., application persona, customer service rules, or API constraints). The eval engine merges this domain prompt with the A2UI protocol instructions.                                                                                     |
| **`protocol_role`**       | string                   | No        | **The A2UI persona instruction passed to the SDK prompt generator.** Specifies the high-level role for UI generation (Default: _"You are an AI assistant. Based on the following request, generate a stream of JSON messages that conform to the provided JSON Schemas."_). Most contributors can leave this omitted. |
| **`generation_rules`**    | string                   | No        | **Technical protocol constraints appended to the SDK workflow prompt.** Defines formatting rules such as required surface ID naming, component root ID constraints, or adjacency list rules. Most contributors can leave this omitted to use standard protocol defaults.                                              |
| **`allowed_surface_ids`** | array of strings         | No        | List of valid surface identifiers the model is allowed to target (Default: `["main"]`).                                                                                                                                                                                                                               |

---

### Detailed breakdown of key concepts

#### 1. Why `catalog` is required

Every A2UI evaluation requires a component catalog. Making `catalog` mandatory removes ambiguity for contributors, solver prompt generators, and validators. A contributor always explicitly declares the catalog path (such as `specification/{version}/catalogs/basic/catalog.json` for standard protocol widgets or a domain catalog path like `specification/{version}/catalogs/customer_a/catalog.json`).

#### 2. Why `messages` is the preferred terminology

Across the LLM ecosystem (OpenAI, Anthropic, LiteLLM, Ollama, and Inspect AI), `messages` is the universal term for chat interaction sequences:

- **Direct framework alignment**: Inspect AI stores conversation turns in `state.messages`. Using `messages` in our YAML schema creates a 1:1 conceptual mapping.
- **Avoids ambiguity**: The word "context" is overloaded in AI (often referring to RAG retrieval chunks, context windows, or A2UI action event contexts like `action.event.context`). `messages` unambiguously refers to the chat history.
- **Consistent single-turn and multi-turn authoring**:
    - **Single-turn prompt**: `messages` contains a single user turn (`role: user`, `content: "Create a login form"`).
    - **Multi-turn conversation**: `messages` contains prior user, assistant, and tool turns, ending with the user turn that prompts the UI response.

#### 3. `target` vs `description`

- **`description`** is a high-level summary of what the test case does, used for human documentation and readability in test manifests.
- **`target`** is the detailed rubric evaluated by the grading model. It specifies the exact expectations for the UI, such as required component types (e.g. "Must contain a Card with a TextField and a primary Button"), data bindings (e.g. "TextField must bind to `/auth/email`"), and interactive actions.

#### 4. `system_prompt` vs `protocol_role`

- **`system_prompt`** represents the **domain application persona**. In a real application, an agent has domain rules unrelated to A2UI (for example: _"You are the Acme Airlines Agent. Always confirm passenger baggage before checkout."_).
- **`protocol_role`** represents the **A2UI protocol prompt**. This is the standard SDK instruction telling the LLM that it must output structured JSON conforming to the A2UI schema.
- The eval engine merges both: domain instructions are presented first, followed by protocol instructions.

#### 5. `generation_rules`

- This field controls the technical A2UI rules injected into the prompt's `## Workflow Description:` section.
- Standard protocol rules (e.g. _"Construct the UI on surfaceId 'main'"_ and _"Ensure there is one root component with id 'root'"_) are injected by default.
- If a test case needs custom protocol behavior (for example, rendering to a surface named `'sidebar'`), the contributor specifies those extra rules in `generation_rules`.

---

### JSON schema specification

The schema in [eval/datasets/dataset_schema.json](../../eval/datasets/dataset_schema.json) validates the clean dataset structure with `catalog` required:

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Example multi-turn agentic data point (YAML)

Below is an example of an agentic data point representing a flight booking assistant that interacts via tools before rendering a custom A2UI interface:

```
/* Detailed source-code truncated for AI context efficiency. */
```

### Example single-turn data point (YAML)

Below is an example of a migrated single-turn core data point:

```yaml
- name: contact_form
  dataset: core_v0_9_1
  description: Renders a contact form with email and submit button.
  catalog: 'specification/{version}/catalogs/basic/catalog.json'
  messages:
    - role: user
      content: 'Create a contact form with an email text field and submit button.'
  target: |
    The response must contain a Card or Column with a TextField bound to '/contact/email' and a primary Button.
```

---

## 3. Eval engine execution mechanics

When executing an evaluation sample, the solver in [eval/a2ui_eval/strategies/format.py](../../eval/a2ui_eval/strategies/format.py) coordinates prompt merging, chat message list assembly, inference, and scoring.

### Step 1: System prompt generation and merging

The solver merges the domain-specific system prompt with the protocol instructions generated by the A2UI SDK:

1. **SDK prompt generation**: The A2UI SDK `DirectJsonPromptGenerator` loads the required `catalog` and generates protocol rules, JSON schemas, component catalog definitions, and output tag requirements (`<a2ui-json>`).
2. **Domain prompt merging**: If the data point includes a `system_prompt`, the solver combines them into a unified system instruction:

```python
def merge_system_prompts(domain_prompt: str, a2ui_prompt: str) -> str:
    """Merges domain-specific rules with A2UI protocol instructions."""
    parts = []
    if domain_prompt.strip():
        parts.append(f"## Domain Instructions\n{domain_prompt.strip()}")
    if a2ui_prompt.strip():
        parts.append(f"## UI Protocol Instructions\n{a2ui_prompt.strip()}")
    return "\n\n".join(parts)
```

3. The merged prompt is inserted as the first message (`ChatMessageSystem`) in Inspect AI's `state.messages`.

### Step 2: Chat messages assembly

The solver populates `state.messages` directly from the sample's `messages` array:

- **User turns**: Converted to `ChatMessageUser(content=turn["content"])`.
- **Assistant turns**: Converted to `ChatMessageAssistant(content=turn.get("content", ""), tool_calls=turn.get("tool_calls"))`.
- **Tool turns**: Converted to `ChatMessageTool(content=turn["content"], tool_call_id=turn["tool_call_id"])`.

The final turn in `messages` triggers the assistant's UI generation response.

### Step 3: Model inference

The solver invokes `measured_generate()`, passing the assembled message list to the model. The model generates its completion on the final turn.

### Step 4: Multi-stage scoring

1. **Programmatic validation ([a2ui_scorer](../../eval/a2ui_eval/scorers.py))**:
    - Resolves the required `catalog` path specified in the data point.
    - Parses JSON from `<a2ui-json>` tags.
    - Runs the catalog validator ([validate_components](../../python/a2ui_agent/README.md)) to verify schema adherence, parent-child references, and root component presence.
2. **LLM judge scoring ([measured_model_graded_qa](../../eval/a2ui_eval/scorers.py))**:
    - Evaluates the generated UI against the `target` criteria using the grading model (e.g. `google/gemini-3.6-flash`).
    - Produces a grade of `C` (Correct), `P` (Partial Credit), or `I` (Incorrect).

---

## 4. Contributor guide: checking in data points and encryption

This step-by-step guide is for contributors adding or updating data points in the A2UI evaluation framework.

### Why data points are encrypted

Evaluation datasets are encrypted at rest in Git using **Transcrypt**. This prevents public search engines and automated LLM training web crawlers from indexing our test prompts and answers, avoiding artificial score inflation from model memorization.

### Step 1: Initial decryption setup

Before modifying or viewing datasets, initialize Transcrypt with the repository evaluation password:

```bash
cd eval
bin/transcrypt -p <PASSWORD>
```

_(Request the password from an A2UI maintainer if you do not have it.)_

Once decrypted, all YAML files in `eval/datasets/` appear as regular plaintext files on your local filesystem.

### Step 2: Create or update a dataset file

1. Create a new YAML file under `eval/datasets/<dataset_name>.yaml` (for example, `eval/datasets/customer_a_data.yaml`).
2. Add your evaluation samples following the standard chat completion format with a required `catalog`:

```yaml
- name: customer_a_login_form
  dataset: customer_a_data
  description: Tests generation of a secure login card with email and password fields.
  catalog: 'specification/{version}/catalogs/basic/catalog.json'
  system_prompt: 'You are the Customer A Authentication Agent. Help users sign in.'
  messages:
    - role: user
      content: 'Create a login form with email, password, and a submit button.'
  target: |
    The response must contain:
    1. A Card or Column root component.
    2. A TextField for email bound to '/auth/email'.
    3. A TextField for password bound to '/auth/password'.
    4. A primary Button labeled 'Sign In'.
```

### Step 3: Validate your dataset against the schema

Run the automated dataset schema test before running evaluations:

```bash
uv run python -m pytest tests/test_dataset.py
```

You can also validate specific dataset files directly:

```bash
uv run python -m a2ui_eval.dataset --validate datasets/customer_a_data.yaml
```

If your YAML file violates the schema (e.g. missing required fields like `catalog` or unknown properties), the validator will output the exact line and error.

### Step 4: Run a local evaluation test

Test how your new data points perform against Gemini models:

```bash
# Set your API key
export GEMINI_API_KEY="your_api_key"

# Run a quick sanity check on your new dataset (2 samples, flash-lite)
uv run main.py --dataset customer_a_data --sanity

# Run the full evaluation on your dataset
uv run main.py --dataset customer_a_data
```

### Step 5: Inspect results in the log viewer

Start Inspect AI's interactive web viewer to examine model outputs, merged system prompts, and validator rationales:

```bash
uv run inspect view start
```

Open `http://localhost:7575` in your browser to view the trace of each sample.

### Step 6: Commit and push changes

Because `.gitattributes` configures Transcrypt filters for `*.yaml` files in the `eval/datasets/` directory, Git will automatically encrypt the files when staging:

```bash
git add eval/datasets/customer_a_data.yaml
git commit -m "feat(eval): add customer_a_data evaluation dataset"
git push origin your-branch
```

To verify that files are encrypted before pushing, run:

```bash
git diff --cached
```

If Transcrypt is active, the staged diff will show encrypted cipher text.

---

## 5. Migration path for existing data points

The evaluation framework migrated legacy monolithic prompt files (`prompts_v0_9_1.yaml` and `prompts_v1_0.yaml`) into clean, modular dataset files (`core_v0_9_1.yaml` and `core_v1_0.yaml`) conforming to the new `messages` schema.

### Migration strategy

1. **Standardizing on `messages`**: Single-string `promptText` queries are converted into structured `messages` arrays with role-based conversation turns (`user`, `assistant`, `tool`, `system`).
2. **Mandatory component catalogs**: Every sample specifies an explicit relative `catalog` path (e.g. `specification/{version}/catalogs/basic/catalog.json`).
3. **Modular dataset separation**: Data points are partitioned into logical, manageable YAML files under `eval/datasets/` that are dynamically discovered by the dataset loader.
4. **In-memory runtime fallback (loader safety)**: To prevent breakage if a developer branch or scratch file still contains legacy fields, the dataset loader in [eval/a2ui_eval/dataset.py](../../eval/a2ui_eval/dataset.py) includes a runtime normalizer that converts `promptText` to `messages` and maps legacy field aliases on the fly.

---

## Code changes roadmap

| File Path                                                                        | Nature of Change | Purpose                                                                                                                                     |
| :------------------------------------------------------------------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
| [eval/datasets/dataset_schema.json](../../eval/datasets/dataset_schema.json)     | Update           | Require `catalog`, use `messages` for chat turns, and include `dataset`, `system_prompt`, `protocol_role`, and `generation_rules` fields.   |
| [eval/datasets/core_v0_9_1.yaml](../../eval/datasets)                            | Create           | Migrated v0.9.1 data points using the `messages` format and explicit `catalog`.                                                             |
| [eval/datasets/core_v1_0.yaml](../../eval/datasets)                              | Create           | Migrated v1.0 data points using the `messages` format and explicit `catalog`.                                                               |
| [eval/a2ui_eval/dataset.py](../../eval/a2ui_eval/dataset.py)                     | Update           | Add dataset discovery, `messages` array conversion to Inspect AI `ChatMessage` objects, required `catalog` enforcement, and validation CLI. |
| [eval/a2ui_eval/strategies/format.py](../../eval/a2ui_eval/strategies/format.py) | Update           | Implement domain system prompt merging and `messages` chat history prepending.                                                              |
| [eval/a2ui_eval/scorers.py](../../eval/a2ui_eval/scorers.py)                     | Update           | Use explicit `catalog` path in `a2ui_scorer`.                                                                                               |
| [eval/tasks.py](../../eval/tasks.py)                                             | Update           | Point to migrated datasets and accept `dataset` and `datasets` filtering parameters.                                                        |
| [eval/main.py](../../eval/main.py)                                               | Update           | Add `--dataset` and `--datasets` CLI flags.                                                                                                 |
| [eval/bin/report_evals.py](../../eval/bin/report_evals.py)                       | Update           | Add per-dataset grouping in console summaries and markdown reports.                                                                         |
| [eval/bin/run_ci_evals.py](../../eval/bin/run_ci_evals.py)                       | Update           | Pass dataset filtering arguments to `main.py`.                                                                                              |
| [eval/tests/test_dataset.py](../../eval/tests/test_dataset.py)                   | Update           | Add unit tests for dataset loading, `messages` chat turn parsing, required `catalog` check, and schema validation.                          |

---

### Proposals Spec Driven Development (`docs/proposals/spec_driven_development.md`)

# **Scaling A2UI codebases with spec-driven development**

# **Background**

The A2UI team has adopted recent development practices of using agents to write the majority of our code, using designs, specifications, prompts and other codebases as inputs to guide it. In this paradigm, the job of human developers is primarily to write and maintain the documentation that agents use to write code. This spec-driven development (SDD) approach is being adopted across the software industry in various ways. Members of the A2UI team have tried many different approaches, including generating detailed design docs which are then reviewed by humans for implementation, maintaining markdown guides which can be used to implement multiple variants of a codebase (e.g. `renderer_guide.md` for web renderers) or creating detailed Github issues that are used by agents to implement features.

The A2UI team aims to write and maintain several codebases across multiple languages with a small team. We have an opportunity to do this more efficiently by formalizing our use of spec-driven development, and building shared tooling to help agents follow it smoothly. We can reuse existing approaches to spec-driven development, but adapt them to work with our specific circumstances where we own a family of codebases which implement the same functionality across different languages.

# **Goals**

Adopt spec-driven development with a standardized approach across the A2UI team in service of the following goals:

- Encourage a culture of where we spend more effort creating and reviewing specifications.
- Allow the A2UI team to more quickly implement features across SDK implementations in multiple languages.
- Allow contributors outside of the core A2UI team to more efficiently write and maintain their own A2UI SDKs, for example the Jetpack Composer and Swift UI renderers.
- Allow the A2UI team to collaborate more efficiently by standardizing the way that we record SDK and feature specifications.
- Increase the productivity of agents working in our codebase on any task by giving them better access to relevant design documentation.
- Make it easier for humans and agents to understand the discrepancies between different SDK codebases by emphasizing better definition of features and a clear separation between required features and optional (a.k.a. new or experimental) features.
- Avoid disrupting existing workflows used by team members and ensure they still have freedom to experiment with novel techniques.

# **Overview**

This document outlines the **Spec-Driven Development (SDD)** methodology for the A2UI repository. The goal of SDD is to streamline the implementation of the A2UI protocol and its features across multiple programming languages and UI frameworks by establishing clear, language-agnostic specifications (called **Blueprints**) and leveraging AI coding agents to scale development.

```mermaid
graph TD
    FB[Feature Blueprint] -->|Merges into| MB[Module Blueprint]
    FB -->|Guides implementation of| CB[Codebase Blueprint]
    MB -->|Specifies architecture of| CB
    CB -->|Documents| C[Codebase Implementation]
```

Under this model:

1. **Module Blueprints** define the high-level architecture, core interfaces, and behavior of repository modules (e.g., `a2ui_core`, `a2ui_inference`, `a2ui_react`, etc.).
2. **Feature Blueprints** describe specific feature additions or behavioral changes to a module.
3. **Codebase Blueprints** reside within each platform's implementation folder, tracking implemented features and documenting local design decisions or deviations.

Formal blueprints are primarily used for major features, e.g. the addition of a new public API, behavior, protocol version or architectural change. By having these specifications to be checked into the codebase, we create a natural opportunity for review of feature designs before they are implemented. We also ensure that when we add a feature to one SDK codebase, we can easily port it to other languages.

### **Smaller features**

Smaller features can still be implemented ad-hoc with no formal blueprint. These small feature typically:

- Make changes to functionality that is not explicitly documented in the module blueprint, or
- Address local bugs, refactorings, or performance optimizations that do not affect the public API or cross-language protocol compliance, or
- Add codebase-specific utility functions or internal helpers that do not impact compatibility or consistency with other SDKs.

Specification-driven development is still useful for these features, but the specifications don’t always need to be checked into the file system. They could be checked in as blueprints, or written in Github issues, or exist as temporary files on a developer’s file system.

# **Document types**

## **Feature blueprint**

Feature blueprints describe a _diff_ in functionality that can be implemented in a codebase.

### **Required features**

A **Required Feature Blueprint** describes a feature that has its design merged into all relevant module blueprints. It is expected to be _eventually_ implemented in all codebases for the module. Required feature blueprints are added (or promoted from _optional_ status) _before_ they are implemented in all codebases and there are no guaruntee that the feature is implemented in all codebases within any particular timeframe. It is the job of codebase owners to keep their feature sets as up to date as possible. The codebase blueprints are the source of truth for which features are implemented in each codebase.

- _Agents implementing new codebases_ for a particular module never need to read required feature blueprints. They can completely implement the module and all its required features using only the module blueprint, because it has all the necessary details from existing required feature blueprints.
- _Agents implementing new required features in existing codebases_ primarily use the required feature blueprint to design and implement changes.

### **Optional features**

An **Optional Feature Blueprint** describes a feature that is not baked into the module blueprint and is not expected to be implemented in all codebases. It allows platforms to support experimental or framework-specific features without forcing compliance across all SDKs.

- **Decoupled Lifecycle**: Optional feature blueprints exist as standalone specification files in `blueprints/features/` and are not merged into the base Module Blueprint.
- **Ad-hoc Implementation**: Each codebase can decide independently whether to support an optional feature based on platform capabilities and user needs.
- **Discovery**: Codebases that implement an optional feature must list it in their `codebase.blueprint.md` under `implemented_features` to let clients and agents know it is supported.

### **Feature dependencies**

A feature blueprint can optionally specify a list of **dependencies** in its frontmatter. This list includes other feature blueprints that this feature directly depends on. The purpose of this field is to provide a pragmatic way for coding agents to identify other recent features that might be missing from a codebase and need to be implemented first, rather than being an exhaustive list of all architectural dependencies.

### **my_feature.blueprint.md structure (Example)**

Every feature blueprint must follow a standardized Markdown structure with YAML frontmatter. The feature is named with a date prefix, e.g. `YYYY_MM_DD_feature_name.blueprint.md`, so that if there are many feature blueprints, it's easy to sort them by date and find the most recent and relevant ones. The date in the filename and frontmatter must match, and it is the date that the feature blueprint was initially written.

_(Note: This date is used solely for rough chronological sorting of features. It does **not** indicate any dependency structure—a feature does not necessarily depend on previously created features, nor does it imply it does not depend on features proposed later.)_

Below is an example feature blueprint for a dynamic theming feature, written in a language-agnostic way:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## **Module blueprint**

A **Module Blueprint** describes an entire architectural module in a language-agnostic way. It serves as the primary source of truth for building a new codebase from scratch or verifying the correctness of an existing one.

All _required_ features that affect the module are merged into the module blueprint when the feature is added or promoted, so that new codebases can be implemented using _only_ the module blueprint and without consulting specific feature blueprints. Module blueprints act as a coherent, compacted description of the module, ensuring that the overall module specification does not have unbounded growth over time as features are added. As features are layered on top of each other, it is expected that the module blueprint will find concise ways to describe the overall system which are smaller than a simple concatenation of the feature blueprints.

### **a2ui_core.blueprint.md Structure (Example)**

Every module blueprint must follow a standardized Markdown structure with YAML frontmatter. Below is an example module blueprint for the core state layer (`a2ui_core`):

```md
---
name: a2ui_core
included_features: 
  - bidirectional_rpc
  - dynamic_binding
---

# **Core State Layer (a2ui_core) Module Blueprint**

## **Architecture Overview**

The core state layer is the framework-agnostic engine of A2UI. It is responsible for parsing inbound JSON streams from the agent, maintaining the active UI surface models, resolving JSON Pointer data bindings, and dispatching client actions back to the transport layer.

## **Core Interfaces**

- **`MessageProcessor`**: The central controller that ingests `A2uiMessage` envelopes and directs updates.
  ...

## **Conformance Test Plan**

Every implementation of `a2ui_core` must pass the core conformance test suite:

- **JSON Parsing Suite**: Validates envelope compliance against `server_to_client.json` and throws `A2uiValidationError` on schema violations.
- **Data Model Binding Suite**: Verifies absolute and relative pointer resolution, type coercion rules, and reactive signal emission.
- **Path to Mock Data**: `specification/v1_0/test/conformance/a2ui_core/`
```

## **Codebase blueprint**

A **Codebase** is a concrete, language-specific or framework-specific implementation of a module. Examples of codebases in this repository include `typescript/core/web_core` (TypeScript implementation of `a2ui_core`), `typescript/renderers/react` (React implementation of `a2ui_react`), and `kotlin/agent_sdk_legacy` (Kotlin implementation of `a2ui_inference` and `a2ui_core`).

Every codebase must contain a `codebase.blueprint.md` file in its root directory. This file maps the concrete implementation back to the language-agnostic module blueprint, tracking its feature support and documenting local engineering decisions. The codebase blueprint should be updated _at the same time as the code_ to keep it consistent with the codebase.

### **codebase.blueprint.md Structure (Example)**

Below is an example codebase blueprint for a React renderer codebase (`a2ui_react`):

```
---
associated_module: a2ui_react
implemented_features: 
  - dynamic_theming
  - call_function_rpc
---
# **React Renderer Codebase Blueprint**
## **Architecture & Styling**
This codebase implements the `a2ui_react` module blueprint using React 19 and standard functional components.
* **Reactivity**: We map the core `a2ui_core` state signals to React state via a custom `useSignal` hook to trigger declarative re-renders.
* **Context Propagation**: We use React Context (`ComponentContext.Provider`) to propagate the data binding scopes recursively down the widget tree.
## **Technical Decisions & Overrides**
* **Dynamic Binders**: Unlike static languages, we utilize TypeScript runtime reflection to implement **Generic Binders**. This automatically resolves `DynamicString` properties into static props at the adapter layer, avoiding manual boilerplate for custom components.
* **Event System**: To handle React's synthetic event loop, we throttle input change actions (e.g., `TextField` keystrokes) in the adapter before committing them to the local `DataModel` to optimize performance.
```

# **Developer journeys**

This section explains what steps will be taken by developers and agents to perform common tasks using spec-driven development.

## **Specify a new required feature**

1. Create required feature blueprint **(significant human input required)**
2. Update module blueprint based on the feature blueprint, to ensure the module blueprint fully specifies the feature and how to implement it. Add the feature name to the module’s “included features”. (coding agent)
3. Send PR for review. You can also include an implementation in a codebase in the same PR if you want \- see “Implement an optional or required feature in a codebase”.

## **Specify a new optional feature**

1. Create optional feature blueprint **(significant human input required)**
2. Send PR for review. You can also include an implementation in a codebase in the same PR if you want \- see “Implement an optional or required feature in a codebase”.

## **Promote an optional feature to be required**

1. Update module blueprint based on the feature blueprint, and add it to the module’s “included_features”. (coding agent)
2. Send PR for review.

## **Implement an optional or required feature in a codebase**

1. Verify that the codebase does not already contain the feature
2. Create a temporary design describing in detail how the feature should be implemented in the specific codebase, taking into account the feature blueprint, the codebase blueprint, and the actual codebase code. This file should not be checked in. **(human input required)**
3. Use the temporary design to implement the feature
4. Update the codebase blueprint to add the feature to the "implemented_features" list and include any codebase-specific decisions that were made as part of the feature implementation.
5. Send PR for review.

## **Implement all the features necessary to bring a codebase “up to date”**

1. Read the codebase blueprint and module blueprint and identify all the required features in the module that are not in the codebase.
2. Implement each feature in chronological order, based on their blueprints, following the steps to implement a feature above.
3. Consult the module blueprint and verify that the codebase now matches it, making minor changes to the codebase as necessary to make it as consistent as possible to the module blueprint.
4. Update the codebase blueprint to add the feature to the "implemented_features" list.
5. Send PR for review, either one PR per feature, or one PR for the entire update.

## **Resolve inconsistencies between a module blueprint and all of its associated codebases**

1. Read the relevant module blueprint
2. Search for all codebases that associated with the module
3. Analyse every codebase associated with the module, identifying:
    1. Required features that are missing from each codebase
    2. Discrepancies between the blueprint and the actual implementation e.g. API names or structures which are inconsistent
    3. Discrepancies between the codebases, for which the module blueprint provides no guidance.
4. Report the above and propose actions to take to reduce the inconsistencies including:
    1. Adding additional detail to the blueprints to reduce ambiguity
    2. Update the module blueprint to explicitly mark a detail as being a codebase-level decision
    3. Updating codebases to match the module blueprints
    4. Update the codebase blueprint to document a reason that it has intentionally deviated from the module blueprint for a language-specific reason.
5. Implement some of the proposed actions, based on human discretion **(significant human input required)**
6. Send PR for review.

## **Implement a new codebase**

1. Create a temporary design describing in detail how the codebase should be implemented based on the module blueprint. **(significant human input required)**
2. Implement the module based on the temporary design
3. Create a new codebase blueprint, summarizing the design of details that are not specified in the module blueprint.
4. Split up the changes into manageable chunks to review over several PRs.

## **Clean up feature blueprints**

Feature blueprints undergo a clean, Git-centric lifecycle to prevent the blueprints directory from becoming cluttered with obsolete specifications.

1. **Required Features**: Once a required feature has been fully implemented in all active codebases and its requirements have been integrated into the base Module Blueprint, the feature blueprint file is moved to the archived/ folder.
2. **Optional Features**: Optional feature blueprints remain in `blueprints/features/` as long as they are actively supported. If they are promoted to required, they are integrated into the Module Blueprint and deleted. If they are deprecated or abandoned, they are moved to the archived/ folder.

# **Implementation**

## **Folder structure**

To keep specifications organized and isolated by default, all SDD blueprints, validation tools, and specialized skills reside in the top-level `/blueprints/` directory:

```
/
├── blueprints/
│   ├── README.md                           # Directive instructing agents to ignore folder unless explicitly requested
│   ├── validate_blueprints.py              # Blueprint frontmatter and structure validator
│   ├── link_skills.sh                      # Helper script to symlink blueprint skills into .agents/skills/
│   ├── modules/                            # Language-agnostic Module Blueprints
│   │   ├── a2ui_core.blueprint.md
│   │   └── a2ui_framework_adapter.blueprint.md
│   ├── features/                           # Unmerged / Optional Feature Blueprints (no date prefix)
│   │   ├── dynamic_theming.blueprint.md
│   │   └── archived/                       # Merged / Required Feature Blueprints
│   │       └── bidirectional_rpc.blueprint.md
│   ├── codebases/                          # Codebase Blueprints tracking module compliance by commit hash
│   │   ├── typescript/
│   │   │   ├── core/
│   │   │   │   └── web_core/
│   │   │   │       └── codebase.blueprint.md
│   │   │   └── renderers/
│   │   │       └── react/
│   │   │           └── codebase.blueprint.md
│   │   └── python/
│   │       └── a2ui_core/
│   │           └── codebase.blueprint.md
│   └── skills/                             # SDD Blueprint Skills (isolated from default agent use)
│       ├── a2ui-blueprint-maintenance/
│       ├── a2ui-blueprint-navigator/
│       ├── a2ui-create-feature-blueprint/
│       └── a2ui-implement-feature-from-blueprint/
```

## **Skills**

To support automated execution of spec-driven tasks without cluttering default agent contexts, specialized SDD skills are maintained in `blueprints/skills/`. Developers can optionally symlink them into `.agents/skills/` using `blueprints/link_skills.sh`:

```bash
# Enable SDD skills locally
./blueprints/link_skills.sh

# Remove local SDD symlinks when done
rm -f .agents/skills/a2ui-blueprint-navigator \
      .agents/skills/a2ui-create-feature-blueprint \
      .agents/skills/a2ui-implement-feature-from-blueprint \
      .agents/skills/a2ui-blueprint-maintenance
```

- **`a2ui-blueprint-navigator`**: A read-only analytical guide. It discovers blueprints and inspects codebase compliance against module blueprint git commit hashes (`module_blueprint_commit`).
- **`a2ui-create-feature-blueprint`**: Provides instructions on how to create a feature blueprint inside `blueprints/features/` without date prefixes.
- **`a2ui-implement-feature-from-blueprint`**: Provides instructions on implementing feature specs and updating codebase compliance commit hashes.
- **`a2ui-blueprint-maintenance`**: Manages merging feature specs into Module Blueprints and archiving feature blueprints to `blueprints/features/archived/`.

## **Blueprint validation**

We implement a blueprint validator script (`blueprints/validate_blueprints.py`) that verifies all blueprints conform to required schemas and naming rules. It runs on CI (`.github/workflows/validate_blueprints.yml`) to block submission of invalid blueprints.

The validation script checks:

- **Frontmatter compliance**: Verify all mandatory YAML fields are present and correctly typed.
- **Entity naming rules**: Ensure feature names and module names use snake_case and match their filenames (`feature_name.blueprint.md`).
- **Commit hash & reference integrity**: Validate that `codebase_path`, `associated_module`, optional `module_blueprint_commit`, and `implemented_features` in codebase blueprints point to valid targets.

## **Creation of initial blueprints**

- Module blueprints: We will migrate our existing guides and documentation in the blueprint formats described above. E.g. renderer_guide.md will become the module blueprints for core and framework adapter layers.
- Codebase blueprints: We will have Gemini generate these by analysing the codebases.

---

### Public Roadmap (`docs/public/roadmap.md`)

# Roadmap

This roadmap outlines the current state and future plans for the A2UI project. The project is under active development, and priorities may shift based on community feedback and emerging use cases.

## Current Status

### Protocol

| Version    | Status       | Notes                                   |
| ---------- | ------------ | --------------------------------------- |
| **v0.8**   | 🆗 Prior     | Initial public release, minimal support |
| **v0.9**   | 🆗 Prior     | Feature complete, legacy support        |
| **v0.9.1** | 🆗 Current   | stable release                          |
| **v1.0**   | 📋 Candidate | release candidate                       |

### Renderers

| Client libraries                                           | Status      | Platform             | Notes                                                               |
| ---------------------------------------------------------- | ----------- | -------------------- | ------------------------------------------------------------------- |
| **Web Core Lib**                                           | ✅ Stable   | Web                  | Shared core lib for all web renderers                               |
| **Web Components (Lit)**                                   | ✅ Stable   | Web                  | Framework-agnostic, works anywhere                                  |
| **Angular**                                                | ✅ Stable   | Web                  | Full Angular integration                                            |
| **Flutter (GenUI SDK)**                                    | ✅ Stable   | Multi-platform       | Works on mobile, web, desktop                                       |
| **React**                                                  | ✅ Stable   | Web                  | Official React renderer                                             |
| [**Lynx**](https://lynxjs.org/next/react/genui/a2ui.html)  | ✅ Stable   | Mobile, Web, Desktop | ReactLynx renderer for A2UI v0.9                                    |
| **SwiftUI**                                                | 📋 Planned  | iOS/macOS            | Planned for Q2 2026                                                 |
| **Jetpack Compose**                                        | 📋 Planned  | Android              | Planned for Q2 2026                                                 |
| **Vue**                                                    | 💡 Proposed | Web                  | Community interest                                                  |
| [**Svelte/Kit**](https://svelte.dev/docs/kit/introduction) | 💡 Proposed | Web                  | [Community interest](https://news.ycombinator.com/item?id=46287728) |
| **ShadCN (React)**                                         | 💡 Proposed | Web                  | Community interest                                                  |

### Transports

| Transport                        | Status      | Notes                      |
| -------------------------------- | ----------- | -------------------------- |
| **A2A Protocol**                 | ✅ Complete | Native A2A transport       |
| **AG-UI**                        | ✅ Complete | Day-zero compatibility     |
| **REST API**                     | ✅ Complete | Request/response over HTTP |
| **WebSockets**                   | ✅ Complete | Bidirectional WS           |
| **MCP (Model Context Protocol)** | ✅ Complete | Context sharing            |

### Agent frameworks

| Integration                      | Status         | Notes                                                                              |
| -------------------------------- | -------------- | ---------------------------------------------------------------------------------- |
| **Any agent with A2A support**   | ✅ Complete    | Day-zero compatibility thanks to A2A protocol                                      |
| **Any agent with AG-UI support** | ✅ Complete    | Day-zero compatibility thanks to AG-UI protocol                                    |
| **AG2**                          | ✅ Complete    | [A2UIAgent](https://docs.ag2.ai/latest/docs/user-guide/reference-agents/a2uiagent) |
| **ADK**                          | 🚧 In Progress | Still designing developer ergonomics, see [samples](../../samples/agent/adk)       |
| **Genkit**                       | 💡 Proposed    | Community interest                                                                 |
| **LangGraph**                    | 💡 Proposed    | Community interest                                                                 |
| **CrewAI**                       | 💡 Proposed    | Community interest                                                                 |
| **Claude Agent SDK**             | 💡 Proposed    | Community interest                                                                 |
| **OpenAI Agent SDK**             | 💡 Proposed    | Community interest                                                                 |
| **Microsoft Agent Framework**    | 💡 Proposed    | Community interest                                                                 |
| **AWS Strands Agent SDK**        | 💡 Proposed    | Community interest                                                                 |

## Recent Milestones

### Q2 2025

Many research projects across multiple Google teams, including integration into internal products and agents.

### Q4 2025 v0.8

- v0.8.0 spec released
- A2A extension (thanks Google A2A team! teased at [a2asummit.ai](https://a2asummit.ai))
- Flutter renderer (thanks Flutter team!)
- Angular renderer (thanks Angular team!)
- Web components (Lit) renderer (thanks Opal team & friends!)
- AG-UI / CopilotKit integration (thanks CopilotKit team!)
- Github public release (Apache 2.0)

### Q2 2026 v0.9

- Release spec 0.9
- Release web core and renderers to support spec 0.9
- Launch official A2UI React renderer
- Improve theming support for renderers
- Launch A2UI Agents SDK (python)
- Improve developer ergonomics

## Upcoming Milestones

### Q3 2026 v0.9 & v1.0

**Jetpack Compose Renderer (Android):**

- Native Compose UI components
- Material Design 3 support
- Android platform integration

**SwiftUI Renderer (iOS/macOS):**

- Native SwiftUI components
- iOS design language support
- macOS compatibility

**Performance Optimizations**

- Renderer performance benchmarks
- Lazy loading for large component trees
- Virtual scrolling for lists
- Component memoization strategies

### Q4 2026 v1.0

**Finalize v1.0 of the protocol with:**

- Stability guarantees
- Migration path from v0.9
- Comprehensive test suite
- Certification program for renderers

## Long-Term Vision

### Full App UIs

Configurable, Customizable UIs - facilitated by A2UI (agent optional)

- Developer tooling for A2UI at build time
- Patterns for A2UI caching, as config layer for static UI
- Designs and samples for full app composition

### Multi-Agent Coordination

Enhanced support for multiple agents contributing to the same UI:

- Recommended agent composition patterns
- Conflict resolution strategies
- Shared surface management

### Accessibility Features

First-class accessibility support:

- ARIA attribute generation
- Screen reader optimization
- Keyboard navigation standards
- Contrast and color guidance

### Advanced UI Patterns

Support for more complex UI interactions:

- Drag and drop
- Gestures and animations
- 3D rendering
- AR/VR interfaces (exploratory)

### Ecosystem Growth

- More framework integrations
- Third-party component libraries
- Agent marketplace integration
- Enterprise features and support

## How to Influence the Roadmap

We welcome community input on priorities:

1. **Submit feedback form**: Use [this anonymous form](https://forms.gle/Tj8E3dMsJ1NcvQnFA) to share your requirements and feedback
2. **Vote on Issues**: Give 👍 to GitHub issues you care about
3. **Propose Features**: Open a discussion on GitHub (search for existing discussions first)
4. **Submit PRs**: Build the features you need (search for existing PRs first)
5. **Join Discussions**: Share your use cases and requirements (search for existing discussions first)

## Planned Release Cycle

- **Major versions** (1.0, 2.0): Annual or when significant breaking changes are needed
- **Minor versions** (1.1, 1.2): Quarterly with new features
- **Patch versions** (1.1.1, 1.1.2): As needed for bug fixes

## Versioning Policy

A2UI follows [Semantic Versioning](https://semver.org/):

- **MAJOR**: Incompatible protocol changes
- **MINOR**: Backward-compatible functionality additions
- **PATCH**: Backward-compatible bug fixes

## Stay Updated

- Watch the [GitHub repository](https://github.com/a2ui-project/a2ui) for updates
- Star the repo to show your support
- Follow releases to get notified of new versions

---

**Last Updated:** June 2026

Have questions about the roadmap? [Start a discussion on GitHub](https://github.com/a2ui-project/a2ui/discussions).

---

### Public Composer Composer Renderer Integration (`docs/public/composer/composer_renderer_integration.md`)

# A2UI Composer Integration Manual

## Background

The A2UI Composer has no knowledge or integration with any particular catalog or
renderer stack. In order to see the A2UI JSON rendered, it relies on a “Renderer
Application.” The A2UI Composer hosts the Renderer Application in an iframe and
communicates with it via **postMessage**. The iframe hosting the renderer
application has `sandbox='allow-scripts allow-same-origin allow-forms'`, which
should not be a problem for simply rendering the A2UI JSON.

The Renderer Application is responsible for accepting A2UI JSON and using its
renderers to display the result.

## The Bridge

To simplify the work of integrating with the A2UI Composer, a **bridge** has
been created. This is a small amount of Javascript code that the Renderer
Application incorporates, and coordinates all the communication between the A2UI
Composer and the Renderer Application.

To further simplify the integration, different framework-specific wrappers are
provided.

## Examples

Check out the sample renderer apps:

- [Angular](https://github.com/a2ui-project/composer/tree/main/samples/ng-basic-catalog)
- [Lit](https://github.com/a2ui-project/composer/tree/main/samples/lit-basic-catalog)
- [React](https://github.com/a2ui-project/composer/tree/main/samples/react-basic-catalog)

They all serve the same version of the Basic catalog.

When running the hosted [A2UI Composer](https://a2ui-project.github.io/composer/),
you can see each of these renderer applications in action by going to the
Settings page and clicking the Renderer dropdown.

### Using Angular

As an example, we'll walk through creating a Renderer application based on
Angular.

### Add dependencies

First, add the core integration package to your project dependencies list:

```
yarn add a2ui-bridge @a2ui/web_core @a2ui/angular
```

Of course, if you’re using a different package manager, follow the appropriate
steps.

#### Create the wrapper component

Create a new component that looks like this:

```ts
import {Component, inject} from '@angular/core';
import {SurfaceComponent} from '@a2ui/angular/v0_9';
import {A2uiSandboxConnection} from 'a2ui-bridge/angular';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [SurfaceComponent],
  template: `
    <main class="sandbox-shell">
      @if (sandbox.surfaceId()) {
        <a2ui-v09-surface [surfaceId]="sandbox.surfaceId()" />
      } @else {
        <p style="padding: 24px; color: #666; font-family: sans-serif; text-align: center;">
          Waiting for RENDER_A2UI payloads...
        </p>
      }
    </main>
  `,
})
export class AppComponent {
  protected sandbox = inject(A2uiSandboxConnection);
}
```

Note that contents of the `@else` can be modified as you see fit, but the rest
of the template should remain as-is.

#### Bootstrap your renderer application

Configure the standard Angular bootstrapping entrypoint file (`src/main.ts`),
passing your catalog classes dynamically to the sandbox provider mapping:

```ts
import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {provideA2uiSandbox} from 'a2ui-bridge/angular';
import {BasicCatalog} from '@a2ui/angular/v0_9';

bootstrapApplication(AppComponent, {
  providers: [
    provideA2uiSandbox([BasicCatalog]), // Injects and exposes dynamic catalogs
  ],
}).catch((err) => console.error('A2UI Sandbox Bootstrap Failed:', err));
```

Make sure to replace `BasicCatalog` with your catalog.

> NOTE on change detection compatibility: The `provideA2uiSandbox` helper is
> 100% compatible with both standard Zone-based change detection (using `zone.js`)
> and Zoneless change detection (`provideZonelessChangeDetection()`)
> out-of-the-box.

---

### Public Concepts Actions (`docs/public/concepts/actions.md`)

# Handling User Actions

This guide explains how A2UI handles user interactions. Components use the `action` property to trigger either local **Functions** (executed on the renderer) or **Events** (dispatched to the agent). In addition, **Data Model Synchronization** ensures the agent always has access to the full UI state, enabling seamless multi-modal interactions like voice commands. This design enables highly responsive interfaces while maintaining a secure, restricted environment.

## Action Architecture

Actions allow UI components to trigger behavior defined in the [`Action`](../../../specification/v0_9/json/common_types.json#L271-L313) schema in `common_types.json`. Actions can trigger:

1.  **Events**: Dispatched to the Agent for processing (executed on Agent, e.g., clicking "Submit").
2.  **Functions**: Executed entirely on the renderer using [`FunctionCall`](../../../specification/v0_9/json/common_types.json#L200-L242) (executed on Renderer, e.g., opening a URL).

### 1. Functions (Local)

Functions execute immediate behavior on the renderer without a network round-trip. The agent is not informed of local function calls. They use the `functionCall` keyword.

```json
{
  "id": "help-btn",
  "component": "Button",
  "child": "help-text",
  "action": {
    "functionCall": {
      "call": "openUrl",
      "args": {"url": "https://a2ui.org/help"}
    }
  }
}
```

Common uses for Functions include:

- **Navigation**: Opening a URL or switching tabs.
- **Validation**: Checking inputs before submission (see Checks below).

### 2. Events (Agent)

Events send data to the agent for processing. They use the `event` keyword.

Components like `Button` expose an `action` property. Here is how an Event is wired:

```json
{
  "id": "submit-btn",
  "component": "Button",
  "child": "btn-text",
  "action": {
    "event": {
      "name": "submit_reservation",
      "context": {
        "time": {"path": "/reservationTime"},
        "size": {"path": "/partySize"}
      }
    }
  }
}
```

- **`name`**: A stable identifier for the agent to switch on.
- **`context`**: A map of key-value pairs. Values can be literal or use a `path` to pull from the current state of the data model.

NOTE: **Context vs. Data Model**: While the Data Model represents the entire state tree of a surface, the `context` in an action is effectively a hand-picked **"view"** or subset of that state. This simplifies the Agent's job by providing exactly the values needed for a specific event, without requiring the Agent to navigate a potentially large and complex data model.

### Basic Catalog Function Validation (Checks)

The basic catalog defines a limited set of checks that can be performed on the renderer. Interactive components can define a list of `checks` (using the [`Checkable`](../../../specification/v0_9/json/common_types.json#L258-L270) schema in `common_types.json`). For a `Button`, if any check fails, the button is **automatically disabled** on the renderer.

- **UX Focus**: Validation checks are designed to manage **UI State (User Experience)** by preventing invalid interactions before they happen. They are not a replacement for **Data Integrity** checks, which must still be performed on the agent.

This allows the UI to enforce requirements (like a non-empty field) before the user even tries to submit.

```json
{
  "id": "submit-button",
  "component": "Button",
  "child": "submit-text",
  "checks": [
    {
      "condition": {
        "call": "required",
        "args": {"value": {"path": "/partySize"}}
      },
      "message": "Party size is required"
    }
  ],
  "action": {"event": {"name": "submit_booking"}}
}
```

## Local State Updates & The "Write" Contract

Before an Event is even dispatched, the renderer is already managing the state of the UI locally. A2UI defines a **Read/Write Contract** for all input components (like `TextField`, `CheckBox`, or `Slider`).

1.  **Read (Model → View)**: When a component renders, it pulls its value from the bound `path` in the Data Model.
2.  **Write (View → Model)**: As soon as a user interacts (e.g., typing a character or clicking a checkbox), the renderer **immediately** writes the new value into the local Data Model.

This means the local model is **always** the source of truth for the UI's current state. This "View-to-Model" synchronization happens purely on the renderer. The data model is only sent to the agent when an event occurs (like a Button click).

IMPORTANT: **Synchronous Updates**: Local model updates are **synchronous**. This guarantees that the Data Model is fully updated before any Event resolves its `context` paths or a `DataModelSync` payload is packaged. There are no race conditions between typing and clicking; the "Write" is always committed first.

This local-first approach offers a significant **Performance Benefit**. Because synchronization is immediate and local, developers don't need to implement network debouncing or worry about latency jitters as a user types in a `TextField`. The network is completely protected from "UI noise" (like individual keystrokes) until the user is ready to dispatch a formal Event.

### The Form Submission Pattern

This separation allows for a robust form submission pattern:

- **Binding**: A `TextField` is bound to `/reservationTime`.
- **Interaction**: The user types "7:00 PM". The local model at `/reservationTime` is updated instantly.
- **Submission**: The user clicks a "Book" button. The button's Event resolves the `path: "/reservationTime"` from the local model and sends the current value to the agent.

## User Interaction Flow

When a user interacts with a component (e.g., clicks a button):

1.  **Resolve**: The renderer resolves all `path` references in the `context` against the local **Data Model**.
2.  **Construct**: The renderer builds an `action` payload conforming to [`client_to_server.json`](../../../specification/v0_9/json/client_to_server.json).
3.  **Dispatch**: The payload is sent via the chosen transport (e.g., A2A, WebSockets).

### Example: The Action Payload (v0.9)

If a user clicks the button above with a data model containing `{"reservationTime": "7:00 PM", "partySize": 4}`, the renderer sends a message using the `action` key:

```json
{
  "version": "v0.9",
  "action": {
    "name": "submit_reservation",
    "surfaceId": "booking-surface",
    "sourceComponentId": "submit-btn",
    "timestamp": "2026-02-25T10:40:00Z",
    "context": {
      "time": "7:00 PM",
      "size": 4
    }
  }
}
```

IMPORTANT: **A Note on Versioning (v0.8 vs v0.9)**: In v0.8, the top-level payload key was `userAction` (e.g., `{"userAction": {...}}`). v0.9 transitioned to the simpler `action` key shown above. Standard protocol parsers expect the key corresponding to the version declared in the payload.

## Agent Processing

The Agent (or an Orchestrator) receives this event and acts on it. In an agentic system, the agent usually converts the event into a hidden user query for the LLM.

**Example Agent Processing (Python):**

```python
if action_name == "submit_reservation":
    time = context.get("time")
    size = context.get("size")
    # Feed this to the LLM
    query = f"User submitted a reservation for {size} people at {time}."
    response = await llm.generate(query)
```

## Renderer-to-Agent Error Reporting

In addition to Events triggered by the user, the renderer can report system-level errors back to the agent using the `error` payload defined in [`client_to_server.json`](../../../specification/v0_9/json/client_to_server.json).

### Validation Failures

If the agent sends A2UI JSON that violates the catalog schema or protocol rules, the renderer sends a `VALIDATION_FAILED` error. This is a critical feedback loop for agentic systems:

```json
{
  "version": "v0.9",
  "error": {
    "code": "VALIDATION_FAILED",
    "surfaceId": "booking-surface",
    "path": "/components/0/children",
    "message": "Expected array of strings, got null."
  }
}
```

The agent can catch this error, apologize (or self-correct internally), and re-send the corrected UI.

## Data Model Sync (v0.9)

A2UI v0.9 introduced a powerful "stateless" synchronization feature. This allows the renderer to automatically include the **entire data model** of a surface in the metadata of every message it sends to the agent.

### Enabling Sync

Synchronization is requested by the agent during surface initialization. By setting `sendDataModel: true` in the `createSurface` message, the agent instructs the renderer to start the sync loop.

```json
{
  "version": "v0.9",
  "createSurface": {
    "surfaceId": "booking-surface",
    "catalogId": "https://a2ui.org/catalogs/v1/basic.json",
    "sendDataModel": true
  }
}
```

### Sync on the Wire

When sync is enabled, the renderer does not send the data model as a separate message. Instead, it attaches it as **metadata** to the outgoing transport envelope (e.g., an A2A message).

In an A2A (Agent-to-Agent) binding, the data model is placed in an `a2uiClientDataModel` object within the envelope's `metadata` field.

**Example A2A Envelope with Sync:**

```json
{
  "parts": [{"text": "Submit the reservation"}],
  "metadata": {
    "a2uiClientDataModel": {
      "version": "v0.9",
      "surfaces": {
        "booking-surface": {
          "reservationTime": "7:00 PM",
          "partySize": 4,
          "notes": "Window seat preferred"
        }
      }
    }
  }
}
```

### Why use Data Model Sync?

- **Simpler Wiring**: You don't need to manually map every input field into a button's `context` property. The agent can simply inspect the metadata to see the current state of all fields.
- **Stateless Agents**: The agent doesn't need to maintain local state for every user session; it receives the full current context with every single interaction.
- **Verbal Shortcuts**: Allows the user to trigger Events via voice or text (e.g., "okay submit") even without clicking a specific button. Since the agent receives the updated data model with the text message, it can process the request immediately.

## Renderer Metadata & Capabilities

Before an agent can safely send a UI, the renderer must advertise which component catalogs it supports. This is handled via the `a2uiClientCapabilities` object.

### Advertising Capabilities

Renderers include an `a2uiClientCapabilities` object in the **metadata** of their messages to the agent (e.g., in the `metadata` field of an A2A `Message`).

```json
{
  "v0.9": {
    "supportedCatalogIds": [
      "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
      "https://my-company.com/catalogs/v1/custom.json"
    ],
    "inlineCatalogs": []
  }
}
```

- **`supportedCatalogIds`**: An array of catalog URIs the renderer can render.
- **`inlineCatalogs`**: (Optional) For development or specialized environments, allows sending the full catalog schema inline.

Without this handshake, an agent cannot be certain that the renderer can handle the specific components being sent.

## Transport & Encoding

A2UI is transport-agnostic, but it is most commonly used over **A2A (Agent-to-Agent)** or WebSockets. Understanding how the payload is wrapped is crucial for implementation.

### A2A Encoding

In the standard A2A binding, A2UI messages are encoded as an A2A **DataPart**. To identify it as an A2UI payload, the part must be wrapped with specific metadata:

- **mimeType**: `application/a2ui+json`

The `data` field of the `DataPart` contains a **list** of A2UI messages. This allows multiple updates (e.g., `createSurface` followed by `updateComponents`) to be sent in a single network packet.

NOTE: **A2A Versioning**: The use of a **list** in the `data` field was introduced in **A2A v1.0**. Earlier versions of the A2A protocol expect the `data` field to contain a single JSON object.

```json
{
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  },
  "data": [
    {
      "version": "v0.9",
      "action": { ... }
    }
  ]
}
```

## Security Considerations

A2UI is designed with secure, sandboxed communication as a core principle. Because the protocol relies on passing user state and interaction triggers over the network, it enforces strict boundaries on data visibility and execution.

### Sandboxed Execution

A core selling point of A2UI is security through restriction. By prohibiting arbitrary code execution (like injecting raw JavaScript) from the agent, A2UI ensures that agents can only trigger pre-registered behaviors. The `functionCall` mechanism acts as a safe, sandboxed way for the agent to interact with the renderer's environment without exposing the user to malicious scripts.

### Data Model Isolation and Orchestrator Routing

When `sendDataModel: true` is enabled, the renderer includes the surface's entire data model in outgoing messages. Developers must understand the visibility of this data:

- **Point-to-Point Visibility**: Only the backend receiving the transport envelope (the Agent that created the surface, or an intermediate Orchestrator) can read this payload.
- **The Orchestrator's Responsibility**: In a multi-agent architecture, a central Orchestrator often routes user intents to specialized sub-agents. The Orchestrator must enforce **data isolation**. It is responsible for parsing the `a2uiClientDataModel`, identifying the `surfaceId`, and ensuring that the data model is only passed to the specific sub-agent that owns that surface. Data from one agent's surface must never leak to another agent.

## Orchestration & Routing

In multi-agent systems, a central **Orchestrator** often manages interactions between a user and several specialized sub-agents. A key challenge is ensuring that `action` messages from the renderer are routed back to the specific sub-agent that generated the UI surface.

### The Surface Ownership Pattern

To handle routing in a multi-agent architecture, an orchestrator must maintain a mapping of each `surfaceId` to its owning sub-agent. The official Python SDK provides the [`A2uiSubagentMap`](../../../python/a2ui_adk/src/a2ui/adk/orchestration/a2ui_subagent_map.py) utility to manage this mapping safely.

For a complete working example, see the [orchestrator agent executor](../../../samples/community/agent/adk/orchestrator/orchestrator_agent_executor.py) sample.

#### 1. Mapping Ownership from Server Events

When a sub-agent emits an A2UI `createSurface` or `deleteSurface` the orchestrator intercepts the message and records the ownership in the session state using `update_from_server_event`.

```python
from a2ui.adk import A2uiSubagentMap, SurfaceIdAlreadyExistsError
from google.adk.a2a.executor.a2a_agent_executor import A2aAgentExecutorConfig
from google.adk.a2a.executor.config import ExecuteInterceptor
from google.adk.a2a.events import Event as A2AEvent
from google.adk.events.event import Event
from google.adk.sessions import SessionService, Session

async def after_event_save_surface_id(a2a_event: A2AEvent, event: Event, session_service: SessionService, session: Session):
    for a2a_part in a2a_event.status.message.parts:
        try:
            await A2uiSubagentMap.update_from_server_event(
                a2a_part,
                event.author,
                session_service,
                session
            )
        except SurfaceIdAlreadyExistsError as e:
            # Handle surface ID collision
            pass
    return a2a_event

config = A2aAgentExecutorConfig(
    execute_interceptors=[
        ExecuteInterceptor(after_event=after_event_save_surface_id)
    ]
)
```

#### 2. Routing Client Events

When the client renderer sends an A2UI `action` or `error` message back, the orchestrator looks up the `surfaceId` in the session state using `get_subagent_name_for_client_event` and routes the request to the correct sub-agent.

```python
from a2ui.adk import A2uiSubagentMap
from google.adk.agents.llm_agent import LlmAgent
from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_request import LlmRequest
from google.adk.models.llm_response import LlmResponse
from google.genai import types as genai_types
from google.adk.agents.remote_a2a_agent import convert_genai_part_to_a2a_part

async def route_client_event(callback_context: CallbackContext, llm_request: LlmRequest):
    a2a_part = convert_genai_part_to_a2a_part(llm_request.contents[-1].parts[-1]) # Assume response has a single a2a part

    target_agent = await A2uiSubagentMap.get_subagent_name_for_client_event(
        a2a_part,
        callback_context.state
    )

    if target_agent:
        # Programmatically trigger the planner's transfer_to_agent function
        return LlmResponse(
            content=genai_types.Content(
                parts=[
                    genai_types.Part(
                        function_call=genai_types.FunctionCall(
                            name="transfer_to_agent",
                            args={"agent_name": target_agent},
                        )
                    )
                ]
            )
        )

orchestrator_agent = LlmAgent(
    name="orchestrator",
    before_model_callback=route_client_event,
    # other configs ...
)
```

This pattern ensures that the bidirectional communication loop remains intact and stateful for each feature area.

### Preventing Data Leakage via Metadata Stripping

In a multi-agent environment, the `a2uiClientDataModel` object can contain the state for multiple surfaces owned by different sub-agents. To prevent sensitive data leakage, an orchestrator must **strip** the data model metadata to include only the surfaces owned by the target sub-agent.

You can use the `strip_unowned_surfaces_from_data_model` method in an outbound interceptor to mutate the data model dictionary in place.

```python
from a2ui.adk import A2uiSubagentMap
from a2a.client.middleware import ClientCallInterceptor, ClientCallContext
from a2a.types import AgentCard

class A2UIMetadataInterceptor(ClientCallInterceptor):
    async def intercept(self, request_payload: dict, agent_card: AgentCard, context: ClientCallContext):
        message = request_payload.get("params", {}).get("message")

        # Strip the data model to prevent data leakage
        if data_model := message.get("metadata", {}).get("a2uiClientDataModel"):
            await A2uiSubagentMap.strip_unowned_surfaces_from_data_model(
                agent_card.name,
                data_model,
                context.state,
            )

        return request_payload
```

By stripping the metadata, the orchestrator ensures that each sub-agent receives only the portion of the data model that it is authorized to see.

WARNING: **Security Risk - State Scraping**: If an orchestrator fails to strip the `a2uiClientDataModel`, a malicious or compromised sub-agent could read the state of other active surfaces. For example, a weather sub-agent could scrape sensitive data from a banking surface if the orchestrator leaks the entire multi-surface data model. Stripping is a mandatory security requirement for multi-agent systems.

---

## Comprehensive Examples

### 1. Button Submit (Explicit Context)

This example shows a button that explicitly gathers the data it needs to send.

**Component Definition:**

```json
{
  "id": "submit-button",
  "component": "Button",
  "child": "submit-text",
  "action": {
    "event": {
      "name": "submit_booking",
      "context": {
        "partySize": {"path": "/partySize"},
        "reservationTime": {"path": "/reservationTime"}
      }
    }
  }
}
```

**Resulting Action Payload:**
The agent receives an `action` object with the `partySize` and `reservationTime` directly in the `context` field.

### 2. Verbal Submit (Data Model Sync)

In this scenario, the user doesn't click a button. Instead, they say "Okay, submit the form."

**Initialization:**
The agent created the surface with `sendDataModel: true`:

```json
{
  "version": "v0.9",
  "createSurface": {
    "surfaceId": "booking-surface",
    "catalogId": "...",
    "sendDataModel": true
  }
}
```

**Renderer Transmission:**
The renderer sends an A2A message containing the user's text and the data model in the metadata:

```json
{
  "parts": [{"text": "Okay, submit the form"}],
  "metadata": {
    "a2uiClientDataModel": {
      "version": "v0.9",
      "surfaces": {
        "booking-surface": {
          "partySize": 4,
          "reservationTime": "7:00 PM"
        }
      }
    }
  }
}
```

**Agent Processing:**
The agent sees the user's intent ("submit") and looks at the `metadata` to find the current values of `partySize` and `reservationTime`, allowing it to complete the task without further clarification.

---

### Public Concepts Catalogs (`docs/public/concepts/catalogs.md`)

# A2UI Catalogs

## Overview

This guide defines the A2UI Catalog architecture and provides a roadmap for implementation. It explains the structure of catalog schemas, outlines strategies for using the pre-built "Basic Catalog” versus defining your own application-specific catalog, and details the technical protocols for catalog negotiation, versioning, and runtime validation.

## Catalog Schema

A catalog schema is a [JSON Schema file](../../../specification/v0_9/json/client_capabilities.json#L62C5-L95C6) outlining the components, functions, and themes that agents can use to define A2UI surfaces using server-driven UI. All A2UI JSON sent from the agent is validated against the chosen catalog.

[Catalog JSON Schema](../../../specification/v0_9/json/client_capabilities.json#L62C5-L95C6) is below

```json
{
  "Catalog": {
    "type": "object",
    "description": "A collection of component and function definitions.",
    "properties": {
      "catalogId": {
        "type": "string",
        "description": "Unique identifier for this catalog."
      },
      "components": {
        "type": "object",
        "description": "Definitions for UI components supported by this catalog.",
        "additionalProperties": {
          "$ref": "https://json-schema.org/draft/2020-12/schema"
        }
      },
      "functions": {
        "type": "array",
        "description": "Definitions for functions supported by this catalog.",
        "items": {
          "$ref": "#/$defs/FunctionDefinition"
        }
      },
      "theme": {
        "title": "A2UI Theme",
        "description": "A schema that defines a catalog of A2UI theme properties.",
        "type": "object",
        "additionalProperties": {
          "$ref": "https://json-schema.org/draft/2020-12/schema"
        }
      }
    },
    "required": ["catalogId"],
    "additionalProperties": false
  }
}
```

## Catalog Strategy

Every A2UI surface is driven by a Catalog. A catalog is simply a JSON Schema file that tells the agent which components, functions, and themes are available for it to use.

Whether you are building a simple prototype or a complex production application, the requirement is the same: you must provide a catalog definition that the agent uses to express UI.

### The Basic Catalog

To help developers get started quickly, the A2UI team maintains the [Basic Catalog](../../../specification/v0_9/catalogs/basic/catalog.json).

This is a pre-defined catalog file that contains a basic set of general-purpose components (Buttons, Inputs, Cards) and functions. It is not a special "type" of catalog; it is simply a version of a catalog that we have already written and have open source renderers for.

The basic catalog allows you to bootstrap an application or validate A2UI concepts without needing to write your own schema from scratch. It is intentionally sparse to remain easily implementable by different renderers.

Since A2UI is designed for LLMs to generate the UI at either design time or runtime, we do not think portability requires a standardized catalog across multiple clients; the LLM can interpret the catalog for each individual frontend.

[See the A2UI v0.9 basic catalog](../../../specification/v0_9/catalogs/basic/catalog.json)

### Defining Your Own Catalog

While the Basic Catalog is useful for starting out, most production applications will define their own catalog to reflect their specific design system.

By defining your own catalog, you restrict the agent to using exactly the components and visual language that exist in your application, rather than generic inputs or buttons. This catalog can be built entirely from scratch, or it can import definitions from the Basic Catalog to save time (e.g., using the Basic text definitions while defining your own unique Card component).

For simplicity we recommend building catalogs that directly reflect a client's design system rather than trying to map the Basic Catalog to it through an adapter. Since A2UI is designed for GenUI, we expect the LLM can interpret different catalogs for different clients.

[See an example Rizzcharts catalog](../../../samples/community/agent/adk/rizzcharts/catalog_schemas/0.9/rizzcharts_catalog_definition.json)

### Recommendations

| Usecase                             | Recommendation                                                                 | Effort                         |
| :---------------------------------- | :----------------------------------------------------------------------------- | :----------------------------- |
| Adding A2UI to a mature frontend    | Define a catalog that mirrors your existing design system.                     | Medium                         |
| Adding A2UI to a new/greenfield app | Start with Basic Catalog, then evolve into your own catalog as the app evolves | Low (assuming renderer exists) |

## Building a Catalog

A catalog is a JSON Schema file that conforms to the [Catalog schema](../../../specification/v0_9/json/client_capabilities.json#L62C5-L95C6) that defines the components, themes and functions an agent can use when building a surface.

### Example: A Minimal Catalog

Here is a simple catalog defining a single component.

```json
{
  "$id": "https://github.com/.../hello_world/v1/catalog.json",
  "catalogId": "https://github.com/.../hello_world/v1/catalog.json",
  "components": {
    "HelloWorldBanner": {
      "type": "object",
      "description": "A simple banner greeting.",
      "properties": {
        "message": {
          "type": "string",
          "description": "The banner text."
        },
        "backgroundColor": {
          "type": "string",
          "default": "#f0f0f0"
        }
      },
      "required": ["message"]
    }
  }
}
```

When the agent uses that catalog, it generates a payload strictly conforming to that structure:

```json
[
  {
    "version": "v0.9",
    "createSurface": {
      "surfaceId": "hello-world-surface",
      "catalogId": "https://github.com/.../hello_world/v1/catalog.json"
    }
  },
  {
    "version": "v0.9",
    "updateComponents": {
      "surfaceId": "hello-world-surface",
      "components": [
        {
          "id": "root",
          "component": "HelloWorldBanner",
          "message": "Hello, world! Welcome to your first catalog.",
          "backgroundColor": "#4CAF50"
        }
      ]
    }
  }
]
```

### Catalog Linking

A catalog's only external references are to the protocol's `common_types.json` and to **peer catalogs**: other catalogs that the agent or renderer already holds locally, because they are registered with it or supplied together with the referencing catalog. Peer catalogs are never fetched over the network.

A reference into a peer has the form `<peer document>#/components/<Name>` (a whole component, usually inherited with `allOf`), `<peer document>#/components/<Name>/properties/<property>` (one property's schema) or `<peer document>#/functions/<Name>/...`. `<peer document>` is the peer's `catalogId` or `$id`, or a path or file name that ends one of them:

```json
{
  "catalogId": "https://example.com/catalogs/branded/v1/catalog.json",
  "components": {
    "BrandedText": {
      "type": "object",
      "allOf": [
        {"$ref": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json#/components/Text"}
      ],
      "properties": {
        "component": {"const": "BrandedText"},
        "badge": {"$ref": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json#/components/Text/properties/text"}
      },
      "required": ["component", "badge"]
    }
  }
}
```

The SDKs resolve such references at runtime against the other catalogs you register or pass in (`linkCatalogs` / `link_catalogs`, `withPeerCatalogs` / `with_peer_catalogs`; the agent SDKs and `MessageProcessor` link the catalogs they are given). Peers are matched in this order, and the first match wins:

1. `common_types.json` always means the protocol's common types, and a document named exactly `catalog.json` means the referencing catalog itself.
2. A peer whose `catalogId` or `$id` equals the document or ends with it as a path suffix.
3. A path ending in `/catalog.json` that no peer matched in step 2 means the referencing catalog itself.
4. A peer whose `$id` or `catalogId` has the same file name as the document. Only `catalog.json` itself is generic, so `mcp_catalog.json` matches a peer by file name.

A reference that matches no peer is a catalog error. Prefer full `$id`s, which always match exactly one peer. See [Cross-Catalog References](../../../specification/v1_0/docs/a2ui_protocol.md#cross-catalog-references) in the v1.0 specification for the normative rules.

You can also bundle external references into a freestanding catalog at build time. This catalog registration process, also called **"Linking"**, is consolidated under a single, multi-platform Node.js script (**`register-catalogs.js`**).

This linking script is natively wrapped inside **Xcode Build Phases** (for iOS/macOS client builds) and **Gradle tasks** (for Android client builds) to compile, aggregate, and link static and dynamic schemas seamlessly during your application's build phase. Renderers that don't resolve peer catalogs at runtime need bundled catalogs.

### Composition & Imports

You do not have to define everything from scratch. You can define a catalog which uses existing components from the basic or other catalogs, and one that reusing the existing rendering logic.

#### Example: Extending the Basic Catalog

This catalog imports all elements from the Basic Catalog and adds a new `SuggestionChips` component.

```json
{
  "$id": "https://github.com/.../hello_world_with_all_basic/v1/catalog.json",
  "catalogId": "https://github.com/.../hello_world_with_all_basic/v1/catalog.json",
  "components": {
    "allOf": [
      {"$ref": "basic_catalog_definition.json#/components"},
      {
        "SuggestionChips": {
          "type": "object",
          "description": "A list of suggested prompts",
          "properties": {
            "suggestions": {
              "type": "array",
              "description": "The suggested prompts."
            }
          },
          "required": ["suggestions"]
        }
      }
    ]
  }
}
```

**Make sure to link and resolve external references during compilation using your platform's Xcode Build Phase or Gradle task (running `register-catalogs.js`).**

#### Example: Cherry-picking Components

This catalog imports only `Text` from the Basic Catalog to build a simple Popup surface.

```json
{
  "$id": "https://github.com/.../hello_world_with_some_basic/v1/catalog.json",
  "catalogId": "https://github.com/.../hello_world_with_some_basic/v1/catalog.json",
  "components": {
    "allOf": [
      {"$ref": "catalogs/basic/catalog.json#/components/Text"},
      {
        "Popup": {
          "type": "object",
          "description": "A modal overlay that displays an icon and text.",
          "properties": {
            "text": {"$ref": "common_types.json#/$defs/ComponentId"}
          },
          "required": ["text"]
        }
      }
    ]
  }
}
```

**Make sure to link and resolve external references during compilation using your platform's Xcode Build Phase or Gradle task (running `register-catalogs.js`).**

### Implementing Renderers

Client renderers implement the catalog by mapping the schema definition to actual code.

First, define the component API in TypeScript matching your catalog schema:

```typescript
// api.ts
import {ComponentApi} from '@a2ui/web_core/v0_9';
import {z} from 'zod';

export const HelloWorldBannerApi = {
  name: 'HelloWorldBanner',
  schema: z.object({
    message: z.string(),
    backgroundColor: z.string().default('#f0f0f0'),
  }).strict(),
} satisfies ComponentApi;
```

Next, implement the component extending `CatalogComponent`:

```typescript
// hello_world_banner.ts
import {CatalogComponent} from '@a2ui/angular/v0_9';
import {Component, computed} from '@angular/core';
import {HelloWorldBannerApi} from './api';

@Component({
  selector: 'hello-world-banner',
  template: `
    <div [style.background-color]="backgroundColor()">
      <h2>Hello World Banner</h2>
      <p>{{ message() }}</p>
    </div>
  `,
})
export class HelloWorldBanner extends CatalogComponent<typeof HelloWorldBannerApi> {
  protected readonly message = computed(() => this.props()['message']?.value() || '');
  protected readonly backgroundColor = computed(() => this.props()['backgroundColor']?.value() || '#f0f0f0');
}
```

Finally, register your custom components in an `AngularCatalog`:

```typescript
// catalog.ts
import {AngularCatalog, BASIC_COMPONENTS, BASIC_FUNCTIONS} from '@a2ui/angular/v0_9';
import {HelloWorldBanner} from './hello_world_banner';
import {HelloWorldBannerApi} from './api';

const customBannerComponent = {
  ...HelloWorldBannerApi,
  component: HelloWorldBanner
};

export const MY_CATALOG = new AngularCatalog(
  'https://github.com/.../hello_world/v1/catalog.json',
  [...BASIC_COMPONENTS, customBannerComponent],
  BASIC_FUNCTIONS
);
```

You can see a working example of a client renderer in the [Orchestrator demo](../../../samples/community/client/angular/projects/orchestrator/src/a2ui-catalog/catalog.ts).

> [!NOTE]
> The Orchestrator demo currently uses v0.8 APIs. For a v0.9 example of catalog registration, see the [DemoCatalog](../../../typescript/renderers/angular/a2ui_explorer/src/app/demo-catalog.ts) in the Angular explorer.
>
> Additionally, for client-side functions, the client determines the function's execution boundary (such as `clientOnly` status) at runtime by reading its configuration from the active catalog definition.

## A2UI Catalog Negotiation

Because clients and agents can support multiple catalogs, they must agree on which catalog to use through a catalog negotiation handshake.

### Step 1: Agent advertises its support catalogs (optional)

The agent may optionally advertise which catalogs it is capable of speaking (e.g., in the A2A Agent Card). This is informational; it helps the client know if the agent supports their specific features, but the client doesn’t have to use it.

Example of an A2A AgentCard advertising that the agent supports the basic and rizzcharts catalogs

```json
{
  "name": "Ecommerce Dashboard Agent",
  "description": "This agent visualizes ecommerce data...",
  "capabilities": {
    "extensions": [
      {
        "uri": "https://a2ui.org/a2a-extension/a2ui/v0.8",
        "description": "Provides agent driven UI using the A2UI JSON format.",
        "params": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
            "https://github.com/.../rizzcharts_catalog_definition.json"
          ]
        }
      }
    ]
  }
}
```

### Step 2: Client advertises its support catalogs (required)

The client sends a list of supportedCatalogIds to the Agent, ordered by preference, in the metadata of every message. This tells the agent exactly what the client is prepared to render right now.

Example of A2A message containing the supportedCatalogIds in metadata

```json
{
  "parts": [
    {
      "text": "What is the current status of my flight?"
    }
  ],
  "metadata": {
    "a2uiClientCapabilities": {
      "supportedCatalogIds": [
        "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
        "https://github.com/.../rizzcharts_catalog_definition.json"
      ]
    }
  }
}
```

### Step 3: Agent Selection

When the agent creates a new surface, it selects the best match from the client's `supportedCatalogIds` list. This choice is locked for the lifetime of that surface. If no compatible catalog is found, the agent will not send a UI.

Example A2UI Message from the agent defining the catalog_id used in a surface

```json
{
  "createSurface": {
    "surfaceId": "salesDashboard",
    "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
  }
}
```

## Catalog Naming & Versioning

A2UI component catalogs require versioning because catalog definitions are often built in at compile time, so any mismatch between what an agent generates and what a client can render can affect the UI.

### CatalogId Naming Convention

The `catalogId` is a unique text identifier used for negotiation between the client and the agent.

- **Format:** While the `catalogId` is technically a string, the A2UI convention is to use a **URI** (e.g., `https://example.com/catalogs/mysurface/v1/catalog.json`).
- **Purpose:** We use URIs to make the ID globally unique and easy for human developers to inspect in a browser.
- **No Runtime Fetching:** This URI does not imply that the agent or client downloads the catalog at runtime. **The catalog definition must be known to the agent and client beforehand (at compile/deploy time)**. The URI serves only as a stable identifier.
- **JSON Schema Compatibility (`$id` and `catalogId`):** Because A2UI catalogs are currently represented as JSON Schema documents, catalog definitions should include both `$id` (for JSON Schema tooling) and `catalogId` (for A2UI SDKs and catalog negotiation), setting both fields to the same URI.

### Versioning Guidelines

Catalogs should be treated like APIs where version skew between agents and renderers is expected. Catalogs must maintain forward and backward compatibility across versions so that agents, renderers, and templates can evolve without breaking active sessions or stored transcripts.

#### Catalog Schema Evolution Rules

To maintain backward and forward compatibility, the following rules apply:

1. **Additive Only**: It's safe to add new components, functions, or optional properties.
2. **Deprecate Rather than Delete**: Never delete existing components, functions, or properties. Mark them `deprecated: true` along with an `x-deprecated-reason` instead. Renderers should retain handling logic for deprecated components and properties to maintain backward compatibility for historical transcripts, cached states, and templates.
3. **Type Invariance**: Renderers may ignore fields that change the type of existing fields. Catalogs should avoid changing the data type of an existing field. Note that add enum to a string doesn't change the type and won't break anything since enums are expected to be open.
4. **Open Enums**: Treat enum definitions as open so older renderers do not fail when new enum variants are introduced upstream. Catalogs declare enums normally, just the renderer implementation should handle unknown enum variants.
5. **Graceful Degradation**: Renderers should provide a graceful fallback for unknown components instead of failing the entire view hierarchy or surface.
6. **Round-Trip Unknown Component/Field Preservation**: Intermediary services such as orchestrators should preserve unknown properties when serializing/deserializing messages.
7. **Major Version Bumps**: Reserve major catalog version bumps strictly for sweeping cleanups (e.g., removing long-deprecated fields) or fundamentally breaking structural changes.

#### Deprecating Catalog Properties

When deprecating an existing component, function, or property:

- **`deprecated`** (boolean, optional): Standard JSON Schema annotation indicating that a component, function, or property is deprecated.
- **`x-deprecated-reason`** (string, optional): Human-readable explanation of why the entity is deprecated and what to use instead.

```json
{
  "TextBox": {
    "type": "object",
    "properties": {
      "color": {
        "type": "string",
        "description": "Icon color specification.",
        "deprecated": true,
        "x-deprecated-reason": "Use style property to set color using CSS."
      },
      "style": {
        "type": "string",
        "description": "CSS properties such as color."
      }
    }
  }
}
```

### Major Version Bumps with CatalogId

When introducing fundamentally breaking changes that necessitate a major version bump, include the version in the `catalogId` URI. This allows using A2UI catalog negotiation to support multiple versions simultaneously during a migration, ensuring zero downtime.

**Recommended Pattern:**

| Change Type  | URI Example                    | Description                                                   |
| :----------- | :----------------------------- | :------------------------------------------------------------ |
| **Current**  | .../rizzcharts/v1/catalog.json | Version 1.x. Supports all additive updates in the 1.x branch. |
| **Breaking** | .../rizzcharts/v2/catalog.json | A new schema introducing breaking structural changes.         |

### Handling Migrations

To upgrade a catalog across major versions without breaking active agents, use A2UI Catalog Negotiation:

1. **Client Update:** The client updates its list of `supportedCatalogIds` to include _both_ the old and new versions (e.g., `[".../v2/...", ".../v1/..."]`).
2. **Agent Update:** Agents are rebuilt with the v2 schema. When they see the client supports v2, they prefer it.
3. **Legacy Support:** Older agents that have not yet been rebuilt will continue to match against v1 in the client's list, ensuring they remain functional.

## A2UI Schema Validation & Fallback

To ensure a stable user experience, A2UI employs a two-phase validation strategy. This "defense in depth" approach catches errors as early as possible while ensuring clients remain robust when facing unexpected payloads.

### Two-Phase Validation

1. **Agent-Side (Pre-Send):** Before transmitting any UI payload, the agent runtime validates the generated JSON against the catalog definition.
    - Purpose: To catch hallucinated properties or malformed structures at the source.
    - Outcome: If validation fails, the agent can attempt to fix or regenerate the A2UI JSON, or it can do graceful degradation such as falling back to text in a conversational app.
2. **Client-Side:** Upon receiving the payload, the client library validates the JSON against its local definition of the catalog.
    - Purpose: Security and stability. This ensures that the code executing on the user's device strictly conforms to the expected contract, protecting against version mismatches or compromised agent outputs.
    - Outcome: Failures here are reported back to the agent using the “error” client message

### Graceful Degradation

Even if a payload passes schema validation, the renderer may encounter runtime issues (e.g., a missing asset, a component implementation not yet loaded, or a platform-specific limitation).

Clients should not crash when encountering these errors. Instead, they should employ Graceful Degradation:

- **Unknown Components:** If a component is recognized in the schema but not implemented in the renderer, render a "safe" fallback (e.g., a generic card with the component's debug name) or skip rendering that specific node entirely.
- **Text Fallback:** If the entire surface fails to render, display the raw text description (if available) or a generic error message: _"This interface could not be displayed."_

### Client-to-Server Error Reporting

When the client detects a validation error or a runtime failure, it can report this back to the agent. This allows the agent system to log the failure for developers or adjust its future behavior.

The client sends a `VALIDATION_FAILED` event using the standard A2UI Client-to-Server Event Schema.

Example of client reporting a missing required field

```json
{
  "version": "v0.9",
  "error": {
    "code": "VALIDATION_FAILED",
    "surfaceId": "flight-status-card-123",
    "path": "/components/FlightCard/flightNumber",
    "message": "Missing required property 'flightNumber' in component 'FlightCard'."
  }
}
```

## Inline Catalogs

Inline catalogs sent by the client at runtime are supported but not recommended in production. More details about them can be found [here](../../../specification/v0_9/docs/a2ui_protocol.md#client-capabilities--metadata).

---

### Public Concepts Components (`docs/public/concepts/components.md`)

# Components & Structure

A2UI uses an **adjacency list model** for component hierarchies. Instead of nested JSON trees, components are a flat list with ID references.

## Why Flat Lists?

**Traditional nested approach:**

- LLM must generate perfect nesting in one pass
- Hard to update deeply nested components
- Difficult to stream incrementally

**A2UI adjacency list:**

- Flat structure, easy for LLMs to generate.
- Send components incrementally.
- Update any component by ID.
- Clear separation of structure and data.

## The Adjacency List Model

=== "v0.8"

    ```json
    {
      "surfaceUpdate": {
        "components": [
          {
            "id": "root",
            "component": {
              "Column": {
                "children": { "explicitList": ["greeting", "buttons"] }
              }
            }
          },
          {
            "id": "greeting",
            "component": {
              "Text": { "text": { "literalString": "Hello" } }
            }
          },
          {
            "id": "buttons",
            "component": {
              "Row": {
                "children": { "explicitList": ["cancel-btn", "ok-btn"] }
              }
            }
          },
          {
            "id": "cancel-btn",
            "component": {
              "Button": {
                "child": "cancel-text",
                "action": { "name": "cancel" }
              }
            }
          },
          {
            "id": "cancel-text",
            "component": {
              "Text": { "text": { "literalString": "Cancel" } }
            }
          },
          {
            "id": "ok-btn",
            "component": {
              "Button": {
                "child": "ok-text",
                "action": { "name": "ok" }
              }
            }
          },
          {
            "id": "ok-text",
            "component": {
              "Text": { "text": { "literalString": "OK" } }
            }
          }
        ]
      }
    }
    ```

=== "v0.9 and later"

    ```json
    {
      "version": "v0.9.1",
      "updateComponents": {
        "surfaceId": "main",
        "components": [
          {
            "id": "root",
            "component": "Column",
            "children": ["greeting", "buttons"]
          },
          {
            "id": "greeting",
            "component": "Text",
            "text": "Hello"
          },
          {
            "id": "buttons",
            "component": "Row",
            "children": ["cancel-btn", "ok-btn"]
          },
          {
            "id": "cancel-btn",
            "component": "Button",
            "child": "cancel-text",
            "action": { "event": { "name": "cancel" } }
          },
          {
            "id": "cancel-text",
            "component": "Text",
            "text": "Cancel"
          },
          {
            "id": "ok-btn",
            "component": "Button",
            "child": "ok-text",
            "action": { "event": { "name": "ok" } }
          },
          {
            "id": "ok-text",
            "component": "Text",
            "text": "OK"
          }
        ]
      }
    }
    ```

    v0.9 and later use a flatter component format: `"component": "Text"` instead of nested `{"Text": {...}}`, and children are simple arrays instead of `{"explicitList": [...]}`.

Components reference children by ID, not by nesting.

## Component Basics

Every component has:

1. **ID**: Unique identifier (`"welcome"`)
2. **Type**: Component type (`Text`, `Button`, `Card`)
3. **Properties**: Configuration specific to that type

=== "v0.8"

    ```json
    {
      "id": "welcome",
      "component": {
        "Text": {
          "text": { "literalString": "Hello" },
          "usageHint": "h1"
        }
      }
    }
    ```

=== "v0.9 and later"

    ```json
    {
      "id": "welcome",
      "component": "Text",
      "text": "Hello",
      "variant": "h1"
    }
    ```

## The Basic Catalog

To help developers get started quickly, the A2UI team maintains the [Basic Catalog](../../../specification/v0_9_1/catalogs/basic/catalog.json).

This is a pre-defined catalog file that contains a basic set of general-purpose components (Buttons, Inputs, Cards). It is not a special "type" of catalog; it is simply a version of a catalog that has open source renderers available.

For the complete component gallery with examples, see [Component Reference](../reference/components.md).

## Static vs. Dynamic Children

=== "v0.8"

    **Static (`explicitList`)** - Fixed list of child IDs:

    ```json
    {
      "children": {
        "explicitList": ["back-btn", "title", "menu-btn"]
      }
    }
    ```

    **Dynamic (`template`)** - Generate children from data array:

    ```json
    {
      "children": {
        "template": {
          "dataBinding": "/items",
          "componentId": "item-template"
        }
      }
    }
    ```

    For each item in `/items`, render the `item-template`. See [Data Binding](data-binding.md) for details.

=== "v0.9 and later"

    **Static** - Fixed list of child IDs:

    ```json
    {
      "children": ["back-btn", "title", "menu-btn"]
    }
    ```

    **Dynamic** - Generate children from data array:

    ```json
    {
      "children": {
        "path": "/items",
        "componentId": "item-template"
      }
    }
    ```

    For each item in `/items`, render the `item-template`. See [Data Binding](data-binding.md) for details.

## Hydrating with Values

Components get their values two ways:

=== "v0.8"

    - **Literal** - Fixed value: `{"text": {"literalString": "Welcome"}}`
    - **Data-bound** - From data model: `{"text": {"path": "/user/name"}}`

=== "v0.9 and later"

    - **Literal** - Fixed value: `{"text": "Welcome"}`
    - **Data-bound** - From data model: `{"text": {"path": "/user/name"}}`

LLMs can generate components with literal values or bind them to data paths for dynamic content.

## Composing Surfaces

Components compose into **surfaces** (widgets):

=== "v0.8"

    1. LLM generates component definitions via `surfaceUpdate`
    2. LLM populates data via `dataModelUpdate`
    3. LLM signals render via `beginRendering`
    4. Client renders all components as native widgets

=== "v0.9 and later"

    1. LLM creates a surface via `createSurface` (specifying catalog; in v1.0, can also include initial data model and components)
    2. LLM generates component definitions via `updateComponents`
    3. LLM populates data via `updateDataModel`
    4. Client renders all components as native widgets

A surface is a complete, cohesive UI (form, dashboard, chat, etc.).

## Incremental Updates

Incremental updates support the following operations:

- **Add** - Send new component definitions with new IDs
- **Update** - Send component definitions with existing ID and new properties
- **Remove** - Update parent's `children` list to exclude removed IDs

The flat structure makes all updates simple ID-based operations.

## Defining Your Own Catalog

While the Basic Catalog is useful for starting out, most production applications will define their own catalog to reflect their specific design system.

By defining your own catalog, you restrict the agent to using exactly the components and visual language that exist in your application, rather than generic inputs or buttons.

See [Defining Your Own Catalog Guide](../guides/defining-your-own-catalog.md) for implementation details.

## Best Practices

1. **Descriptive IDs**: Use `"user-profile-card"` not `"c1"`
2. **Shallow hierarchies**: Avoid deep nesting
3. **Separate structure from content**: Use data bindings, not literals
4. **Reuse with templates**: One template, many instances via dynamic children

---

### Public Concepts Data Binding (`docs/public/concepts/data-binding.md`)

# Data Binding

Data binding connects UI components to application state using JSON Pointer paths ([RFC 6901](https://tools.ietf.org/html/rfc6901)). It allows A2UI to efficiently define layouts for large arrays of data and to show updated content without regenerating it from scratch.

## Structure vs. State

A2UI separates:

1. **UI Structure** (Components): What the interface looks like
2. **Application State** (Data Model): What data it displays

This enables:

- Reactive updates.
- Data-driven UIs.
- Reusable templates.
- Bidirectional binding.

## The Data Model

Each surface has a JSON object holding state:

```json
{
  "user": {"name": "Alice", "email": "alice@example.com"},
  "cart": {
    "items": [{"name": "Widget", "price": 9.99, "quantity": 2}],
    "total": 19.98
  }
}
```

## JSON Pointer Paths

**Syntax:**

- `/user/name` - Object property
- `/cart/items/0` - Array index (zero-based)
- `/cart/items/0/price` - Nested path

**Example:**

```json
{"user": {"name": "Alice"}, "items": ["Apple", "Banana"]}
```

- `/user/name` → `"Alice"`
- `/items/0` → `"Apple"`

## Literal vs. Path Values

=== "v0.8"

    **Literal (fixed):**
    ```json
    {
      "id": "title",
      "component": {
        "Text": {
          "text": { "literalString": "Welcome" }
        }
      }
    }
    ```

    **Data-bound (reactive):**
    ```json
    {
      "id": "username",
      "component": {
        "Text": {
          "text": { "path": "/user/name" }
        }
      }
    }
    ```

=== "v0.9 and later"

    **Literal (fixed):**
    ```json
    {
      "id": "title",
      "component": "Text",
      "text": "Welcome"
    }
    ```

    **Data-bound (reactive):**
    ```json
    {
      "id": "username",
      "component": "Text",
      "text": { "path": "/user/name" }
    }
    ```

When `/user/name` changes from "Alice" to "Bob", the text **automatically updates** to "Bob".

## Reactive Updates

Components bound to data paths automatically update when the data changes:

=== "v0.8"

    ```json
    {
      "id": "status",
      "component": {
        "Text": {
          "text": {"path": "/order/status"}
        }
      }
    }
    ```

=== "v0.9 and later"

    ```json
    {
      "id": "status",
      "component": "Text",
      "text": {"path": "/order/status"}
    }
    ```

- **Initial:** `/order/status` = "Processing..." → displays "Processing..."
- **Update:** Send a data model update with `status: "Shipped"` → displays "Shipped"

No component updates needed—just data updates.

## Dynamic Lists

Use templates to render arrays:

=== "v0.8"

    ```json
    {
      "id": "product-list",
      "component": {
        "Column": {
          "children": {
            "template": {
              "dataBinding": "/products",
              "componentId": "product-card"
            }
          }
        }
      }
    }
    ```

=== "v0.9 and later"

    ```json
    {
      "id": "product-list",
      "component": "Column",
      "children": {
        "path": "/products",
        "componentId": "product-card"
      }
    }
    ```

**Data:**

```json
{
  "products": [
    {"name": "Widget", "price": 9.99},
    {"name": "Gadget", "price": 19.99}
  ]
}
```

**Result:** Two cards rendered, one per product.

### Scoped Paths

Inside a template, paths are scoped to the array item:

=== "v0.8"

    ```json
    {
      "id": "product-name",
      "component": {
        "Text": {
          "text": {"path": "/name"}
        }
      }
    }
    ```

    - For `/products/0`, `/name` resolves to `/products/0/name` → "Widget"
    - For `/products/1`, `/name` resolves to `/products/1/name` → "Gadget"

=== "v0.9 and later"

    ```json
    {
      "id": "product-name",
      "component": "Text",
      "text": {"path": "name"}
    }
    ```

    - For `/products/0`, `name` resolves to `/products/0/name` → "Widget"
    - For `/products/1`, `name` resolves to `/products/1/name` → "Gadget"

Adding/removing items automatically updates the rendered components.

## Input Bindings

Interactive components update the data model bidirectionally:

=== "v0.8"

    | Component          | Example                                     | User Action      | Data Update                |
    | ------------------ | ------------------------------------------- | ---------------- | -------------------------- |
    | **TextField**      | `{"text": {"path": "/form/name"}}`          | Types "Alice"    | `/form/name` = `"Alice"`   |
    | **CheckBox**       | `{"value": {"path": "/form/agreed"}}`       | Checks box       | `/form/agreed` = `true`    |
    | **MultipleChoice** | `{"selections": {"path": "/form/country"}}` | Selects "Canada" | `/form/country` = `["ca"]` |

=== "v0.9 and later"

    | Component          | Example                                     | User Action      | Data 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"]` |

## Best Practices

- **Use granular updates**: Update only changed paths.

=== "v0.8"

    ```json
    {
      "dataModelUpdate": {
        "path": "/user",
        "contents": [{"key": "name", "valueString": "Alice"}]
      }
    }
    ```

=== "v0.9 and later"

    ```json
    {
      "version": "v0.9.1",
      "updateDataModel": {
        "surfaceId": "user_profile",
        "path": "/user/name",
        "value": "Alice"
      }
    }
    ```

- **Organize by domain**: Group related data.

    ```json
    {"user": {...}, "cart": {...}, "ui": {...}}
    ```

- **Pre-compute display values**: Formats data (currency, dates) on the agent before sending.

    ```json
    {"price": "$19.99"} // Not: {"price": 19.99}
    ```

---

### Public Concepts Data Flow (`docs/public/concepts/data-flow.md`)

# Data Flow

How messages flow from agents to UI.

## Architecture

```
Agent (LLM) → A2UI Generator → Transport (SSE/WS/A2A)
                                      ↓
Client (Stream Reader) → Message Parser → Renderer → Native UI
```



## Message Format

A2UI defines a sequence of JSON messages that describe the UI. When streamed, these messages are often formatted as **JSON Lines (JSONL)**, where each line is a complete JSON object.

=== "v0.8"

    ```jsonl
    {
      "surfaceUpdate": {
        "surfaceId": "main",
        "components": [...]
      }
    }
    {
      "dataModelUpdate": {
        "surfaceId": "main",
        "contents": [
          {
            "key": "user",
            "valueMap": [
              { "key": "name", "valueString": "Alice" }
            ]
          }
        ]
      }
    }
    {
      "beginRendering": {
        "surfaceId": "main",
        "root": "root-component"
      }
    }
    ```

=== "v0.9"

    ```jsonl
    {
      "version": "v0.9",
      "createSurface": {
        "surfaceId": "main",
        "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
      }
    }
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "main",
        "components": [...]
      }
    }
    {
      "version": "v0.9",
      "updateDataModel": {
        "surfaceId": "main",
        "path": "/user",
        "value": { "name": "Alice" }
      }
    }
    ```

**Why this format?**

A sequence of self-contained JSON objects is streaming-friendly, easy for LLMs to generate incrementally, and resilient to errors.

## Lifecycle Example: Restaurant Booking

**User:** "Book a table for 2 tomorrow at 7pm"

=== "v0.8"

    **1. Agent defines UI structure:**

    ```json
    {
      "surfaceUpdate": {
        "surfaceId": "booking",
        "components": [
          {
            "id": "root",
            "component": {
              "Column": {
                "children": {
                  "explicitList": ["header", "guests-field", "submit-btn"]
                }
              }
            }
          },
          {
            "id": "header",
            "component": {
              "Text": {
                "text": { "literalString": "Confirm Reservation" },
                "usageHint": "h1"
              }
            }
          },
          {
            "id": "guests-field",
            "component": {
              "TextField": {
                "label": { "literalString": "Guests" },
                "text": { "path": "/reservation/guests" }
              }
            }
          },
          {
            "id": "submit-btn",
            "component": {
              "Button": {
                "child": "submit-text",
                "action": {
                  "name": "confirm",
                  "context": [
                    { "key": "details", "value": { "path": "/reservation" } }
                  ]
                }
              }
            }
          }
        ]
      }
    }
    ```

    **2. Agent populates data:**

    ```json
    {
      "dataModelUpdate": {
        "surfaceId": "booking",
        "path": "/reservation",
        "contents": [
          { "key": "datetime", "valueString": "2025-12-16T19:00:00Z" },
          { "key": "guests", "valueString": "2" }
        ]
      }
    }
    ```

    **3. Agent signals render:**

    ```json
    {
      "beginRendering": {
        "surfaceId": "booking",
        "root": "root"
      }
    }
    ```

    **4. User edits guests to "3"** → Client updates `/reservation/guests` automatically

    **5. User clicks "Confirm"** → Client sends action:

    ```json
    {
      "userAction": {
        "name": "confirm",
        "surfaceId": "booking",
        "context": {
          "details": {
            "datetime": "2025-12-16T19:00:00Z",
            "guests": "3"
          }
        }
      }
    }
    ```

    **6. Agent responds** → Updates UI or sends:

    ```json
    { "deleteSurface": { "surfaceId": "booking" } }
    ```

=== "v0.9"

    **1. Agent creates surface:**

    ```json
    {
      "version": "v0.9",
      "createSurface": {
        "surfaceId": "booking",
        "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
      }
    }
    ```

    **2. Agent defines UI structure:**

    ```json
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "booking",
        "components": [
          {
            "id": "root",
            "component": "Column",
            "children": ["header", "guests-field", "submit-btn"]
          },
          {
            "id": "header",
            "component": "Text",
            "text": "Confirm Reservation",
            "variant": "h1"
          },
          {
            "id": "guests-field",
            "component": "TextField",
            "label": "Guests",
            "value": { "path": "/reservation/guests" }
          },
          {
            "id": "submit-btn",
            "component": "Button",
            "child": "submit-text",
            "variant": "primary",
            "action": {
              "event": {
                "name": "confirm",
                "context": {
                  "details": { "path": "/reservation" }
                }
              }
            }
          }
        ]
      }
    }
    ```

    **3. Agent populates data:**

    ```json
    {
      "version": "v0.9",
      "updateDataModel": {
        "surfaceId": "booking",
        "path": "/reservation",
        "value": {
          "datetime": "2025-12-16T19:00:00Z",
          "guests": "2"
        }
      }
    }
    ```

    **4. User edits guests to "3"** → Client updates `/reservation/guests` automatically

    **5. User clicks "Confirm"** → Client sends action:

    ```json
    {
      "version": "v0.9",
      "action": {
        "name": "confirm",
        "surfaceId": "booking",
        "context": {
          "details": {
            "datetime": "2025-12-16T19:00:00Z",
            "guests": "3"
          }
        }
      }
    }
    ```

    **6. Agent responds** → Updates UI or sends:

    ```json
    {
      "version": "v0.9",
      "deleteSurface": { "surfaceId": "booking" }
    }
    ```

## Transport Options

A2UI is transport-agnostic — any mechanism that can deliver JSON messages works:

- **[A2A Protocol](https://a2a-protocol.org/)**: Standardized agent-to-agent communication, also used for agent-to-UI delivery
- **[AG-UI](https://ag-ui.com/)**: Bidirectional, real-time agent-UI protocol
- **REST / HTTP**: Simple request-response or Server-Sent Events (SSE) for one-way streaming
- **WebSocket**: Persistent bidirectional connection, ideal for real-time updates and user actions
- **Any other transport**: gRPC, message queues, custom protocols — if it can carry JSON, it works

See [transports](transports.md) for implementation details.

## Progressive Rendering

Instead of waiting for the entire response to be generated before showing anything to the user, chunks of the response can be streamed to the client as they are generated and progressively rendered.

Users see UI building in real-time instead of staring at a spinner.

## Error Handling

The system handles errors as follows:

- **Malformed messages:** Skip and continue, or send error back to agent for correction.
- **Network interruptions:** Display error state, reconnect, agent resends or resumes.

## Performance

To optimize performance:

- **Batching:** Buffer updates for 16ms, batch render together.
- **Diffing:** Compare old/new components, update only changed properties.
- **Granular updates:** Update `/user/name` not entire `/` model.

---

### Public Concepts Glossary (`docs/public/concepts/glossary.md`)

# Glossary

**A2UI protocol, between renderer and agent:**

The A2UI protocol defines a conversation between an **agent** and a **renderer**:

1. The **renderer** sends its **UI capabilities** as a set of A2UI catalogs, with **instructions** on how to use them.
2. The **agent** then repeats a loop:
    - Sends **UI** to render and **functions** to call, based on the catalog it received
    - Receives **user input** from the renderer
    - Updates the **data** shown in the UI

**Agent and model:**

To produce responses for the renderer, the agent sends requests to a model. The model can be:

- a remote or local LLM, in most cases
- another agent, in more complex orchestrations
- a deterministic engine, usually for testing

**Interaction overview:**

```mermaid
sequenceDiagram
    participant Renderer
    participant Agent
    participant Model

    Renderer->>Agent: Catalog & instructions

    loop Agentic flow
        Renderer->>Agent: User input
        Agent->>Model: Context + User input
        Model->>Agent: Response
        Agent->>Agent: Parse response
        Agent->>Renderer: Data + UI Updates. Function calls.
    end
```

**A2UI SDKs:**

The A2UI team provides two SDKs for a number of languages and frameworks:

- **Agent SDK**: sets up the agent side of the interaction with the renderer and the model.
- **Framework adapter SDK (aka renderer SDK)**: sets up the renderer side of the interaction with the agent and handles incoming messages.

**Terms in this glossary:**

The terms below are grouped into three categories:

- **A2UI protocol terms**: interaction between the renderer and the agent.
- **A2UI agent terms**: agent architecture and the Agent SDK.
- **Generative UI terms**: general generative UI concepts.

## A2UI protocol terms

Terms required by the A2UI protocol.

### A2UI agent and A2UI renderer

The protocol is designed for **AI-powered agents**, but it works with deterministic agents as well. For example, an agent may return a pre-canned A2UI UI.

If the agent is stateless, or does not guarantee that it preserves the catalog, the renderer should send the catalog with every message.

Some agents use a predefined catalog, so renderers must either support that catalog or use an adapter.

### GenUI component

A UI component that the agent is allowed to use. Examples: date picker, carousel, button, hotel selector.

### Catalog

1. Itemized renderer capabilities:
    - List of components that the agent can use to generate UI
    - List of functions that can be called by the renderer or the agent
    - Styles and themes
2. An explanation of how to use those capabilities.

Depending on the use case, catalog components can be more or less domain-specific:

- **Less specific**:

    Basic UI primitives like buttons, labels, rows, columns, option-selectors and so on.

- **More specific**:

    Components like HotelCheckout or FlightSelector.

### Basic catalog

A catalog maintained by the A2UI team for getting started with A2UI quickly.

See the [basic catalog](../../../specification/v0_9_1/catalogs/basic/catalog.json).

### Catalog transformer

A rule set that filters, adapts, or mutates a pristine **catalog** before system prompt instructions are generated or payload validation schemas are compiled.

#### Why catalog transformers are needed

A catalog specifies every component and function that a renderer supports, but agents often need to prune or restrict it:

- **Context window optimization**: A catalog can define dozens of components and functions. Injecting all of their JSON schemas into a model's system prompt costs context window tokens, adds prompt latency, and raises inference costs. A pruning transformer keeps only the components that the agent's task needs.
- **Capability guardrails**: Some workflows or security roles need interactive features restricted. For example, a guest mode may allow display cards and text, but no form inputs or administrative components.
- **Model signature reduction**: Pruning function rules and validation checks produces compact prompt instructions for small models.

#### Example catalog transformers

- `ComponentPruningTransformer`: a utility class that filters the catalog based on a list of allowed component names.

- `FunctionPruningTransformer`: a utility class that filters the catalog based on a list of allowed function names.

### Capabilities object

The set of catalogs that are available for use. An agent or a renderer advertises what it supports through this set, so the other side knows what it may send.

For example, if a renderer supports Basic, Hotels and Flights catalogs, it will advertise them in its capabilities object.

A capabilities object is exchanged through transport metadata or an initialization payload, not as an [A2UI message](#a2ui-message). The exact placement is transport-specific.

The objects are named differently in earlier versions of the protocol: v0.9 and v0.9.1 call them client and server capabilities, and v0.8 defines only a client-side schema.

### Surface

An area of UI, built by the A2UI agent and managed by the A2UI renderer, that consists of a number of components. Surfaces cannot nest.

### A2UI message

A message between the agent and the renderer.

Because the protocol supports streaming, a message can be finished (fully delivered) or unfinished (partially delivered). A finished message is either completed (delivered successfully) or interrupted (delivery stopped because of a technical problem).

See the [data flow guide](data-flow.md).

### Agent turn

The set of messages that the agent sends before it starts waiting for user input.

### Data model

An observable, hierarchical, JSON-like object, shared between the renderer and the agent and updatable by both. Each surface has its own data model.

Components can bind to nodes of the data model and update automatically when those values change.

The data model gives two-way synchronization: it captures user interactions into a state object that is sent to the agent, and it lets the agent push data updates back to the UI.

See the [data binding guide](data-binding.md).

### Data reference

In a component definition, a reference to a data element, resolved either by a path in the data model or by value.

See the [example in the basic catalog](../../../specification/v0_9/catalogs/basic/catalog.json#L23).

### Function <a id="renderer-function"></a>

A named, catalog-defined operation with a declared argument signature and return type. Functions execute logic without sending raw executable code between the agent and renderer.

Functions are defined in catalogs and can execute on either the renderer or the agent:

- **Renderer function**: A function executed on the **renderer**. Renderer functions handle client-side tasks such as formatting values, validating input fields, navigating, or controlling local UI state. The agent can also request the renderer to execute a function (for example, to display a notification or trigger device feedback).
- **Agent function**: A function executed on the **agent**. When the UI requires server-side logic (such as checking inventory, querying a database, or verifying credentials), the renderer requests the agent to execute the function and return the result.

An A2UI function is not the same as an LLM tool:

| Feature      | A2UI function                                                            | LLM tool invocation                                |
| ------------ | ------------------------------------------------------------------------ | -------------------------------------------------- |
| Executor     | A2UI renderer (for renderer functions) or agent (for agent functions).   | Model host or agent environment outside the UI.    |
| Timing       | During UI rendering, on user interaction, or as a request between turns. | Before or during model response generation.        |
| Purpose      | UI logic: validation, formatting, client actions, or app operations.     | Model reasoning, web search, database retrieval.   |
| Definition   | Declared in an A2UI catalog with argument and return signatures.         | Declared in a tool definition passed to the model. |
| State access | Scoped to surface data context, local UI state, or catalog methods.      | Scoped to external tools, APIs, and services.      |

For details on how functions are routed and executed between the agent and renderer, see [Functions in A2UI in the protocol specification](../specification/v1.0-a2ui.md#functions-in-a2ui-content-execution).

### Function call

An invocation of a catalog function with a set of arguments.

Function calls appear in several contexts:

- **Dynamic value bindings**: The renderer calls a renderer function to calculate a component property value dynamically (for example, formatting a date or currency).
- **Validation rules**: The renderer calls a renderer function to validate user input before submission.
- **Component interaction triggers**: The renderer calls a renderer function when a user interacts with a component (for example, opening a URL).
- **Remote procedure calls (RPCs)**: The agent requests the renderer to execute a renderer function, or the renderer requests the agent to execute an agent function.

Function calls execute locally when the target function is implemented in the caller's environment. When the function resides on the other side of the agent-renderer boundary, the call is communicated over the protocol. In architectures where the agent and renderer run within the same process (such as a standalone desktop application), these calls can execute in-process without network transport.

### Action

An event triggered by a user interaction with a UI component that is dispatched from the renderer to the agent.

An action informs the agent that an interaction occurred (such as clicking a button or selecting an option). It conveys the user's intent along with an action name, relevant values extracted from the renderer data model, and an optional description of the action.

Actions represent user intent communicated back to the agent to drive conversational turns or business logic. In contrast, when a component interaction triggers behavior directly without notifying the agent (such as opening a URL or running a client-side calculation), it performs a [function call](#function-call) rather than dispatching an action.

See the [detailed guide on actions](actions.md).

## A2UI agent terms

Terms used to describe agent architecture and the Agent SDK.

### A2UI tag

In model-to-agent messages, a delimiter tag such as `<a2ui-json>` or `<a2ui>` that bounds an A2UI payload block inside the model's text output.

A single model turn can mix conversational text and structured UI blocks, so A2UI tags mark where each UI block starts and ends.

### Inference format

The format of the structured UI blocks in model-to-agent messages, for example JSON, [Express DSL syntax](https://github.com/a2ui-project/a2ui/tree/main/python/a2ui_agent/src/a2ui/inference_formats/express), or Elemental HTML tags.

### Phases of parsing of model-to-agent responses

**Tag unwrapping:**

The first phase of response parsing (`unwrap`), where the parser scans the model response for opening and closing **A2UI tags**, and separates conversational text (e.g., _"Here is your summary:"_) from the enclosed raw UI blocks.

**Compilation:**

The second phase of response parsing (`compile`), where the raw UI blocks extracted during unwrapping (standard JSON, Express DSL syntax, or Elemental HTML tags) are parsed, decompiled, and transformed into standard A2UI protocol payloads such as `createSurface` and `updateDataModel`.

### Agent architecture

An A2UI agent can be built in several ways:

- **Same-process or server-side**:

    The agent and the renderer may live in one process of a client side application. Example: a desktop Flutter application.

    Or the renderer may live on the box that displays the UI, and the agent on another box (server).

- **Orchestrator agent**:

    A central orchestrator manages interactions between a user and several specialized sub-agents. The orchestrator can be in the same process or on the server.

- **Pulling / pushing**:

    An agent can wait for messages and requests from the renderer, or push them to it.

- **Stateful / stateless**:

    Agents can preserve state or be stateless.

- **Mixed with other protocols**:

    A2UI can be used in combination with other protocols. For example, an agent may be an MCP and/or A2A server.

- **Something else**:

    Custom variations of the options above are also possible.

### Recommended code organization

Agent and renderer functionality consists of layers that can be developed separately and reused:

- **Core library**:

    Set of primitives needed to describe a catalog and to interact with the agent.

    For example, see the [JavaScript web core library](../../../typescript/core/web_core/README.md).

- **Catalog schema**:

    Definition of a catalog in the form of JSON.

    For example, see the [basic catalog schema](../../../specification/v0_9_1/catalogs/basic/catalog.json).

- **Agent SDK**:

    Code that implements the agent's interaction with the model and the renderer.

- **Framework adapter (or renderer SDK)**:<a id="fw-adapter"></a>

    Code that runs the agent's instructions in a concrete framework. For example:
    - JavaScript core and catalogs may be adapted to Angular, Electron, React and Lit frameworks.
    - Dart core and catalogs may be adapted to Flutter and Jaspr frameworks.

    See the [Angular adapter](../../../typescript/renderers/angular/README.md).

- **Catalog implementation**:

    Implementation of the catalog schema for a framework.

    For example:
    - See the [Angular implementation of the basic catalog](../../../typescript/renderers/angular/src/v0_9/catalog/basic)

```mermaid
flowchart TD;
cimpl-->fadapter("Framework<br>Adapter");
cimpl("Catalog<br>Implementation")-->cschema("Catalog<br>Schema");
cschema-->core("Core<br>Library");
agentsdk("Agent SDK")-->cschema;
agentsdk-->core;
fadapter-->core;
renderer-->fadapter;
renderer("Renderer")-->cimpl;
agent("Agent")-->agentsdk;
```

## Generative UI terms

Terms that the A2UI protocol does not require, but that are common in the context of generative UI.

### Known patterns of GenUI

- **Chat**:

    Pieces of generated UI appear one by one, sorted by time, in a vertically scrollable area, mixed with user input.

- **Canvas**:

    A space for collaboration with an agent.

- **Dashboard**:

    Pieces of generated UI are organized by meaning rather than by time, and stay pinned where the user expects to see them.

- **Wizard**:

    Pieces of generated UI are shown one by one, to collect the information needed for a certain task.

### NoAI information

Information categorized as **not accessible by AI**, for example credit card details.

Application owners decide which information is not accessible by AI, and the answer is **different in different contexts**. For example, in some products medical history should never go to the AI, while in others the AI relies on medical history to help with diagnostics.

The term matters in the GenUI context, because end users want to **clearly see** which of their input may go to the AI and which may not.

---

### Public Concepts Transports (`docs/public/concepts/transports.md`)

# Transports (Message Passing)

Transports deliver A2UI messages from agents to clients. A2UI is transport-agnostic: use any method that can send JSON.

The actual component rendering is done by the [renderer](../reference/renderers.md),
and the [agents](../reference/agents.md) are responsible for generating the A2UI messages.
Getting the messages from the agent to the client is the job of the transport.

## How It Works

```
Agent → Transport → Client Renderer
```

A2UI defines a sequence of JSON messages. The transport layer is responsible for delivering this sequence from the agent to the client. A common transport mechanism is a stream using a format like JSON Lines (JSONL), where each line is a single A2UI message.

## Available Transports

| Transport                    | Status      | Use Case                                                 |
| ---------------------------- | ----------- | -------------------------------------------------------- |
| **A2A Protocol**             | ✅ Stable   | Multi-agent systems, enterprise meshes                   |
| **AG-UI**                    | ✅ Stable   | Full stack React, Vue, Angular applications (CopilotKit) |
| **REST API**                 | 📋 Planned  | Simple HTTP endpoints                                    |
| **WebSockets**               | 💡 Proposed | Real-time bidirectional                                  |
| **SSE (Server-Sent Events)** | 💡 Proposed | Web streaming                                            |

## A2A Protocol

The [Agent2Agent (A2A) protocol](https://a2a-protocol.org) provides secure,
standardized agent communication. An A2A extension provides easy integration with A2UI.

**Benefits:**

- Security and authentication built-in.
- Bindings for many message formats, auth, and transport protocols.
- Clean separation of concerns.

If you are using A2A, this should be nearly automatic.

TODO: Add a detailed guide.

**See:** [A2A Extension Specification](../specification/v0.8-a2a-extension.md)

## AG-UI

[AG-UI](https://ag-ui.com/) translates A2UI messages to AG-UI events and handles transport and state sync automatically. It is commonly used for full stack React, Vue, and Angular applications. CopilotKit is AG-UI's creator and primary consumer.

**See:** [Use A2UI with Any Agent Framework (Using AG-UI)](../guides/a2ui-with-any-agent-framework.md): Set up CopilotKit with your agent framework of choice and enable A2UI rendering.

## Custom Transports

You can use any transport that sends JSON:

**HTTP/REST:**

```javascript
// TODO: Add an example
```

**WebSockets:**

```javascript
// TODO: Add an example
```

**Server-Sent Events:**

```javascript
// TODO: Add an example
```

## Next Steps

- **[A2A Protocol Docs](https://a2a-protocol.org)**: Learn about A2A
- **[A2A Extension Spec](../specification/v0.8-a2a-extension.md)**: A2UI + A2A details

---

### Public Ecosystem A2ui In The World (`docs/public/ecosystem/a2ui-in-the-world.md`)

# A2UI in the World

A2UI is being adopted by teams at Google and partner organizations to build the next generation of agent-driven applications. Here are real-world examples of where A2UI is making an impact.

## Production Deployments

### Google Opal: AI Mini-Apps for Everyone

[Opal](http://opal.google) enables hundreds of thousands of people to build, edit, and share AI mini-apps using natural language—no coding required.

**How Opal uses A2UI:**

The Opal team at Google has been a **core contributor to A2UI** from the beginning. They use A2UI to power the dynamic, generative UI system that makes Opal's AI mini-apps possible.

- **Rapid prototyping**: Build and test new UI patterns quickly.
- **User-generated apps**: Anyone can create apps with custom UIs.
- **Dynamic interfaces**: UIs adapt to each use case automatically.

> "A2UI is foundational to our work. It gives us the flexibility to let the AI drive the user experience in novel ways, without being constrained by a fixed front-end. Its declarative nature and focus on security allow us to experiment quickly and safely."
>
> **— Dimitri Glazkov**, Principal Engineer, Opal Team

**Learn more:** [opal.google](http://opal.google)

---

### Gemini Enterprise: Custom Agents for Business

Gemini Enterprise enables businesses to build powerful, custom AI agents tailored to their specific workflows and data.

**How Gemini Enterprise uses A2UI:**

A2UI is being integrated to allow enterprise agents to render **rich, interactive UIs** within business applications—going beyond simple text responses to guide employees through complex workflows.

- **Data entry forms**: AI-generated forms for structured data collection.
- **Approval dashboards**: Dynamic UIs for review and approval processes.
- **Workflow automation**: Step-by-step interfaces for complex tasks.
- **Custom enterprise UIs**: Tailored interfaces for industry-specific needs.

> "Our customers need their agents to do more than just answer questions; they need them to guide employees through complex workflows. A2UI will allow developers building on Gemini Enterprise to have their agents generate the dynamic, custom UIs needed for any task, from data entry forms to approval dashboards, dramatically accelerating workflow automation."
>
> **— Fred Jabbour**, Product Manager, Gemini Enterprise

> **Note:** A2UI rendering in Gemini Enterprise currently requires self-serve agents registered using the Agent-to-Agent (A2A) path (`a2aAgentDefinition`). Managed agents deployed on Vertex AI Agent Engine and registered using the `adkAgentDefinition` path do not currently support A2UI rendering.

**Learn more:** [Gemini Enterprise](https://cloud.google.com/gemini)

---

### Flutter GenUI SDK: Generative UI for Mobile

The [Flutter GenUI SDK](https://docs.flutter.dev/ai/genui) brings dynamic, AI-generated UIs to Flutter applications across mobile, desktop, and web.

**How GenUI uses A2UI:**

GenUI SDK uses **A2UI as the underlying protocol** for communication between server-side agents and Flutter applications. When you use GenUI, you're using A2UI under the covers.

- **Cross-platform support**: Same agent works on iOS, Android, web, desktop.
- **Native performance**: Flutter widgets rendered natively on each platform.
- **Brand consistency**: UIs match your app's design system.
- **Server-driven UI**: Agents control what's shown without app updates.

> "Our developers choose Flutter because it lets them quickly create expressive, brand-rich, custom design systems that feel great on every platform. A2UI was a great fit for Flutter's GenUI SDK because it ensures that every user, on every platform, gets a high quality native feeling experience."
>
> **— Vijay Menon**, Engineering Director, Dart & Flutter

**Try it:**

- [GenUI Documentation](https://docs.flutter.dev/ai/genui)
- [Getting Started Video](https://www.youtube.com/watch?v=nWr6eZKM6no)
- [Verdure Example](https://github.com/flutter/genui/tree/main/examples/verdure) (client-server A2UI sample)

---

### Google ADK: Agent Development Kit

The [Agent Development Kit](https://google.github.io/adk-docs/) (ADK) is Google's open-source framework for building and deploying AI agents. The built-in developer UI, [ADK Web](https://github.com/google/adk-web), includes native A2UI rendering.

**How ADK uses A2UI:**

ADK integrated the A2UI v0.8 basic catalog to automatically render spec-compliant agent parts as native UI components directly in the chat. ADK also handles A2UI↔A2A message conversion, so agents built with ADK can send rich UI to any A2UI-capable client.

- **Built-in rendering**: ADK Web renders A2UI components natively in the dev UI.
- **A2A integration**: A2UI messages are converted between A2A DataPart metadata and ADK events.
- **Agent SDK**: The [A2UI Python agent SDK](../../../python/a2ui_agent) provides an ADK extension for generating A2UI from agents.

**Try it:**

- [ADK Documentation](https://google.github.io/adk-docs/)
- [ADK Web](https://github.com/google/adk-web) (developer UI with A2UI support)
- [Agent Development Guide](../guides/agent-development.md) (building A2UI agents with ADK)

---

## Partner Integrations

### AG-UI / CopilotKit: Full-Stack Agentic Framework

[AG-UI](https://ag-ui.com/) provides the protocol and [CopilotKit](https://www.copilotkit.ai/) provides the primary full-stack framework for building agentic applications, with **day-zero A2UI compatibility**.

**How they work together:**

AG-UI excels at creating high-bandwidth connections between custom frontends and their dedicated agents. By adding A2UI support, developers get the best of both worlds:

- **State synchronization**: AG-UI handles app state and chat history.
- **A2UI rendering**: Render dynamic UIs from third-party agents.
- **Multi-agent support**: Coordinate UIs from multiple agents.
- **Framework integrations**: React, Vue, Angular, and other app surfaces through CopilotKit.

> "AG-UI excels at creating a high-bandwidth connection between a custom-built front-end and its dedicated agent. By adding support for A2UI, we're giving developers the best of both worlds. They can now build rich, state-synced applications that can also render dynamic UIs from third-party agents via A2UI. It's a perfect match for a multi-agent world."
>
> **— Atai Barkai**, Founder of CopilotKit and AG-UI

**Learn more:**

- [AG-UI](https://ag-ui.com/)
- [CopilotKit](https://www.copilotkit.ai/)

---

### AG2: Multi-Agent Framework with Native A2UI

[AG2](https://ag2.ai/) is a popular multi-agent framework, offering advanced orchestration of agents. Its [A2UIAgent](https://docs.ag2.ai/latest/docs/user-guide/reference-agents/a2uiagent) is a reference agent with native A2UI support, enabling AG2 agents to generate rich, interactive UI served over both A2A and AG-UI.

**How AG2 uses A2UI:**

A2UIAgent extends AG2's ConversableAgent with built-in A2UI capabilities — prompt engineering, schema validation with retry, and action handling — so developers can add generative UI to their agents without custom rendering code.

- **Validated output**: Built-in schema validation and retry ensures reliable A2UI generation.
- **Dual transport**: Serves the same UI over A2A (JSON-RPC) and AG-UI (SSE).
- **Cross-platform**: One agent serves web, desktop, and mobile clients.
- **Custom catalogs**: Extend the component catalog with domain-specific components.

> "A2UIAgent brings the A2UI protocol to AG2, enabling agent expression with dynamic, rich, and interactive UIs. Reliable, client-agnostic rendering means our developers spend less time on integration and more time building great experiences."
>
> **— Mark Sze**, Founding Engineer, AG2

**Learn more:**

- [A2UIAgent Documentation](https://docs.ag2.ai/latest/docs/user-guide/reference-agents/a2uiagent)
- [Technical Deep Dive](https://docs.ag2.ai/latest/docs/blog/2026/03/20/AG2-A2UI/) — Building A2UI agents with AG2
- [A2UIAgent + Flutter Example](https://github.com/ag2ai/build-with-ag2/tree/main/a2ui/flutter) — A2UIAgent served over A2A to a Flutter GenUI client
- [AG2](https://ag2.ai/)

---

### Google's AI-Powered Products

As Google adopts AI across the company, A2UI provides a **standardized way for AI agents to exchange user interfaces**, not just text.

**Internal agent adoption:**

- **Multi-agent workflows**: Multiple agents contribute to the same surface.
- **Remote agent support**: Agents running on different services can provide UI.
- **Standardization**: Common protocol across teams reduces integration overhead.
- **External exposure**: Internal agents can be easily exposed externally (e.g., Gemini Enterprise).

> "Much like A2A lets any agent talk to another agent regardless of platform, A2UI standardizes the user interface layer and supports remote agent use cases through an orchestrator. This has been incredibly powerful for internal teams, allowing them to rapidly develop agents where rich user interfaces are the norm, not the exception. As Google pushes further into generative UI, A2UI provides a perfect platform for server-driven UI that renders on any client."
>
> **— James Wren**, Senior Staff Engineer, AI Powered Google

---

## Community Projects

The A2UI community is building exciting projects:

### Open Source Examples

- **Restaurant Finder** ([samples/agent/adk/restaurant_finder](../../../samples/agent/adk/restaurant_finder))
    - Table reservation with dynamic forms
    - Gemini-powered agent
    - Full source code available

- **Component Gallery** ([samples/client/angular - gallery mode](../../../samples/client/angular))
    - Interactive showcase of all components
    - Live examples with code
    - Great for learning

### Third-Party Integrations

- **[json-render](https://json-render.dev/docs/a2ui)** — Vercel's React library for rendering A2UI component catalogs via Zod schemas. See [json-render vs. A2UI comparison](https://dipjyotimetia.medium.com/vercels-json-render-vs-google-s-a2ui-the-head-to-head-6f213cf1a23b).
- **[OpenClaw Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — OpenClaw uses A2UI to render agent-generated UI on connected devices via its canvas system. See [architecture overview](https://ppaolo.substack.com/p/openclaw-system-architecture-overview).

### Community Contributions

Have you built something with A2UI? [Share it with the community!](community.md)

---

## Next Steps

For more information, see the following resources:

- [Quickstart Guide](../quickstart.md) - Try the demo.
- [Agent Development](../guides/agent-development.md) - Build an agent.
- [Client Setup](../guides/client-setup.md) - Integrate a renderer.
- [Community](community.md) - Join the community.

---

**Using A2UI in production?** Share your story on [GitHub Discussions](https://github.com/a2ui-project/a2ui/discussions).

---

### Public Ecosystem Community (`docs/public/ecosystem/community.md`)

# Community

Welcome to the A2UI community! The project is building the future of agent-driven interfaces together.

## Get Involved

A2UI is an open-source project licensed under Apache 2.0. Contributions are welcome from developers, researchers, and anyone interested in advancing agentic user interfaces.

## Community Showcase

Built something with A2UI? Show it off!

The best way to share your work is to **post in [GitHub Discussions](https://github.com/a2ui-project/a2ui/discussions)** with a short description, a link to your code, and a demo video (4 minutes or less). Notable projects are featured in the docs and release notes.

**Community-built renderers** are listed on the [Ecosystem Renderers](renderers.md) page — check there for community implementations and instructions for adding your own.

**Official samples** [in the repo](../../../samples/README.md) are a great reference for what good A2UI projects look like:

## Project Partners

A2UI is developed in collaboration with Google Opal, Flutter (GenUI SDK), Gemini Enterprise, AG-UI / CopilotKit, and the A2A team. For full details and case studies, see [A2UI in the World](a2ui-in-the-world.md).

If you have made significant contributions to A2UI, please submit your name to this list.

## Code of Conduct

A2UI is committed to providing a welcoming and inclusive environment for everyone. All participants are expected to:

- Be respectful and considerate.
- Welcome newcomers and help them get started.
- Focus on what's best for the community.
- Show empathy towards others.

Unacceptable behavior will not be tolerated. Report concerns to the project maintainers.

## Recognition

All contributions are appreciated! Contributors are recognized in:

- GitHub's contributor graph.
- Release notes.
- Project acknowledgments.

Significant contributors may be invited to join the project's maintainer team.

## Stay Updated

To stay informed about project updates:

- **Watch the GitHub repo** for notifications.
- **Star the repo** to bookmark and show support.
- **Follow releases** to get notified of new versions.

## Ways to Contribute

**[github.com/a2ui-project/a2ui](https://github.com/a2ui-project/a2ui)**

- **Report Issues**: Found a bug? [Open an issue](https://github.com/a2ui-project/a2ui/issues).
- **Build Renderers**: See the [roadmap](../roadmap.md) for planned frameworks.
- **Share Examples**: Post with `#A2UI` on X/LinkedIn, start a [discussion](https://github.com/a2ui-project/a2ui/discussions).
- **Improve Docs**: PRs welcome in the `docs/` directory.

## Questions?

If you have questions:

- Check the [documentation](../introduction/what-is-a2ui.md).
- Search [GitHub Discussions](https://github.com/a2ui-project/a2ui/discussions).
- Ask in [GitHub Issues](https://github.com/a2ui-project/a2ui/issues).

Thank you for being part of the A2UI community!

---

### Public Ecosystem Renderers (`docs/public/ecosystem/renderers.md`)

# Ecosystem Renderers

Community and third-party A2UI renderer implementations.

> NOTE
> These renderers are maintained by their respective authors, not the A2UI team. Check each project for compatibility, version support, and maintenance status.

> TIP
> Looking for the **official** A2UI React renderer? See [`@a2ui/react`](https://www.npmjs.com/package/@a2ui/react) — the core A2UI React renderer maintained by the A2UI team.

## Community Renderers

| Renderer                                                                               | Platform                                                            | v0.8 | v0.9 | v1.0 | Activity                                                                                                                                                                                                                                         | Links                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---- | ---- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **easyops-cn/a2ui-sdk** (`@a2ui-sdk/react`)                                            | React (Web)                                                         | ✅   | ❌   | —    |                                         | [GitHub](https://github.com/easyops-cn/a2ui-sdk) · [npm](https://www.npmjs.com/package/@a2ui-sdk/react) · [Docs](https://a2ui-sdk.js.org/)                                                             |
| **lmee/A2UI-Android**                                                                  | Android (Compose)                                                   | ✅   | ❌   | —    |                                             | [GitHub](https://github.com/lmee/A2UI-Android)                                                                                                                                                         |
| **sivamrudram-eng/a2ui-react-native**                                                  | React Native                                                        | ✅   | ❌   | —    |             | [GitHub](https://github.com/sivamrudram-eng/a2ui-react-native)                                                                                                                                         |
| **zhama/a2ui**                                                                         | React (Web)                                                         | ✅   | ❌   | —    | —                                                                                                                                                                                                                                                | [npm](https://www.npmjs.com/package/@zhama/a2ui)                                                                                                                                                       |
| **jem-computer/A2UI-react**                                                            | React (Web)                                                         | ✅   | ❌   | —    |                                 | [GitHub](https://github.com/jem-computer/A2UI-react)                                                                                                                                                   |
| **BBC6BAE9/a2ui-swift**                                                                | Apple native (SwiftUI, UIKit, AppKit)                               | ✅   | ✅   | —    |                                         | [GitHub](https://github.com/BBC6BAE9/a2ui-swift)                                                                                                                                                       |
| **a2ui-vue**                                                                           | Vue (Web)                                                           | ✅   | ✅   | —    |                                       | [GitHub](https://github.com/shawnwang15/a2ui-vue) · [npm](https://www.npmjs.com/package/a2ui-vue) · [Docs](https://shawnwang15.github.io/a2ui-vue/en/)                                                 |
| **AGenUI/AGenUI**                                                                      | iOS, Android, HarmonyOS                                             | ❌   | ✅   | —    |                                                     | [GitHub](https://github.com/AGenUI/AGenUI) · [Official Website](https://genui.amap.com/)                                                                                                               |
| **lynx-family/lynx-stack** (`@lynx-js/genui/a2ui`)                                     | Lynx (Mobile, Web, Desktop)                                         | ❌   | ✅   | —    |      | [GitHub](https://github.com/lynx-family/lynx-stack/tree/main/packages/genui/a2ui) · [npm](https://www.npmjs.com/package/@lynx-js/genui) · [Docs](https://lynxjs.org/next/react/genui/a2ui.html)        |
| **BoteAI/a2ui** (`@boteai/a2ui-render`)                                                | React (Web)                                                         | ✅   | ✅   | —    |                                                         | [GitHub](https://github.com/BoteAI/a2ui) · [npm](https://www.npmjs.com/package/@boteai/a2ui-render)                                                                                                    |
| **kokoro-ele/a2ui-ink** (`@evanyu/a2ui-ink`)                                           | Terminal / CLI (Ink)                                                | ❌   | ✅   | —    |                                         | [GitHub](https://github.com/kokoro-ele/a2ui-ink) · [npm](https://www.npmjs.com/package/@evanyu/a2ui-ink)                                                                                               |
| **yessGlory17/generative-mui** (`@yessglory/generative-mui-react`)                     | React + Material UI (Web)                                           | ❌   | ✅   | —    |                           | [GitHub](https://github.com/yessGlory17/generative-mui) · [npm](https://www.npmjs.com/package/@yessglory/generative-mui-react)                                                                         |
| **ChaliceForAuri/a2ui-svelte** (`svelte-a2ui`)                                         | Svelte 5 (Web)                                                      | ❌   | ✅   | ✅   |                           | [GitHub](https://github.com/ChaliceForAuri/a2ui-svelte) · [npm](https://www.npmjs.com/package/svelte-a2ui) · [Demo](https://chaliceforauri.github.io/a2ui-svelte/)                                     |
| **Language-Lit/material3-expressive-a2ui** (`@language-lit/material3-expressive-a2ui`) | React + Material 3 Expressive (Web)                                 | ❌   | ✅   | —    |   | [GitHub](https://github.com/Language-Lit/material3-expressive-a2ui) · [npm](https://www.npmjs.com/package/@language-lit/material3-expressive-a2ui) · [Demo & Docs](https://m3e.language-lit.com/a2ui/) |
| **uny/a2ui-compose** (`dev.ynagai.a2ui:a2ui-material3`)                                | Compose Multiplatform (Android, iOS, desktop, macOS, web JS/wasmJs) | ❌   | ❌   | ✅   |                                               | [GitHub](https://github.com/uny/a2ui-compose) · [Maven Central](https://central.sonatype.com/namespace/dev.ynagai.a2ui) · [API docs](https://uny.github.io/a2ui-compose/)                              |

### Notable Mentions

These projects are early-stage or experimental:

- **[xpert-ai/a2ui-react](https://www.npmjs.com/package/@xpert-ai/a2ui-react)** (`@xpert-ai/a2ui-react`) — React renderer with ShadCN UI components (v0.0.1, published Jan 2026).
- **[josh-english-2k18/a2ui-3d-renderer](https://github.com/josh-english-2k18/a2ui-3d-renderer)** — Experimental Three.js/WebGL 3D renderer for A2UI (~2 stars).
- **[AINative-Studio/ai-kit-a2ui](https://github.com/AINative-Studio/ai-kit-a2ui)** — React + ShadCN renderer for the AIKit framework (~2 stars).

### Related Projects

These projects are not directly A2UI renderers but are closely related and do support A2UI:

| Project                                        | Platform                                | Description                                                                                                                                                                                              | Links                                                                                                                                            |
| ---------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| **vercel-labs/json-render** (`@json-render/*`) | React, Vue, Svelte, Solid, React Native | Generative UI framework by Vercel — uses its own JSON schema (not A2UI protocol) with Zod-based component catalogs. Supports streaming, 36 pre-built shadcn/ui components, and cross-platform rendering. | [GitHub](https://github.com/vercel-labs/json-render) · [npm](https://www.npmjs.com/package/@json-render/core) · [Docs](https://json-render.dev/) |

### Agent-Side Libraries

These projects produce A2UI rather than rendering it.

| Project                                              | Language   | Description                                                                                                                                                                                                             | Links                                                                                                                                                               |
| ---------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Max-Health-Inc/prefab** (`@maxhealth.tech/prefab`) | TypeScript | Server-side component library that emits A2UI from a typed component tree, with a diagnostic for anything the Basic Catalog cannot express. Also serves A2UI over MCP as an `a2ui://` resource or an embedded resource. | [GitHub](https://github.com/Max-Health-Inc/prefab) · [npm](https://www.npmjs.com/package/@maxhealth.tech/prefab) · [Docs](https://maxhealth.tech/prefab/guide/a2ui) |

### Ecosystem Utilities

- **[@a2ui/markdown-it](https://www.npmjs.com/package/@a2ui/markdown-it)** — Enables markdown rendering in the Text widgets of all renderers.

### Highlights

**easyops-cn/a2ui-sdk** (`@a2ui-sdk/react`) is the most fully-featured community React renderer, with 11 published versions, Radix UI primitives, Tailwind CSS styling, and a dedicated docs site. It was [announced on the A2UI discussions](https://github.com/a2ui-project/a2ui/discussions/489). For the official A2UI React renderer, see [`@a2ui/react`](https://www.npmjs.com/package/@a2ui/react).

**lmee/A2UI-Android** fills an important gap — it's currently the only Jetpack Compose renderer, covering Android 5.0+ with 20+ components, data binding, and accessibility support.

**sivamrudram-eng/a2ui-react-native** is the only React Native renderer, enabling A2UI on iOS and Android via a single codebase.

**BBC6BAE9/a2ui-swift** is a Swift-based, spec-faithful native Apple renderer for
A2UI. It supports SwiftUI, UIKit, and AppKit through a shared `A2UISwiftCore`
layer, and runs across iOS, iPadOS, macOS, tvOS, visionOS, and watchOS. The
project supports A2UI v0.8, v0.9, and v0.9.1, with a focus on close alignment
with the official A2UI specification and Apple-native platform behavior. It
prioritizes spec-level interoperability and native platform expression over
pixel-identical rendering across different platforms. Default rendering uses
native Apple controls and platform-appropriate interaction patterns aligned with
the Human Interface Guidelines, while apps can still customize styling and
behavior through A2UI catalogs, themes, and custom components.

**AGenUI/AGenUI** is a cross-platform native renderer for A2UI v0.9, supporting iOS, Android, and HarmonyOS through a shared C++ core. It is designed for high performance, extensibility, and cross-platform consistency. AGenUI fully implements A2UI v0.9 and provides runtime APIs for extending UI components and function calls. It also introduces a [custom Catalog](https://github.com/AGenUI/AGenUI/blob/main/agenui_catalog.json) that extends the Basic Catalog with Table, Carousel, Web, RichText, and a Styles property for richer appearance and layout control, while staying aligned with A2UI’s extensible Catalog model. See the [component demo](https://genui.amap.com/components), the corresponding open-source [A2UI Generation Skill](https://github.com/AGenUI/AGenUI/tree/main/skills/a2ui-generation), and learn more on [GitHub](https://github.com/AGenUI/AGenUI).

**lynx-family/lynx-stack** (`@lynx-js/genui/a2ui`) provides the ReactLynx renderer for A2UI v0.9. It consumes validated server-to-client A2UI messages through a `MessageStore`, renders approved ReactLynx components from caller-supplied catalogs, and forwards generated UI actions through `onAction`. The published `@lynx-js/genui` package exposes the A2UI renderer via the `a2ui` subpath, while the GenUI CLI supports build-time catalog artifact and A2UI system prompt generation.

**yessGlory17/generative-mui** (`@yessglory/generative-mui-react`) is a **Material UI** renderer for A2UI (v0.9.1). It maps all 18 Basic Catalog components one-to-one onto MUI and renders them **inside the host app's existing `<ThemeProvider>`** — the surface has no theme of its own, so it inherits the host palette/typography and re-skins top-to-bottom when the theme changes. It splits into a framework-neutral core (`@yessglory/generative-mui-core` — Zod schemas, JSONL parser, JSON Pointer, a deterministic subscribable `SurfaceStore`, and provider-agnostic agent tool schemas) and the React/MUI adapter, with the one-way `react → core` dependency enforced at lint time. Beyond the Basic Catalog it ships an opt-in Extended Catalog (charts via `@mui/x-charts`, Table, and more), two-way data binding, `checks`-driven validation, streaming resilience (incremental skeletons, append-only string deltas, cycle/depth and per-node error boundaries), and security guards (unregistered types never execute; `sx`/`style`/`className` from the agent are stripped; a ReDoS length cap on local `regex`).

**ChaliceForAuri/a2ui-svelte** (`svelte-a2ui`) is a Svelte 5 renderer built natively on runes, targeting the v1.0 Candidate spec (component property names shared with v0.9). It covers the full Basic Catalog — all 18 components, the complete 59-name `Icon` enum plus the `{svgPath}` variant, all 14 built-in functions, `checks` validation, and collection templates — and replays the specification's own contact-form fixture in its test suite. The protocol core is a pure reducer with structural sharing, held in `$state.raw` so unchanged components skip re-rendering entirely; the threat model assumes a hostile agent (catalog allowlist, `on*`/function stripping, prototype-pollution refusal, escape-then-markup for text, bounded recursion, `callableFrom` enforcement). Transports include HTTP JSONL/SSE, the A2A extension binding (`application/a2ui+json` DataParts, renderer metadata lifting), and AG-UI activities (including the middleware's `a2ui-surface` type), with `a2uiRendererCapabilities` advertised on every outbound message. Styling is entirely host-owned CSS custom properties. The project is Apache-2.0 licensed, and a [hosted demo](https://chaliceforauri.github.io/a2ui-svelte/) streams the booking-form scenario live.

**Language-Lit/material3-expressive-a2ui** (`@language-lit/material3-expressive-a2ui`) is a **Material 3 Expressive** renderer for A2UI v0.9.1, built on Google's `@a2ui/web_core` message processor. It maps all 18 Basic Catalog components one-to-one onto the [Material 3 Expressive](https://m3e.language-lit.com) React design system, so agent-generated surfaces share one theme, one type scale, and one motion system with the rest of the host app. It ships a `useA2ui` hook and an `A2uiSurface` component, two-way data binding, `checks`-driven validation, streaming placeholders for children named before they arrive, actions with resolved context, and an extensible catalog. The same catalog also plugs into the official `@a2ui/react` surface. The package has zero runtime dependencies beyond its peers (React, the design system, and `web_core`), styles only through design tokens, and is MIT licensed. A [scripted live demo](https://m3e.language-lit.com/a2ui/) streams four scenarios in the browser with no backend.

**uny/a2ui-compose** (`dev.ynagai.a2ui:a2ui-material3`) is a Compose Multiplatform renderer that draws Android, iOS, desktop (JVM), macOS and web (Kotlin/JS and Kotlin/Wasm) from a single `commonMain`. It targets the v1.0 specification only and carries no v0.8/v0.9 compatibility layer, so it is listed under v1.0 only — see the [protocol version](https://github.com/uny/a2ui-compose#protocol-version) note for why. The Material 3 module covers all 18 Basic Catalog components (every component the specification's 43 examples name), the built-in functions, `checks` validation and collection templates; `a2ui-core` is a Compose-free module with the protocol types, JSON Pointer binding and function evaluation, and `a2ui-compose` sits between the two with no design system attached, for hosts that bring their own widgets. Markdown in `Text` is a parser-free subset by default, with lists, tables and code fences behind an optional `a2ui-material3-markdown` module. The renderer fetches nothing itself — images go through a host-provided loader, and links are reduced to their labels so nothing opens a URL past `openUrl`. Apache-2.0, published to Maven Central, with a gallery app that replays the specification's examples on desktop, wasmJs and native macOS.

## Submitting a Renderer

If you have built an A2UI renderer, submit it to be listed here.

### How to submit

To submit a renderer, follow these steps:

1. **Fork** the [a2ui-project/a2ui](https://github.com/a2ui-project/a2ui) repository
2. **Edit** this file (`docs/ecosystem/renderers.md`) — add a row to the Community Renderers table with your renderer's name, platform, npm package (if any), version support, and a link to the source
3. **Open a PR** against `a2ui-project/a2ui` with a short description of your renderer
4. **Post in [GitHub Discussions](https://github.com/a2ui-project/a2ui/discussions)** — let the community know what you built! A short demo video goes a long way.

Need inspiration? Browse the **[community samples](../../../samples)** in the repo — these cover Angular, Lit, and ADK-based agents and are a good starting point.

### What makes a good community renderer?

A listing is more likely to be accepted and used if it meets the following criteria:

- Has **published source code** (open-source preferred, MIT or Apache 2.0).
- Clearly states **which A2UI spec version(s)** it supports (v0.8, v0.9, v1.0).
- Covers the **basic components** from the other A2UI renderers: text, buttons, inputs, basic layout components, etc.
- Includes a **README** with install instructions and a minimal usage example.
- Is **actively maintained** — flag it as archived if you're no longer supporting it.

Community renderers don't need to be production-ready to be listed — experimental and early-stage projects are welcome in the Notable Mentions section.

---

### Public Guides A2ui With Any Agent Framework (`docs/public/guides/a2ui-with-any-agent-framework.md`)

# Use A2UI with Any Agent Framework & Harness

A2UI is a declarative UI format. [AG-UI](https://ag-ui.com/) is the transport
that carries A2UI messages between an agent and an app. Use this guide to add
A2UI to an AG-UI app or harness backed by ADK, LangGraph, Mastra, Strands,
CrewAI, Google Chat, Slack, or any other agent framework or service that
supports AG-UI.

<style>
  .agui-demo-video {
    border-radius: 8px;
    display: block;
    margin: 24px auto;
    max-width: 100%;
    width: 75%;
  }

  @media (max-width: 700px) {
    .agui-demo-video {
      width: 100%;
    }
  }
</style>

<video class="agui-demo-video" controls playsinline preload="metadata">
  <source src="https://cdn.copilotkit.ai/docs/a2ui/ag-ui-a2ui-demo.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>

The examples below use AG-UI-compatible runtime tooling so you can focus on
the A2UI surface: enabling the renderer, giving your agent a catalog, and
streaming UI updates back to the user. For protocol-level setup and concepts,
see the [AG-UI docs](https://docs.ag-ui.com/).

## Agent skills

If you are using a coding agent to wire this up, load the
[AG-UI `ag-ui-a2ui-integration` skill](https://github.com/ag-ui-protocol/ag-ui/tree/main/skills/ag-ui-a2ui-integration)
before it modifies your app. It covers AG-UI framework adapters, supported
`create-ag-ui-app` flags, transport setup, A2UI runtime and renderer wiring,
and end-to-end verification for AG-UI + A2UI apps.

If your app uses CopilotKit for A2UI rendering, also load the
[CopilotKit `copilotkit` skill](https://github.com/CopilotKit/CopilotKit/blob/main/skills/copilotkit/SKILL.md)
for CopilotKit v2 runtime, provider, theme, and catalog conventions.

## 1. Set up AG-UI

Start from the agent framework you already use, then add an AG-UI runtime
connection between the agent and your app. The runtime streams agent events,
including A2UI messages, to the client surface.

Use the AG-UI CLI to scaffold an AG-UI app with the client and agent framework
you want:

```bash
npx create-ag-ui-app@latest
```

You can also start directly from supported framework templates:

```bash
npx create-ag-ui-app@latest --adk
npx create-ag-ui-app@latest --langgraph-py
npx create-ag-ui-app@latest --langgraph-js
```

Strands has no scaffold flag yet — wrap an existing Strands agent (see the
Strands panels below).

The important part is the transport contract: your app receives AG-UI events
and routes A2UI payloads to an A2UI renderer. Some scaffold paths use
[CopilotKit's A2UI runtime](https://docs.copilotkit.ai/generative-ui/a2ui)
with Next.js under the hood, but the setup surface stays AG-UI-first.

## 2. Set up your agent or harness

The A2UI steps are the same across frameworks: connect your agent to AG-UI,
enable A2UI payloads, and render those payloads in the app. Start with the
framework or harness you already use. The snippets below come from the
corresponding AG-UI integrations and show the framework-native agent shape
that AG-UI wraps.

=== "ADK"

    Use ADK when your agent already runs on Google's Agent Development Kit. The
    AG-UI ADK middleware exposes the agent as an AG-UI event stream:

    ```python
    from fastapi import FastAPI
    from ag_ui_adk import ADKAgent, AGUIToolset, add_adk_fastapi_endpoint
    from google.adk.agents import Agent

    my_agent = Agent(
        name="assistant",
        instruction="You are a helpful assistant.",
        tools=[
            AGUIToolset(),  # Adds tools provided by the AG-UI client.
        ],
    )

    agent = ADKAgent(
        adk_agent=my_agent,
        app_name="my_app",
        user_id="user123",
    )

    app = FastAPI()
    add_adk_fastapi_endpoint(app, agent, path="/chat")
    ```

    See the
    [AG-UI ADK middleware](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/adk-middleware/python).

=== "LangGraph (Python)"

    Use LangGraph when your agent workflow is a graph of stateful nodes. Start from
    your normal LangGraph agent — A2UI needs no extra tool wiring on the graph:

    ```python
    from copilotkit import CopilotKitMiddleware
    from langchain.agents import create_agent
    from langchain_google_genai import ChatGoogleGenerativeAI

    gemini = ChatGoogleGenerativeAI(
        model="gemini-2.5-pro",
        thinking_budget=1024,
    )

    # A plain LangGraph agent — no A2UI tool wiring on the graph. The CopilotKit
    # runtime forwards your frontend catalog and injects the `generate_a2ui` tool;
    # include CopilotKitMiddleware to get A2UI capability.
    graph = create_agent(
        model=gemini,
        tools=[],
        middleware=[CopilotKitMiddleware()],
        system_prompt="You are a helpful assistant.",
    )
    ```

    LangGraph's A2UI tool runs in the CopilotKit middleware layer, so include
    `CopilotKitMiddleware` to get A2UI capability. The CopilotKit runtime forwards
    your catalog and injects `generate_a2ui` automatically. The example uses Gemini
    via LangChain's Google GenAI integration.

    See the
    [AG-UI LangGraph integration](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/langgraph/python)
    and the
    [ChatGoogleGenerativeAI integration](https://docs.langchain.com/oss/python/integrations/chat/google_generative_ai).

=== "LangGraph (FastAPI)"

    Use the FastAPI variant when you serve the same LangGraph graph behind a FastAPI
    app. The agent shape is identical — export the same `graph` and serve it through
    the AG-UI LangGraph endpoint:

    ```python
    from copilotkit import CopilotKitMiddleware
    from langchain.agents import create_agent
    from langchain_google_genai import ChatGoogleGenerativeAI

    gemini = ChatGoogleGenerativeAI(
        model="gemini-2.5-pro",
        thinking_budget=1024,
    )

    graph = create_agent(
        model=gemini,
        tools=[],
        middleware=[CopilotKitMiddleware()],
        system_prompt="You are a helpful assistant.",
    )
    ```

    See the
    [AG-UI LangGraph integration](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/langgraph/python).

=== "LangGraph (TypeScript)"

    Use the TypeScript variant when your LangGraph agent is written in TypeScript.
    The shape mirrors the Python agent — a plain graph plus the CopilotKit
    middleware:

    ```ts
    import { createAgent } from "langchain";
    import { ChatOpenAI } from "@langchain/openai";
    import { copilotkitMiddleware } from "@copilotkit/sdk-js/langgraph";

    export const graph = createAgent({
      model: new ChatOpenAI({ model: "gpt-4o" }),
      tools: [],
      middleware: [copilotkitMiddleware],
      systemPrompt: "You are a helpful assistant.",
    });
    ```

    See the
    [AG-UI LangGraph TypeScript integration](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/langgraph/typescript).

=== "Strands (Python)"

    Use Strands when your agent orchestration is built on AWS Strands. Wrap a plain
    Strands agent with the AG-UI Strands adapter:

    ```python
    from strands import Agent
    from ag_ui_strands import StrandsAgent

    strands_agent = Agent(
        system_prompt="You are a helpful assistant.",
    )

    agent = StrandsAgent(
        agent=strands_agent,
        name="my-agent",
        description="A Strands agent exposed via AG-UI",
    )
    ```

    See the
    [AG-UI AWS Strands integration](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/aws-strands/python).

=== "Strands (TypeScript)"

    Use the TypeScript variant when your Strands agent is written in TypeScript. The
    AG-UI Strands adapter wraps the Strands agent for AG-UI clients:

    ```ts
    import { Agent } from "@strands-agents/sdk";
    import { StrandsAgent } from "@ag-ui/aws-strands";
    import { createStrandsApp } from "@ag-ui/aws-strands/server";

    const strandsAgent = new Agent({
      systemPrompt: "You are a helpful assistant.",
      tools: [],
    });

    const aguiAgent = new StrandsAgent({
      agent: strandsAgent,
      name: "MyAgent",
      description: "A Strands agent exposed via AG-UI",
    });

    const app = await createStrandsApp(aguiAgent, { path: "/invocations" });
    app.listen(8000);
    ```

    See the
    [AG-UI AWS Strands integration](https://github.com/ag-ui-protocol/ag-ui/tree/main/integrations/aws-strands/typescript).

=== "Slack"

    Use Slack when the user experience lives in a Slack app. Route the Slack thread
    into the same AG-UI agent endpoint. The same AG-UI event stream can feed a
    Slack harness and render A2UI through the surface's client bridge.

    <video class="agui-demo-video" controls playsinline preload="metadata">
      <source src="https://cdn.copilotkit.ai/docs/a2ui/ag-ui-slack-demo.mp4" type="video/mp4">
      Your browser does not support the video tag.
    </video>

    CopilotKit's Slack adapter already implements this pattern:

    ```ts
    import { createBot } from "@copilotkit/bot";
    import {
      slack,
      SanitizingHttpAgent,
      defaultSlackTools,
      defaultSlackContext,
    } from "@copilotkit/bot-slack";

    const bot = createBot({
      adapters: [
        slack({
          botToken: process.env.SLACK_BOT_TOKEN!,
          appToken: process.env.SLACK_APP_TOKEN!,
        }),
      ],
      agent: (threadId) => {
        const agent = new SanitizingHttpAgent({
          url: process.env.AGENT_URL!,
        });
        agent.threadId = threadId;
        return agent;
      },
      tools: [...defaultSlackTools],
      context: [...defaultSlackContext],
    });

    bot.onMention(async ({ thread }) => {
      await thread.runAgent();
    });

    await bot.start();
    ```

These snippets establish the AG-UI server connection. Slack uses the same
AG-UI/A2UI contract through its own harness and client bridge. The next
sections turn on A2UI rendering, catalogs, and component definitions inside the
app surface.

## 3. Enable A2UI

Start from the developer experience you want: define the catalog definitions the
agent can see, map each definition to a renderer, create the catalog, and pass
that catalog into CopilotKit. The frontend catalog config is the target A2UI
activation surface.

```tsx
import {CopilotKit, CopilotChat} from '@copilotkit/react-core/v2';
import {
  createCatalog,
  type CatalogDefinitions,
  type CatalogRenderers,
} from '@copilotkit/a2ui-renderer';
import {z} from 'zod';

// catalog definitions — describe the building block components to the agent
export const catalogDefinitions = {
  Card: {
    description: 'A titled card container.',
    props: z.object({title: z.string(), subtitle: z.string().optional()}),
  },
  PrimaryButton: {
    description: 'A styled primary button.',
    props: z.object({label: z.string(), action: z.any().optional()}),
  },
} satisfies CatalogDefinitions;

// catalog renderers — how each primitive renders in the DOM (React, in this example)
export const catalogRenderers = {
  Card: MyCard,
  PrimaryButton: MyPrimaryButton,
} satisfies CatalogRenderers<typeof catalogDefinitions>;

// definitions + renderers together define a catalog declaration
const catalog = createCatalog(catalogDefinitions, catalogRenderers, {
  catalogId: 'my-catalog',
  includeBasicCatalog: true,
});

<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{catalog}}>
  <CopilotChat />
</CopilotKit>;
```

Passing a catalog to the provider auto-enables A2UI and injects the
`generate_a2ui` tool, so your agent can produce surfaces with no extra runtime
config (CopilotKit ≥ 1.61.2). You can opt out, or opt in manually without a
catalog, by configuring the runtime directly:

```ts title="app/api/copilotkit/route.ts"
import {CopilotRuntime} from '@copilotkit/runtime';

const runtime = new CopilotRuntime({
  agents: {default: myAgent},
  a2ui: {injectA2UITool: true},
});
```

Scope to specific agents with `a2ui: { injectA2UITool: true, agents: ["my-agent"] }`.
For fixed-schema flows where your agent already returns `a2ui_operations`,
`a2ui: true` or `a2ui: {}` is enough.

### Custom components (BYOC)

A2UI ships with a built-in catalog (Text, Image, Card, …) that gets you a
working surface immediately. The expanded BYOC flow below shows the same
catalog pattern split across files for a real app:

1. **Definitions**: Zod schemas plus a natural-language description. This
   is what the agent sees in its system prompt. Note that for client-side functions, the client determines the function's execution boundary (such as clientOnly status) at runtime by reading its configuration from the active catalog definition.
2. **Renderers**: Typed React components, one per definition. This is
   what the user sees.
3. **Registration**: Pass the catalog through the provider so the A2UI
   renderer knows how to draw your components.

#### 1. Define component schemas

Create platform-agnostic definitions with Zod. The `description` field
gets injected into the agent's prompt so the LLM knows when to reach for
each component; the schema validates the props the agent sends.

```ts title="lib/a2ui/definitions.ts"
import {z} from 'zod';

export const myDefinitions = {
  StatusBadge: {
    description: 'A colored status badge.',
    props: z.object({
      text: z.string(),
      variant: z.enum(['success', 'warning', 'error']).optional(),
    }),
  },
  Metric: {
    description: 'A key metric with label and value.',
    props: z.object({
      label: z.string(),
      value: z.string(),
      trend: z.enum(['up', 'down']).optional(),
    }),
  },
};

export type MyDefinitions = typeof myDefinitions;
```

#### 2. Create React renderers

Map each definition to a React component. `createCatalog` is generic over
the definitions type, so the props your renderer receives are type-checked
against the Zod schema, so a typo in `props.text` is a compile error.

```tsx title="lib/a2ui/renderers.tsx"
'use client';

import {createCatalog, type CatalogRenderers} from '@copilotkit/a2ui-renderer';
import {myDefinitions, type MyDefinitions} from './definitions';

const myRenderers: CatalogRenderers<MyDefinitions> = {
  StatusBadge: ({props}) => {
    const colors = {
      success: {bg: '#dcfce7', text: '#166534'},
      warning: {bg: '#fef3c7', text: '#92400e'},
      error: {bg: '#fee2e2', text: '#991b1b'},
    };
    const c = colors[props.variant ?? 'success'];
    return (
      <span
        style={{
          padding: '2px 8px',
          borderRadius: 9999,
          fontSize: '0.75rem',
          background: c.bg,
          color: c.text,
        }}
      >
        {props.text}
      </span>
    );
  },

  Metric: ({props}) => (
    <div>
      <div style={{fontSize: '0.75rem', color: '#6b7280'}}>{props.label}</div>
      <div style={{fontSize: '1.5rem', fontWeight: 700}}>
        {props.value} {props.trend === 'up' ? '↑' : props.trend === 'down' ? '↓' : ''}
      </div>
    </div>
  ),
};

export const myCatalog = createCatalog(myDefinitions, myRenderers, {
  catalogId: 'my-app-catalog',
  includeBasicCatalog: true, // merges with built-in components
});
```

`catalogId` is the stable handle the agent uses to target this catalog;
`includeBasicCatalog: true` keeps the built-in components available
alongside your own (omit it to render _only_ your components).

#### 3. Pass the catalog to CopilotKit

```tsx title="app/layout.tsx"
'use client';

import {CopilotKitProvider} from '@copilotkit/react-core/v2';
import '@copilotkit/react-core/v2/styles.css';
import {myCatalog} from '@/lib/a2ui/renderers';

export default function Layout({children}: {children: React.ReactNode}) {
  return (
    <CopilotKitProvider runtimeUrl="/api/copilotkit" a2ui={{catalog: myCatalog}}>
      {children}
    </CopilotKitProvider>
  );
}
```

Agents will now see your custom components alongside the built-ins and
can use them in any A2UI surface they emit.

For the full BYOC reference (multiple catalogs, theming hooks, advanced
patterns), see CopilotKit's
[Custom Components (BYOC) section](https://docs.copilotkit.ai/generative-ui/a2ui).

## 4. Advanced usage

For the full A2UI integration surface (custom catalogs, fine-grained control,
advanced patterns), see CopilotKit's
[A2UI docs](https://docs.copilotkit.ai/generative-ui/a2ui).

## What's next

- **[A2UI Composer](https://a2ui-composer.ag-ui.com/)**: Build widgets visually.
- **[Concepts › Transports](../concepts/transports.md)**: How A2UI maps onto AG-UI.
- **[v0.9 specification](../specification/v0.9-a2ui.md)**: The underlying protocol.

---

### Public Guides A2ui Over Mcp (`docs/public/guides/a2ui_over_mcp.md`)

# A2UI over Model Context Protocol (MCP)

This guide shows you how to serve **rich, interactive A2UI interfaces** from an **MCP server** using Tools and Embedded Resources. By the end, you'll have a working MCP server that returns A2UI components to any MCP-compatible client.

<video width="100%" height="auto" controls playsinline style="display: block; aspect-ratio: 16/9; object-fit: cover; border-radius: 8px; margin-bottom: 24px;">
  <source src="../assets/guides-a2ui-over-mcp-tour.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>

## Prerequisites

Ensure you have the following installed before you begin:

- **Python** (version 3.10 or later).
- **[uv](https://docs.astral.sh/uv/)** for fast Python package management.
- **Node.js** (version 18 or later) for the MCP Inspector.

## Quick Start: Run the Sample

Before diving into the protocol details, let's get a working example running. The A2UI repository includes a ready-to-go MCP recipe demo.

```bash
# Clone the repo (if you haven't already)
git clone https://github.com/a2ui-project/a2ui.git
cd a2ui/samples/community/mcp/a2ui-over-mcp-recipe

# Start the MCP server (SSE transport on port 8000)
uv run .
```

### Option A: Interacting via the MCP Inspector

In a separate terminal, launch the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to interact with the server:

```bash
npx @modelcontextprotocol/inspector@latest --web --transport sse --server-url http://localhost:8000/sse
```

Open `http://localhost:6274`:

1. Click **List Resources** → you will see `a2ui://recipe-form` and `a2ui://recipe-card`.
2. Read a resource → the content contains the static A2UI presentation template (`createSurface` and `updateComponents`) with data bindings.
3. Click **List Tools** → you will see `get_recipe_form_a2ui` and `get_recipe_a2ui`, both carrying `_meta.ui` links to their respective presentation template resource.
4. Run `get_recipe_form_a2ui` → the tool returns the initial form selection state wrapped in an `updateDataModel` message.
5. Run `get_recipe_a2ui` with custom parameters → the tool returns dynamic recipe details wrapped in an `updateDataModel` message.

> [!NOTE]
> The sample uses a local path reference to the A2UI Agent SDK. For your own projects, install from PyPI:
>
> ```bash
> pip install a2ui-agent-sdk
> ```

### Option B: Running the Recipe Client Web App

To run the interactive web client:

> [!NOTE]
> Running built-in sample applications within the A2UI repository uses Yarn workspaces (`yarn install` / `yarn dev`). Outside this repository, you can use any package manager (npm, pnpm, yarn).

1. In a new terminal window, navigate to the client directory:
    ```bash
    cd client
    ```
2. Install dependencies:
    ```bash
    yarn install
    ```
3. Start the Vite development server:
    ```bash
    yarn dev
    ```
4. Open your browser to `http://localhost:5173`.

When the application loads, the client connects to the MCP server via SSE and executes `get_recipe_form_a2ui`. It reads `_meta.ui` to fetch and cache the `a2ui://recipe-form` presentation template, then applies the returned `updateDataModel` to populate default choices (`Grilled`, `Chicken`). Picking options and clicking **"Get Recipe"** executes `get_recipe_a2ui`, fetching `a2ui://recipe-card` and dynamically rendering the recipe details in the right column.



See all samples at [`samples/community/mcp/`](../../../samples/community/mcp).

## Decoupled Architecture: Separating Presentation from Data

A2UI over MCP separates user interfaces into two layers:

1. **Static Presentation Templates via MCP Resources (`resources/read`)**:
   Layouts containing component trees (`createSurface` and `updateComponents`) with data bindings (such as `/title`, `/cookTime`, `/image`) are served as MCP resources under custom URIs (e.g., `a2ui://recipe-form`, `a2ui://recipe-card`) with MIME type `application/a2ui+json`. Because templates contain no hardcoded data values, the client can fetch and cache them locally.
2. **Dynamic Data Updates via MCP Tools (`tools/call`)**:
   When a tool executes, the server returns only the dynamic values needed by the template, packaged as an A2UI `updateDataModel` message.
3. **Tool UI Metadata (`_meta.ui`)**:
   The tool links to its presentation template by including a `_meta.ui` object in its tool definition and in its `CallToolResult`:
    ```json
    "_meta": {
      "ui": {
        "resourceUri": "a2ui://recipe-card",
        "mimeType": "application/a2ui+json"
      }
    }
    ```
4. **Client-Side Resolution & Hydration**:
   The client host inspects `_meta.ui.resourceUri`, checks its local template cache (or fetches the resource from the server on first load), initializes the surface layout, and applies the dynamic `updateDataModel` from the tool response.

> [!IMPORTANT]
> **MIME Type Uniformity**
> Both static template resources and dynamic tool payloads use the `application/a2ui+json` MIME type. In tool responses, data model updates are returned inside an `EmbeddedResource` alongside a fallback `TextContent`. This identification allows client applications to route payloads directly to A2UI processors.

### Delivery Flow

```
1. Tool Invocation
Client → tools/call (e.g. get_recipe_a2ui) → MCP Server
                                                  ↓
                                        Compute dynamic values
                                                  ↓
Client ← CallToolResult (updateDataModel) ← MCP Server
         + _meta.ui: { resourceUri: "a2ui://recipe-card" }

2. Template Resolution (Cached After First Fetch)
If "a2ui://recipe-card" is not in client cache:
  Client → resources/read ("a2ui://recipe-card") → MCP Server
  Client ← Template (createSurface, updateComponents) ← MCP Server

3. Surface Hydration
Client applies updateDataModel from tool response to the surface.
A2UI Renderer updates display.
```

### 1. Defining Presentation Templates as MCP Resources

Expose static layout templates via `resources/list` and `resources/read`:

```python
@app.list_resources()
async def list_resources() -> list[types.Resource]:
    return [
        types.Resource(
            uri="a2ui://recipe-form",
            name="Recipe Form",
            mimeType="application/a2ui+json",
            description="Static form allowing users to pick cuisine and protein.",
        ),
        types.Resource(
            uri="a2ui://recipe-card",
            name="Recipe Card",
            mimeType="application/a2ui+json",
            description="Static recipe card layout template.",
        ),
    ]


@app.read_resource()
async def read_resource(uri: str) -> list[ReadResourceContents]:
    if str(uri) == "a2ui://recipe-form":
        return [
            ReadResourceContents(
                content=json.dumps(recipe_form_json),
                mime_type="application/a2ui+json",
            )
        ]
    if str(uri) == "a2ui://recipe-card":
        return [
            ReadResourceContents(
                content=json.dumps(recipe_a2ui_json),
                mime_type="application/a2ui+json",
            )
        ]
    raise ValueError(f"Unknown resource: {uri}")
```

### 2. Declaring Tool UI Metadata

Declare the presentation resource URI on the tool definition:

```python
types.Tool(
    name="get_recipe_a2ui",
    title="Get Recipe A2UI",
    description="Returns recipe data and links to the recipe-card template.",
    inputSchema={
        "type": "object",
        "properties": {
            "cookingStyle": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Selected cooking styles",
            },
            "protein": {
                "type": "array",
                "items": {"type": "string"},
                "description": "Selected proteins",
            },
        },
        "additionalProperties": True,
    },
    _meta={
        "ui": {
            "resourceUri": "a2ui://recipe-card",
            "mimeType": "application/a2ui+json",
        }
    },
)
```

### 3. Returning Dynamic Data via Tool Execution

In the tool call handler, return the dynamic state as an `updateDataModel` message with `_meta.ui`:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Catalog Negotiation

Before a server can send A2UI to a client, they must establish which catalogs are available. Depending on your architecture, this can happen in one of two ways.

### Option A: During MCP Initialization (Recommended)

MCP is a stateful session protocol, so the most efficient approach is to declare capabilities once during connection setup. The client declares its A2UI support under `capabilities`:

```json
{
  "jsonrpc": "2.0",
  "method": "initialize",
  "id": "init-123",
  "params": {
    "protocolVersion": "2025-11-25",
    "clientInfo": {
      "name": "a2ui-enabled-client",
      "version": "1.0.0"
    },
    "capabilities": {
      "a2ui": {
        "clientCapabilities": {
          "v0.9": {
            "supportedCatalogIds": [
              "https://a2ui.org/specification/v0_9/basic_catalog.json"
            ]
          }
        }
      }
    }
  }
}
```

The server stores this state for the duration of the session.

### Option B: Per-Message Metadata (For Stateless Servers)

If your server must remain stateless, the client can pass A2UI capabilities in the `_meta` field of every tool call:

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": "id-123",
  "params": {
    "name": "generate_report",
    "arguments": {"date": "2026-03-01"},
    "_meta": {
      "a2ui": {
        "clientCapabilities": {
          "v0.9": {
            "supportedCatalogIds": [
              "https://a2ui.org/specification/v0_9/basic_catalog.json"
            ],
            "inlineCatalogs": []
          }
        }
      }
    }
  }
}
```

## Handling User Actions

Interactive components like `Button` can trigger actions that are sent back to the server as MCP tool calls.

### 1. Define a Button with an Action

In your A2UI JSON, add an `action` to a component:

```json
{
  "id": "confirm-button",
  "component": {
    "Button": {
      "child": "confirm-button-text",
      "action": {
        "event": {
          "name": "confirm_booking",
          "context": {
            "start": "/dates/start",
            "end": "/dates/end"
          }
        }
      }
    }
  }
}
```

### 2. Client Sends the Action as a Tool Call

When the user clicks the button, the client resolves data bindings (like `/dates/start`) against the surface state and sends a tool call with the required action fields:

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": "id-456",
  "params": {
    "name": "a2ui_action",
    "arguments": {
      "name": "confirm_booking",
      "surfaceId": "booking-surface",
      "sourceComponentId": "confirm-button",
      "timestamp": "2026-03-20T12:00:00Z",
      "context": {
        "start": "2026-03-20",
        "end": "2026-03-25"
      }
    }
  }
}
```

### 3. Handle the Action on the Server

```python
@app.tool()
async def a2ui_action(
    name: str,
    surfaceId: str,
    sourceComponentId: str,
    timestamp: str,
    context: dict[str, Any],
) -> types.CallToolResult:
    """Handle A2UI user actions."""
    if name == "confirm_booking":
        # Process the booking, then return confirmation UI
        return types.CallToolResult(content=[
            types.TextContent(
                type="text",
                text=f"Booking confirmed for {surfaceId}: {context['start']} to {context['end']}"
            )
        ])
    raise ValueError(f"Unknown action: {name}")
```

> [!NOTE]
> All five action fields (`name`, `surfaceId`, `sourceComponentId`, `timestamp`, and `context`) are required by the A2UI specification. Declaring all fields in the tool parameters prevents MCP SDKs from stripping `surfaceId` or other fields, losing the originating surface context.

## Error Handling

Clients can report A2UI rendering and validation errors back to the server via a tool call:

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": "id-789",
  "params": {
    "name": "a2ui_error",
    "arguments": {
      "code": "VALIDATION_FAILED",
      "surfaceId": "booking-surface",
      "path": "/components/0/text",
      "message": "Failed to parse A2UI payload."
    }
  }
}
```

Handle it on the server:

```python
@app.tool()
async def a2ui_error(
    code: str,
    surfaceId: str,
    message: str,
    path: str | None = None,
) -> types.CallToolResult:
    """Handle A2UI client errors."""
    # Log the error, retry, or send a fallback UI
    return types.CallToolResult(content=[
        types.TextContent(
            type="text",
            text=f"Acknowledged error {code} on surface {surfaceId}: {message}"
        )
    ])
```

## Verbalization and Visibility Control

Control whether the LLM can "read" A2UI payloads in subsequent turns using MCP **Resource Annotations**:

```python
a2ui_resource = types.EmbeddedResource(
    type="resource",
    resource=types.TextResourceContents(
        uri="a2ui://training-plan-page",
        mimeType="application/a2ui+json",
        text=json.dumps(a2ui_payload)
    ),
    # Show the UI to the user, but hide the raw JSON from the LLM
    annotations=types.Annotations(audience=["user"])
)
```

| Audience        | Behavior                                               |
| --------------- | ------------------------------------------------------ |
| _(empty)_       | Visible to both user and LLM                           |
| `["user"]`      | Rendered for the user; hidden from LLM context         |
| `["assistant"]` | Available to LLM for follow-up reasoning; not rendered |

## Using the A2UI Agent SDK

For production use, the **A2UI Agent SDK** handles schema management, validation, and prompt generation for you:

```bash
pip install a2ui-agent-sdk
```

```python
from a2ui.core.basic_catalog import BasicCatalog
from a2ui.core.schema import ProtocolVersion
from a2ui.inference_formats.direct_json import DirectJsonFormat
from a2ui.utils import validate_payload

# Initialize the inference format with the basic catalog
inference_format = DirectJsonFormat([BasicCatalog(ProtocolVersion.V0_9)])

# Validate A2UI output before sending. This raises A2uiValidationError if a
# renderer holding the catalog would reject the payload.
selected_catalog = inference_format.catalogs[0]
validate_payload([selected_catalog], a2ui_payload)
```

See the full [Agent Development Guide](agent-development.md) for details on schema management, dynamic catalogs, and streaming.

## Next Steps

- [A2UI Specification](../specification/v0.9-a2ui.md) — full protocol reference
- [Component Gallery](../reference/components.md) — browse available components
- [MCP Apps in A2UI Surface](mcp-apps-in-a2ui.md) — embed HTML-based MCP apps inside A2UI
- [Client Setup](client-setup.md) — build a renderer that displays A2UI

---

### Public Guides Agent Development (`docs/public/guides/agent-development.md`)

# Agent Development Guide

Build AI agents that generate A2UI interfaces. This guide covers generating and streaming UI messages from LLMs.

## Quick Overview

Building an A2UI agent:

1. **Understand user intent** → Decide what UI to show
2. **Generate A2UI JSON** → Use LLM structured output or prompts
3. **Validate & stream** → Check schema, send to client
4. **Handle actions** → Respond to user interactions

## Start with a simple agent

This guide uses the ADK to build a simple agent, starting with text and upgrading it to A2UI.

See step-by-step instructions at the [ADK quickstart](https://google.github.io/adk-docs/get-started/python/).

```bash
pip install google-adk
adk create my_agent
```

> **TIP**: If you are using `uv` and working within the sample directories (or a project that already depends on `google-adk`), you can use `uv run adk` instead of installing it globally:
>
> ```bash
> uv run adk create my_agent
> ```

Then edit the `my_agent/agent.py` file with a very simple agent for restaurant recommendations.

```
/* Detailed source-code truncated for AI context efficiency. */
```

Don't forget to set the `GOOGLE_API_KEY` environment variable to run this example.

```bash
echo 'GOOGLE_API_KEY="YOUR_API_KEY"' > .env
```

You can test out this agent with the ADK web interface:

```bash
adk web
```

Select `my_agent` from the list, and ask questions about restaurants in New York. You should see a list of restaurants in the UI as plain text.

## Generating A2UI Messages

Getting the LLM to generate A2UI messages requires some prompt engineering. The SDK provides the `DirectJsonFormat` inference format to help you generate a system prompt that includes the A2UI schema and examples from your component catalog.

First, make sure you have `a2ui-agent-sdk` installed (it is included in the samples). The agent SDK does not depend on an agent framework. The A2A and ADK integrations are separate packages: install `a2ui-a2a` to serve A2UI over A2A, and `a2ui-adk[a2a]` to use the ADK toolset and converters.

In your agent file (e.g., `agent.py`), import the necessary classes:

```python
from a2ui.core.basic_catalog import BasicCatalog
from a2ui.core.schema import ProtocolVersion
from a2ui.inference_formats.direct_json import DirectJsonFormat
```

Then, you can use `DirectJsonFormat` to generate the system prompt. This ensures that the schema and examples are correctly formatted and up to date.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Understanding the Output

Your agent will no longer strictly output text. Instead, it will output text and a **JSON list** of A2UI messages.

The `A2UI_SCHEMA` that we imported is a standard JSON schema that defines valid operations like:

- `render` (displaying a UI)
- `update` (changing data in an existing UI)

Because the output is structured JSON, you may parse and validate it before sending it to the client.

```python
# 1. Parse the JSON
# Warning: Parsing the output as JSON is a fragile implementation useful for documentation.
# LLMs often put Markdown fences around JSON output, and can make other mistakes.
# Rely on frameworks to parse the JSON for you.
parsed_json_data = json.loads(json_string_cleaned)

# 2. Validate against A2UI_SCHEMA
# This ensures the LLM generated valid A2UI commands
jsonschema.validate(
    instance=parsed_json_data, schema=self.a2ui_schema_object
)
```

By validating the output against `A2UI_SCHEMA`, you ensure that your client never receives malformed UI instructions.

TODO: Continue this guide with examples of how to parse, validate, and send the output to the client renderer without the A2A extension.

---

### Public Guides Authoring Components (`docs/public/guides/authoring-components.md`)

# Authoring Custom Components

!!! tip "Authoring components for multiple frameworks?"

    See [Authoring Universal Components](authoring-universal-components.md) to learn how to write a single W3C Custom Element that works directly across Lit, React, and Angular renderers.

Learn how to define, implement, and register custom components in A2UI using the `rizzcharts` sample as an example. This guide focuses on authoring a component around your Angular code.

## Overview

Authoring a new component involves four main steps:

1.  **Define the Catalog Schema**: Specify the component's properties and types in a JSON Schema.
2.  **Define the Component (Client)**: Implement the UI using your framework (e.g., Angular).
3.  **Register with the Renderer (Client)**: Add the component to your client-side catalog.
4.  **Invoke from the Agent**: Instruct the agent to use the component via `send_a2ui_json_to_client`.

---

## 1. Defining the Catalog Schema

The catalog schema defines the API of your catalog. It lists available components and their properties, which the agent uses to construct UI payloads.

**This schema acts as a contract between the client and the server (agent).** Both must agree on this schema for rendering to work. The client advertises what catalogs it supports, and the server selects a compatible one. For details on how this handshake works, see [A2UI Catalog Negotiation](../concepts/catalogs.md#a2ui-catalog-negotiation).

In the [`rizzcharts`](../../../samples/community/agent/adk/rizzcharts/python/README.md) example, the catalog schema is defined in [`rizzcharts_catalog_definition.json`](../../../samples/community/agent/adk/rizzcharts/catalog_schemas/0.9/rizzcharts_catalog_definition.json).

Here is the schema for the `Chart` component:

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

## 2. Implementing the Component (Client)

Implement your component using your client-side framework. For Angular, your component should extend `CatalogComponent` provided by `@a2ui/angular/v0_9`.

In the `rizzcharts` example, the `Chart` component is defined in `chart.ts`.

First, define the component API in TypeScript. This should match the JSON Schema defined in Step 1.

```typescript
// api.ts
import {ComponentApi} from '@a2ui/web_core/v0_9';
import {z} from 'zod';

export const ChartApi = {
  name: 'Chart',
  schema: z.object({
    type: z.enum(['doughnut', 'pie']),
    title: z.string().optional(),
    chartData: z.array(
      z.object({
        label: z.string(),
        value: z.number(),
        drillDown: z.array(
          z.object({
            label: z.string(),
            value: z.number(),
          })
        ).optional(),
      })
    ),
  }).strict(),
} satisfies ComponentApi;
```

Now implement the Angular component:

```typescript
import {CatalogComponent} from '@a2ui/angular/v0_9';
import {Component, computed} from '@angular/core';
import {BaseChartDirective} from 'ng2-charts';
import {ChartApi} from './api';

@Component({
  selector: 'a2ui-chart',
  imports: [BaseChartDirective],
  template: `
    <div>
      <h2>{{ title() }}</h2>
      <canvas baseChart [data]="chartData()" [type]="chartType()"></canvas>
    </div>
  `,
})
export class Chart extends CatalogComponent<typeof ChartApi> {
  protected readonly chartType = computed(() => this.props()['type']?.value() || 'pie');
  protected readonly title = computed(() => this.props()['title']?.value() || '');
  protected readonly chartData = computed(() => {
    const rawData = this.props()['chartData']?.value() || [];
    return {
      labels: rawData.map(item => item.label),
      datasets: [
        {
          data: rawData.map(item => item.value),
        },
      ],
    };
  });
}
```

Keep these key points in mind when implementing components:

- **Extend `CatalogComponent`**: This gives you access to the type-safe `props` signal input.
- **Use `props()` Signal**: Access resolved properties reactively via `this.props()['propertyName']?.value()`. The framework automatically handles resolving data bindings and expressions.

---

## 3. Registering with the Renderer (Client)

Once the component is implemented, register it in your client catalog. This maps the component name (used by agents) to the implementation class.

You use the `AngularCatalog` class to define your catalog.

```typescript
import {AngularCatalog, BASIC_COMPONENTS, BASIC_FUNCTIONS} from '@a2ui/angular/v0_9';
import {Chart} from './chart';
import {ChartApi} from './api';

const customChartComponent = {
  ...ChartApi,
  component: Chart
};

export const RIZZ_CHARTS_CATALOG = new AngularCatalog(
  'https://github.com/.../rizzcharts_catalog_definition.json',
  [...BASIC_COMPONENTS, customChartComponent],
  BASIC_FUNCTIONS
);
```

Key points for registration:

- **Eager Registration**: Component classes are registered directly in the catalog definition.

---

## 4. Invoking from the Agent

To use the custom component, you initialize the agent with tools from the A2UI SDK that understand your catalog. The SDK handles resolving the catalog and providing examples to the model.

Here is how the flow wires up:

### 4.1 Session Preparation (Executor)

The execution layer (e.g., `RizzchartsAgentExecutor`) intercepts the incoming message to detect if A2UI is enabled and what catalogs the client supports. It resolves the catalog and saves it to the session state.

```python
# In agent_executor.py
from a2ui.inference_formats.direct_json import DirectJsonFormat
from a2ui.utils import resolve_catalogs

use_ui = try_activate_a2ui_extension(context)
if use_ui:
    # Resolve the catalogs based on client capabilities
    catalogs = resolve_catalogs(
        self.catalog_configs, capabilities, accepts_inline_catalogs=True
    )
    inference_format = DirectJsonFormat(catalogs, examples_path=self.examples_path)
    examples = inference_format.prompt_generator.generate_examples(validate=True)

    # Save to session (Event contains state_delta)
    await runner.session_service.append_event(
        session,
        Event(
            actions=EventActions(
                state_delta={
                    _A2UI_ENABLED_KEY: True,
                    _A2UI_CATALOGS_KEY: catalogs,
                    _A2UI_EXAMPLES_KEY: examples,
                }
            ),
        ),
    )
```

### 4.2 Agent Tool Setup

The Agent uses [SendA2uiToClientToolset](../../../python/a2ui_adk/src/a2ui/adk/send_a2ui_to_client_toolset.py) to give the agent a tool that it can use to send A2UI to the client.

```python
from a2ui.adk import SendA2uiToClientToolset
from a2ui.utils import resolve_catalogs

a2ui_catalogs = resolve_catalogs(self.catalog_configs, capabilities)
agent.tools = [
    SendA2uiToClientToolset(
        a2ui_enabled=True,
        a2ui_catalogs=a2ui_catalogs,
        a2ui_examples=examples,
    )
]
```

### 4.3 Tool Execution

Invocations of the tool in [SendA2uiToClientToolset](../../../python/a2ui_adk/src/a2ui/adk/send_a2ui_to_client_toolset.py) by the LLM are intercepted in the A2A Agent Executor using the [A2uiEventConverter](../../../python/a2ui_adk/src/a2ui/adk/a2a/event_converter.py). This automatically translates tool calls into A2A Dataparts with the A2UI payload.

```python
from a2ui.adk import A2uiEventConverter

config = A2aAgentExecutorConfig(event_converter=A2uiEventConverter())
```

---

### Public Guides Authoring Universal Components (`docs/public/guides/authoring-universal-components.md`)

# Authoring universal components

Universal components allow you to write a custom UI component once as a Web Component and use it directly across Lit, React, Angular, and more. They work for any renderer that implements support for A2UI universal web components.

## Quick start

Creating and using a universal component involves three steps:

1. **Define the component schema**: Declare the properties your component accepts.
2. **Build the component**: Implement the visual structure and behavior using `A2uiLitElement`.
3. **Register it in your app**: Add the component to your catalog in Lit, React, Angular, or another supported renderer.

This guide uses [Lit](https://lit.dev) (`A2uiLitElement`), the recommended way to build universal components. You can also use standard Web Components without Lit; see [Writing a component without Lit](#writing-a-component-without-lit).

Install `@a2ui/web_core`, `lit`, and `zod` alongside the renderer package for your host framework (`@a2ui/angular`, `@a2ui/react`, or `@a2ui/lit`):

```bash
npm install @a2ui/web_core lit zod
```

---

## 1. Define the component schema

Create an API definition with the component name and a Zod schema describing its properties. Use schemas from `@a2ui/web_core/v0_9` for values that the agent can bind to data model paths or actions.

```typescript
// stat-card.api.ts
import {z} from 'zod';
import {
  type ComponentApi,
  DynamicStringSchema,
  ChildListSchema,
  ActionSchema,
} from '@a2ui/web_core/v0_9';

export const StatCardApi = {
  name: 'StatCard',
  schema: z.object({
    title: DynamicStringSchema,
    value: DynamicStringSchema,
    changePercentage: z.number().optional(),
    trend: z.enum(['up', 'down', 'neutral']).optional(),
    action: ActionSchema.optional(),
    children: ChildListSchema.optional(),
  }),
} satisfies ComponentApi;
```

---

## 2. Build the component

A universal component is a class that extends `A2uiLitElement`, parameterized with the API from step 1 (`A2uiLitElement<typeof StatCardApi>`).

Your class needs to:

1. Set `protected override readonly api` to the API object. The base class uses its schema to resolve the incoming properties.
2. Implement `render()` and return a Lit template built from the resolved properties.
3. Optionally declare `static styles` for the component's CSS.

The base class gives you:

- `this.controller.props`: the resolved properties. Data-bound values arrive as plain values, `ActionSchema` properties arrive as functions you call to trigger the action (`props.action?.()`), and dynamic properties get a setter (`props.setValue()`) for two-way binding.
- `this.renderNode(childId)`: renders a child component referenced by your schema.

When you are done, export a `WebComponentImplementation`: the API, the custom element tag name, and the element class. This is the object you register in a catalog.

```
/* Detailed source-code truncated for AI context efficiency. */
```

The renderer registers the element in `customElements` (via `registerUniversalElement`) before rendering a surface, so the `@customElement` decorator is optional. You may keep the `@customElement` decorator if you also use the element outside A2UI.

---

## 3. Register and use the component in your application

To use `statCardComponent`, add it to a catalog and pass that catalog to your renderer:

=== "Angular"

    Add the component to an `AngularCatalog` and register the catalog with `provideA2Ui`. Set `useUniversalComponents: true` so the renderer mounts Web Component entries (without it they render a placeholder):

    ```typescript
    // app.config.ts
    import {ApplicationConfig} from '@angular/core';
    import {
      AngularCatalog,
      BASIC_COMPONENTS,
      BASIC_FUNCTIONS,
      provideA2Ui,
    } from '@a2ui/angular/v0_9';
    import {statCardComponent} from './stat-card.js';

    export const myCatalog = new AngularCatalog(
      'my-catalog',
      '0.9',
      [...BASIC_COMPONENTS, statCardComponent],
      BASIC_FUNCTIONS,
    );

    export const appConfig: ApplicationConfig = {
      providers: [
        provideA2Ui({
          catalogs: [myCatalog],
          useUniversalComponents: true,
          actionHandler: (action) => console.log('Action:', action),
        }),
      ],
    };
    ```

    Render a surface with `SurfaceComponent`. The custom element never appears in your own templates, so no `CUSTOM_ELEMENTS_SCHEMA` is needed:

    ```typescript
    // app.component.ts
    import {Component} from '@angular/core';
    import {SurfaceComponent} from '@a2ui/angular/v0_9';

    @Component({
      selector: 'app-root',
      standalone: true,
      imports: [SurfaceComponent],
      template: `<a2ui-v09-surface surfaceId="main" />`,
    })
    export class AppComponent {}
    ```

=== "React"

    Add the component to a `Catalog`, create a `MessageProcessor` with it, and render each surface with `A2uiSurface`:

    ```
/* Detailed source-code truncated for AI context efficiency. */
```

    You can mix React components and universal components in the same catalog and nest them in any order. React context, error boundaries, and event bubbling continue to work across universal components.

=== "Lit"

    Add the component to a `Catalog`, create a `MessageProcessor` with it, and pass each surface to the `<a2ui-surface>` element:

    ```
/* Detailed source-code truncated for AI context efficiency. */
```

When your application receives A2UI messages from an agent, pass them to `renderer.processMessages(messages)` (Angular) or `processor.processMessages(messages)` (React and Lit). See [Connecting to Agents](client-setup.md#connecting-to-agents) for transport setup and [Invoking from the Agent](authoring-components.md#4-invoking-from-the-agent) for exposing your catalog schema to the agent.

??? tip "Testing locally without an agent"

    To verify your component in the browser before connecting an agent transport, pass a sample `createSurface` and `updateComponents` payload (with a root component whose `id` is `'root'`) to `processMessages`:

    ```typescript
    processor.processMessages([
      {
        version: 'v0.9',
        createSurface: {surfaceId: 'main', catalogId: 'my-catalog'},
      },
      {
        version: 'v0.9',
        updateComponents: {
          surfaceId: 'main',
          components: [
            {
              id: 'root',
              component: 'StatCard',
              title: 'Revenue',
              value: '$12,400',
              changePercentage: 4.2,
              trend: 'up',
            },
          ],
        },
      },
    ]);
    ```

---

## Common patterns

### Handling actions

When your schema includes `ActionSchema`, the agent can send either a server event or a client-side function call. You do not need to check which type of action was sent. In your template, call `action()` directly:

```typescript
${props.action
  ? html`<button @click=${() => props.action?.()}>Open</button>`
  : nothing}
```

The agent payload sets up the action:

```json
{
  "id": "card-1",
  "component": "StatCard",
  "title": "Revenue",
  "value": "$24,500",
  "action": {
    "event": {
      "name": "VIEW_REVENUE_REPORT",
      "context": {
        "reportId": "q3-2026"
      }
    }
  }
}
```

When the user clicks the button, A2UI automatically resolves any context values and sends the event to the agent.

### Rendering child components

If your component is a container (like a grid, list, or card), add a child property to your schema using `ChildListSchema` or `ComponentIdSchema`.

In your template, call `this.renderNode(childId)` for each child ID:

```typescript
import {type ResolvedChildList} from '@a2ui/web_core/v0_9/universal';

override render() {
  const children: ResolvedChildList = this.controller.props.children ?? [];

  return html`
    <div class="card-grid">
      ${children.map((childId) => html`
        <div class="grid-item">
          ${this.renderNode(childId)}
        </div>
      `)}
    </div>
  `;
}
```

`this.renderNode()` resolves the child component from the surface model and renders it with the appropriate catalog implementation, whether it is a basic catalog component, another universal component, or a component written for the host framework (in React, a React component renders into its own host element).

### Two-way data binding for form inputs

For properties defined with dynamic schemas (such as `DynamicStringSchema`, `DynamicNumberSchema`, or `DynamicBooleanSchema`), A2UI automatically generates a typed setter method on `props`. For example, a property named `value` produces `setValue()`, while a property named `checked` produces `setChecked()`.

Calling the setter writes the new value directly back to the bound data model path:

```typescript
override render() {
  const props = this.controller.props;

  return html`
    <input
      type="text"
      .value=${props.value ?? ''}
      @input=${(e: Event) =>
        props.setValue((e.target as HTMLInputElement).value)}
    />
  `;
}
```

If the agent bound `value` to a data model path (for example, `{"path": "/user/name"}`), calling `props.setValue()` updates that path and automatically triggers re-renders for any other components bound to the same data.

### Styling and theming

Like any `LitElement`, an `A2uiLitElement` renders into a Shadow Root by default, so its `static styles` are encapsulated. CSS custom properties still inherit through the shadow boundary, which lets the host application theme the component without reaching inside it:

=== "Angular"

    In your global `styles.css` (or on `:host` in a component stylesheet, since Angular's default emulated view encapsulation scopes component selectors away from dynamically created custom elements):

    ```css
    /* Style custom element instances */
    a2ui-stat-card {
      --border-color: #3b82f6;
      --card-background: #eff6ff;
    }
    ```

=== "React"

    In your `App.css` or stylesheet:

    ```css
    /* Style custom element instances */
    a2ui-stat-card {
      --border-color: #3b82f6;
      --card-background: #eff6ff;
    }
    ```

=== "Lit"

    In `MyApp`'s `static styles` (which shares a shadow root with `<a2ui-surface>`):

    ```typescript
    static override styles = css`
      a2ui-stat-card {
        --border-color: #3b82f6;
        --card-background: #eff6ff;
      }
    `;
    ```

    If you are styling from a global page stylesheet (`index.html`) outside a Shadow DOM host like `<my-app>`, set the custom properties on `:root` or `my-app` so they inherit across `<my-app>`'s shadow boundary:

    ```css
    my-app {
      --border-color: #3b82f6;
      --card-background: #eff6ff;
    }
    ```

If you want the host application's global stylesheet, design system, or utility classes (such as Tailwind or Bootstrap) to apply inside your component, opt into the Light DOM by overriding `createRenderRoot()`:

```typescript
override createRenderRoot() {
  return this;
}
```

`A2uiLitElement` still applies your `static styles` in the Light DOM. It rewrites `:host` to the element's tag name, scopes the remaining selectors under it, and adopts the resulting stylesheet into the document (or the enclosing shadow root) once per tag.

### Writing a component without Lit

Lit simplifies data binding and event handling, but it is not required. You can achieve the same result using standard Web Components.

To build a universal component without Lit, your custom element must:

1. Extend `HTMLElement` and implement `A2uiWebComponentElement` by accepting a `context` property (`ComponentContext`) from the renderer.
2. Create a `GenericBinder(context, schema)` when connected and subscribe to resolved property updates to update the DOM.
3. Unsubscribe and dispose the `GenericBinder` when disconnected or re-bound.
4. Export a `WebComponentImplementation` with the API, `tagName`, and element class.

The example below implements these steps for a `StatBadgeApi` with `title` and `value` properties (defined like `StatCardApi` in step 1):

```
/* Detailed source-code truncated for AI context efficiency. */
```

Register `statBadgeComponent` in a catalog exactly like `statCardComponent` in step 3.

To render child components (after adding `children: ChildListSchema.optional()` to `StatBadgeApi.schema`), add a `renderChildren()` method to `StatBadgeElement` in `stat-badge.ts` and call it from `render()`. Reuse created elements across renders so children preserve their state:

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Public Guides Client Setup (`docs/public/guides/client-setup.md`)

# Client Setup Guide

Integrate A2UI into your application using the renderer for your platform.

## Renderers

| Renderer                                                      | Platform           | v0.8 | v0.9 | Status             |
| ------------------------------------------------------------- | ------------------ | ---- | ---- | ------------------ |
| **[React](../../../typescript/renderers/react)**              | Web                | ✅   | ✅   | ✅ Stable          |
| **[Lit (Web Components)](../../../typescript/renderers/lit)** | Web                | ✅   | ✅   | ✅ Stable          |
| **[Angular](../../../typescript/renderers/angular)**          | Web                | ✅   | ✅   | ✅ Stable          |
| **[Flutter (GenUI SDK)](https://docs.flutter.dev/ai/genui)**  | Mobile/Desktop/Web | ✅   | ✅   | ✅ Stable          |
| **Jetpack Compose**                                           | Android            | —    | —    | 🚧 Planned Q2 2026 |

For more see all [A2UI Renderers](../reference/renderers.md) and [Community A2UI Renderers](../ecosystem/renderers.md).

## Component Catalogs

A component catalog is any collection of components. A2UI provides a "Basic Catalog" but we expect you will add your own components, or shared libraries or fully replace the basic components with your own.

**Your design system is what matters.** You can register any collection of components and functions, and A2UI will work with them. The catalog is just the contract between your agent and your renderer.

See [Defining Your Own Catalog](defining-your-own-catalog.md) for how to define a catalog that matches your design system.

## Shared Web Library

All web renderers (Lit, Angular, React) share a common foundation: **`@a2ui/web_core`**. This library provides the message processor, state management, and data binding logic that every web renderer needs. Each framework-specific renderer builds on top of it, adding only the rendering layer for its framework.

This means core protocol handling is consistent across web platforms — only the component rendering differs.

The shared `web_core` library provides:

- **Message Processor**: Manages A2UI state and processes incoming messages.

## Web Components (Lit)

```bash
npm install @a2ui/lit @a2ui/web_core
```

Once installed, you can use the renderer in your app. The Lit renderer uses:

- **Message Processor**: Wraps the A2UI message processor.
- **`<a2ui-surface>` component**: Renders surfaces in your app.
- **Lit Signals**: Provides reactive state management for automatic UI updates.

**See working example:** [Lit shell sample](../../../samples/client/lit/shell) — Check its README for detailed run instructions.

## Angular

```bash
npm install @a2ui/angular @a2ui/web_core
```

Once installed, you can use the renderer in your app. The Angular renderer provides:

- **`A2uiRendererService`**: A service that manages the A2UI message processor and reactive model.
- **`a2ui-v09-component-host` component**: A dynamic component host that renders A2UI components from a surface.
- **`A2UI_RENDERER_CONFIG` token**: Used to configure the renderer with catalogs and action handlers.

### Setup Example (v0.9)

A2UI uses versioned imports for its protocol-specific implementations. For v0.9, configure your application providers using `provideA2Ui` as follows:

```typescript
import {ApplicationConfig} from '@angular/core';
import {provideA2Ui, BasicCatalog} from '@a2ui/angular/v0_9';

export const appConfig: ApplicationConfig = {
  providers: [
    provideA2Ui({
      catalogs: [new BasicCatalog()],
      actionHandler: action => {
        console.log('Action dispatched:', action);
      },
    }),
  ],
};
```

#### Dependency Injection in Action Handler

If your `actionHandler` needs to inject dependencies (for example, to call a service when an action is dispatched), you can pass a factory function to `provideA2Ui`. Within this factory function, you can use Angular's `inject()` function:

```typescript
import {ApplicationConfig, inject} from '@angular/core';
import {provideA2Ui, BasicCatalog} from '@a2ui/angular/v0_9';
import {MyActionDispatcherService} from './my-action-dispatcher.service';

export const appConfig: ApplicationConfig = {
  providers: [
    provideA2Ui(() => {
      const dispatcher = inject(MyActionDispatcherService);
      return {
        catalogs: [new BasicCatalog()],
        actionHandler: action => dispatcher.dispatch(action),
      };
    }),
  ],
};
```

**See working example:** [Angular samples](../../../samples/client/angular)

### Streaming

By default, the Angular client uses the streaming API. To disable streaming, set the `ENABLE_STREAMING` environment variable to `false` before starting the app:

```bash
export ENABLE_STREAMING=false
yarn start restaurant
```

> [!NOTE]
> **Package Manager Usage:** The `yarn start` command above is specific to running the sample application within the A2UI monorepo repository. For your own regular usage and standalone projects outside this repository, use the package manager of your choice (e.g. npm, pnpm).

## React

```bash
npm install @a2ui/react @a2ui/web_core
```

The React renderer provides:

- **`MessageProcessor` class**: A class that manages the A2UI message processor and reactive model.
- **`<A2UISurface>` component**: Renders A2UI surfaces in your React app
- **`useA2UI()` hook**: Accesses the message processor from any component

**See working example:** [React shell](../../../samples/client/react/shell)

## Flutter (GenUI SDK)

```bash
flutter pub add flutter_genui
```

Flutter uses the GenUI SDK which provides native A2UI rendering.

**Docs:** [GenUI SDK](https://docs.flutter.dev/ai/genui) | [GitHub](https://github.com/flutter/genui) | [README in GenUI Flutter Package](https://github.com/flutter/genui/blob/main/packages/genui/README.md#getting-started-with-genui)

## Connecting to Agents

Your client application needs to:

1. **Receive A2UI messages** from the agent (via transport)
2. **Process messages** using the Message Processor
3. **Send user actions** back to the agent

Common transport options:

- **Server-Sent Events (SSE)**: One-way streaming from server to client
- **WebSockets**: Bidirectional real-time communication
- **A2A Protocol**: Standardized agent-to-agent communication with A2UI support

See [samples/client/lit/shell/client.ts](../../../samples/client/lit/shell/client.ts) for an example of using the A2A protocol client.

**See:** [Transports guide](../concepts/transports.md)

## Handling User Actions

When users interact with A2UI components (clicking buttons, submitting forms, etc.), the client:

1. Captures the action event from the component
2. Resolves any data context needed for the action
3. Sends the action to the agent
4. Processes the agent's response messages

See the `@a2uiaction` event handler in `#maybeRenderData` in [samples/client/lit/shell/app.ts](../../../samples/client/lit/shell/app.ts) for an example of handling button clicks and form submissions.

## Error Handling

Common errors to handle:

- **Invalid Surface ID**: Surface referenced before `beginRendering` (v0.8) or `createSurface` (v0.9) was received.
- **Invalid Component ID**: Component IDs must be unique within a surface.
- **Invalid Data Path**: Check data model structure and JSON Pointer syntax.
- **Schema Validation Failed**: Verify message format matches A2UI specification.

See `try...catch` blocks in `#sendMessage` in [samples/client/lit/shell/app.ts](../../../samples/client/lit/shell/app.ts) for examples of handling communication errors.

## Next Steps

- **[Quickstart](../quickstart.md)**: Try the demo application
- **[Theming & Styling](theming.md)**: Customize the look and feel
- **[Defining Your Own Catalog](defining-your-own-catalog.md)**: Extend the component catalog
- **[Agent Development](agent-development.md)**: Build agents that generate A2UI
- **[Reference Documentation](../reference/messages.md)**: Deep dive into the protocol

---

### Public Guides Defining Your Own Catalog (`docs/public/guides/defining-your-own-catalog.md`)

# Defining Your Own Catalog

While the [Basic Catalog](../../../specification/v0_9/catalogs/basic/catalog.json) is useful for starting out and bootstrapping an application, most production applications will define their own catalog to reflect their specific design system.

By defining your own catalog, you restrict the agent to using exactly the components and visual language that exist in your application, rather than generic inputs or buttons.

## Why Define Your Own Catalog?

Every A2UI surface is driven by a **Catalog**. A catalog is simply a JSON Schema file that tells the agent which components, functions, and themes are available for it to use.

Defining your own catalog offers the following benefits:

- **Design System Alignment**: Restrict the agent to using exactly the components and visual language that exist in your application.
- **Security and Type Safety**: You register entire catalogs with your client application, ensuring that only trusted components are rendered.
- **No Mappers Needed**: It is recommended to build catalogs that directly reflect your client's design system rather than trying to map a generic catalog (like the Basic Catalog) to it through an adapter.

The Basic Catalog is just one example and is intentionally sparse to remain easily implementable by different renderers.

## How It Works

1.  **Define the Catalog**: Create a catalog definition (JSON Schema) listing the components, functions, and styles your application supports.
2.  **Register the Catalog**: Register the catalog and its corresponding component implementations (renderers) with your client application.
3.  **Announce Support**: The client informs the agent which catalogs it supports (via `supportedCatalogIds`).
4.  **Agent Selects Catalog**: The agent chooses a catalog for a given UI surface (via `catalogId` inside the creation message, like `createSurface`).
5.  **Agent Generates UI**: The agent generates component messages using the components defined in that catalog by name.

## Implementation Guide

It is recommended to create catalogs that directly map to your existing component library.

=== "Web (Lit / Angular / React)"

    To implement your own catalog on the web:

    - Create a JSON Schema containing your component definitions.
    - Create your own `Component` objects and `Catalog` object within your chosen web renderer.
        - Provide the schema or reference ID to the agent.

    _Detailed guides for each framework coming soon._

=== "Flutter"

    To implement your own catalog in Flutter:

    - Define a JSON Schema describing your widget properties.
    - Map the schema to Flutter widgets using a custom renderer.

    *Detailed Flutter integration guide coming soon.*

## Security Considerations

When defining and registering catalogs:

1.  **Allowlist components**: Only register components you trust in your catalog definition. Don't expose components that offer dangerous capabilities (e.g., executing arbitrary scripts) unless strictly controlled.
2.  **Validate properties**: Always validate component properties from agent messages to ensure they match expected type constraints.
3.  **Sanitize text**: Avoid rendering un-sanitized content provided by the agent unless safe bounds are established.

## Next Steps

- **[Theming & Styling](theming.md)**: Customize the look and feel of components.
- **[Component Reference](../reference/components.md)**: Explore standard types that might be available for reuse.
- **[Agent Development](agent-development.md)**: Build agents that interact with your Catalog.

---

### Public Guides Mcp Apps In A2ui (`docs/public/guides/mcp-apps-in-a2ui.md`)

# MCP Apps Integration in A2UI Surfaces

This guide explains how **Model Context Protocol (MCP) Applications** are integrated and displayed within the **A2UI** surface, along with the security model and testing guidelines.

> NOTE: Looking for the core A2UI-over-MCP protocol? See [A2UI over MCP](a2ui_over_mcp.md) for how to return A2UI JSON payloads from MCP tool calls.

## Overview

The Model Context Protocol (MCP) allows MCP servers to deliver rich, interactive HTML-based user interfaces to hosts. A2UI provides a secure environment to run these third-party applications.



## Double-Iframe Isolation Pattern

To run untrusted third-party code securely, A2UI utilizes a **double-iframe** isolation pattern. This approach isolates raw DOM injection from the main application while maintaining a structured JSON-RPC channel.

### Security Rationale

Standard single-iframe sandboxing with `allow-scripts` is often bypassed if combined with `allow-same-origin`, which defeats the containerization. Any iframe with `allow-scripts` and `allow-same-origin` can escape its sandbox by programmatically interacting with its parent DOM or removing its own sandbox attribute.

To prevent this, A2UI strictly excludes `allow-same-origin` for the inner iframe where the third-party application runs.

### The Architecture

1.  **[Sandbox Proxy (`sandbox.html`)](../../../samples/client/shared/mcp_apps_inner_iframe/sandbox.html)**: An intermediate `iframe` served from the same origin. It isolates raw DOM injection from the main app while maintaining a structured JSON-RPC channel.
    - Permissions: **Do not sandbox** in the host template (e.g., [`mcp-app.ts`](../../../samples/community/client/lit/mcp-apps-in-a2ui-sample/mcp-app.ts) or [`mcp-apps-component.ts`](../../../samples/community/client/lit/mcp-apps-in-a2ui-sample/ui/custom-components/mcp-apps-component.ts)).
    - Host origin validation: Validates that messages come from the expected host origin.
2.  **Embedded App (Inner Iframe)**: The innermost `iframe`. Injected dynamically via `srcdoc` with restricted permissions.
    - Permissions: `sandbox="allow-scripts allow-forms allow-popups allow-modals"` (**MUST NOT** include `allow-same-origin`, `allow-top-navigation`, or `allow-top-navigation-by-user-activation`).
    - Isolation: Removes access to `localStorage`, `sessionStorage`, `IndexedDB`, and cookies due to unique origin.
    - Top-level window hijacking defense: Omitting `allow-top-navigation` and `allow-top-navigation-by-user-activation` prevents embedded scripts from executing frame-busting attacks (such as `window.top.location = "..."`) to redirect the host window away.
    - Hyperlink exfiltration defense: Omitting `allow-popups` and capturing link navigations prevents untrusted content from exfiltrating data via clickjacking into spawned windows.

### Physical Iframe Nesting

```mermaid
flowchart TD
    subgraph "Host Application"
        A[A2UI Page] --> B["Host Component e.g., McpApp"]
    end
    subgraph "Sandbox Proxy"
        B -->|Message Relay| C[iframe sandbox.html]
    end
    subgraph "Embedded App"
        C -->|Dynamic Injection| D[inner iframe untrusted content]
    end
```

### End-to-End Architecture & Lifecycle Flow

The complete cycle—including layout tree hierarchy, completely separated backend actors (the Proxy Agent and the MCP Server), and how isolated third-party widgets interact reactively with their native siblings (e.g., the Pong game's scoreboard)—is detailed below:

```mermaid
graph TD
    %% 1. Top Tier (Strict vertical hierarchy)
    MCPServer["MCP App Server<br/>(Hosts widget resources & core tools)"]

    %% 2. Middle-Top Tier
    Agent["AI Agent<br/>(A2UI Backend Coordinator)"]

    %% 3. Subgraph for Host layout tree (Bottom Tier)
    subgraph HostApp ["Host Application"]
        direction TB
        Shell["A2UI Rendering Engine & State Manager<br/>(Orchestrates native layout & state bindings)"]

        subgraph LayoutTree ["A2UI Component Tree"]
            McpComponent["McpApp Component<br/>(Sandboxed HTML/JS Widget)"]
            SiblingComponent["Other A2UI Components<br/>(e.g., PongScoreBoard)"]
        end

        Shell <-->|"1. Initialize postMessage Event Bridge"| McpComponent
        Shell -.->|"5. Reactive State Update<br/>(e.g., Render updated score)"| SiblingComponent
    end

    %% Vertical Channel connecting Top to Middle-Top
    MCPServer ==>|"MCP Protocol (SSE / Stdio)"| Agent

    %% Unidirectional Data Cycle (Flowing vertically through the center)
    McpComponent ==>|"2. Tool Action Request<br/>(e.g., score_update)"| Shell
    Shell ==>|"3. Action Delegation (A2UI Protocol)"| Agent
    Agent ==>|"4. State Mutation & Sync (dataModelUpdate)"| Shell

    %% Style Sibling Relationship
    McpComponent -.->|"No Direct Access (Strictly Isolated)"| SiblingComponent
```

#### How the Sibling Update Loop Works:

1. **Initialize postMessage Event Bridge (1)**: The host shell instantiates the double-iframe sandbox and establishes a secure message relay bridge with the `McpApp` component.
2. **Tool Action Request (2)**: When a user interacts with the sandboxed app (e.g., scores a point in the Pong game), the app triggers a tool action by posting a message over the postMessage bridge.
3. **Action Delegation (3)**: The host layout engine intercepts the action and delegates its execution to the `AI Proxy Agent` over the A2UI/A2A protocol. The agent optionally coordinates with the `MCP App Server` using the standard MCP Protocol (SSE / Stdio) if external calculation or resources are required.
4. **State Mutation & Sync (4)**: The agent processes the action, mutates the master session state, and pushes a `dataModelUpdate` back to the host state manager.
5. **Reactive State Update (5)**: The host updates its local store, triggering a reactive update on sibling A2UI components (such as native scoreboards or displays) bound to that state path. Direct communication between the sandboxed component and native sibling elements is strictly blocked to maintain containerization security.

## Usage / Code Example

The MCP Apps component typically resolves to a `custom` node in the A2UI catalog. Here is how a developer might use it in their code.

### 1. Register within the Catalog

You must register the component in your catalog application. For example, in Angular:

```typescript
import {Catalog} from '@a2ui/web_core/v0_9';
import {z} from 'zod';
import {McpApp} from './mcp-app';
import {Button} from './button';
import {Snackbar} from './snackbar';

const McpAppSchema = z.object({
  content: z.union([z.string(), z.object({id: z.string()})]).optional(),
  allowedTools: z.array(z.string()).optional(),
  title: z.string().optional(),
});

export const DEMO_CATALOG = new Catalog(
  'my_app.org/some_catalog.json',
  'v0.9',
  [
    {name: 'McpApp', component: McpApp, schema: McpAppSchema},
    {
      name: 'Button',
      component: Button,
      schema: z.object({
        label: z.string(),
        action: z.any().optional(),
      }),
    },
    {
      name: 'Snackbar',
      component: Snackbar,
      schema: z.object({
        message: z.string(),
        durationMs: z.number().default(3000),
      }),
    },
  ]
);
```

### 2. Usage in A2UI Message

In the Host or Agent context, send an A2UI message that translates to this custom node.

```json
{
  "type": "custom",
  "name": "McpApp",
  "properties": {
    "content": "<h1>Hello, World!</h1>",
    "title": "My MCP App"
  }
}
```

If the content is complex or requires encoding, you can pass a URL-encoded string:

```json
{
  "type": "custom",
  "name": "McpApp",
  "properties": {
    "content": "url_encoded:%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E",
    "title": "My MCP App"
  }
}
```

## Communication Protocol

Communication between the Host and the embedded inner iframe is facilitated via a structured JSON-RPC channel over `postMessage`.

- **Events**: The Host Component listens for a `SANDBOX_PROXY_READY_METHOD` message from the proxy.
- **Bridging**: An `AppBridge` handles message relaying. Developers (specifically the MCP App Developer inside the untrusted iframe) can call tools on the MCP server using `bridge.callTool()`.
- **The Host**: Resolves callbacks (e.g., specific resizing, Tool results).

### Limitations

Because `allow-same-origin` is strictly omitted for the innermost iframe, the following conditions apply:

- The MCP app **cannot** use `localStorage`, `sessionStorage`, `IndexedDB`, or cookies. Each application runs with a unique origin.
- Direct DOM manipulation by the parent is blocked. All interactions must proceed via message passing.

## Prerequisites

To run the samples, ensure you have the following installed:

- **Python 3.10+** — Required for the agent and MCP server backends
- **[uv](https://docs.astral.sh/uv/)** — Fast Python package manager (used to run all Python samples)
- **Node.js 18+** and **Yarn** — Required for building and running the sample client apps within this monorepo workspace.
- **A `GEMINI_API_KEY`** — Required by all ADK-based agents. Get one from [Google AI Studio](https://aistudio.google.com/apikey)

> [!NOTE]
> **Package Manager Usage:** Running the built-in sample applications within the A2UI repository requires Yarn as configured by Corepack workspaces. For your own regular usage and standalone projects outside this repository, use the package manager of your choice (e.g. npm, pnpm).

> ⚠️ **Environment variable setup**: You can either export `GEMINI_API_KEY` in your shell or create a `.env` file in each agent directory. The agents use `dotenv` to load `.env` files automatically.
>
> ```bash
> # Option 1: Export in shell
> export GEMINI_API_KEY="your-api-key-here"
>
> # Option 2: Create .env file in the agent directory
> echo 'GEMINI_API_KEY=your-api-key-here' > .env
> ```

## Samples

There are two primary samples demonstrating MCP Apps integration. Each sample requires running **multiple terminals** — one for each backend service and one for the client.

---

### Sample 1: MCP App Standalone Sample (Lit Client & ADK Agent)

This sample verifies the sandbox with a Lit-based client and an ADK-based A2A agent.

#### Step 1: Start the Agent

In a separate terminal, navigate to the agent directory and start the agent:

```bash
cd samples/agent/adk/mcp-apps-in-a2ui-sample
uv run agent.py
```

The agent will run on `http://localhost:8000`.

#### Step 2: Start the Client

In a new terminal, navigate to the client directory and start the dev server (requires building the Lit renderer first):

```bash
cd samples/client/lit/mcp-apps-in-a2ui-sample
yarn install
yarn dev
```

The client starts at `http://localhost:5173/`.

#### Step 3: Open in Browser

Open your browser and navigate to `http://localhost:5173/`. You should see the A2UI interface loading the MCP App.

**What to expect**: A page loading the MCP App in a sandboxed iframe. Clicking the "Call Agent Tool" button inside the iframe will trigger an action that is handled by the agent.

---

### Sample 2: MCP Apps (Calculator + Pong) (Angular Client + MCP Server + Proxy Agent)

This sample verifies the sandbox with an Angular-based client, an MCP Proxy Agent, and a remote MCP Server. It requires **three** backend processes.

#### Step 1: Start the MCP Server (Calculator)

```bash
cd samples/community/mcp/mcp-apps-calculator/
uv run .
```

The MCP server starts on `http://localhost:8000` (or another port if 8000 is occupied, e.g. `uv run . --port 8001`) using SSE transport.

#### Step 2: Start the MCP Apps Proxy Agent

In a **new terminal**:

```bash
cd samples/community/agent/adk/mcp_app_proxy/
export GEMINI_API_KEY="your-key"  # or use a .env file
uv run .
```

The proxy agent starts on `http://localhost:10006` by default.

#### Step 3: Build and Start the Angular Client

First, build the renderer packages by running `yarn build:all` at the **repository root directory**:

```bash
# Run at repository root
yarn build:all
```

Then, in a **new terminal**, navigate to the client directory, install local dependencies, and start the app (which automatically bundles the sandbox iframe proxy and starts the development server):

```bash
# Navigate to the client directory
cd samples/community/client/angular/

# Install local dependencies
yarn install

# Start the app and bundle sandbox
yarn start mcp_calculator
```

> ⚠️ **`yarn build:all` is required**: `yarn build:all` compiles the A2UI renderer packages that the Angular app depends on. Running `yarn start mcp_calculator` automatically bundles the sandbox proxy into the Angular project's public assets before starting the server.

The client starts at `http://localhost:4200/`.

#### Step 4: Open in Browser

Navigate to:

```
http://localhost:4200/?disable_security_self_test=true
```

**What to expect**: A set of smart chips to load calculator app or pong app will be rendered. Both apps run in their own sandboxed iframes.

|                                                 Calculator App                                                 |                                 Pong App                                  |
| :------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------: |
|  |  |

---

## URL Options for Testing

For testing purposes, you can opt-out of the security self-test by using specific URL query parameters.

### `disable_security_self_test=true`

This query parameter allows you to bypass the security self-test that verifies iframe isolation. This is useful for debugging and testing environments where the double-iframe setup may not pass strict origin checks (e.g., `localhost` development).

Example usage:

```
http://localhost:4200/?disable_security_self_test=true
```

## Troubleshooting

| Problem                                           | Solution                                                                                         |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `GEMINI_API_KEY environment variable not set`     | Export the key or add a `.env` file in the agent directory                                       |
| Python version error on `restaurant_finder` agent | Install Python 3.13+ (required by that sample's `pyproject.toml`)                                |
| `yarn build:renderer` fails                       | Make sure you ran `yarn install` first in `samples/client/lit/`                                  |
| Angular client shows blank page                   | Ensure you ran `yarn build:sandbox` before `yarn start`                                          |
| MCP app iframe doesn't load                       | Check that both the MCP server (port 8000) and proxy agent (port 10006) are running              |
| `ng serve` not found                              | Run `yarn install` to install dev dependencies including `@angular/cli`                          |
| "URL with hostname not allowed"                   | Angular 21 restricts allowed hosts. Use `localhost` (the default) — do not pass `--host 0.0.0.0` |
| Security self-test fails in dev                   | Add `?disable_security_self_test=true` to the URL                                                |

---

### Public Guides Renderer Development (`docs/public/guides/renderer-development.md`)

# A2UI Renderer Implementation Guide

This document outlines the required features for a new renderer implementation of the A2UI protocol. It is intended for developers building new renderers (e.g., for React, Flutter, iOS, etc.).

> NOTE: Version-Aware Guide
>
> This guide provides implementation checklists for v0.8, v0.9.1 (Current Production), and v1.0 (Candidate). Use the tabs below to select the version you are targeting.

## Web Renderers: Use `@a2ui/web_core` (`web_core`)

If you're building a renderer for the web (React, Vue, Svelte, etc.), you don't need to implement message processing, state management, or schema validation from scratch. The **[`@a2ui/web_core`](../../../typescript/core/web_core)** package (`web_core`) provides all the framework-agnostic logic that the maintained Lit, Angular, and React renderers share.

### What `web_core` provides

| Module                                   | What it does                                                                                     |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------ |
| **`MessageProcessor`**                   | Processes the A2UI JSONL stream, dispatches messages, manages surface lifecycle                  |
| **`SurfaceModel` / `SurfaceGroupModel`** | State management for surfaces, components, and data models                                       |
| **`DataModel` / `DataContext`**          | Data binding resolution, path-based lookups, template list rendering                             |
| **`ComponentModel`**                     | Component tree state, adjacency list → tree resolution                                           |
| **Types & Schemas**                      | TypeScript types for all A2UI components, primitives, colors, styles, and JSON schema validation |
| **Expression parser**                    | Client-side function evaluation (v0.9+)                                                          |

### How the maintained renderers use it

All three web renderers follow the same pattern — `web_core` handles the protocol, the renderer handles the UI:

```typescript
// Types — shared across all renderers
import type * as Types from '@a2ui/web_core/types/types';
import type * as Primitives from '@a2ui/web_core/types/primitives';

// v0.8: Message processing and state
import {A2uiMessageProcessor} from '@a2ui/web_core/data/model-processor';

// v0.9.1 / v1.0: Message processing, surfaces, catalogs
import {MessageProcessor} from '@a2ui/web_core/v0_9';
import {SurfaceModel} from '@a2ui/web_core/v0_9';

// Styles and layout helpers
import * as Styles from '@a2ui/web_core/styles/index';
```

Your renderer only needs to:

1. **Map A2UI component types to your framework's components** (e.g., `Text` → `<p>`, `Button` → `<button>`)
2. **Subscribe to state changes** from `web_core` and re-render
3. **Forward user actions** back through the `MessageProcessor`

See the [React renderer](../../../typescript/renderers/react), [Lit renderer](../../../typescript/renderers/lit), and [Angular renderer](../../../typescript/renderers/angular) for working examples of this pattern.

### Version support

`web_core` exports API sets per version:

- `@a2ui/web_core/v0_8` — stable v0.8
- `@a2ui/web_core/v0_9` — v0.9/v0.9.1 support with `createSurface`, custom catalogs, client-side functions
- `@a2ui/web_core/v1_0` — candidate v1.0 support including RPC action responses

> TIP: Start with `web_core`
>
> Building a web renderer without `web_core` means reimplementing ~3,000 lines of message processing, state management, and schema validation. Unless you have a specific reason to diverge, use it.

---

## I. Core Protocol Implementation Checklist

This section details the fundamental mechanics of the A2UI protocol. A compliant renderer must implement these systems to successfully parse the server stream, manage state, and handle user interactions.

=== "v0.8"

    - **JSONL Stream Parsing**: Read a streaming response line by line, decoding each line as a distinct JSON object.
    - **Message Dispatcher**: Identify message types (`beginRendering`, `surfaceUpdate`, `dataModelUpdate`, `deleteSurface`) and route to the correct handler.
    - **Surface Management**:
        - Key surfaces by `surfaceId`.
        - Handle `surfaceUpdate`: Add/update components in the surface's buffer.
        - Handle `deleteSurface`: Remove the surface and all associated data/components.
    - **Component Buffering**:
        - Maintain a component buffer (e.g., `Map<String, Component>`) for each surface.
        - Reconstruct the UI tree by resolving `id` references (`children.explicitList`, `child`, `contentChild`, etc.).
    - **Data Model Store**:
        - Maintain data model state for each surface.
        - Handle `dataModelUpdate`: Update values at paths using the adjacency list representation (`[{ "key": "name", "valueString": "Bob" }]`).
    - **Progressive Rendering**:
        - Buffer updates until `beginRendering` is received.
        - Start rendering from the specified `root` ID upon receiving `beginRendering`. Apply theme styles.
    - **Data Binding Resolution**:
        - Resolve `BoundValue` objects using `literalString` / `literalNumber` / `path`.
    - **Dynamic Lists**:
        - For `children.template`, iterate over the data list at `template.dataBinding` and render components using `template.componentId`.
    - **Client-to-Server**:
        - Dispatch `userAction` containing context with resolved paths to the server.
        - Include `a2uiClientCapabilities` in transport metadata.

=== "v0.9.1 (Current)"

    - **JSONL Stream Parsing**: Read a streaming response line by line, decoding each line as a distinct JSON object.
    - **Message Dispatcher**: Identify message types (`createSurface`, `updateComponents`, `updateDataModel`, `deleteSurface`) and route to the correct handler.
    - **MIME Type Validation**: Intercept payloads based on the standardized `application/a2ui+json` MIME type.
    - **Surface Management**:
        - Key surfaces by `surfaceId`.
        - Handle `createSurface`: Create surface, bind `catalogId`, register `theme` and `sendDataModel`.
        - Handle `updateComponents`: Add/update components in flat format using `"component": "Type"` discriminators.
        - Handle `deleteSurface`: Remove the surface and all associated data/components.
    - **Component Buffering**:
        - Maintain a component buffer (e.g., `Map<String, Component>`) for each surface.
        - Reconstruct the UI tree by resolving ID references in container component `children` arrays or `child` fields.
    - **Data Model Store**:
        - Maintain data model state for each surface.
        - Handle `updateDataModel`: Update data at paths using standard JSON objects with upsert semantics.
    - **Progressive Rendering**:
        - Render immediately upon parsing a valid root component (ID `root`) in `updateComponents`. Do not wait for a special rendering signal.
    - **Data Binding Resolution**:
        - Resolve simplified bound values (either literals or `{"path": "..."}`).
    - **Dynamic Lists**:
        - For child templates, iterate over data arrays at `path` and render templates specified by `componentId`.
    - **Client-side Functions**:
        - Evaluate registered catalog-defined functions (e.g. `formatString` interpolation).
    - **Client-to-Server**:
        - Dispatch `action` (replaces `userAction`) containing context with resolved paths.
        - Automatically include the full client-side data model in the metadata if `sendDataModel` was requested.
        - Send structured `ValidationFailed` error messages to the server if a schema validation fails.

=== "v1.0 (Candidate)"

    All requirements from v0.9.1, with the following extensions:
    - **Surface Properties**:
        - Handle `createSurface` with `surfaceProperties` (renamed from `theme`). Custom primary brand colors are no longer supported inside the surface schema.
    - **Directional Function Calls (RPC)**:
        - Handle `callRendererFunction` messages from the agent and return `rendererFunctionResponse` (or `error`).
    - **Client-to-Server**:
        - Support initiating `callAgentFunction` messages to the agent for remote function execution.
        - If using A2A, every A2A `Message` sent to the server must include an `a2uiClientCapabilities` object in the `metadata` field of the A2A `Message`.
    - **Capabilities**:
        - Expose `surfaceProperties` in place of `theme` during capabilities exchange.

---

## II. Basic Component Catalog Checklist

To ensure a consistent user experience across platforms, A2UI defines a basic set of components. Your client should map these abstract definitions to their corresponding native UI widgets.

=== "v0.8"

    - **Text**: Render text. Support `usageHint` (h1-h5, body, caption).
    - **Image**: Render image from URL. Support `fit` and `usageHint` (avatar, hero, etc.).
    - **Icon**: Render system icons.
    - **Video**: Render video player.
    - **AudioPlayer**: Render audio player with description.
    - **Divider**: Render horizontal/vertical lines.
    - **Row** / **Column**: Arrange children horizontally/vertically. Support `distribution` and `alignment`. Support child `weight`.
    - **List**: Render scrollable list.
    - **Card**: Box layout with rounded corners and shadows.
    - **Tabs**: Tabbed navigation using `tabItems`.
    - **Modal**: Popup triggered by `entryPointChild` displaying `contentChild`.
    - **Button**: Clickable button triggering `userAction`. Support `primary` variant.
    - **CheckBox**: Boolean checkbox.
    - **TextField**: Input field supporting `label`, `textFieldType` (`shortText`, `longText`, etc.), and `validationRegexp`.
    - **MultipleChoice**: Support `options`, `maxAllowedSelections`, and single/multiple value selections.
    - **Slider**: Support ranges using `minValue`, `maxValue`.

=== "v0.9.1 (Current)"

    - **Text**: Render text. Support `variant` (replaces `usageHint`).
    - **Image**: Render image from URL. Support `fit` and `variant`.
    - **Icon**: Render system icons.
    - **Video**: Render video player.
    - **AudioPlayer**: Render audio player with description.
    - **Divider**: Render horizontal/vertical lines.
    - **Row** / **Column**: Arrange children horizontally/vertically. Support `justify` and `align`. Support child `weight`.
    - **List**: Render scrollable list.
    - **Card**: Box layout with rounded corners and shadows.
    - **Tabs**: Tabbed navigation using `tabs`.
    - **Modal**: Popup triggered by `trigger` displaying `content`.
    - **Button**: Clickable button triggering `action`. Support `variant` (primary, borderless).
    - **CheckBox**: Boolean checkbox.
    - **TextField**: Input field supporting `label`, `value` (replaces `text`), `variant` (`shortText`, `longText`, etc.), and `checks` (validation functions).
    - **ChoicePicker**: (Replaces MultipleChoice) Support `options` and `variant` (`mutuallyExclusive`, `multipleSelection`).
    - **Slider**: Support ranges using `min`, `max` (replaces `minValue`, `maxValue`).

=== "v1.0 (Candidate)"

    All components from v0.9.1, with the following extensions:
    - **Video**: Support the `posterUrl` property to display a preview image.
    - **TextField**: Support the `placeholder` property.

---

### Public Guides Theming (`docs/public/guides/theming.md`)

# Theming & Styling

Customize the look and feel of A2UI components to match your brand.

## The A2UI Styling Philosophy

A2UI follows a **renderer-controlled styling** approach by default, but allows for flexibility through catalogs:

- **Agents describe _what_ to show** (components and structure)
- **Renderers decide _how_ it looks** (colors, fonts, spacing)

However, the protocol is flexible enough to allow agents to influence styling when needed.

## Styling Layers

A2UI styling works in layers:

```mermaid
flowchart TD
    A["Agent-provided styling<br/>Semantic hints and theme data<br/>(e.g., usageHint: 'h1')"]
    B["Catalog Theming<br/>Catalog interprets theme data<br/>or uses defaults"]
    C["Platform theming<br/>Developer customizes<br/>(CSS variables, stylesheets...)"]
    D["Rendered Output"]

    A --> B --> C --> D
```

## Agent-provided styling information

### Semantic hints

Agents provide semantic hints (not visual styles) to guide rendering. In the _basic catalog_:

```json
{
  "id": "title",
  "component": {
    "Text": {
      "text": {"literalString": "Welcome"},
      "usageHint": "h1"
    }
  }
}
```

**Common `usageHint` values:**

- Text: `h1`, `h2`, `h3`, `h4`, `h5`, `body`, `caption`
- Other components have their own hints (see [Component Reference](../reference/components.md))

The catalog elements map these semantic hints to actual components on the target platform, and styles them.

### `theme` property

The A2UI protocol allows for an arbitrary `theme` property in the `createSurface` message. For now, this property is
defined as `z.any().optional()` in the Zod schema, meaning the agent can pass any JSON structure that the client
renderer and catalog understand.

- See the schema definition in [server-to-client.ts](../../../typescript/core/web_core/src/v0_9/schema/server-to-client.ts).
- See the `Catalog` class and `themeSchema` in [catalog/types.ts](../../../typescript/core/web_core/src/catalog/types.ts).

**Note:** The _basic catalog_ components are not wired to use the `theme` coming from the agent.

_Want to influence this design? Chime in here: [#1118](https://github.com/a2ui-project/a2ui/issues/1118)._

## Catalog theming

Theming is a responsibility of the catalog implementation. Each catalog can provide whatever theming solution it wants.
As an example, this is how the default _basic catalog_ does it:

### The Web Basic Catalog Theming

On the web, the _basic catalog_ provided by the default A2UI renderers is themed by overriding CSS variables.

Basic catalog components inject a small stylesheet with default values for these variables. The stylesheet targets
`:where(:root)` so their specificity is minimal, and the host app can override them easily.

For example, to override the primary color, you can simply add this to your app's CSS:

```css
:root {
  --a2ui-color-primary: #ff5722;
}
```

See the default styles in [default.ts](../../../typescript/core/web_core/src/universal/basic_catalog/styles/default.ts).

**See some examples per-platform:**

- [Lit samples](../../../samples/client/lit)
- [Angular samples](../../../samples/client/angular)
- [React samples](../../../samples/client/react)

### Per-component overrides

Beyond global theming, each component of the _basic catalog_ exposes custom variables to further refine its appearance.
For example, the `Card` component exposes a `--a2ui-card-background` variable.

Check the documentation of each component to see what variables it exposes.

## Common Styling Features

### Dark Mode

The default web renderers support automatic dark mode based on system preferences (`prefers-color-scheme`).

To always force dark or light mode (or to programmatically control switching), use the classnames `a2ui-light` or
`a2ui-dark` in an ancestor element of the generated code.

### Custom Fonts

Fonts can be loaded as in any other web application. The _basic catalog_ components attempt to inherit the font family
of their container, but offer two overridable values: `--a2ui-font-family-title` and `--a2ui-font-family-monospace` to
set a different font for headings and monospace text blocks.

## Flutter

Flutter has built-in theming support. See:

- [Use themes to share colors and font styles](https://docs.flutter.dev/cookbook/design/themes) from the Flutter docs.

## Best Practices

### 1. Use Semantic Hints, Not Visual Properties

When defining your components, agents should provide semantic hints (`usageHint`), never visual styles:

```json
// ✅ Good: Semantic hint
{
  "component": {
    "Text": {
      "text": {"literalString": "Welcome"},
      "usageHint": "h1"
    }
  }
}

// ❌ Bad: Visual properties (not supported)
{
  "component": {
    "Text": {
      "text": {"literalString": "Welcome"},
      "fontSize": 24,
      "color": "#FF0000"
    }
  }
}
```

### 2. Maintain Accessibility

- Ensure sufficient color contrast (WCAG AA: 4.5:1 for normal text, 3:1 for large text)
- Test with screen readers
- Support keyboard navigation
- Test in both light and dark modes

### 3. Use Design Tokens

Define reusable design tokens (colors, spacing, etc.) and reference them throughout your styles for consistency.

### 4. Test Across Platforms

- Test your theming on all target platforms (web, mobile, desktop)
- Verify both light and dark modes
- Check different screen sizes and orientations
- Ensure consistent brand experience across platforms

## Next Steps

- **[Defining Your Own Catalog](defining-your-own-catalog.md)**: Build custom components with your styling
- **[Component Reference](../reference/components.md)**: See styling options for all components
- **[Client Setup](client-setup.md)**: Set up the renderer in your app

---

### Public Introduction Agent Ui Ecosystem (`docs/public/introduction/agent-ui-ecosystem.md`)

# How Does A2UI Compare?

The agentic UI space is evolving rapidly. Here's how A2UI relates to the other major approaches.

## At a Glance

|                    | **A2UI**                                        | **MCP Apps**                                                                     | **AG-UI**                                                |
| ------------------ | ----------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------- |
| **Approach**       | Declarative component blueprints                | Pre-built HTML via `ui://` URIs                                                  | High-bandwidth protocol connecting backends to frontends |
| **Rendering**      | Native components (Angular, Flutter, Lit, etc.) | Sandboxed `iframe`                                                               | Developer-defined (any framework)                        |
| **Styling**        | Host app controls: inherits design system       | Isolated: remote server controls appearance                                      | Developer controls: part of the host app                 |
| **Security**       | Declarative data, no code execution             | Sandboxed iframe isolation                                                       | Trusted code within your own app                         |
| **Multi-agent**    | ✅ Across trust boundaries                      | ✅ Multiple MCP servers                                                          | ⚠️ Primarily single-agent                                |
| **Cross-platform** | ✅ Web, mobile, desktop, native                 | ⚠️ Web-focused (iframe)                                                          | ✅ Protocol is framework-agnostic                        |
| **LLM generation** | ✅ Designed for streaming output                | ❌ Pre-built by server                                                           | ✅ Via A2UI integration                                  |
| **Spec**           | Open protocol (Apache 2.0)                      | [MCP extension](https://modelcontextprotocol.io/docs/extensions/apps) (SEP-1865) | Open source (by CopilotKit)                              |

## A2UI vs MCP Apps

[MCP Apps](https://blog.modelcontextprotocol.io/posts/2025-11-21-mcp-apps/) treat UI as a **resource**: servers provide pre-built HTML via `ui://` URIs, rendered in sandboxed iframes. The remote integration controls all content and appearance, with configuration happening through tool calling. A2UI takes a **declarative UI** approach: agents send component blueprints, but the host application controls styling, theming, and how those components are configured and rendered. Choose MCP Apps when the server should own the full UI experience; choose A2UI when you want dynamic, cross-platform UI that fits naturally into your app.

## A2UI vs AG-UI / CopilotKit

[AG-UI](https://ag-ui.com/) is a **transport protocol** connecting agent backends to frontends with real-time state sync. A2UI is a **UI format**: the payload that describes what to render. They're complementary: use AG-UI as the pipe, A2UI as the content. AG-UI is a project by the [CopilotKit](https://copilotkit.ai) team. AG-UI has day-zero A2UI compatibility.

## A2UI vs ChatKit (OpenAI)

[ChatKit](https://platform.openai.com/docs/guides/chatkit) offers a tightly integrated experience within the OpenAI ecosystem. A2UI shares some design philosophy with ChatKit: both define a set of basic components and use a configurable, declarative abstraction layer. A2UI is **platform-agnostic** and designed for developers building their own agentic surfaces across web, mobile, and desktop, or for multi-agent systems where agents need to render UI across trust boundaries.

## Using Them Together

These approaches are complementary, not competing:

- **A2UI + AG-UI**: AG-UI as transport, A2UI as the generative UI format.
- **A2UI + A2A**: A2UI messages sent via the [A2A protocol](../concepts/transports.md) for multi-agent systems.
- **A2UI + MCP**: Upcoming bridge lets MCP servers provide A2UI blueprints alongside HTML resources.

## Further Reading

For more information, see the following resources:

- [What is A2UI?](what-is-a2ui.md): Protocol overview.
- [Transports](../concepts/transports.md): How A2UI messages travel between agents and clients.
- [Where is A2UI Used?](../ecosystem/a2ui-in-the-world.md): Case studies and adopters.

---

### Public Introduction How To Use (`docs/public/introduction/how-to-use.md`)

# How to Use A2UI

Choose the integration path that matches your role and use case.

## Three Paths

### Path 1: Building a Host Application (Frontend)

Integrate A2UI rendering into your existing app or build a new agent-powered frontend.

**Choose a renderer:**

- **Web:** Lit, Angular, React.
- **Mobile/Desktop:** Flutter GenUI SDK.

**Quick setup:**

For Angular:

```bash
npm install @a2ui/angular @a2ui/web_core
```

For React:

```bash
npm install @a2ui/react @a2ui/web_core
```

Connect to agent messages (SSE, WebSockets, or A2A) and customize styling to match your brand.

**Next:** [Client Setup Guide](../guides/client-setup.md) | [Theming](../guides/theming.md)

---

### Path 2: Building an Agent (Backend)

Create an agent that generates A2UI responses for any compatible client.

**Choose your framework:**

- **Python:** Google ADK, LangChain, custom.
- **Node.js:** A2A SDK, Vercel AI SDK, custom.

Include the A2UI schema in your LLM prompts, generate JSONL messages, and stream to clients over SSE, WebSockets, or A2A.

**Next:** [Agent Development Guide](../guides/agent-development.md)

---

### Path 3: Using an Existing Framework

Use A2UI through frameworks with built-in support:

- **[AG-UI / CopilotKit](https://ag-ui.com/)** - Full-stack agentic app framework with A2UI rendering.
- **[Flutter GenUI SDK](https://docs.flutter.dev/ai/genui)** - Cross-platform generative UI (uses A2UI internally).

**Next:** [Agent UI Ecosystem](agent-ui-ecosystem.md) | [Where is A2UI Used?](../ecosystem/a2ui-in-the-world.md)

---

### Public Introduction What Is A2ui (`docs/public/introduction/what-is-a2ui.md`)

# What is A2UI?

**A2UI (Agent to UI) is a declarative UI protocol for agent-driven interfaces.** AI agents generate rich, interactive UIs that render natively across platforms (web, mobile, desktop) without executing arbitrary code.

## The Problem

**Text-only agent interactions are inefficient:**

```
User: "Book a table for 2 tomorrow at 7pm"
Agent: "Okay, for what day?"
User: "Tomorrow"
Agent: "What time?"
...
```

**Better:** Agent generates a form with date picker, time selector, and submit button. Users interact with UI, not text.

## The Challenge

In multi-agent systems, agents often run remotely (different servers, organizations). They can't directly manipulate your UI—they must send messages.

**Traditional approach:** Send HTML/JavaScript in iframes.

- Heavy, visually disjointed.
- Security complexity.
- Doesn't match app styling.

**Need:** Transmit UI that's safe like data, expressive like code.

## The Solution

A2UI: JSON messages describing UI that:

- LLMs generate as structured output.
- Travel over any transport (A2A, AG-UI, SSE, WebSockets).
- Client renders using its own native components.

**Result:** Client controls security and styling, agent-generated UI feels native.

### Example

=== "v0.8 (Legacy)"

    ```jsonl
    {
      "surfaceUpdate": {
        "surfaceId": "booking",
        "components": [
          {
            "id": "title",
            "component": {
              "Text": {
                "text": { "literalString": "Book Your Table" },
                "usageHint": "h1"
              }
            }
          },
          {
            "id": "datetime",
            "component": {
              "DateTimeInput": {
                "value": { "path": "/booking/date" },
                "enableDate": true
              }
            }
          },
          {
            "id": "submit-text",
            "component": {
              "Text": {
                "text": { "literalString": "Confirm" }
              }
            }
          },
          {
            "id": "submit-btn",
            "component": {
              "Button": {
                "child": "submit-text",
                "action": { "name": "confirm_booking" }
              }
            }
          }
        ]
      }
    }
    {
      "dataModelUpdate": {
        "surfaceId": "booking",
        "contents": [
          {
            "key": "booking",
            "valueMap": [
              { "key": "date", "valueString": "2025-12-16T19:00:00Z" }
            ]
          }
        ]
      }
    }
    {
      "beginRendering": {
        "surfaceId": "booking",
        "root": "title"
      }
    }
    ```

=== "v0.9 (Stable)"

    ```jsonl
    {
      "version": "v0.9.1",
      "createSurface": {
        "surfaceId": "booking",
        "catalogId": "https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"
      }
    }
    {
      "version": "v0.9.1",
      "updateComponents": {
        "surfaceId": "booking",
        "components": [
          {
            "id": "title",
            "component": "Text",
            "text": "Book Your Table",
            "variant": "h1"
          },
          {
            "id": "datetime",
            "component": "DateTimeInput",
            "value": { "path": "/booking/date" },
            "enableDate": true
          },
          {
            "id": "submit-text",
            "component": "Text",
            "text": "Confirm"
          },
          {
            "id": "submit-btn",
            "component": "Button",
            "child": "submit-text",
            "variant": "primary",
            "action": {
              "event": { "name": "confirm_booking" }
            }
          }
        ]
      }
    }
    {
      "version": "v0.9.1",
      "updateDataModel": {
        "surfaceId": "booking",
        "path": "/booking",
        "value": {
          "date": "2025-12-16T19:00:00Z"
        }
      }
    }
    ```

    A2UI messages use `createSurface` to initialize the surface, a flat component structure, and include a `version` field.

Client renders these messages as native components (Angular, Flutter, React, etc.).

## Core Value

**1. Security:** Declarative data, not code. Agent requests components from client's trusted catalog. No code execution risk.

**2. Native Feel:** No iframes. Client renders with its own UI framework. Inherits app styling, accessibility, performance.

**3. Portability:** One agent response works everywhere. Same JSON renders on web (Lit/Angular/React), mobile (Flutter/SwiftUI/Jetpack Compose), desktop.

## Design Principles

**1. LLM-Friendly:** Flat component list with ID references. Easy to generate incrementally, correct mistakes, stream.

**2. Framework-Agnostic:** Agent sends abstract component tree. Client maps to native widgets (web/mobile/desktop).

**3. Separation of Concerns:** Three layers—UI structure, application state, client rendering. Enables data binding, reactive updates, clean architecture.

## What A2UI Is NOT

- Not a framework (it is a protocol).
- Not a replacement for HTML (for agent-generated UIs, not static sites).
- Not a robust styling system (client controls styling with limited server-side styling support).
- Not limited to web (works on mobile and desktop).

## Key Concepts

A2UI relies on the following key concepts:

- **Surface**: Canvas for components (dialog, sidebar, main view).
- **Component**: UI element (Button, TextField, Card, etc.).
- **Data Model**: Application state, components bind to it.
- **Catalog**: Available component types.
- **Message**: JSON object (`surfaceUpdate`, `dataModelUpdate`, `beginRendering`, etc.).

For a comparison of similar projects, see [Agent UI Ecosystem](agent-ui-ecosystem.md).

---

### Public Introduction Who Is It For (`docs/public/introduction/who-is-it-for.md`)

# Who is A2UI For?

Developers building AI agents with rich, interactive UIs.

## Three Audiences

### 1. Host App Developers (Frontend)

Build multi-agent platforms, enterprise assistants, or cross-platform apps where agents generate UI.

**Why A2UI:**

- Brand control: client owns styling and design system.
- Multi-agent: support local, remote, and third-party agents.
- Secure: declarative data, no code execution.
- Cross-platform: web, mobile, desktop.
- Interoperable: open source, same spec with multiple renderers.

**Get started:** [Client Setup](../guides/client-setup.md) | [Theming](../guides/theming.md) | [Defining Your Own Catalog](../guides/defining-your-own-catalog.md)

### 2. Agent Developers (Backend/AI)

Build agents that generate forms, dashboards, and interactive workflows.

**Why A2UI:**

- LLM-friendly: flat structure, easy to generate incrementally.
- Rich interactions: beyond text (forms, tables, visualizations).
- Generations not tools: UI as part of the generated output from the agent.
- Portable: one agent response works across all A2UI clients.
- Streamable: progressive rendering as you generate.

**Get started:** [Agent Development](../guides/agent-development.md)

### 3. Platform Builders (SDK Creators)

Build agent orchestration platforms, frameworks, or UI integrations.

Do you bring remote agents into your app?

Do you ship your agent into other apps you don't necessarily control?

**Why A2UI:**

- Standard protocol: interoperable with A2A and other transports.
- Extensible: custom component catalogs.
- Open source (Apache 2.0).

**Get started:** [Community](../ecosystem/community.md) | [Roadmap](../roadmap.md)

---

## When to Use A2UI

Use A2UI in the following scenarios:

- **Agent-generated UI**: Core purpose.
- **Multi-agent systems**: Standard protocol across trust boundaries.
- **Cross-platform apps**: One agent, many renderers (web/mobile/desktop).
- **Security critical**: Declarative data, no code execution.
- **Brand consistency**: Client controls styling.

Do not use A2UI for:

- **Static websites**: Use HTML/CSS.
- **Simple text-only chat**: Use Markdown.
- **Remote widgets not integrated with client**: Use iframes, like [MCP Apps](../introduction/agent-ui-ecosystem.md).
- **Rapid UI + Agent app built together**: Use [AG-UI / CopilotKit](../introduction/agent-ui-ecosystem.md).

See [Agent UI Ecosystem](../introduction/agent-ui-ecosystem.md) for a detailed comparison.

---

### Public Reference Agents (`docs/public/reference/agents.md`)

# Agents (Server-Side)

Agents are server-side programs that generate A2UI messages in response to user requests.

The actual component rendering is done by the [renderer](renderers.md),
after messages are [transported](../concepts/transports.md) to the client.
The agent is only responsible for generating the A2UI messages.

## How Agents Work

The agent workflow typically involves the following steps:

1. **Receive** user message.
2. **Process** with LLM (Gemini, GPT, Claude, etc.).
3. **Generate** A2UI JSON messages as structured output.
4. **Send** to client via transport.

User interactions from the client can be treated as new user input.

## Sample Agents

The A2UI repository includes sample agents you can learn from:

- [Restaurant Finder](../../../samples/agent/adk/restaurant_finder)
    - Table reservations with forms.
    - Written with the ADK.
- [Rizzcharts](../../../samples/community/agent/adk/rizzcharts/python)
    - A2UI Custom components demo.
    - Written with the ADK.
- [Orchestrator](../../../samples/community/agent/adk/orchestrator)
    - Passes A2UI messages from remote subagents.
    - Written with the ADK.

## Agent Types in A2A

### 1. User Facing Agent (standalone)

A user facing agent is one that is directly interacted with by the user.

### 2. User Facing Agent as a host for a Remote Agent

This is a pattern where the user facing agent is a host for one or more remote agents. The user facing agent will call the remote agent and the remote agent will generate the A2UI messages. This is a common pattern in [A2A](https://a2a-protocol.org) with the client agent calling the server agent.

In this pattern, the user-facing agent can handle messages in two ways:

- The user facing agent may "passthrough" the A2UI message without altering them.
- The user facing agent may alter the A2UI message before sending it to the client.

### 3. Remote Agent

A remote agent is not directly a part of the user facing UI. Instead it is registered in as a remote agent and can be called by the user facing agent. This is a common pattern in [A2A](https://a2a-protocol.org) with the client agent calling the server agent.

---

### Public Reference Components (`docs/public/reference/components.md`)

# Component Gallery

This page showcases all A2UI components with examples and usage patterns.

> NOTE: Schema Files
>
> === "v0.8"
>
>     [:material-code-json: Standard Catalog Definition (JSON Schema)](../../../specification/v0_8/json/standard_catalog_definition.json)
>
> === "v0.9"
>
>     [:material-code-json: Basic Catalog Definition (JSON Schema)](../../../specification/v0_9/catalogs/basic/catalog.json)

---

## Layout Components

### Row

Horizontal layout container. Children are arranged left-to-right.

=== "v0.8"

    **Properties:** `children` (`explicitList` or `template`), `distribution`, `alignment`

    ```json
    {
      "id": "toolbar",
      "component": {
        "Row": {
          "children": { "explicitList": ["btn1", "btn2", "btn3"] },
          "distribution": "spaceBetween",
          "alignment": "center"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `children` (array or template), `justify`, `align`

    ```json
    {
      "id": "toolbar",
      "component": "Row",
      "children": ["btn1", "btn2", "btn3"],
      "justify": "spaceBetween",
      "align": "center"
    }
    ```

### Column

Vertical layout container. Children are arranged top-to-bottom.

=== "v0.8"

    **Properties:** `children` (`explicitList` or `template`), `distribution`, `alignment`

    ```json
    {
      "id": "content",
      "component": {
        "Column": {
          "children": { "explicitList": ["header", "body", "footer"] },
          "distribution": "start",
          "alignment": "stretch"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `children` (array or template), `justify`, `align`

    ```json
    {
      "id": "content",
      "component": "Column",
      "children": ["header", "body", "footer"],
      "justify": "start",
      "align": "stretch"
    }
    ```

### List

Scrollable list of items. Supports static children and dynamic templates.

=== "v0.8"

    **Properties:** `children` (`explicitList` or `template`), `direction`, `alignment`

    ```json
    {
      "id": "message-list",
      "component": {
        "List": {
          "children": {
            "template": {
              "dataBinding": "/messages",
              "componentId": "message-item"
            }
          },
          "direction": "vertical"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `children` (array or template), `direction`, `align`

    ```json
    {
      "id": "message-list",
      "component": "List",
      "children": {
        "componentId": "message-item",
        "path": "/messages"
      },
      "direction": "vertical"
    }
    ```

---

## Display Components

### Text

Display text content with styling hints.

=== "v0.8"

    **Properties:** `text` (BoundValue), `usageHint`

    `usageHint` values: `h1`, `h2`, `h3`, `h4`, `h5`, `caption`, `body`

    ```json
    {
      "id": "title",
      "component": {
        "Text": {
          "text": { "literalString": "Welcome to A2UI" },
          "usageHint": "h1"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `text` (string or DataBinding), `variant`

    `variant` values: `h1`, `h2`, `h3`, `h4`, `h5`, `caption`, `body`

    ```json
    {
      "id": "title",
      "component": "Text",
      "text": "Welcome to A2UI",
      "variant": "h1"
    }
    ```

### Image

Display images from URLs.

=== "v0.8"

    **Properties:** `url` (BoundValue), `fit`, `usageHint`

    ```json
    {
      "id": "hero",
      "component": {
        "Image": {
          "url": { "literalString": "https://example.com/hero.png" },
          "fit": "cover",
          "usageHint": "hero"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `url` (string or DataBinding), `fit`, `variant`

    ```json
    {
      "id": "hero",
      "component": "Image",
      "url": "https://example.com/hero.png",
      "fit": "cover",
      "variant": "hero"
    }
    ```

### Icon

Display icons from the basic set defined in the catalog.

=== "v0.8"

    **Properties:** `name` (BoundValue)

    ```json
    {
      "id": "check-icon",
      "component": {
        "Icon": {
          "name": { "literalString": "check" }
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `name` (string or DataBinding)

    ```json
    {
      "id": "check-icon",
      "component": "Icon",
      "name": "check"
    }
    ```

### Divider

Visual separator line.

=== "v0.8"

    **Properties:** `axis`

    ```json
    {
      "id": "separator",
      "component": {
        "Divider": {
          "axis": "horizontal"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `axis`

    ```json
    {
      "id": "separator",
      "component": "Divider",
      "axis": "horizontal"
    }
    ```

---

## Interactive Components

### Button

Clickable button that triggers an action.

=== "v0.8"

    **Properties:** `child` (component ID), `primary` (boolean), `action`

    ```json
    {
      "id": "submit-btn",
      "component": {
        "Button": {
          "child": "submit-text",
          "primary": true,
          "action": {
            "name": "submit_form"
          }
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `child` (component ID), `variant`, `action`

    ```json
    {
      "id": "submit-btn",
      "component": "Button",
      "child": "submit-text",
      "variant": "primary",
      "action": {
        "event": {
          "name": "submit_form"
        }
      }
    }
    ```

### TextField

Text input field with optional validation.

=== "v0.8"

    **Properties:** `label` (BoundValue), `text` (BoundValue), `textFieldType`, `validationRegexp`

    `textFieldType` values: `shortText`, `longText`, `number`, `obscured`, `date`

    ```json
    {
      "id": "email-input",
      "component": {
        "TextField": {
          "label": { "literalString": "Email Address" },
          "text": { "path": "/user/email" },
          "textFieldType": "shortText"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `label` (string), `value` (string or DataBinding), `textFieldType`, `validationRegexp`

    `textFieldType` values: `shortText`, `longText`, `number`, `obscured`, `date`

    ```json
    {
      "id": "email-input",
      "component": "TextField",
      "label": "Email Address",
      "value": { "path": "/user/email" },
      "textFieldType": "shortText"
    }
    ```

### CheckBox

Boolean toggle.

=== "v0.8"

    **Properties:** `label` (BoundValue), `value` (BoundValue, boolean)

    ```json
    {
      "id": "terms-checkbox",
      "component": {
        "CheckBox": {
          "label": { "literalString": "I agree to the terms" },
          "value": { "path": "/form/agreedToTerms" }
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `label` (string), `value` (DataBinding, boolean)

    ```json
    {
      "id": "terms-checkbox",
      "component": "CheckBox",
      "label": "I agree to the terms",
      "value": { "path": "/form/agreedToTerms" }
    }
    ```

### Slider

Numeric range input.

=== "v0.8"

    **Properties:** `value` (BoundValue), `minValue`, `maxValue`

    ```json
    {
      "id": "volume",
      "component": {
        "Slider": {
          "value": { "path": "/settings/volume" },
          "minValue": 0,
          "maxValue": 100
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `value` (DataBinding), `minValue`, `maxValue`

    ```json
    {
      "id": "volume",
      "component": "Slider",
      "value": { "path": "/settings/volume" },
      "minValue": 0,
      "maxValue": 100
    }
    ```

### DateTimeInput

Date and/or time picker.

=== "v0.8"

    **Properties:** `value` (BoundValue), `enableDate`, `enableTime`

    ```json
    {
      "id": "date-picker",
      "component": {
        "DateTimeInput": {
          "value": { "path": "/booking/date" },
          "enableDate": true,
          "enableTime": false
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `value` (DataBinding), `enableDate`, `enableTime`

    ```json
    {
      "id": "date-picker",
      "component": "DateTimeInput",
      "value": { "path": "/booking/date" },
      "enableDate": true,
      "enableTime": false
    }
    ```

### MultipleChoice (v0.8) / ChoicePicker (v0.9)

Select one or more options from a list.

=== "v0.8"

    **Properties:** `options` (array), `selections` (BoundValue), `maxAllowedSelections`

    ```json
    {
      "id": "country-select",
      "component": {
        "MultipleChoice": {
          "options": [
            { "label": { "literalString": "USA" }, "value": "us" },
            { "label": { "literalString": "Canada" }, "value": "ca" }
          ],
          "selections": { "path": "/form/country" },
          "maxAllowedSelections": 1
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `options` (array), `selections` (DataBinding), `maxAllowedSelections`

    ```json
    {
      "id": "country-select",
      "component": "ChoicePicker",
      "options": [
        { "label": "USA", "value": "us" },
        { "label": "Canada", "value": "ca" }
      ],
      "selections": { "path": "/form/country" },
      "maxAllowedSelections": 1
    }
    ```

---

## Container Components

### Card

Container with elevation/border and padding.

=== "v0.8"

    **Properties:** `child` (component ID)

    ```json
    {
      "id": "info-card",
      "component": {
        "Card": {
          "child": "card-content"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `child` (component ID)

    ```json
    {
      "id": "info-card",
      "component": "Card",
      "child": "card-content"
    }
    ```

### Modal

Overlay dialog triggered by an entry point component.

=== "v0.8"

    **Properties:** `entryPointChild` (component ID), `contentChild` (component ID)

    ```json
    {
      "id": "confirmation-modal",
      "component": {
        "Modal": {
          "entryPointChild": "open-modal-btn",
          "contentChild": "modal-content"
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `entryPointChild` (component ID), `contentChild` (component ID)

    ```json
    {
      "id": "confirmation-modal",
      "component": "Modal",
      "entryPointChild": "open-modal-btn",
      "contentChild": "modal-content"
    }
    ```

### Tabs

Tabbed interface for organizing content into switchable panels.

=== "v0.8"

    **Properties:** `tabItems` (array of `{ title, child }`)

    ```json
    {
      "id": "settings-tabs",
      "component": {
        "Tabs": {
          "tabItems": [
            { "title": { "literalString": "General" }, "child": "general-tab" },
            { "title": { "literalString": "Privacy" }, "child": "privacy-tab" }
          ]
        }
      }
    }
    ```

=== "v0.9"

    **Properties:** `tabItems` (array of `{ title, child }`)

    ```json
    {
      "id": "settings-tabs",
      "component": "Tabs",
      "tabItems": [
        { "title": "General", "child": "general-tab" },
        { "title": "Privacy", "child": "privacy-tab" }
      ]
    }
    ```

---

## Common Properties

All components share:

- `id` (required): Unique identifier within the surface.
- `accessibility`: Accessibility attributes (label, role).
- `weight`: Flex-grow value when inside a Row or Column.

## Version Differences Summary

The component names and properties are largely the same across versions. The structural differences are:

| Aspect             | v0.8                               | v0.9                             |
| ------------------ | ---------------------------------- | -------------------------------- |
| Component wrapper  | `"component": { "Text": { ... } }` | `"component": "Text", ...props`  |
| String values      | `{ "literalString": "Hello" }`     | `"Hello"`                        |
| Children           | `{ "explicitList": ["a", "b"] }`   | `["a", "b"]`                     |
| Data binding       | `{ "path": "/data" }`              | `{ "path": "/data" }` (same)     |
| Text/Image styling | `usageHint`                        | `variant`                        |
| Button styling     | `primary: true`                    | `variant: "primary"`             |
| Action format      | `{ "name": "..." }`                | `{ "event": { "name": "..." } }` |
| Choice component   | `MultipleChoice`                   | `ChoicePicker`                   |
| Layout alignment   | `distribution`, `alignment`        | `justify`, `align`               |
| TextField value    | `text`                             | `value`                          |

## Live Examples

To see all components in action:

```bash
cd samples/client/angular
yarn start gallery
```

> [!NOTE]
> **Package Manager Usage:** Running the built-in sample applications within the A2UI repository requires Yarn (`yarn start gallery`) as configured by Corepack workspaces. For your own regular usage and standalone projects outside this repository, use the package manager of your choice (e.g. npm, pnpm).

## Further Reading

> NOTE: Schema Files
>
> === "v0.8"
>
>     [:material-code-json: Standard Catalog Definition (JSON Schema)](../../../specification/v0_8/json/standard_catalog_definition.json)
>
> === "v0.9"
>
>     [:material-code-json: Basic Catalog Definition (JSON Schema)](../../../specification/v0_9/catalogs/basic/catalog.json)

- **[Defining Your Own Catalog](../guides/defining-your-own-catalog.md)**: Build your own components
- **[Theming Guide](../guides/theming.md)**: Style components to match your brand

---

### Public Reference Messages (`docs/public/reference/messages.md`)

# Message Types

This reference provides detailed documentation for all A2UI message types.

## Message Format

All A2UI messages are JSON objects sent as JSON Lines (JSONL). Each line contains exactly one message.

=== "v0.8 Message Types"

    - `beginRendering` — Signal the client to render a surface
    - `surfaceUpdate` — Add or update components
    - `dataModelUpdate` — Update application state
    - `deleteSurface` — Remove a surface

=== "v0.9 Message Types"

    - `createSurface` — Create a surface and specify its catalog
    - `updateComponents` — Add or update components
    - `updateDataModel` — Update application state
    - `deleteSurface` — Remove a surface

    All v0.9 messages include a `"version": "v0.9"` field.

---

## beginRendering (v0.8) / createSurface (v0.9)

Signals the client to initialize and render a surface.

=== "v0.8 — `beginRendering`"

    ### Schema

    ```typescript
    {
      beginRendering: {
        surfaceId: string;      // Required: Unique surface identifier
        root: string;           // Required: The ID of the root component to render
        catalogId?: string;     // Optional: URL of component catalog
        styles?: object;        // Optional: Styling information
      }
    }
    ```

    ### Properties

    | Property    | Type   | Required | Description                                                                             |
    | ----------- | ------ | -------- | --------------------------------------------------------------------------------------- |
    | `surfaceId` | string | ✅        | Unique identifier for this surface.                                                     |
    | `root`      | string | ✅        | The `id` of the component that should be the root of the UI tree for this surface.      |
    | `catalogId` | string | ❌        | Identifier for the component catalog. Defaults to the v0.8 basic catalog if omitted. |
    | `styles`    | object | ❌        | Styling information for the UI, as defined by the catalog.                              |

    ### Example

    ```json
    {
      "beginRendering": {
        "surfaceId": "main",
        "root": "root-component"
      }
    }
    ```

    **With a custom catalog:**

    ```json
    {
      "beginRendering": {
        "surfaceId": "custom-ui",
        "root": "root-custom",
        "catalogId": "https://my-company.com/a2ui/v0.8/my_custom_catalog.json"
      }
    }
    ```

    Must be sent after component definitions. The client buffers `surfaceUpdate` and `dataModelUpdate` messages until `beginRendering` is received.

=== "v0.9 — `createSurface`"

    ### Schema

    ```typescript
    {
      version: "v0.9";
      createSurface: {
        surfaceId: string;      // Required: Unique surface identifier
        catalogId: string;      // Required: URL of component catalog
        theme?: object;         // Optional: Theme configuration
        sendDataModel?: boolean; // Optional: Request client to send data model updates
      }
    }
    ```

    ### Properties

    | Property        | Type    | Required | Description                                                     |
    | --------------- | ------- | -------- | --------------------------------------------------------------- |
    | `surfaceId`     | string  | ✅        | Unique identifier for this surface.                             |
    | `catalogId`     | string  | ✅        | Identifier for the component catalog.                           |
    | `theme`         | object  | ❌        | Theme configuration (e.g., `primaryColor`).                     |
    | `sendDataModel` | boolean | ❌        | If true, client sends data model changes back to the server.    |

    ### Example

    ```json
    {
      "version": "v0.9",
      "createSurface": {
        "surfaceId": "main",
        "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
      }
    }
    ```

    The root component is determined by convention: one component in `updateComponents` must have `"id": "root"`. The `catalogId` is required.

---

## surfaceUpdate (v0.8) / updateComponents (v0.9)

Add or update components within a surface.

=== "v0.8 — `surfaceUpdate`"

    ### Schema

    ```typescript
    {
      surfaceUpdate: {
        surfaceId: string;        // Required: Target surface
        components: Array<{       // Required: List of components
          id: string;             // Required: Component ID
          component: {            // Required: Wrapper for component data
            [ComponentType]: {    // Required: Exactly one component type
              ...properties       // Component-specific properties
            }
          }
        }>
      }
    }
    ```

    ### Properties

    | Property     | Type   | Required | Description                    |
    | ------------ | ------ | -------- | ------------------------------ |
    | `surfaceId`  | string | ✅        | ID of the surface to update    |
    | `components` | array  | ✅        | Array of component definitions |

    ### Component Object

    Each object in the `components` array must have:

    - `id` (string, required): Unique identifier within the surface
    - `component` (object, required): A wrapper object that contains exactly one key, which is the component type (e.g., `Text`, `Button`).

    ### Examples

    **Single component:**

    ```json
    {
      "surfaceUpdate": {
        "surfaceId": "main",
        "components": [
          {
            "id": "greeting",
            "component": {
              "Text": {
                "text": {"literalString": "Hello, World!"},
                "usageHint": "h1"
              }
            }
          }
        ]
      }
    }
    ```

    **Multiple components (adjacency list):**

    ```json
    {
      "surfaceUpdate": {
        "surfaceId": "main",
        "components": [
          {
            "id": "root",
            "component": {
              "Column": {
                "children": {"explicitList": ["header", "body"]}
              }
            }
          },
          {
            "id": "header",
            "component": {
              "Text": {
                "text": {"literalString": "Welcome"}
              }
            }
          },
          {
            "id": "body",
            "component": {
              "Card": {
                "child": "content"
              }
            }
          },
          {
            "id": "content",
            "component": {
              "Text": {
                "text": {"path": "/message"}
              }
            }
          }
        ]
      }
    }
    ```

    **Updating existing component:**

    ```json
    {
      "surfaceUpdate": {
        "surfaceId": "main",
        "components": [
          {
            "id": "greeting",
            "component": {
              "Text": {
                "text": {"literalString": "Hello, Alice!"},
                "usageHint": "h1"
              }
            }
          }
        ]
      }
    }
    ```

    The component with `id: "greeting"` is updated (not duplicated).

    ### Usage Notes

    Keep these usage notes in mind:
    - One component must be designated as the `root` in the `beginRendering` message to serve as the tree root.
    - Components form an adjacency list (flat structure with ID references).
    - Sending a component with an existing ID updates that component.
    - Children are referenced by ID.
    - Components can be added incrementally (streaming).

=== "v0.9 — `updateComponents`"

    ### Schema

    ```typescript
    {
      version: "v0.9";
      updateComponents: {
        surfaceId: string;        // Required: Target surface
        components: Array<{       // Required: List of components
          id: string;             // Required: Component ID
          component: string;      // Required: Component type name
          ...properties           // Component-specific properties (flat)
        }>
      }
    }
    ```

    ### Properties

    | Property     | Type   | Required | Description                    |
    | ------------ | ------ | -------- | ------------------------------ |
    | `surfaceId`  | string | ✅        | ID of the surface to update    |
    | `components` | array  | ✅        | Array of component definitions |

    ### Component Object

    The component structure is flat:

    - `id` (string, required): Unique identifier within the surface
    - `component` (string, required): Component type name (e.g., `"Text"`, `"Button"`)
    - All other properties are top-level on the component object.

    ### Examples

    **Single component:**

    ```json
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "main",
        "components": [
          {
            "id": "greeting",
            "component": "Text",
            "text": "Hello, World!",
            "variant": "h1"
          }
        ]
      }
    }
    ```

    **Multiple components:**

    ```json
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "main",
        "components": [
          {
            "id": "root",
            "component": "Column",
            "children": ["header", "body"]
          },
          {
            "id": "header",
            "component": "Text",
            "text": "Welcome"
          },
          {
            "id": "body",
            "component": "Card",
            "child": "content"
          },
          {
            "id": "content",
            "component": "Text",
            "text": {"path": "/message"}
          }
        ]
      }
    }
    ```

    **Updating existing component:**

    ```json
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "main",
        "components": [
          {
            "id": "greeting",
            "component": "Text",
            "text": "Hello, Alice!",
            "variant": "h1"
          }
        ]
      }
    }
    ```

    ### Usage Notes

    Keep these usage notes in mind:
    - One component must have `"id": "root"` to serve as the tree root (convention, not a separate message field).
    - Component type is a string (`"component": "Text"`) instead of a wrapper object.
    - Properties are flat on the component object (no nesting under type key).
    - Data binding uses `{"path": "/pointer"}` (JSON Pointer) — same key name as v0.8 but with standard JSON Pointer paths.
    - Components can be added incrementally (streaming).

### Errors

| Error                  | Cause                                  | Solution                                                                                                                                                                                      |
| ---------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Surface already exists | `surfaceId` is already in use          | Ensure `surfaceId` is globally unique for the renderer's lifetime. If using an orchestrator with subagents, the orchestrator is empowered to manage surface IDs as needed to avoid conflicts. |
| Surface not found      | `surfaceId` does not exist             | Ensure `surfaceId` matches the created surface. In v0.8, surfaces are implicit, but v0.9+ requires `createSurface`.                                                                           |
| Invalid component type | Unknown component type                 | Check component type exists in the negotiated catalog.                                                                                                                                        |
| Invalid property       | Property doesn't exist for this type   | Verify against catalog schema.                                                                                                                                                                |
| Circular reference     | Component references itself as a child | Fix component hierarchy.                                                                                                                                                                      |

---

## dataModelUpdate (v0.8) / updateDataModel (v0.9)

Update the data model that components bind to.

=== "v0.8 — `dataModelUpdate`"

    ### Schema

    ```typescript
    {
      dataModelUpdate: {
        surfaceId: string;      // Required: Target surface
        path?: string;          // Optional: Path to a location in the model
        contents: Array<{       // Required: Data entries
          key: string;
          valueString?: string;
          valueNumber?: number;
          valueBoolean?: boolean;
          valueMap?: Array<{...}>;
        }>
      }
    }
    ```

    ### Properties

    | Property    | Type   | Required | Description                                                                                          |
    | ----------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- |
    | `surfaceId` | string | ✅        | ID of the surface to update.                                                                         |
    | `path`      | string | ❌        | Path to a location within the data model (e.g., `user`). If omitted, the update applies to the root. |
    | `contents`  | array  | ✅        | An array of data entries as an adjacency list. Each entry has a `key` and a typed `value*` property. |

    ### The `contents` Adjacency List

    The `contents` array is a list of key-value pairs. Each object in the array must have a `key` and exactly one `value*` property (`valueString`, `valueNumber`, `valueBoolean`, or `valueMap`). This structure is LLM-friendly and avoids issues with inferring types from a generic `value` field.

    ### Examples

    **Initialize entire model:**

    ```json
    {
      "dataModelUpdate": {
        "surfaceId": "main",
        "contents": [
          {
            "key": "user",
            "valueMap": [
              { "key": "name", "valueString": "Alice" },
              { "key": "email", "valueString": "alice@example.com" }
            ]
          },
          { "key": "items", "valueMap": [] }
        ]
      }
    }
    ```

    **Update nested property:**

    ```json
    {
      "dataModelUpdate": {
        "surfaceId": "main",
        "path": "user",
        "contents": [
          { "key": "email", "valueString": "alice@newdomain.com" }
        ]
      }
    }
    ```

    This will change `/user/email` without affecting `/user/name`.

    ### Usage Notes

    Keep these usage notes in mind:
    - Data model is per-surface.
    - Components automatically re-render when their bound data changes.
    - Prefer granular updates to specific paths over replacing the entire model.
    - Uses typed value fields (`valueString`, `valueNumber`, `valueBoolean`, `valueMap`) — LLM-friendly, no type inference needed.
    - Any data transformation (e.g., formatting a date) must be done by the server before sending the message.

=== "v0.9 — `updateDataModel`"

    ### Schema

    ```typescript
    {
      version: "v0.9";
      updateDataModel: {
        surfaceId: string;      // Required: Target surface
        path?: string;          // Optional: JSON Pointer path (defaults to "/")
        value?: any;            // Optional: Value to set (omit to delete)
      }
    }
    ```

    ### Properties

    | Property    | Type   | Required | Description                                           |
    | ----------- | ------ | -------- | ----------------------------------------------------- |
    | `surfaceId` | string | ✅        | ID of the surface to update.                          |
    | `path`      | string | ❌        | JSON Pointer path (e.g., `/user/email`). Defaults to `/` (root). |
    | `value`     | any    | ❌        | The value to set. If omitted, the key at `path` is removed. |

    ### Examples

    **Initialize entire model:**

    ```json
    {
      "version": "v0.9",
      "updateDataModel": {
        "surfaceId": "main",
        "path": "/",
        "value": {
          "user": {
            "name": "Alice",
            "email": "alice@example.com"
          },
          "items": []
        }
      }
    }
    ```

    **Update nested property:**

    ```json
    {
      "version": "v0.9",
      "updateDataModel": {
        "surfaceId": "main",
        "path": "/user/email",
        "value": "alice@newdomain.com"
      }
    }
    ```

    ### Usage Notes

    Keep these usage notes in mind:
    - v0.9 uses standard JSON Pointer paths and plain JSON values — no typed wrappers.
    - `path` defaults to `"/"` (root) if omitted.
    - `value` can be any JSON type (string, number, boolean, object, array, null). Omit to delete.
    - Simpler than v0.8's `contents` adjacency list — closer to standard JSON Patch semantics.
    - Components referencing `{"path": "/user/email"}` auto-update when that path changes.

---

## deleteSurface

Remove a surface and all its components and data.

=== "v0.8 — `deleteSurface`"

    ### Schema

    ```typescript
    {
      deleteSurface: {
        surfaceId: string;        // Required: Surface to delete
      }
    }
    ```

    ### Example

    ```json
    {
      "deleteSurface": {
        "surfaceId": "modal"
      }
    }
    ```

=== "v0.9 — `deleteSurface`"

    ### Schema

    ```typescript
    {
      version: "v0.9";
      deleteSurface: {
        surfaceId: string;        // Required: Surface to delete
      }
    }
    ```

    ### Example

    ```json
    {
      "version": "v0.9",
      "deleteSurface": {
        "surfaceId": "modal"
      }
    }
    ```

### Properties

| Property    | Type   | Required | Description                 |
| ----------- | ------ | -------- | --------------------------- |
| `surfaceId` | string | ✅       | ID of the surface to delete |

### Usage Notes

Keep these usage notes in mind:

- Removes all components associated with the surface.
- Clears the data model for the surface.
- Client should remove the surface from the UI.
- Safe to delete non-existent surface (no-op).
- Use when closing modals, dialogs, or navigating away.
- Identical structure in both versions (v0.9 just adds the `version` field).

---

## Message Ordering

### Requirements

Message ordering must satisfy the following requirements:

1. `beginRendering` must come after the initial `surfaceUpdate` messages for that surface.
2. `surfaceUpdate` can come before or after `dataModelUpdate`.
3. Messages for different surfaces are independent.
4. Multiple messages can update the same surface incrementally.

### Recommended Order

=== "v0.8"

    ```jsonl
    { "surfaceUpdate":    { "surfaceId": "main", "components": [...] } }
    { "dataModelUpdate":  { "surfaceId": "main", "contents": {...} } }
    { "beginRendering":   { "surfaceId": "main", "root": "root-id" } }
    ```

=== "v0.9"

    ```jsonl
    { "version": "v0.9", "createSurface":    { "surfaceId": "main", "catalogId": "..." } }
    { "version": "v0.9", "updateComponents": { "surfaceId": "main", "components": [...] } }
    { "version": "v0.9", "updateDataModel":  { "surfaceId": "main", "path": "/", "value": {...} } }
    ```

### Progressive Building

=== "v0.8"

    ```jsonl
    { "surfaceUpdate":   { "surfaceId": "main", "components": [...] } }  // Header
    { "surfaceUpdate":   { "surfaceId": "main", "components": [...] } }  // Body
    { "beginRendering":  { "surfaceId": "main", "root": "root-id" } }   // Render
    { "surfaceUpdate":   { "surfaceId": "main", "components": [...] } }  // Footer
    { "dataModelUpdate": { "surfaceId": "main", "contents": {...} } }    // Data
    ```

=== "v0.9"

    ```jsonl
    { "version": "v0.9", "createSurface":    { "surfaceId": "main", "catalogId": "..." } }
    { "version": "v0.9", "updateComponents": { "surfaceId": "main", "components": [...] } }  // Header
    { "version": "v0.9", "updateComponents": { "surfaceId": "main", "components": [...] } }  // Body + Footer
    { "version": "v0.9", "updateDataModel":  { "surfaceId": "main", "path": "/", "value": {...} } }
    ```

## Validation

=== "v0.8"

    Validate against:

    - **[server_to_client.json](../../../specification/v0_8/json/server_to_client.json)**: Message envelope schema.
    - **[standard_catalog_definition.json](../../../specification/v0_8/json/standard_catalog_definition.json)**: Component schemas.

=== "v0.9"

    Validate against:

    - **[server_to_client.json](../../../specification/v0_9/json/server_to_client.json)**: Message envelope schema.
    - **[catalogs/basic/catalog.json](../../../specification/v0_9/catalogs/basic/catalog.json)**: Component schemas.

## Further Reading

- **[Component Gallery](components.md)**: All available component types
- **[Data Binding Guide](../concepts/data-binding.md)**: How data binding works
- **[Agent Development Guide](../guides/agent-development.md)**: Generate valid messages

---

### Public Reference Renderers (`docs/public/reference/renderers.md`)

# Renderers (Client Libraries)

Renderers convert A2UI JSON messages into native UI components for different platforms.

The [agents](agents.md) are responsible for generating the A2UI messages,
and the [transports](../concepts/transports.md) are responsible for delivering the messages to the client.
The client renderer library must buffer and handle A2UI messages, implement the A2UI lifecycle, render widgets, and route user actions back to the agent.

Let's use the web as an analogy. The A2UI protocol is like HTML. It provides a language and the semantics of the UI model. The agent is like the server that serves HTML to the client. The renderer is like a browser. It talks to the agent, interprets the A2UI protocol, and renders the UI. Just like there are multiple browser engines for HTML, there are multiple different renderers for A2UI.

You have a lot of flexibility, to bring custom components to a renderer, or build your own renderer to support your UI component framework.

## Maintained Renderers

### Web

| Renderer                 | Platform           | v0.8      | v0.9.1    | v1.0       | Links                                                                                |
| ------------------------ | ------------------ | --------- | --------- | ---------- | ------------------------------------------------------------------------------------ |
| **React**                | Web                | ✅ Stable | ✅ Stable | 🚧 Planned | [Code](../../../typescript/renderers/react)                                          |
| **Lit (Web Components)** | Web                | ✅ Stable | ✅ Stable | 🚧 Planned | [Code](../../../typescript/renderers/lit)                                            |
| **Angular**              | Web                | ✅ Stable | ✅ Stable | 🚧 Planned | [Code](../../../typescript/renderers/angular)                                        |
| **Flutter (GenUI SDK)**  | Mobile/Desktop/Web | ✅ Stable | ✅ Stable | 🚧 Planned | [Docs](https://docs.flutter.dev/ai/genui) · [Code](https://github.com/flutter/genui) |

### Mobile

| Renderer                | Platform           | v0.8      | v0.9.1    | v1.0       | Links                                                                                                                                                        |
| ----------------------- | ------------------ | --------- | --------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Flutter (GenUI SDK)** | Mobile/Desktop/Web | ✅ Stable | ✅ Stable | 🚧 Planned | [Docs](https://docs.flutter.dev/ai/genui) · [Code](https://github.com/flutter/genui)                                                                         |
| **SwiftUI**             | iOS/macOS          | —         | —         | 🚧 Planned | —                                                                                                                                                            |
| **Jetpack Compose**     | Android            | —         | ✅ Alpha  | 🚧 Planned | [Docs](https://developer.android.com/develop/ui/compose/agentic) · [Code](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:a2ui/) |

Check the [Roadmap](../roadmap.md) for more.

## Ecosystem Renderers

The community is building A2UI renderers for additional platforms:

- **[json-render](https://json-render.dev/docs/a2ui)** — Vercel's React library for rendering A2UI catalogs via Zod schemas ([comparison](https://dipjyotimetia.medium.com/vercels-json-render-vs-google-s-a2ui-the-head-to-head-6f213cf1a23b))
- **[A2UI-Android](https://github.com/lmee/A2UI-Android)** — Community Jetpack Compose renderer, 20+ components (~15 ⭐, v0.8)
- **[a2ui-react-native](https://github.com/sivamrudram-eng/a2ui-react-native)** — React Native renderer for iOS/Android (~9 ⭐, v0.8)
- **[Lynx A2UI](https://lynxjs.org/next/react/genui/a2ui.html)** — ReactLynx renderer for A2UI (v0.9)
- **[AGenUI](https://github.com/AGenUI/AGenUI)** — Cross-platform native renderer covering iOS, Android, and HarmonyOS. (v0.9)

See the **[full ecosystem renderers list](../ecosystem/renderers.md)** for more community projects and how to submit your own.

## How Renderers Work

The rendering process typically involves the following steps:

1. **Receive** A2UI messages from the transport.
2. **Parse** the JSON and validate against the schema.
3. **Render** using platform-native components.
4. **Style** according to your app's theme.

## Using a Renderer

Get started integrating A2UI into your application by following the setup guide for your chosen renderer:

- **[React](../guides/client-setup.md#react)**
- **[Lit (Web Components)](../guides/client-setup.md#web-components-lit)**
- **[Angular](../guides/client-setup.md#angular)**
- **[Flutter (GenUI SDK)](../guides/client-setup.md#flutter-genui-sdk)**

## Building a Renderer

Want to build a renderer for your platform?

- See the [Roadmap](../roadmap.md) for planned frameworks.
- Review existing renderers for patterns.
- Check out our [Renderer Development Guide](../guides/renderer-development.md) for details on implementing a renderer.

A compliant renderer must meet the following key requirements:

- Parse A2UI JSON messages, specifically the adjacency list format.
- Map A2UI components to native widgets.
- Handle data binding, lifecycle events.
- Process a sequence of incremental A2UI messages to build and update the UI.
- Support server-initiated updates.
- Support user actions.

For more information, see the following resources:

- **[Client Setup Guide](../guides/client-setup.md)**: Integration instructions.
- **[Quickstart](../quickstart.md)**: Try the Lit renderer.
- **[Component Reference](components.md)**: What components to support.

---

### Public Specification V0.8 A2a Extension (`docs/public/specification/v0.8-a2a-extension.md`)

# A2UI Extension for A2A Protocol <span class="version-badge legacy">v0.8 — Legacy</span>

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_8/docs/a2ui_extension_specification.md`. Any updates to the specification will automatically appear here.

> NOTE: Version Compatibility
>
> This extension specification applies to A2UI v0.8 and the A2A Protocol. For the base A2UI protocol, see [v0.8 Protocol Specification](v0.8-a2ui.md) (Legacy).

For more information, see the following related documentation:

- [A2UI Protocol v0.8](v0.8-a2ui.md) (Legacy).
- [A2A Protocol Documentation](https://a2a-protocol.org).

---

--8<-- "specification/v0_8/docs/a2ui_extension_specification.md"

---

### Public Specification V0.8 A2ui (`docs/public/specification/v0.8-a2ui.md`)

# A2UI Protocol <span class="version-badge legacy">v0.8 — Legacy</span>

> Version 0.8 is a legacy release, maintained for backward compatibility. For production use, consider [v0.9.1 (Current)](v0.9.1-a2ui.md).

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_8/docs/a2ui_protocol.md`. Any updates to the specification will automatically appear here.

For more information, see the following related documentation:

- [v0.9.1 Protocol Specification](v0.9.1-a2ui.md) (Current).
- [v0.9 Protocol Specification](v0.9-a2ui.md) (Stable).
- [v1.0 Protocol Specification](v1.0-a2ui.md) (Candidate).
- [Evolution Guide: v0.8 → v0.9](v0.9-evolution-guide.md).
- [A2A Extension Specification](v0.8-a2a-extension.md) (Legacy).

---

--8<-- "specification/v0_8/docs/a2ui_protocol.md"

---

### Public Specification V0.9 A2ui (`docs/public/specification/v0.9-a2ui.md`)

# A2UI Protocol <span class="version-badge stable">v0.9 — Stable</span>

> Version 0.9 is the stable protocol family. For production use, consider [v0.9.1 (Current)](v0.9.1-a2ui.md).

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_9/docs/a2ui_protocol.md`. Any updates to the specification will automatically appear here.

For more information, see the following related documentation:

- [v0.9.1 Protocol Specification](v0.9.1-a2ui.md) (Current).
- [v0.8 Protocol Specification](v0.8-a2ui.md) (Legacy).
- [v1.0 Protocol Specification](v1.0-a2ui.md) (Candidate).
- [Evolution Guide: v0.8 → v0.9](v0.9-evolution-guide.md).

---

--8<-- "specification/v0_9/docs/a2ui_protocol.md"

---

### Public Specification V0.9 Evolution Guide (`docs/public/specification/v0.9-evolution-guide.md`)

# Evolution Guide <span class="version-badge info">v0.8 → v0.9</span>

> This guide is automatically included from `specification/v0_9/docs/evolution_guide.md`. Any updates will automatically appear here.

For more information, see the following related documentation:

- [A2UI Protocol v0.8](v0.8-a2ui.md) (Legacy - what you're migrating from).
- [A2UI Protocol v0.9](v0.9-a2ui.md) (Stable - what you're migrating to).

---

--8<-- "specification/v0_9/docs/evolution_guide.md"

---

### Public Specification V0.9.1 A2ui Extension Specification (`docs/public/specification/v0.9.1-a2ui-extension-specification.md`)

# A2UI Extension for A2A Protocol <span class="version-badge stable">v0.9.1 — Current</span>

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_9_1/docs/a2ui_extension_specification.md`. Any updates to the specification will automatically appear here.

> NOTE: Version Compatibility
>
> This extension specification applies to A2UI v0.9.1 and the A2A Protocol. For the base A2UI protocol, see [v0.9.1 Protocol Specification](v0.9.1-a2ui.md).

For more information, see the following related documentation:

- [A2UI Protocol v0.9.1](v0.9.1-a2ui.md) (Current).
- [A2A Protocol Documentation](https://a2a-protocol.org).

---

--8<-- "specification/v0_9_1/docs/a2ui_extension_specification.md"

---

### Public Specification V0.9.1 A2ui (`docs/public/specification/v0.9.1-a2ui.md`)

# A2UI Protocol <span class="version-badge stable">v0.9.1 — Current</span>

> Version 0.9.1 is the current production release. For the legacy version, see [v0.8 (Legacy)](v0.8-a2ui.md).

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_9_1/docs/a2ui_protocol.md`. Any updates to the specification will automatically appear here.

For more information, see the following related documentation:

- [v0.9 Protocol Specification](v0.9-a2ui.md) (Previous Stable).
- [Evolution Guide: v0.9 → v0.9.1](v0.9.1-evolution-guide.md).

---

--8<-- "specification/v0_9_1/docs/a2ui_protocol.md"

---

### Public Specification V0.9.1 Basic Catalog Implementation Guide (`docs/public/specification/v0.9.1-basic-catalog-implementation-guide.md`)

# Basic Catalog Implementation Guide <span class="version-badge stable">v0.9.1 — Current</span>

> NOTE: Living Document
>
> This specification is automatically included from `specification/v0_9_1/docs/basic_catalog_implementation_guide.md`. Any updates to the specification will automatically appear here.

---

--8<-- "specification/v0_9_1/docs/basic_catalog_implementation_guide.md"

---

### Public Specification V0.9.1 Evolution Guide (`docs/public/specification/v0.9.1-evolution-guide.md`)

# Evolution Guide <span class="version-badge info">v0.9 → v0.9.1</span>

> This guide is automatically included from `specification/v0_9_1/docs/evolution_guide.md`. Any updates will automatically appear here.

For more information, see the following related documentation:

- [A2UI Protocol v0.9](v0.9-a2ui.md) (Previous Stable - what you're migrating from).
- [A2UI Protocol v0.9.1](v0.9.1-a2ui.md) (Current - what you're migrating to).

---

--8<-- "specification/v0_9_1/docs/evolution_guide.md"

---

### Public Specification V1.0 A2ui Extension Specification (`docs/public/specification/v1.0-a2ui-extension-specification.md`)

# A2UI Extension for A2A Protocol <span class="version-badge info">v1.0 — Candidate</span>

> NOTE: Living Document
>
> This specification is automatically included from `specification/v1_0/extensions/a2a/docs/a2ui_extension_specification.md`. Any updates to the specification will automatically appear here.

> NOTE: Version Compatibility
>
> This extension specification applies to A2UI v1.0 (previously known as v0.10 in draft) and the A2A Protocol. For the base A2UI protocol, see [v1.0 Protocol Specification](v1.0-a2ui.md).

For more information, see the following related documentation:

- [A2UI Protocol v1.0](v1.0-a2ui.md) (Candidate).
- [A2A Protocol Documentation](https://a2a-protocol.org).

---

--8<-- "specification/v1_0/extensions/a2a/docs/a2ui_extension_specification.md"

---

### Public Specification V1.0 A2ui (`docs/public/specification/v1.0-a2ui.md`)

# A2UI Protocol <span class="version-badge info">v1.0 — Candidate</span>

> Version 1.0 (previously v0.10 in draft) is currently a release candidate. For production use, consider [v0.9.1 (Current)](v0.9.1-a2ui.md).

> NOTE: Living Document
>
> This specification is automatically included from `specification/v1_0/docs/a2ui_protocol.md`. Any updates to the specification will automatically appear here.

For more information, see the following related documentation:

- [v0.9.1 Protocol Specification](v0.9.1-a2ui.md) (Current).
- [Evolution Guide: v0.9.1 → v1.0](v1.0-evolution-guide.md).

---

--8<-- "specification/v1_0/docs/a2ui_protocol.md"

---

### Public Specification V1.0 Basic Catalog Implementation Guide (`docs/public/specification/v1.0-basic-catalog-implementation-guide.md`)

# Basic Catalog Implementation Guide <span class="version-badge info">v1.0 — Candidate</span>

> NOTE: Living Document
>
> This specification is automatically included from `catalogs/basic/v1/basic_catalog_implementation_guide.md`. Any updates to the specification will automatically appear here.

---

--8<-- "catalogs/basic/v1/basic_catalog_implementation_guide.md"

---

### Public Specification V1.0 Evolution Guide (`docs/public/specification/v1.0-evolution-guide.md`)

# Evolution Guide <span class="version-badge info">v0.9.1 → v1.0</span>

> This guide is automatically included from `specification/v1_0/docs/evolution_guide.md`. Any updates will automatically appear here.

For more information, see the following related documentation:

- [A2UI Protocol v0.9.1](v0.9.1-a2ui.md) (Current - what you're migrating from).
- [A2UI Protocol v1.0](v1.0-a2ui.md) (Candidate - what you're migrating to).

---

--8<-- "specification/v1_0/docs/evolution_guide.md"

---

### Specification V0 8 Docs A2ui Extension Specification (`specification/v0_8/docs/a2ui_extension_specification.md`)

# A2UI (Agent-to-Agent UI) Extension spec

## Overview

This extension implements the A2UI (Agent-to-Agent UI) spec, a format for agents to send streaming, interactive user interfaces to clients.

## Extension URI

The URI of this extension is https://a2ui.org/a2a-extension/a2ui/v0.8

This is the only URI accepted for this extension.

## Core concepts

The A2UI extension is built on the following main concepts:

Surfaces: A "Surface" is a distinct, controllable region of the client's UI. The spec uses a surfaceId to direct updates to specific surfaces (e.g., a main content area, a side panel, or a new chat bubble). This allows a single agent stream to manage multiple UI areas independently.

Catalog Definition Document: The a2ui extension is component-agnostic. All UI components (e.g., Text, Row, Button) and their stylings are defined in a separate Catalog Definition Schema. This allows clients and servers to negotiate which catalog to use.

Schemas: The a2ui extension is defined by three primary JSON schemas:

Catalog Definition Schema: A standard format for defining a library of components and styles.

Server-to-Client Message Schema: The core wire format for messages sent from the agent to the client (e.g., surfaceUpdate, dataModelUpdate).

Client-to-Server Event Schema: The core wire format for messages sent from the client to the agent (e.g., userAction).

Client Capabilities: The client sends its capabilities to the server in an `a2uiClientCapabilities` object. This object is included in the `metadata` field of every A2A `Message` sent from the client to the server. This object allows the client to declare which catalogs it supports.

## Agent Card details

Agents advertise their A2UI capabilities in their AgentCard within the `AgentCapabilities.extensions` list. The `params` object defines the agent's specific UI support.

Example AgentExtension block:

```json
{
  "uri": "https://a2ui.org/a2a-extension/a2ui/v0.8",
  "description": "Ability to render A2UI",
  "required": false,
  "params": {
    "supportedCatalogIds": [
      "https://a2ui.org/specification/v0_8/standard_catalog_definition.json",
      "https://my-company.com/a2ui/v0.8/my_custom_catalog.json"
    ],
    "acceptsInlineCatalogs": true
  }
}
```

### Parameter definitions

- `params.supportedCatalogIds`: (OPTIONAL) An array of strings, where each string is a URI pointing to a component Catalog Definition Schema that the agent can generate.
- `params.acceptsInlineCatalogs`: (OPTIONAL) A boolean indicating if the agent can accept an `inlineCatalogs` array in the client's `a2uiClientCapabilities`. If omitted, this defaults to `false`.

## Extension activation

Clients indicate their desire to use the A2UI extension by specifying it via the transport-defined A2A extension activation mechanism.

For JSON-RPC and HTTP transports, this is indicated via the X-A2A-Extensions HTTP header.

For gRPC, this is indicated via the X-A2A-Extensions metadata value.

Activating this extension implies that the server can send A2UI-specific messages (like surfaceUpdate) and the client is expected to send A2UI-specific events (like userAction).

## Data encoding

A2UI messages are encoded as an A2A `DataPart`.

To identify a `DataPart` as containing A2UI data, it must have the following metadata:

- `mimeType`: `application/json+a2ui`

The `data` field of the `DataPart` contains the A2UI JSON message (e.g., `surfaceUpdate`, `userAction`).

Example A2UI DataPart:

```json
{
  "data": {
    "beginRendering": {
      "surfaceId": "outlier_stores_map_surface"
    }
  },
  "kind": "data",
  "metadata": {
    "mimeType": "application/json+a2ui"
  }
}
```

---

### Specification V0 8 Docs A2ui Protocol (`specification/v0_8/docs/a2ui_protocol.md`)

<div style="text-align: center;">
  <div class="centered-logo-text-group">
    <img src="../../../docs/public/assets/A2UI_dark.svg" alt="A2UI Protocol Logo" width="100">
    <h1>A2UI (Agent to UI) Protocol</h1>
  </div>
</div>

A Specification for a JSONL-Based, Streaming UI Protocol

Created: Sep 19, 2025
Updated: Nov 12, 2025

## Design requirements

The A2UI (Agent to UI) protocol should be a system where an LLM can stream a platform-agnostic, abstract UI definition to a client, which then renders it progressively using a native widget set. Every major design choice is traced back to the core challenges of LLM generation, perceived performance, and platform independence.

### Requirement: The protocol must be easily generated by a Transformer Large Language Model (LLM)

This is the most critical driver. This requirement directly leads to several design choices:

Declarative, Simple Structure: The protocol should use a straightforward, declarative format ("this is a column with these children") rather than an imperative one ("now, add a column; then, append a text widget to it"). LLMs excel at generating structured, declarative data.

Flat Component List (Adjacency List): Requiring an LLM to generate a perfectly nested JSON tree in a single pass is difficult and error-prone. A flat list of components, where relationships are defined by simple string IDs, is much easier to generate piece by piece. The model can "think" of a component, give it an ID, and then reference that ID later without worrying about tree depth or object nesting.

Stateless Messages: Each JSONL message is a self-contained unit of information (componentUpdate, dataModelUpdate). This is ideal for a streaming LLM, which can output these messages incrementally as it processes a request.

### Requirement: The UI must render progressively for a fast, responsive user experience

The system must feel fast to the user, even if the full UI is complex and takes time to generate.

Streaming via JSONL/SSE: This is a direct solution. The client doesn't have to wait for a single, massive JSON payload. It can start receiving and processing UI components immediately, improving perceived performance.

### Requirement: The protocol must be platform-agnostic

The same server-side logic should be able to render a UI on a Flutter app, a web browser, or potentially other platforms without modification.

Client-Defined widget catalog: This is the core of the platform-agnostic design. The protocol should define an abstract component tree (e.g., "I need a Card with a Row inside"). It is the client's responsibility to map these abstract types to its native widget implementations (a Flutter Card widget, an HTML `<div>` with card styling, etc.). The server only needs to know the names of the components the client supports.

### Requirement: State management must be efficient and decoupled from the UI structure

Changing a piece of text in the UI should not require resending the entire UI definition.

Separation of Data and Components: Having distinct componentUpdate and data model update messages is key. The UI structure can be sent once, and subsequent updates can be small dataModelUpdate messages that only contain the changed data.

### Requirement: The communication architecture must be robust and scalable

The system needs a clear, reliable way to handle both server-pushed UI and client-initiated events.

Unidirectional UI Stream: Using a one-way stream (SSE) for UI updates simplifies the client's logic. It only needs to listen and react. This is a more robust pattern for server-push than trying to manage a complex bidirectional channel.

Event Handling: Event handling is done via an A2A message from the client to the server agent

## Introduction

The A2UI Protocol is a protocol designed for rendering user interfaces from a stream of JSON objects sent from a server. Its core philosophy emphasizes a clean separation of UI structure and application data, enabling progressive rendering as the client processes each message.

The protocol is designed to be "LLM-friendly," meaning its structure is declarative and straightforward, making it easy for a generative model to produce. A core feature of A2UI is its extensible component model. The set of available UI components is not fixed by the protocol but is defined in a separate **Catalog**, allowing for platform-specific or custom components.

Communication occurs via a JSON Lines (JSONL) stream. The client parses each line as a distinct message and incrementally builds the UI. The server-to-client protocol defines four message types:

- `surfaceUpdate`: Provides a list of component definitions to be added to or updated in a specific UI area called a "surface."
- `dataModelUpdate`: Provides new data to be inserted into or to replace a surface's data model. Each surface has its own data model.
- `beginRendering`: Signals to the client that it has enough information to perform the initial render, specifying the ID of the root component and, optionally, the component catalog to use.
- `deleteSurface`: Explicitly removes a surface and its contents from the UI.

Client-to-server communication for user interactions is handled separately via an A2A message. This message can be one of two types:

- `userAction`: Reports a user-initiated action from a component.
- `error`: Reports a client-side error.
  This keeps the primary data stream unidirectional.

## Section 1: Foundational architecture and data flow

This document specifies the architecture and data formats for the A2UI protocol. The design is guided by principles of strict separation of concerns, versioning, and progressive rendering.

### 1.1. Core philosophy: decoupling and contracts

The central philosophy of A2UI is the decoupling of three key elements:

1.  **The Component Tree (The Structure):** A server-provided tree of abstract components that describes the UI's structure. This is defined by `surfaceUpdate` messages.
2.  **The Data Model (The State):** A server-provided JSON object containing the dynamic values that populate the UI, such as text, booleans, or lists. This is managed via `dataModelUpdate` messages.
3.  **The Widget Registry (The "Catalog"):** A client-defined mapping of component types (e.g., "Row", "Text") to concrete, native widget implementations. This registry is **part of the client application**, not the protocol stream. The server must generate components that the target client's registry understands.

### 1.2. The JSONL stream: The unit of communication

All UI descriptions are transmitted from the server to the client as a stream of JSON objects, formatted as JSON Lines (JSONL). Each line is a separate, compact JSON object representing a single message. This allows the client to parse and process each part of the UI definition as it arrives, enabling progressive rendering.

### 1.3. Surfaces: Managing Multiple UI Regions

A **Surface** is a contiguous portion of screen real estate into which a A2UI UI can be rendered. The protocol introduces the concept of a `surfaceId` to uniquely identify and manage these areas. This allows a single A2UI stream to control multiple, independent UI regions simultaneously. Each surface has a separate root component and a separate hierarchy of components. Each surface has a separate data model, to avoid collision of keys when working with a large number of surfaces.

For example, in a chat application, each AI-generated response could be rendered into a separate surface within the conversation history. A separate, persistent surface could be used for a side panel that displays related information.

The `surfaceId` is a property within each server-to-client message that directs changes to the correct area. It is used with messages like `beginRendering`, `surfaceUpdate`, `dataModelUpdate`, and `deleteSurface` to target a specific surface.

### 1.4. Data Flow Model

The A2UI protocol is composed of a server-to-client stream describing UI and individual events sent to the server. The client consumes the stream, builds the UI, and renders it. Communication occurs via a JSON Lines (JSONL) stream, typically transported over **Server-Sent Events (SSE)**.

1.  **Server Stream:** The server begins sending the JSONL stream over an SSE connection.
2.  **Client-Side Buffering:** The client receives messages and buffers them:
    - `surfaceUpdate`: Component definitions are stored in a `Map<String, Component>`, organized by `surfaceId`. If a surface doesn't exist, it is created.
    - `dataModelUpdate`: The client's internal JSON data model is built or updated.

3.  **Render Signal:** The server sends a `beginRendering` message with the `root` component's ID. This prevents a "flash of incomplete content." The client buffers incoming components and data but waits for this explicit signal before attempting the first render, ensuring the initial view is coherent.
4.  **Client-Side Rendering:** The client, now in a "ready" state, starts at the `root` component. It recursively walks the component tree by looking up component IDs in its buffer. It resolves any data bindings against the data model and uses its `WidgetRegistry` to instantiate native widgets.
5.  **User Interaction and Event Handling:** The user interacts with a rendered widget (e.g., taps a button). The client constructs a `userAction` JSON payload, resolving any data bindings from the component's `action.context`. It sends this payload to the server via an A2A message.
6.  **Dynamic Updates:** The server processes the `userAction`. If the UI needs to change in response, the server sends new `surfaceUpdate` and `dataModelUpdate` messages over the original SSE stream. As these arrive, the client updates its component buffer and data model, and the UI re-renders to reflect the changes. The server can also send `deleteSurface` to remove a UI region.

```mermaid
sequenceDiagram
    participant Server
    participant Client

    Server->>+Client: SSE Connection (JSONL Stream)
    Client->>Client: 1. Parse JSONL message
    loop Until 'beginRendering'
        Client->>Client: 2a. Process surfaceUpdate
        Client->>Client: 2b. Process dataModelUpdate
    end
    Client->>Client: 3. Process beginRendering (rootId: 'root', isReady: true)
    Note right of Client: 4. Triggers UI build for a surface
    Client->>Client: 5. Build widget tree from 'root'
    Client->>Client: 6. Resolve data bindings
    Client->>Client: 7. Look up widgets in WidgetRegistry
    Client-->>-Server: (UI is rendered)

    Note over Client: 8. User interacts with UI (e.g., clicks button)
    Client->>Client: 9. Construct userAction payload
    Client->>+Server: 10. A2A Message sent to server (Client Event JSON with userAction)
    Server-->>-Client: 11. OK

    loop Dynamic Updates in Response to Event
        Server->>+Client: surfaceUpdate, dataModelUpdate, or deleteSurface (via SSE)
        Client->>Client: Update component map, data model, or remove surface
        Note right of Client: Triggers UI rebuild
        Client-->>-Server: (UI is updated)
    end
```

### 1.5. Full Stream Example

The following is a complete, minimal example of a JSONL stream that renders a user profile card.

```jsonl
{"surfaceUpdate": {"components": [{"id": "root", "component": {"Column": {"children": {"explicitList": ["profile_card"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "profile_card", "component": {"Card": {"child": "card_content"}}}]}}
{"surfaceUpdate": {"components": [{"id": "card_content", "component": {"Column": {"children": {"explicitList": ["header_row", "bio_text"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "header_row", "component": {"Row": {"alignment": "center", "children": {"explicitList": ["avatar", "name_column"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "avatar", "component": {"Image": {"url": {"literalString": "https://www.example.com/profile.jpg"}}}}]}}
{"surfaceUpdate": {"components": [{"id": "name_column", "component": {"Column": {"alignment": "start", "children": {"explicitList": ["name_text", "handle_text"]}}}}]}}
{"surfaceUpdate": {"components": [{"id": "name_text", "component": {"Text": {"usageHint": "h3", "text": {"literalString": "A2A Fan"}}}}]}}
{"surfaceUpdate": {"components": [{"id": "handle_text", "component": {"Text": {"text": {"literalString": "@a2a_fan"}}}}]}}
{"surfaceUpdate": {"components": [{"id": "bio_text", "component": {"Text": {"text": {"literalString": "Building beautiful apps from a single codebase."}}}}]}}
{"dataModelUpdate": {"contents": {}}}
{"beginRendering": {"root": "root"}}
```

## Section 2: The Component Model

A2UI's component model is designed for flexibility, separating the protocol from the component set.

### 2.1. Catalog Negotiation

A **Catalog** defines the contract between the server and the client for the UI that can be rendered. It contains a list of supported component types (e.g., `Row`, `Text`), their properties, and available styles. A catalog is defined by a **Catalog Definition Document**.

There is a **Standard Catalog** associated with each version of the A2UI protocol. For v0.8, its identifier is `https://a2ui.org/specification/v0_8/standard_catalog_definition.json`.

Catalog IDs are simple string identifiers. While they can be anything, it is conventional to use a URI within a domain that you own, to simplify debugging, avoid confusion, and avoid name collisions. Furthermore, if any changes are made to a catalog that could break compatibility between an agent and renderer, a new `catalogId` **must** be assigned. This ensures clear versioning and prevents unexpected behavior if an agent has changes but the client does not, or vice versa.

The negotiation process allows the client and server to agree on which catalog to use for a given UI surface. This process is designed to be flexible, supporting standard, custom, and even dynamically-defined catalogs.

The flow is as follows:

#### 1. Server Advertises Capabilities

The server (agent) advertises its capabilities in its Agent Card as part of the A2A protocol. For A2UI, this includes which catalogs it supports and whether it can handle catalogs defined inline by the client.

- `supportedCatalogIds` (array of strings, optional): A list of IDs for all pre-defined catalogs the agent is known to support.
- `acceptsInlineCatalogs` (boolean, optional): If `true`, the server can process `inlineCatalogs` sent by the client. Defaults to `false`.

**Example Server Agent Card Snippet:**

```json
{
  "name": "Restaurant Finder",
  "capabilities": {
    "extensions": [
      {
        "uri": "https://a2ui.org/a2a-extension/a2ui/v0.8",
        "params": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_8/standard_catalog_definition.json",
            "https://my-company.com/a2ui/v0.8/my_custom_catalog.json"
          ],
          "acceptsInlineCatalogs": true
        }
      }
    ]
  }
}
```

Note that this is not a strict contract and purely included as a signal to help orchestrators and clients identify agents with matching UI capabilities. At runtime, orchestrating agents may dynamically delegate tasks to subagents which support additional catalogs that the orchestrating agent did not advertise. Thus, clients should consider the advertised supportedCatalogIds as a subset of the true catalogs that the agent or its subagents may support.

#### 2. Client Declares Supported Catalogs

In **every** message sent to the server, the client includes an `a2uiClientCapabilities` object within the A2A `Message`'s `metadata` field. This object informs the agent server of all catalogs the client can render.

- `supportedCatalogIds` (array of strings, required): A list of identifiers for all pre-defined catalogs the client supports. The client must explicitly include the standard catalog ID here if it supports the standard catalog. The contents of these catalogs are expected to be compiled into the agent server and not downloaded at runtime, in order to prevent malicious content being injected into the prompt dynamically, and ensure predictable results.
- `inlineCatalogs` (array of objects, optional): An array of full Catalog Definition Documents. This allows a client to provide custom, on-the-fly catalogs, typically for use in local development workflows where it is faster to update a catalog in one place on the client. This may only be provided if the server has advertised `acceptsInlineCatalogs: true`.

**Example A2A Message with Client Capabilities:**

```json
{
  "metadata": {
    "a2uiClientCapabilities": {
      "supportedCatalogIds": [
        "https://a2ui.org/specification/v0_8/standard_catalog_definition.json",
        "https://my-company.com/a2ui_catalogs/custom-reporting-catalog-1.2"
      ],
      "inlineCatalogs": [
        {
          "catalogId": "https://my-company.com/inline_catalogs/temp-signature-pad-catalog",
          "components": {
            "SignaturePad": {
              "type": "object",
              "properties": {"penColor": {"type": "string"}}
            }
          },
          "styles": {}
        }
      ]
    }
  },
  "message": {
    "prompt": {
      "text": "Find me a good restaurant"
    }
  }
}
```

#### 3. Server Chooses Catalog and Renders

The server receives the client's capabilities and chooses a catalog to use for a specific UI surface. The server specifies its choice in the `beginRendering` message using the `catalogId` field.

- `catalogId` (string, optional): The identifier of the chosen catalog. This ID must be one of the `supportedCatalogIds` or the `catalogId` from one of the `inlineCatalogs` provided by the client.

If the `catalogId` is omitted, the client **MUST** default to the standard catalog for the protocol version (`https://a2ui.org/specification/v0_8/standard_catalog_definition.json`).

**Example `beginRendering` Message:**

```json
{
  "beginRendering": {
    "surfaceId": "unique-surface-1",
    "catalogId": "https://my-company.com/inline_catalogs/temp-signature-pad-catalog",
    "root": "root-component-id"
  }
}
```

Each surface can use a different catalog, providing a high degree of flexibility, particularly in multi-agent systems where different agents may support different catalogs.

#### Schemas for Developers

When building an agent, it is recommended to use a resolved schema that includes the specific component catalog you are targeting (e.g., a custom schema combining `server_to_client.json` with your `https://my-company.com/a2ui_catalogs/custom-reporting-catalog-1.2` definition). This provides the LLM with a strict definition of all available components and their properties, as well as the catalog-specific styles, leading to more reliable UI generation. The generic `server_to_client.json` is the abstract wire protocol, while the resolved schema is the concrete tool for generation.

In order to do the substitution, based on the standard `server_to_client_schema` and a `custom_catalog_definition` object, you can use JSON manipulation logic similar to:

```py
component_properties = custom_catalog_definition["components"]
style_properties = custom_catalog_definition["styles"]
resolved_schema = copy.deepcopy(server_to_client_schema)

resolved_schema["properties"]["surfaceUpdate"]["properties"]["components"]["items"]["properties"]["component"]["properties"] = component_properties
resolved_schema["properties"]["beginRendering"]["properties"]["styles"]["properties"] = style_properties
```

See `server_to_client_with_standard_catalog.json` for an example of a resolved
schema which has the components substituted in.

### 2.2. The `surfaceUpdate` Message

This message is the primary way UI structure is defined. It contains a `surfaceId` and a `components` array.

```json
{
  "surfaceUpdate": {
    "surfaceId": "main_content_area",
    "components": [
      {
        "id": "unique-component-id",
        "component": {
          "Text": {
            "text": { "literalString": "Hello, World!" }
          }
        }
      },
      {
        "id": "another-component-id",
        "component": { ... }
      }
    ]
  }
}
```

- `components`: A required flat list of component instances.

### 2.3. The Component Object

Each object in the `components` array has the following structure:

- `id`: A required, unique string that identifies this specific component instance. This is used for parent-child references.
- `component`: A required object that defines the component's type and properties.

### 2.4.`component` (Generic Object)

On the wire, this object is generic. Its structure is not defined by the core A2UI protocol. Instead, its validation is based on the active **Catalog**. It is a wrapper object that **must** contain exactly one key, where the key is the string name of the component type from the catalog (e.g., `"Text"`, `"Row"`). The value is an object containing the properties for that component, as defined in the catalog.

**Example:** A `Text` component:

```json
"component": {
  "Text": {
    "text": { "literalString": "This is text" }
  }
}
```

A `Button` component:

```json
"component": {
  "Button": {
    "label": { "literalString": "Click Me" },
    "action": { "name": "submit_form" }
  }
}
```

The full set of available component types and their properties is defined by a **Catalog Schema**, not in the core protocol schema.

## Section 3: UI Composition

### 3.1. The Adjacency List Model

The A2UI protocol defines the UI as a flat list of components. The tree structure is built implicitly using ID references. This is known as an adjacency list model.

Container components (like `Row`, `Column`, `List`, `Card`) have properties that reference the `id` of their child component(s). The client is responsible for storing all components in a map (e.g., `Map<String, Component>`) and recreating the tree structure at render time.

This model allows the server to send component definitions in any order, as long as all necessary components are present by the time `beginRendering` is sent.

```mermaid
flowchart TD
    subgraph "Server Stream (JSONL)"
        A("<b>surfaceUpdate</b><br>components: [root, title, button, button_text]")
        B("<b>beginRendering</b><br>root: 'root'")
    end

    subgraph "Client-Side Buffer (Map)"
        C("root: {id: 'root', type: Column, children: ['title', 'button']}")
        D("title: {id: 'title', type: Text, text: 'Welcome'}")
        E("button: {id: 'button', type: Button, child: 'button_text'}")
        E_TEXT("button_text: {id: 'button_text', type: Text, text: 'Go'}")
    end

    subgraph "Rendered Widget Tree"
        F(Column) --> G(Text: 'Welcome')
        F --> H(Button)
        H --> I(Text: 'Go')
    end

    A -- "Parsed and stored" --> C
    A -- "Parsed and stored" --> D
    A -- "Parsed and stored" --> E
    A -- "Parsed and stored" --> E_TEXT

    B -- "Triggers build from buffer" --> F
```

### 3.2. Container Children: `explicitList` vs. `template`

Container components (`Row`, `Column`, `List`) define their children using a `children` object, which must contain _either_ `explicitList` or `template`.

- `explicitList`: An array of component `id` strings. This is used for static, known children.
- `template`: An object used to render a dynamic list of children from a data-bound list.

```json
{
  "type": "object",
  "description": "Defines the children of a container component. Must contain exactly one of `explicitList` or `template`.",
  "properties": {
    "explicitList": {
      "type": "array",
      "description": "An ordered list of component IDs that are direct children.",
      "items": {
        "type": "string",
        "description": "The ID of a child component."
      }
    },
    "template": {
      "type": "object",
      "description": "Defines a template for rendering dynamic lists of children.",
      "properties": {
        "dataBinding": {"$ref": "#/definitions/DataPath"},
        "componentId": {
          "type": "string",
          "description": "The ID of the component to use as a template for each item in the data-bound list."
        }
      },
      "required": ["dataBinding", "componentId"],
      "additionalProperties": false
    }
  },
  "minProperties": 1,
  "maxProperties": 1
}
```

### 3.3. Dynamic List Rendering with `template`

To render dynamic lists, a container uses the `template` property.

1.  `dataBinding`: A path to a list in the data model (e.g., `/user/posts`).
2.  `componentId`: The `id` of another component in the buffer to use as a template for each item in the list.

The client will iterate over the list at `dataBinding` and, for each item, render the component specified by `componentId`. The item's data is made available to the template component for relative data binding.

## Section 4: Dynamic Data & State Management

A2UI enforces a clean separation between the UI's structure (components) and its dynamic data (data model).

### 4.1. The `dataModelUpdate` Message

This message is the only way to modify the client's data model.

- `surfaceId`: The unique identifier for the UI surface this data model update applies to.
- `path`: An optional path to a location within the data model (e.g., '/user/name'). If omitted, the update applies to the root of the data model.
- `contents`: An array of data entries arranged as an adjacency list. Each entry must contain a 'key' and exactly one corresponding typed 'value\*' property (e.g. `valueString`, `valueNumber`, `valueBoolean`, `valueMap`).
  - `valueMap`: A JSON object representing a map as an adjacency list.

#### Example: Updating the data model

```json
{
  "dataModelUpdate": {
    "surfaceId": "main_content_area",
    "path": "user",
    "contents": [
      {"key": "name", "valueString": "Bob"},
      {"key": "isVerified", "valueBoolean": true},
      {
        "key": "address",
        "valueMap": [
          {"key": "street", "valueString": "123 Main St"},
          {"key": "city", "valueString": "Anytown"}
        ]
      }
    ]
  }
}
```

### 4.2. Data Binding (The `BoundValue` Object)

Components connect to the data model through binding. Any property that can be data-bound (like `text` on a `Text` component) accepts a `BoundValue` object. This object defines either a literal value, a data path, or both as a shorthand for initialization.

From the catalog schema, a bound `text` property looks like this:

```json
{
  "type": "object",
  "description": "A value that can be either a literal string or bound to the data model.",
  "properties": {
    "literalString": {
      "type": "string",
      "description": "A static string value."
    },
    "path": {"$ref": "#/definitions/DataPath"}
  },
  "minProperties": 1,
  "additionalProperties": false
}
```

A component can also bind to numbers (`literalNumber`), booleans (`literalBoolean`), or arrays (`literalArray`). The behavior depends on which properties are provided:

- **Literal Value Only**: If only a `literal*` value (e.g., `literalString`) is provided, the value is static and displayed directly.

  ```json
  "text": { "literalString": "Hello" }
  ```

- **Path Only**: If only `path` is provided, the value is dynamic. It's resolved from the data model at render time.

  ```json
  "text": { "path": "/user/name" }
  ```

- **Path and Literal Value (Initialization Shorthand)**: If **both** `path` and a `literal*` value are provided, it serves as a shorthand for data model initialization. The client MUST:
  1.  Update the data model at the specified `path` with the provided `literal*` value. This is an implicit `dataModelUpdate`.
  2.  Bind the component property to that `path` for rendering and future updates.

  This allows the server to set a default value and bind to it in a single step.

  ```json
  // This initializes data model at '/user/name' to "Guest" and binds to it.
  "text": { "path": "/user/name", "literalString": "Guest" }
  ```

The client's interpreter is responsible for resolving these paths against the data model before rendering. The A2UI protocol supports direct 1:1 binding; it does not include transformers (e.g., formatters, conditionals). Any data transformation must be performed by the server before sending it in a `dataModelUpdate`.

## Section 5: Event Handling

While the server-to-client UI definition is a one-way stream (e.g., over SSE), user interactions are communicated back to the server using an A2A message.

### 5.1. The Client Event Message

The client sends a single JSON object that acts as a wrapper. It must contain exactly one of the following keys: `userAction` or `error`.

### 5.2. The `userAction` Message

This message is sent when the user interacts with a component that has an action defined. It is the primary mechanism for user-driven events.

The `userAction` object has the following structure:

- `name` (string, required): The name of the action, taken directly from the `action.name` property of the component (e.g., "submit_form").
- `surfaceId` (string, required): The `id` of the surface where the event originated.
- `sourceComponentId` (string, required): The `id` of the component that triggered the event (e.g., "my_button").
- `timestamp` (string, required): An ISO 8601 timestamp of when the event occurred (e.g., "2025-09-19T17:01:00Z").
- `context` (object, required): A JSON object containing the key-value pairs from the component's `action.context`, after resolving all `BoundValue`s against the data model.

The process for resolving the `action.context` remains the same: the client iterates over the `context` array, resolves all literal or data-bound values, and constructs the `context` object.

### 5.3. The `error` Message

This message provides a feedback mechanism for the server. It is sent when the client encounters an error, for instance, during UI rendering or data binding. The content of the object is flexible and can contain any relevant error information.

### 5.4. Event Flow Example (`userAction`)

1.  **Component Definition** (from `surfaceUpdate`):

    ```json
    {
      "surfaceUpdate": {
        "surfaceId": "main_content_area",
        "components": [
          {
            "id": "submit_btn_text",
            "component": {
              "Text": {
                "text": {"literalString": "Submit"}
              }
            }
          },
          {
            "id": "submit_btn",
            "component": {
              "Button": {
                "child": "submit_btn_text",
                "action": {
                  "name": "submit_form",
                  "context": [
                    {
                      "key": "userInput",
                      "value": {"path": "/form/textField"}
                    },
                    {"key": "formId", "value": {"literalString": "f-123"}}
                  ]
                }
              }
            }
          }
        ]
      }
    }
    ```

2.  **Data Model** (from `dataModelUpdate`):

    ```json
    {
      "dataModelUpdate": {
        "surfaceId": "main_content_area",
        "path": "form",
        "contents": [{"key": "textField", "valueString": "User input text"}]
      }
    }
    ```

3.  **User Action:** The user taps the "submit_btn" button.
4.  **Client-Side Resolution:** The client resolves the `action.context`.
5.  **Client-to-Server Request:** The client sends a `POST` request to `https://api.example.com/handle_event` with the following JSON body:

    ```json
    {
      "userAction": {
        "name": "submit_form",
        "surfaceId": "main_content_area",
        "sourceComponentId": "submit_btn",
        "timestamp": "2025-09-19T17:05:00Z",
        "context": {
          "userInput": "User input text",
          "formId": "f-123"
        }
      }
    }
    ```

6.  **Server Response:** The server processes this event. If the UI needs to change as a result, the server sends new `surfaceUpdate` or `dataModelUpdate` messages over the **separate SSE stream**.

## Section 6: Client-Side Implementation

A robust client-side interpreter for A2UI should be composed of several key components:

- **JSONL Parser:** A parser capable of reading the stream line by line and decoding each line as a separate JSON object.
- **Message Dispatcher:** A mechanism (e.g., a `switch` statement) to identify the message type (`beginRendering`, `surfaceUpdate`, etc.) and route it to the correct handler.
- **Component Buffer:** A `Map<String, Component>` that stores all component instances by their `id`. This is populated by `componentUpdate` messages.
- **Data Model Store:** A `Map<String, dynamic>` (or similar) that holds the application state. This is built and modified by `dataModelUpdate` messages.
- **Interpreter State:** A state machine to track if the client is ready to render (e.g., a `_isReadyToRender` boolean that is set to `true` by `beginRendering`).
- **Widget Registry**: A developer-provided map (e.g., `Map<String, WidgetBuilder>`) that associates component type strings ("Row", "Text") with functions that build native widgets.
- **Binding Resolver:** A utility that can take a `BoundValue` (e.g., `{ "path": "/user/name" }`) and resolve it against the Data Model Store.
- **Surface Manager:** Logic to create, update, and delete UI surfaces based on `surfaceId`.
- **Event Handler:** A function, exposed to the `WidgetRegistry`, that constructs and sends the client event message (e.g., `userAction`) to the configured REST API endpoint.

## Section 7: Complete A2UI Server To Client JSON Schema

This section provides the formal JSON Schema for a single server-to-client message in the A2UI JSONL stream. Each line in the stream must be a valid JSON object that conforms to this schema. It includes the entire base catalog of components, but the components may be swapped out for other components supported by the client. It is optimized to be able to be generated in structured output mode from various LLMs.

```json
{% include "../specification/json/server_to_client_with_standard_catalog.json" %}
```

## Section 8: Complete A2UI Client to Server JSON Schema

This section provides the formal JSON Schema for a single client-to-server message in the A2UI protocol.

```json
{% include "../specification/json/client_to_server.json" %}
```

---

### Specification V0 8 Docs Custom Catalog Changes (`specification/v0_8/docs/custom_catalog_changes.md`)

# Summary of Custom Catalog negotiation changes in A2UI v0.8

This document summarizes the changes made to the A2UI protocol in v0.8 to support a more flexible and powerful custom catalog negotiation mechanism. It is intended as a guide for developers implementing these changes in agent or renderer libraries.

The previous mechanism, which involved a single, one-time `clientUiCapabilities` message, has been deprecated. The new approach allows for a more dynamic, per-request declaration of capabilities, enabling a single client to support multiple catalogs and allowing the agent to choose the most appropriate one for each UI surface.

## Key changes to the protocol

1.  **Agent capability advertisement (`supportedCatalogIds`, `acceptsInlineCatalogs`)**: The agent's role in negotiation has been expanded. It now can declare a list of supported catalog IDs, in addition to whether it is capable of processing catalogs defined "inline" by the client.
    - **Relevant Doc**: [`a2ui_extension_specification.md`](./a2ui_extension_specification.md)

2.  **Client capabilities via A2A metadata**: The client now sends its capabilities in an `a2uiClientCapabilities` object. Crucially, this is no longer a standalone message but is included in the `metadata` field of the A2A `Message` for **every** A2A `Message` sent to the agent.
    - This object contains `supportedCatalogIds` (an array of known catalog IDs) and an optional `inlineCatalogs` (an array of full catalog definitions).
    - **Relevant doc**: The new process is explained in the [`a2ui_protocol.md`](./a2ui_protocol.md#catalog-negotiation) section on Catalog Negotiation.
    - **Relevant schema**: [`a2ui_client_capabilities_schema.json`](../json/a2ui_client_capabilities_schema.json)

3.  **Per-Surface catalog selection (`beginRendering`)**: The agent is now responsible for selecting which catalog to use for each UI surface. It signals its choice using the new optional `catalogId` field in the `beginRendering` message. If this field is omitted, the client must default to the Standard Catalog.
    - **Relevant doc**: [`a2ui_protocol.md`](./a2ui_protocol.md#catalog-negotiation)
    - **Relevant schema**: The change is reflected in [`server_to_client.json`](../json/server_to_client.json).

4.  **Catalog definition ID (`catalogId`)**: To facilitate identification, the catalog definition schema itself now has a required `catalogId` field.
    - **Relevant schema**: [`catalog_description_schema.json`](../json/catalog_description_schema.json)

---

## Implementation guide for developers

### For Agent (server) library developers

Your responsibilities are to process the client's declared capabilities and make a rendering choice.

1.  **Advertise capability**: In the agent's capability card, add the `supportedCatalogIds` array and the `acceptsInlineCatalogs: true` parameter within the A2UI extension block to declare which catalogs you support and whether you can handle dynamic ones.

2.  **Parse client capabilities**: On every incoming A2A `Message`, your library must parse the `a2uiClientCapabilities` object in the `metadata` field of the A2A `Message` to determine which catalogs the client supports. You will get a list of `supportedCatalogIds` and potentially a list of `inlineCatalogs`.

3.  **Choose a Catalog**: Before rendering a UI, decide which catalog to use. Your choice must be one of the catalogs advertised by the client in the capabilities object.

4.  **Specify Catalog on render**: When sending the `beginRendering` message for a surface, set the `catalogId` field to the ID of your chosen catalog (e.g., `"https://my-company.com/inline_catalogs/my-custom-catalog"`). If you do not set this field, you are implicitly requesting the use of the standard catalog.

5.  **Generate compliant UI**: Ensure that all components generated in subsequent `surfaceUpdate` messages for that surface conform to the properties and types defined in the chosen catalog.

### For Renderer (client) library developers

Your responsibilities are to accurately declare your capabilities and render surfaces using the catalog selected by the agent.

1.  **Declare capabilities on every request**: For every A2A `Message` your application sends, your library must inject the `a2uiClientCapabilities` object into the `metadata` field of the A2A `Message`.

2.  **Populate `supportedCatalogIds`**: In the capabilities object, populate this array with the string identifiers of all pre-compiled catalogs your renderer supports. If your renderer supports the standard catalog for v0.8, you **should** include its ID: `https://a2ui.org/specification/v0_8/standard_catalog_definition.json`.

3.  **Provide `inlineCatalogs` (optional)**: If your renderer supports dynamically generating or defining catalogs at runtime, include their full, valid Catalog Definition Documents in the `inlineCatalogs` array.

4.  **Process `beginRendering`**: When your renderer receives a `beginRendering` message, it must inspect the new `catalogId` field.

5.  **Select Catalog for surface**:
    - If `catalogId` is present, use the corresponding catalog to render that surface. Your renderer must be able to look up the catalog from its pre-compiled list or from the inline definitions it just sent.
    - If `catalogId` is **absent**, you **must** default to using the Standard Catalog for v0.8 for that surface.

6.  **Manage multiple Catalogs**: Your renderer must be architected to handle multiple surfaces being rendered with different catalogs simultaneously. A dictionary mapping `surfaceId` to the chosen `catalog` is a common approach.

---

### Specification V0 9 Docs A2ui Custom Functions (`specification/v0_9/docs/a2ui_custom_functions.md`)

# Defining Custom Functions

A2UI functions are defined inside a Catalog. When defining your own catalog, you can include custom functions that are specific to your application or design system.

This guide demonstrates how to define a string `trim` function and a hardware query function (`getScreenResolution`) in your catalog.

## 1. Define the Catalog

Create a JSON Schema file (e.g., `my_catalog.json`) that defines your
function parameters.

Use the `functions` property to define a map of function schemas.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## 2. Make the functions available

The `FunctionCall` definition refers to a [catalog-agnostic reference](a2ui_protocol.md#the-basic-catalog).
In your catalog, you simply need to define the `anyFunction` reference:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [{"$ref": "#/functions/trim"}, {"$ref": "#/functions/getScreenResolution"}]
    }
  }
}
```

If you want to incorporate functions defined in the [`catalogs/basic/catalog.json`],
those can be added too:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [
        {"$ref": "#/functions/trim"},
        {"$ref": "#/functions/getScreenResolution"},
        {"$ref": "catalogs/basic/catalog.json#/$defs/anyFunction"}
      ]
    }
  }
}
```

## How Validation Works

When a `FunctionCall` is validated:

1. **Discriminator Lookup:** The validator looks at the `call` property of the
   object.
2. **Schema Matching:**
   - If `call` is "length", it matches `Functions` -> `length`
     and validates the named arguments in `args` against the length rules.
   - If `call` is "trim", it matches `CustomFunctions` -> `trim` and
     validates against your custom rules.
   - If `call` is "unknownFunc", validation FAILS immediately (strict mode).

This strict-by-default approach ensures typos are caught early, while the
modular structure makes it easy to add new capabilities with full type safety.

---

### Specification V0 9 Docs A2ui Extension Specification (`specification/v0_9/docs/a2ui_extension_specification.md`)

# A2UI (Agent-to-Agent UI) Extension spec v0.9

## Overview

This document is intended for developers implementing the A2UI A2A extension. The extension adds A2UI v0.9 support to A2A, a format for agents to send streaming, interactive user interfaces to clients.

Note that A2UI extension activation is optional as clients and agents can negotiate A2UI support using A2A `message.metadata["a2uiClientCapabilities"]` which is attached to every A2A message from the client and contains the supported protocol version and catalogs. Agents advertising A2UI support in their AgentCard is encouraged as clients may rely on it to determine if they should send `message.metadata["a2uiClientCapabilities"]`, however it is not explicitly required.

## Extension URI

The URI of this extension is https://a2ui.org/a2a-extension/a2ui/v0.9

This URI is the canonical way to communicate protocol versioning between clients and agents. The extension URI explicitly encodes the version (e.g., `v0.9`). A client requesting this specific URI indicates it supports the v0.9 schema format.

## Agent Card

Agents are encouraged to advertise their A2UI capabilities in their AgentCard within the `AgentCapabilities.extensions` list. This advertisement is optional, but it informs the client whether to send `message.metadata["a2uiClientCapabilities"]`. The `params` object defines the agent's specific UI support and corresponds directly to the [Server Capabilities Schema](../json/server_capabilities.json).

Example AgentCard payload:

```json
{
  "name": "Dashboard Agent",
  "description": "Agent capable of generating dynamic UI dashboards.",
  "capabilities": {
    "extensions": [
      {
        "uri": "https://a2ui.org/a2a-extension/a2ui/v0.9",
        "description": "Ability to render A2UI v0.9",
        "required": false,
        "params": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v0.9/my_custom_catalog.json"
          ],
          "acceptsInlineCatalogs": true
        }
      }
    ]
  }
}
```

The `params` object corresponds to the `v0.9` object in the `server_capabilities.json` schema:

- `params.supportedCatalogIds` (optional): An array of strings, where each string is an ID identifying a Catalog Definition Schema that the agent can generate. This is not necessarily a resolvable URI.
- `params.acceptsInlineCatalogs` (optional): A boolean indicating if the agent can accept an `inlineCatalogs` array in the client's `a2uiClientCapabilities`. If omitted, this defaults to `false`.

## A2A Extension activation

Activating the A2UI extension is optional. Clients and agents can negotiate A2UI support using `message.metadata["a2uiClientCapabilities"]` A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`.

Specifically:

- If a client includes `message.metadata["a2uiClientCapabilities"]`, the agent can use this object to determine the supported A2UI protocol version and catalogs.
- If an agent returns A2A A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`, the client knows the payload contains A2UI messages.

While explicit activation is not required, clients can still explicitly activate the extension using the transport-defined A2A extension activation mechanism. The [A2A Extensions Guide](https://a2a-protocol.org/latest/topics/extensions/) defines this process.

Note: You should not use `accepted_output_modes: ['a2ui']` (which is not an A2UI standard) to trigger A2UI.

### JSON-RPC and HTTP transports

To activate the A2UI A2A Extension, the `X-A2A-Extensions` HTTP header includes the extension URI.

**Example HTTP `SendMessageRequest`:**

```http
POST /v1/messages HTTP/1.1
Host: agent.example.com
X-A2A-Extensions: https://a2ui.org/a2a-extension/a2ui/v0.9
Content-Type: application/json

{
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
      }
    ]
  }
}
```

To see how the agent parses the extension URI, see [`extension.py`](../../../python/a2ui_a2a/src/a2ui/a2a/extension.py).

### GRPC transport

To activate the A2UI A2A Extension, the client adds the extension URI to A2A `sendMessageParams.metadata["X-A2A-Extensions"]`.

**Example gRPC `SendMessageRequest`:**

```json
{
  "metadata": {
    "X-A2A-Extensions": "https://a2ui.org/a2a-extension/a2ui/v0.9"
  },
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
        }
      ]
    }
  }
}
```

## A2A Client to Server Metadata

Clients attach `a2uiClientCapabilities` and `a2uiClientDataModel` to A2A messages to communicate their state and supported catalogs.

### `a2uiClientCapabilities`

The client sends `sendMessageRequest.message["a2uiClientCapabilities"]` = [Client Capabilities Schema](../json/client_capabilities.json) to advertise which catalogs the renderer supports.

**Example `SendMessageRequest` with Capabilities:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Show me the dashboard."
      }
    ],
    "metadata": {
      "a2uiClientCapabilities": {
        "v0.9": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v0.9/my_custom_catalog.json"
          ]
        }
      }
    }
  }
}
```

### `a2uiClientDataModel`

When a surface enables Data Model Sync, the client sends `sendMessageRequest.message["a2uiClientDataModel"]` = [Client Data Model Schema](../json/client_data_model.json) on every message. This model provides the agent with the latest UI state. For more details, see the [Actions Guide](../../../docs/public/concepts/actions.md).

**Example `SendMessageRequest` with Data Model:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Submit the form."
      }
    ],
    "metadata": {
      "a2uiClientDataModel": {
        "version": "v0.9",
        "surfaces": {
          "main_surface_id": {
            "user_id": "12345",
            "email": "user@example.com"
          }
        }
      }
    }
  }
}
```

## Data encoding

Agents and clients encode A2UI messages as an A2A `DataPart`.

To identify a `DataPart` as containing A2UI data, it must have the following metadata:

- `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`

The `data` field of the `DataPart` contains a list of A2UI JSON messages (e.g., `createSurface`, `updateComponents`, `action`). It MUST be an array of messages.

### Processing Rules

The `data` field contains a list of messages. This list is NOT a transactional unit. Receivers (both Clients and Agents) MUST process messages in the list sequentially.

If a single message in the list fails to validate or apply (e.g., due to a schema violation or invalid reference), the receiver SHOULD report/log the error for that specific message and MUST continue processing the remaining messages in the list.

Atomicity is guaranteed only at the individual message level. However, for a better user experience, a renderer SHOULD NOT repaint the UI until all messages in the list have been processed. This prevents intermediate states from flickering to the user.

### Server-to-client messages

When an agent sends a message to a client (or another agent acting as a client/renderer), the `data` payload must validate against the [Server-to-Client Message List Schema](../json/server_to_client_list.json).

Example DataPart:

```json
{
  "data": [
    {
      "version": "v0.9",
      "createSurface": {
        "surfaceId": "example_surface",
        "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
      }
    },
    {
      "version": "v0.9",
      "updateComponents": {
        "surfaceId": "example_surface",
        "components": [
          {
            "Text": {
              "id": "root",
              "text": "Hello!"
            }
          }
        ]
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

### Client-to-server events

When a client (or an agent forwarding an event) sends a message to an agent, it also uses a `DataPart` with the same `application/a2ui+json` MIME type. However, the `data` payload must validate against the [Client-to-Server Message List Schema](../json/client_to_server_list.json).

Example `action` DataPart:

```json
{
  "data": [
    {
      "version": "v0.9",
      "action": {
        "name": "submit_form",
        "surfaceId": "contact_form_1",
        "sourceComponentId": "submit_button",
        "timestamp": "2026-01-15T12:00:00Z",
        "context": {
          "email": "user@example.com"
        }
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

---

### Specification V0 9 Docs A2ui Protocol (`specification/v0_9/docs/a2ui_protocol.md`)

<div style="text-align: center;">
  <div class="centered-logo-text-group">
    <img src="../../../docs/public/assets/A2UI_dark.svg" alt="A2UI Protocol Logo" width="100">
    <h1>A2UI (Agent to UI) Protocol v0.9</h1>
  </div>
</div>

A Specification for a JSON-Based, Streaming UI Protocol.

**Version:** 0.9
**Status:** Stable
**Created:** Nov 20, 2025

A Specification for a JSON-Based, Streaming UI Protocol

## Introduction

The A2UI Protocol is designed for dynamically rendering user interfaces from a stream of JSON objects sent from a server (Agent). Its core philosophy emphasizes a clean separation of UI structure and application data, enabling progressive rendering as the client processes each message.

Communication occurs via a stream of JSON objects. The client parses each object as a distinct message and incrementally builds or updates the UI. The server-to-client protocol defines four message types:

- `createSurface`: Signals the client to create a new surface and begin rendering it.
- `updateComponents`: Provides a list of component definitions to be added to or updated in a specific surface.
- `updateDataModel`: Provides new data to be inserted into or to replace a surface's data model.
- `deleteSurface`: Explicitly removes a surface and its contents from the UI.

## Changes from previous versions

Version 0.9 of the A2UI protocol represents a philosophical shift from previous versions. While v0.8 was optimized for LLMs that support structured output, v0.9 is designed to be embedded directly within a model's prompt. The LLM is then asked to produce JSON that matches the provided examples and schema descriptions.

This "prompt-first" approach offers several advantages:

1.  **Richer schema:** The protocol is no longer limited by the constraints of structured output formats. This allows for more readable, complex, and expressive component catalogs.
2.  **Modularity:** The schema is now refactored into separate, more manageable components (e.g., [`common_types.json`], [`catalogs/basic/catalog.json`], [`server_to_client.json`]), improving maintainability and modularity.

The main disadvantage of this approach is that it requires more complex post-generation validation, as the LLM is not strictly constrained by the schema. This requires robust error handling and correction, so the system can identify discrepancies and attempt to fix them before rendering, or request a retry or correction from the LLM.

See [the evolution guide](evolution_guide.md) for a detailed explanation of the differences between v0.8 and v0.9.

## Protocol overview & data flow

The A2UI protocol uses a unidirectional stream of JSON messages from the server to the client to describe and update the UI. The client consumes this stream, builds the UI, and renders it. User interactions are handled separately, typically by sending events to a different endpoint, which may in turn trigger new messages on the UI stream.

Here is an example sequence of events (which don't have to be in exactly this order):

1.  **Create Surface:** The server sends a `createSurface` message to initialize the surface.
2.  **Update Surface:** Once a surface has been created, the server sends one or more `updateComponents` messages containing the definitions for all the components that will be part of the surface.
3.  **Update Data Model:** Once a surface has been created, the server can send `updateDataModel` messages at any time to populate or change the data that the UI components will display.
4.  **Render:** The client renders the UI for the surface, using the component definitions to build the structure and the data model to populate the content.
5.  **Dynamic updates:** As the user interacts with the application or as new information becomes available, the server can send additional `updateComponents` and `updateDataModel` messages to dynamically change the UI.
6.  **Delete Surface:** When a UI region is no longer needed, the server sends a `deleteSurface` message to remove it.

```mermaid
sequenceDiagram
    participant Server
    participant Client

    Server->>+Client: 1. createSurface(surfaceId: "main")
    Server->>+Client: 2. updateComponents(surfaceId: "main", components: [...])
    Server->>+Client: 3. updateDataModel(surfaceId: "main", path: "/user", value: "Alice")
    User->>+Client: Interact with UI (e.g. click button)
    Client->>+Server: action(name: "submit", context: {...})
    Client-->>-Server: (UI is displayed)

    Note over Client, Server: Time passes, user interacts, or new data arrives...

    Server->>+Client: 4. updateComponents or updateDataModel (Dynamic Update)
    Note right of Client: Client re-renders the UI to reflect changes
    Client-->>-Server: (UI is updated)

    Server->>+Client: 5. deleteSurface(surfaceId: "main")
    Note right of Client: Client removes the UI for the "main" surface
    Client-->>-Server: (UI is gone)
```

## Transport decoupling

The A2UI protocol is designed to be transport-agnostic. It defines the JSON message structure and the semantic contract between the server (Agent) and the client (Renderer), but it does not mandate a specific transport layer.

### The transport contract

To support A2UI, a transport layer must fulfill the following contract:

1.  **Reliable delivery**: Messages must be delivered in the order they were generated. A2UI relies on stateful updates (e.g., creating a surface before updating it), so out-of-order delivery can corrupt the UI state.
2.  **Message framing**: The transport must clearly delimit individual JSON envelope messages (e.g., using newlines in JSONL, WebSocket frames, or SSE events).
3.  **Metadata support**: The transport must provide a mechanism to associate metadata with messages. This is critical for:
    - **Data model synchronization**: The `sendDataModel` feature requires the client to send the current data model state as metadata alongside user actions.
    - **Capabilities exchange**: Client capabilities (supported catalogs, custom components) and Server capabilities are exchanged via metadata or transport-specific handshakes (like Agent Cards in A2A or initialization in MCP).
4.  **Bidirectional capability (optional)**: While the rendering stream is unidirectional (Server -> Client), interactive applications require a return channel for `action` messages (Client -> Server).

### Transport bindings

While A2UI is agnostic, it is most commonly used with the following transports.

#### A2A (Agent2Agent) binding

[A2A (Agent-to-Agent)](https://a2a-protocol.org/latest/) is an excellent transport option for A2UI in agentic systems, extending A2A with additional payloads.
A2A is uniquely capable of handling remote agent communication, and can also provide a secure and efficient transport between an agentic backend and front end application.

- **Message mapping**: Each A2UI envelope (e.g., `updateComponents`) corresponds to the payload of a single A2A message Part.
- **Metadata**:
  - **Data model**: When `sendDataModel` is active, the client's `a2uiClientDataModel` object is placed in the `metadata` field of the A2A message.
  - **Capabilities**: The `a2uiClientCapabilities` object is placed in the `metadata` field of every A2A `Message` sent from the client to the server.
- **Context**: A2UI sessions typically map to A2A `contextId`. All messages for a set of related surfaces should share the same `contextId`.

#### AG UI (Agent to User Interface) binding

**[AG-UI](https://docs.ag-ui.com/introduction)** is also an excellent transport option for A2UI Agent–User Interaction protocol.
AG UI provides convenient integrations into many agent frameworks and frontends. AG UI provides low latency and shared state message passing between front ends and agentic backends.

#### Other transports

A2UI can also be carried over:

- **[MCP (Model Context Protocol)](https://modelcontextprotocol.io/docs/getting-started/intro)**: Delivered as tool outputs or resource subscriptions.
- **[SSE](https://en.wikipedia.org/wiki/Server-sent_events) with [JSON RPC](https://www.jsonrpc.org/)**: Standard server-sent events for web integrations that support streaming, and JSON RPC for client-server communication.
- **[WebSockets](https://en.wikipedia.org/wiki/WebSocket)**: For bidirectional, real-time sessions.
- **[REST](https://cloud.google.com/discover/what-is-rest-api?hl=en)**: For simple use case, REST APIs will work but lack streaming capabilities.

## The protocol schemas

A2UI v0.9 is defined by three interacting JSON schemas.

### Common types

The [`common_types.json`] schema defines reusable primitives used throughout the protocol.

- **`DynamicString` / `DynamicNumber` / `DynamicBoolean` / `DynamicStringList`**: The core of the data binding system. Any property that can be bound to data is defined as a `Dynamic*` type. It accepts either a literal value, a `path` string ([JSON Pointer]), or a `FunctionCall` (function call).
- **`ChildList`**: Defines how containers hold children. It supports:
  - `array`: A static array of `ComponentId` component references.
  - `object`: A template for generating children from a data binding list (requires a template `componentId` and a data binding `path`).

- **`ComponentId`**: A reference to the unique ID of another component within the same surface.

### Server to client message structure: the envelope

The [`server_to_client.json`] schema is the top-level entry point. Every message streamed by the server must validate against this schema. It handles the message dispatching.

### The Basic Catalog

The [`catalogs/basic/catalog.json`] schema contains the definitions for all specific UI components (e.g., `Text`, `Button`, `Row`), functions (e.g., `required`, `email`), and the theme schema.

**Swappable Catalogs & Validation:**

The [`server_to_client.json`] envelope schema is designed to be catalog-agnostic. It references components and themes using a placeholder filename: `catalog.json` (specifically `$ref: "catalog.json#/$defs/anyComponent"` and `$ref: "catalog.json#/$defs/theme"`).

To validate A2UI messages:

1.  **Basic Catalog**: Map `catalog.json` to `catalogs/basic/catalog.json`.
2.  **Client Catalog**: Map `catalog.json` to your own catalog file (e.g., `my_company_catalog.json`).

This indirection allows the same core envelope schema to be used with any compliant component catalog without modification.

Defining your own catalog allows you to restrict the agent to using exactly the components and visual language that exist in your application. To use your own catalog, simply include it in the prompt in place of the basic catalog. It should have the same form as the basic catalog and use common elements in the [`common_types.json`] schema.

### Validator compliance when defining catalogs

To ensure that automated validators can verify the integrity of your UI tree (checking that parents reference existing children), any catalog you define MUST adhere to the following strict typing rules:

1.  **Single child references:** Any property that holds the ID of another component MUST use the `ComponentId` type defined in `common_types.json`.
    - Use: `"$ref": "common_types.json#/$defs/ComponentId"`
    - Do NOT use: `"type": "string"`

2.  **List references:** Any property that holds a list of children or a template MUST use the `ChildList` type.
    - Use: `"$ref": "common_types.json#/$defs/ChildList"`

Validators determine which fields represent structural links by looking for these specific schema references. If you use a raw string type for an ID, the validator will treat it as static text (like a URL or label) and will not check if the target component exists.

## Envelope message structure

The envelope defines four primary message types, and every message streamed by the server must be a JSON object containing exactly one of the following keys: `createSurface`, `updateComponents`, `updateDataModel`, or `deleteSurface`. The key indicates the type of message, and these are the messages that make up each message in the protocol stream.

### `createSurface`

This message signals the client to create a new surface and begin rendering it. A surface must be created before any `updateComponents` or `updateDataModel` messages can be sent to it. While typically achieved by the agent sending a `createSurface` message, an agent may skip this if it knows the surface has already been created (e.g., by another agent). Once a surface is created, its `surfaceId` and `catalogId` are fixed; to reconfigure them, the surface must be deleted and recreated.

It is an error to try to create a surface with a `surfaceId` that already exists without first deleting it; `surfaceId` must be globally unique for the renderer's lifetime. Orchestrators with subagents are empowered to manage surface IDs as needed to prevent conflicts (e.g., prefixing the subagent's name to the `surfaceId` or requiring subagents to use UUIDs).

One of the components in one of the component lists MUST have an `id` of `root` to serve as the root of the component tree.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be rendered. This must be globally unique for the renderer's lifetime.
- `catalogId` (string, required): A string that uniquely identifies the catalog (components and functions) used for this surface. Note that `catalogId` is a string identifier, not a resolvable URI; while it is conventionally formatted as a URI (e.g., `https://mycompany.com/1.0/somecatalog`) to avoid naming collisions across organizations, it does not need to point to any deployed resource or downloadable file. Client and server developers must agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other.
- `theme` (object, optional): A JSON object containing theme parameters (e.g., `primaryColor`) defined in the catalog's theme schema.
- `sendDataModel` (boolean, optional): If true, the client will send the full data model of this surface in the metadata of every message sent to the server (via the Transport's metadata mechanism). This ensures the surface owner receives the full current state of the UI alongside the user's action or query. Defaults to false.

**Example:**

```json
{
  "version": "v0.9",
  "createSurface": {
    "surfaceId": "user_profile_card",
    "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
    "theme": {
      "primaryColor": "#00BFFF"
    },
    "sendDataModel": true
  }
}
```

### `updateComponents`

This message provides a list of UI components to be added to or updated within a specific surface. The components are provided as a flat list, and their relationships are defined by ID references in an adjacency list. This message may only be sent to a surface that has already been created. Note that components may reference children or data bindings that do not yet exist; clients should handle this gracefully by rendering placeholders (progressive rendering).

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be updated. This is typically a name with meaning (e.g. "user_profile_card"), and it has to be unique within the context of the GenUI session.
- `components` (array, required): A list of component objects. The components are provided as a flat list, and their relationships are defined by ID references in an adjacency list.

**Example:**

```json
{
  "version": "v0.9",
  "updateComponents": {
    "surfaceId": "user_profile_card",
    "components": [
      {
        "id": "root",
        "component": "Column",
        "children": ["user_name", "user_title"]
      },
      {
        "id": "user_name",
        "component": "Text",
        "text": "John Doe"
      },
      {
        "id": "user_title",
        "component": "Text",
        "text": "Software Engineer"
      }
    ]
  }
}
```

### `updateDataModel`

This message is used to send or update the data that populates the UI components. It allows the server to change the UI's content without resending the entire component structure. The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface this data model update applies to.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, optional): The new value for the specified path. If omitted, the key at `path` is removed.

**Example:**

```json
{
  "version": "v0.9",
  "updateDataModel": {
    "surfaceId": "user_profile_card",
    "path": "/user/name",
    "value": "Jane Doe"
  }
}
```

### `deleteSurface`

This message instructs the client to remove a surface and all its associated components and data from the UI.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be deleted.

**Example:**

```json
{
  "version": "v0.9",
  "deleteSurface": {
    "surfaceId": "user_profile_card"
  }
}
```

## Example Stream

The following example demonstrates a complete interaction to render a Contact Form, expressed as a JSONL stream.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Component model

A2UI's component model is designed for flexibility, separating the protocol's structure from the set of available UI components.

### The component object

Each object in the `components` array of an `updateComponents` message defines a single UI component. It has the following structure:

- `id` (`ComponentId`, required): A unique string that identifies this specific component instance. This is used for parent-child references.
- `component` (string, required): Specifies the component's type (e.g., `"Text"`).
- **Component Properties**: Other properties relevant to the specific component type (e.g., `text`, `url`, `children`) are included directly in the component object.

This structure is designed to be both flexible and strictly validated.

### The component catalog

The set of available UI components and functions is defined in a **Catalog**. The basic catalog is defined in [`catalogs/basic/catalog.json`]. While the Basic Catalog is useful for starting out, most production applications will define their own catalog to reflect their specific design system. The server must generate messages that conform to the catalog understood by the client.

#### Catalog Identification & Compatibility

Each catalog is identified by a `catalogId` string. The `catalogId` is a string identifier used for matching catalogs between the client and server. While it is conventional to format catalog IDs as URIs (e.g., `https://mycompany.com/catalogs/v1`) to prevent naming collisions across organizations, a `catalogId` is not required to be a resolvable network resource.

Because A2UI catalogs are represented as JSON Schema documents, catalog definitions should include both `$id` (used by JSON Schema tooling) and `catalogId` (used by A2UI SDKs and catalog negotiation), and both fields should be set to the same URI.

It is up to client and server developers to agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other.

### UI composition: the adjacency list model

The A2UI protocol defines the UI as a flat list of components. The tree structure is built implicitly using ID references. This is known as an adjacency list model.

Container components (like `Row`, `Column`, `List`, and `Card`) have properties that reference the `id` of their child component(s). The client is responsible for storing all components in a map (e.g., `Map<String, Component>`) and recreating the tree structure at render time.

This model allows the server to send component definitions in any order. Rendering can begin as soon as the `root` component is defined, with the client filling in or updating the rest of the tree progressively as additional definitions arrive.

There must be exactly one component with the ID `root` in the component tree, acting as the root of the component tree. Until that component is defined, other component updates will have no visible effect, and they will be buffered until a root component is defined. Once a root component is defined, the client is responsible for rendering the tree in the best way possible based on the available data, skipping invalid references.

```mermaid
flowchart TD
    subgraph "Server Stream"
        A("<b>updateComponents</b><br>components: [root, title, button]")
    end

    subgraph "Client-Side Buffer (Map)"
        C("root: {id: 'root', component: 'Column', children: ['title', 'button']}")
        D("title: {id: 'title', component: 'Text', text: 'Welcome'}")
        E("button: {id: 'button', component: 'Button', child: 'button_label'}")
    end

    subgraph "Rendered Widget Tree"
        F(Column) --> G(Text: 'Welcome')
        F --> H(Button)
    end

    A -- "Parsed and stored" --> C
    A -- "Parsed and stored" --> D
    A -- "Parsed and stored" --> E

```

### Defining actions

Interactive components (like `Button`) use an `action` property to define what happens when the user interacts with them. Actions can either trigger an event sent to the server or execute a local client-side function.

#### Server actions

To send an event to the server, use the `event` property within the `action` object. It requires a `name` and an optional `context`.

```json
{
  "component": "Button",
  "text": "Submit",
  "action": {
    "event": {
      "name": "submit_form",
      "context": {
        "itemId": "123"
      }
    }
  }
}
```

#### Local actions

To execute a local function, use the `functionCall` property within the `action` object. This property references a standard `FunctionCall` object.

```json
{
  "component": "Button",
  "text": "Open Link",
  "action": {
    "functionCall": {
      "call": "openUrl",
      "args": {
        "url": "${/url}"
      }
    }
  }
}
```

## Data model representation: binding, scope

This section describes how UI components **represent** and reference data from the Data Model. A2UI relies on a strictly defined relationship between the UI structure (Components) and the state (Data Model), defining the mechanics of path resolution, variable scope during iteration.

### Path resolution & scope

Data bindings in A2UI are defined using **JSON Pointers** ([RFC 6901]). How a pointer is resolved depends on the current **Evaluation Scope**.

> [!NOTE]
> A2UI extends JSON Pointer to support **Relative Paths** that do not start with a forward slash `/`. This is a deviation from strict RFC 6901 to support template-based list rendering.

> **Note on progressive rendering:** During the initial streaming phase, data paths may resolve to `undefined` if the `updateDataModel` message containing that data has not yet arrived. Renderers should handle `undefined` values gracefully (e.g., by treating them as empty strings or showing a loading indicator) to support progressive rendering.

#### The root scope

By default, all components operate in the **Root Scope**.

- Paths starting with `/` (e.g., `/user/profile/name`) are **Absolute Paths**. They always resolve from the root of the Data Model, regardless of where the component is nested in the UI tree.

#### Collection scopes (relative paths)

When a container component (such as `Column`, `Row`, or `List`) utilizes the **Template** feature of `ChildList`, it creates a new **Child Scope** for each item in the bound array.

- **Template definition:** When a container binds its children to a path (e.g., `path: "/users"`), the client iterates over the array found at that location.
- **Scope instantiation:** For every item in the array, the client instantiates the template component.
- **Relative resolution:** Inside these instantiated components, any path that **does not** start with a forward slash `/` is treated as a **Relative Path**.
  - A relative path `firstName` inside a template iterating over `/users` resolves to `/users/0/firstName` for the first item, `/users/1/firstName` for the second, etc.
  - It is an error to use a non-numeric index on a path segment that refers to an array.

- **Mixing scopes:** Components inside a Child Scope can still access the Root Scope by using an Absolute Path.

#### Example: scope resolution

**Data model:**

```json
{
  "company": "Acme Corp",
  "employees": [
    {"name": "Alice", "role": "Engineer"},
    {"name": "Bob", "role": "Designer"}
  ]
}
```

**Component definition:**

```json
{
  "id": "employee_list",
  "component": "List",
  "children": {
    "path": "/employees",
    "componentId": "employee_card_template"
  }
},
{
  "id": "employee_card_template",
  "component": "Column",
  "children": ["name_text", "company_text"]
},
{
  "id": "name_text",
  "component": "Text",
  "text": { "path": "name" }
  // "name" is Relative. Resolves to /employees/N/name
},
{
  "id": "company_text",
  "component": "Text",
  "text": { "path": "/company" }
  // "/company" is Absolute. Resolves to "Acme Corp" globally.
}
```

#### Type conversion

When a non-string value is interpolated, the client converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **null/undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different client implementations.

### Two-way binding & input components

Interactive components that accept user input (`TextField`, `CheckBox`, `Slider`, `ChoicePicker`, `DateTimeInput`) establish a **Two-Way Binding** with the Data Model.

#### The read/write contract

Unlike static display components (like `Text`), input components modify the client-side data model immediately upon user interaction.

1.  **Read (Model -> View):** When the component renders, it reads its value from the bound `path`. If the Data Model is updated via `updateDataModel`, the component re-renders to reflect the new value.
2.  **Write (View -> Model):** When the user interacts with the component (e.g., types a character, toggles a box), the client **immediately** updates the value at the bound `path` in the local Data Model.

#### Reactivity

Because the local Data Model is the single source of truth, updates from input components are **reactive**.

- If a `TextField` is bound to `/user/name`, and a separate `Text` label is also bound to `/user/name`, the label must update in real-time as the user types in the text field.

#### Server synchronization

It is critical to note that Two-Way Binding is **local to the client**.

- User inputs (keystrokes, toggles) do **not** automatically trigger network requests to the server.
- The updated state is sent to the server only when a specific **User Action** is triggered (e.g., a `Button` click).
- When an `action` is dispatched, the `context` property of the action can reference the modified data paths to send the user's input back to the server.

#### Example: form submission pattern

1.  **Bind:** `TextField` is bound to `/formData/email`.
2.  **Interact:** User types "jane@example.com". The local model at `/formData/email` is updated.
3.  **Action:** A "Submit" button has the following action definition:

    ```json
    "action": {
      "event": {
        "name": "submit_form",
        "context": {
          "email": { "path": "/formData/email" }
        }
      }
    }
    ```

4.  **Send:** When clicked, the client resolves `/formData/email` (getting "jane@example.com") and sends it in the `action` payload.

## Data model updates: synchronization and convergence

While the sections above describe how components reference data, this section defines how the Data Model itself is **updated** and synchronized.

To support reliable data synchronization between the Renderer and the Agent that created the surface, the A2UI protocol uses a simple synchronization mechanism controlled by the `sendDataModel` property in the `createSurface` message.

### Server to client updates

The server sends `updateDataModel` messages to modify the client's data model. These updates follow strict upsert semantics:

- If the path exists, the value is updated.
- If the path does not exist, the value is created.
- If the value is omitted (or set to `undefined`), the key is removed. For arrays, the value at the index is set to `undefined`, preserving length.

The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The ID of the surface to update.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, optional): The new value for the specified path. If omitted, the key at `path` is removed.

**Examples:**

_Update a specific field:_

```json
{
  "version": "v0.9",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/firstName",
    "value": "Alice"
  }
}
```

_Remove a field:_

```json
{
  "version": "v0.9",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/tempData"
  }
}
```

_Replace the entire data model:_

```json
{
  "version": "v0.9",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "value": {
      "user": {"firstName": "Alice", "lastName": "Smith"},
      "preferences": {"theme": "dark"}
    }
  }
}
```

### Client to server updates

When `sendDataModel` is set to `true` for a surface, the client automatically appends the **entire data model** of that surface to the metadata of every message (such as `action` or user query) sent to the server that created the surface. The data model is included using the transport's metadata facility (e.g., the `metadata` field in A2A or a header in HTTP). The payload follows the schema in [`client_data_model.json`](../json/client_data_model.json).

- **Targeted Delivery**: The data model is sent exclusively to the server that created the surface. Data cannot leak to other agents or servers.
- **Trigger:** Data is sent only when a client-to-server message is triggered (e.g., by a user action like a button click). Passive data changes (like typing in a text field) do not trigger a network request on their own; they simply update the local state, which will be sent with the next action.
- **Payload:** The data model is included in the transport metadata, tagged by its `surfaceId`.
- **Convergence:** The server treats the received data model as the current state of the client at the time of the action.

## Client-side logic & validation

A2UI v0.9 generalizes client-side logic into **Functions**. These can be used for validation, data transformation, and dynamic property binding.

### Registered functions

The client supports a set of named **Functions** (e.g., `required`, `regex`, `email`, `add`, `concat`) which are defined in the JSON schema (e.g. `catalogs/basic/catalog.json`) alongside the component definitions. The server references these functions by name in `FunctionCall` objects. This avoids sending executable code.

Input components (like `TextField`, `CheckBox`) can define a list of checks. Each failure produces a specific error message that can be displayed when the component is rendered. Note that for validation checks, the function must return a boolean.

```json
"checks": [
  {
    "call": "required",
    "args": { "value": { "path": "/formData/zip" } },
    "message": "Zip code is required"
  },
  {
    "call": "regex",
    "args": {
      "value": { "path": "/formData/zip" },
      "pattern": "^[0-9]{5}$"
    },
    "message": "Must be a 5-digit zip code"
  }
]
```

### Example: button validation

Buttons can also define `checks`. If any check fails, the button is automatically disabled. This allows the button's state to depend on the validity of data in the model.

```json
{
  "component": "Button",
  "text": "Submit",
  "checks": [
    {
      "condition": {
        "call": "and",
        "args": {
          "values": [
            {
              "call": "required",
              "args": {"value": {"path": "/formData/terms"}}
            },
            {
              "call": "or",
              "args": {
                "values": [
                  {
                    "call": "required",
                    "args": {"value": {"path": "/formData/email"}}
                  },
                  {
                    "call": "required",
                    "args": {"value": {"path": "/formData/phone"}}
                  }
                ]
              }
            }
          ]
        }
      },
      "message": "You must accept terms AND provide either email or phone"
    }
  ]
}
```

## Basic Component Catalog

The [`catalogs/basic/catalog.json`] provides the baseline set of components and functions.

### Components

| Component         | Description                                                                                 |
| :---------------- | :------------------------------------------------------------------------------------------ |
| **Text**          | Displays text. Supports simple Markdown.                                                    |
| **Image**         | Displays an image from a URL.                                                               |
| **Icon**          | Displays a system-provided icon from a predefined list.                                     |
| **Video**         | Displays a video from a URL.                                                                |
| **AudioPlayer**   | A player for audio content from a URL.                                                      |
| **Row**           | A horizontal layout container.                                                              |
| **Column**        | A vertical layout container.                                                                |
| **List**          | A scrollable list of components.                                                            |
| **Card**          | A container with card-like styling.                                                         |
| **Tabs**          | A set of tabs, each with a title and child component.                                       |
| **Divider**       | A horizontal or vertical dividing line.                                                     |
| **Modal**         | A dialog that appears over the main content triggered by a button in the main content.      |
| **Button**        | A clickable button that dispatches an action. Supports 'primary' and 'borderless' variants. |
| **CheckBox**      | A checkbox with a label and a boolean value.                                                |
| **TextField**     | A field for user text input.                                                                |
| **DateTimeInput** | An input for date and/or time.                                                              |
| **ChoicePicker**  | A component for selecting one or more options.                                              |
| **Slider**        | A slider for selecting a numeric value within a range.                                      |

### Functions

| Function           | Description                                                              |
| :----------------- | :----------------------------------------------------------------------- |
| **required**       | Checks that the value is not null, undefined, or empty.                  |
| **regex**          | Checks that the value matches a regular expression string.               |
| **length**         | Checks string length constraints.                                        |
| **numeric**        | Checks numeric range constraints.                                        |
| **email**          | Checks that the value is a valid email address.                          |
| **formatString**   | Does string interpolation of data model values and registered functions. |
| **formatNumber**   | Formats a number with grouping and precision.                            |
| **formatCurrency** | Formats a number as a currency string.                                   |
| **formatDate**     | Formats a date/time using a pattern.                                     |
| **pluralize**      | Selects a localized string based on a numeric count.                     |
| **openUrl**        | Opens a URL in a browser.                                                |
| **and**            | Logical AND operation on a list of boolean values.                       |
| **or**             | Logical OR operation on a list of boolean values.                        |
| **not**            | Logical NOT operation on a boolean value.                                |

### Theme

The basic catalog defines the following theme properties that can be set in the `createSurface` message:

| Property             | Type   | Description                                                                                                                                                                                                               |
| :------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **primaryColor**     | String | The primary brand color used for highlights throughout the UI (e.g., primary buttons, active borders). The renderer may generate variants, such as lighter shades, as needed. Format: Hexadecimal code (e.g., '#00BFFF'). |
| **iconUrl**          | URI    | A URL for an image (e.g., logo or avatar) that identifies the agent or tool associated with the surface.                                                                                                                  |
| **agentDisplayName** | String | Text to be displayed next to the surface to identify the agent or tool that created it (e.g. "Weather Bot").                                                                                                              |

#### Identity and attribution

The `iconUrl` and `agentDisplayName` fields are used to provide attribution to the user, identifying which sub-agent or tool is responsible for a particular UI surface.

In multi-agent systems or orchestrators, the orchestrator is responsible for setting or validating these fields. This ensures that the identity displayed to the user matches the actual agent server being contacted, preventing malicious agents from impersonating trusted services. For example, an orchestrator might overwrite these fields with the verified identity of the sub-agent before forwarding the `createSurface` message to the client.

### The `formatString` function

The `formatString` function supports embedding dynamic expressions directly within string properties. This allows for mixing static text with data model values and function results.

#### `formatString` syntax

Interpolated expressions are enclosed in `${...}`. To include a literal `${` in a string, it must be escaped as `\${`.

#### `formatString` data model binding

Values from the data model can be interpolated using their JSON Pointer path.

- `${/user/profile/name}`: Absolute path.
- `${firstName}`: Relative path (resolved against the current collection scope).

**Example:**

```json
{
  "id": "user_welcome",
  "component": "Text",
  "text": {
    "call": "formatString",
    "args": {
      "value": "Hello, ${/user/firstName}! Welcome back to ${/appName}."
    }
  }
}
```

#### `formatString` client-side functions

Results of client-side functions can be interpolated. Function calls are identified by the presence of parentheses `()`.

- `${now()}`: A function with no arguments.
- `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`: A function with named arguments.

Arguments can be **Literals** (quoted strings, numbers, or booleans), or **Nested Expressions**.

#### `formatString` nested interpolation

Expressions can be nested using additional `${...}` wrappers inside an outer expression to make bindings explicit or to chain function calls.

- **Explicit Binding**: `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`
- **Nested Functions**: `${upper(${now()})}`

#### `formatString` type conversion

When a non-string value is interpolated, the client converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **Null/Undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different client implementations.

## Usage pattern: the prompt-generate-validate loop

The A2UI protocol is designed to be used in a three-step loop with a Large Language Model:

1.  **Prompt**: Construct a prompt for the LLM that includes:
    - The desired UI to be generated.
    - The A2UI JSON schema, including the component catalog.
    - Examples of valid A2UI JSON.

2.  **Generate**: Send the prompt to the LLM and receive the generated JSON output.

3.  **Validate**: Validate the generated JSON against the A2UI schema. If the JSON is valid, it can be sent to the client for rendering. If it is invalid, the errors can be reported back to the LLM in a subsequent prompt, allowing it to self-correct.

This loop allows for a high degree of flexibility and robustness, as the system can leverage the generative capabilities of the LLM while still enforcing the structural integrity of the UI protocol.

### Standard validation error format

If validation fails, the client (or the system acting on behalf of the client) should send an `error` message back to the LLM. To ensure the LLM can understand and correct the error, use the following standard format within the `error` message payload:

- `code` (string, required): Must be `"VALIDATION_FAILED"`.
- `surfaceId` (string, required): The ID of the surface where the error occurred.
- `path` (string, required): The JSON pointer to the field that failed validation (e.g. `/components/0/text`).
- `message` (string, required): A short one-sentence description of why validation failed.

**Example error message:**

```json
{
  "error": {
    "code": "VALIDATION_FAILED",
    "surfaceId": "user_profile_card",
    "path": "/components/0/text",
    "message": "Expected stringOrPath, got integer"
  }
}
```

## Client-to-server messages

The protocol also defines messages that the client can send to the server, which are defined in the [`client_to_server.json`] schema. These are used for handling user interactions and reporting client-side information.

### `action`

This message is sent when the user interacts with a component that has an `action` defined, such as a `Button`.

**Properties:**

- `name` (string, required): The name of the action.
- `surfaceId` (string, required): The ID of the surface where the action originated.
- `sourceComponentId` (string, required): The ID of the component that triggered the action.
- `timestamp` (string, required): An ISO 8601 timestamp.
- `context` (object, required): A JSON object containing any context provided in the component's `action` property.

### Capabilities & metadata

In A2UI v0.9, capabilities and other metadata are exchanged via **Transport metadata** or initialization payloads (e.g., A2A metadata, Agent Cards, or MCP initialization), rather than as first-class A2UI messages.

#### Server capabilities

A server (or agent) advertises its capabilities using the [`server_capabilities.json`] schema. This indicates which catalogs it can generate UI for, and whether it accepts inline catalogs from the client. The exact mechanism depends on the transport (e.g., the `params` object in an A2A AgentCard, or server capabilities in MCP).

#### Client capabilities

The `a2uiClientCapabilities` object in the metadata follows the [`client_capabilities.json`] schema.

**Properties:**

- `supportedCatalogIds` (array of strings, required): String identifiers of supported catalogs.
- `inlineCatalogs`: An array of inline catalog definitions provided directly by the client (useful for custom or ad-hoc components and functions).

#### Client data model

When `sendDataModel` is enabled for a surface, the client includes the `a2uiClientDataModel` object in the metadata, following the [`client_data_model.json`] schema.

**Properties:**

- `surfaces` (object, required): A map of surface IDs to their current data models.

### `error`

This message is used to report a client-side error to the server.

[`catalogs/basic/catalog.json`]: ../catalogs/basic/catalog.json
[`common_types.json`]: ../json/common_types.json
[`server_to_client.json`]: ../json/server_to_client.json
[`client_to_server.json`]: ../json/client_to_server.json
[`server_capabilities.json`]: ../json/server_capabilities.json
[`client_capabilities.json`]: ../json/client_capabilities.json
[`client_data_model.json`]: ../json/client_data_model.json
[JSON Pointer]: https://datatracker.ietf.org/doc/html/rfc6901
[RFC 6901]: https://datatracker.ietf.org/doc/html/rfc6901

---

### Specification V0 9 Docs Basic Catalog Implementation Guide (`specification/v0_9/docs/basic_catalog_implementation_guide.md`)

# A2UI Basic Catalog Implementation Guide

This guide is designed for renderer and client developers implementing the A2UI Basic Catalog (v0.9). It details how to visually present and functionally implement each component and client-side function defined in the catalog.

When building your framework-specific adapters (Layer 3) over the generic A2UI bindings, refer to this document for the expected visual behaviors, suggested layouts, and interaction patterns. This guide uses generic terminology applicable to Web, Mobile (iOS/Android), and Desktop platforms.

---

## 1. Components

### Text

Displays text content.

**Rendering Guidelines:** Text should be rendered using a Markdown parser when possible. If markdown rendering is unavailable or fails, gracefully fallback to rendering the raw text. In such cases, renderers should ideally attempt to strip common Markdown markers (like `**` or `#`) to ensure the text remains legible and aesthetically consistent with the intended presentation.
**Property Mapping:**

- `variant="h1"` through `h5"`: Apply heading styling. Suggested relative font sizes: `h1` (2.5x base), `h2` (2x base), `h3` (1.75x base), `h4` (1.5x base), `h5` (1.25x base).
- `variant="caption"`: Render as smaller text, typically italicized or in a lighter/muted color. Suggested font size: 0.8x base.
- `variant="body"` (default): Standard body text. Uses the base font size (e.g., 16dp/16px).

### Image

Displays an image from a URL.

**Rendering Guidelines:** Ensure the component defaults to a flexible width so it fills its container.
**Property Mapping:**

- `fit`: Map the property to the platform's equivalent content scaling mode (e.g., CSS `object-fit`, iOS `contentMode`, Android `ScaleType`).
- `variant="icon"`: Render very small and square (e.g., 24x24dp).
- `variant="avatar"`: Render small and rounded/circular (e.g., 40x40dp, fully rounded corners).
- `variant="smallFeature"`: Render as a small rectangle (e.g., 100x100dp).
- `variant="mediumFeature"` (default): Render as a medium rectangle (e.g., 100% width up to 300dp, or 200x200dp).
- `variant="largeFeature"`: Render as a large prominent image (e.g., 100% width, max height 400dp).
- `variant="header"`: Render as a full-width banner image, usually at the top of a surface (e.g., 100% width, height 200dp, scaling mode set to cover/crop).

### Icon

Displays a standard system icon.

**Rendering Guidelines:** Map the icon `name` to a system or bundled icon set (e.g., Material Symbols, SF Symbols). The string `name` from the data model (e.g., `accountCircle`) should be converted to the required format (like snake_case `account_circle`) if required by the icon engine. Suggested styling: 24dp size and inherit the current text color.

### Video

A video player.

**Rendering Guidelines:** Render using a native video player component with user controls enabled. Ensure the video container spans the full width of the parent's container for responsiveness. Scrubbing (seeking) should be supported if provided by the native control.

### AudioPlayer

An audio player.

**Rendering Guidelines:** Render using a native audio player component with user controls enabled. Like video, its container should span the full width of its parent. Scrubbing (seeking) should be supported if provided by the native control.

### Row

A horizontal layout container.

**Rendering Guidelines:** Implemented using a horizontal layout container (e.g., CSS Flexbox row, Compose `Row`, SwiftUI `HStack`). Ensure it fills the available width.
**Property Mapping:**

- `justify`: Maps to main-axis alignment (e.g., `justify-content` in CSS, `horizontalArrangement` in Compose). Use equivalents for pushing items to edges (`spaceBetween`) or packing them together (`start`, `center`, `end`).
- `align`: Maps to cross-axis alignment (e.g., `align-items` in CSS, `verticalAlignment` in Compose). Use equivalents for top (`start`), center, or bottom (`end`).

### Column

A vertical layout container.

**Rendering Guidelines:** Implemented using a vertical layout container (e.g., CSS Flexbox column, Compose `Column`, SwiftUI `VStack`).
**Property Mapping:**

- `justify`: Maps to main-axis alignment on the vertical axis.
- `align`: Maps to cross-axis alignment on the horizontal axis.

### List

A scrollable list of components.

**Rendering Guidelines:** Children of a horizontal list should typically have a constrained max-width so they do not stretch indefinitely.
**Property Mapping:**

- `direction="vertical"` (default): Implement as a vertically scrollable view (e.g., CSS `overflow-y: auto`, Compose `LazyColumn`, SwiftUI `ScrollView` vertical).
- `direction="horizontal"`: Implement as a horizontally scrollable view. Hide the scrollbar for a cleaner look if supported by the platform.

### Card

A container with card-like styling that visually groups its child.

**Rendering Guidelines:** Applies a background color distinct from the main surface, rounded corners (e.g., 8dp or 12dp), a subtle shadow or elevation, and inner padding (e.g., 16dp). Note that the card accepts exactly **one** child. If the user wants multiple elements inside a card, they must provide a container (like `Column`) as the single child.

### Tabs

A set of tabs, each with a title and a corresponding child component.

**Rendering Guidelines:** Render a horizontal row of interactive tab headers for the `titles`. Visually indicate the active tab (e.g., bold text, colored bottom border).
**Behavior & State:** Maintain a local `selectedIndex` state (defaulting to 0). When a tab header is tapped, update `selectedIndex` and render _only_ the `child` component that corresponds to that index.

### Divider

A dividing line to separate content.

**Property Mapping:**

- `axis="horizontal"` (default): Render a 1dp tall line spanning 100% width with a subtle border/outline color.
- `axis="vertical"`: Render a 1dp wide line with a set height, spanning the height of the container.

### Modal

A dialog window.

**Rendering Guidelines:**

- **Desktop UIs**: Render as a centered popup or native dialog window over the main content, typically with a dimmed backdrop.
- **Mobile UIs**: Render as a bottom sheet or full-screen dialog over the main content.
- You must provide a mechanism to close the modal (e.g., an "X" button, clicking/tapping the backdrop overlay, or a swipe-to-dismiss gesture).

**Behavior & State:** This component behaves differently than a standard container. It acts as a **Modal Entry Point**. When instantiated, the user only sees the `trigger` child component on the screen (which usually acts and looks like a Button). The modal logic intercepts interactions (taps/clicks) on the `trigger`. When the `trigger` is tapped, the modal opens and displays the `content` child component.

### Button

An interactive button that dispatches a protocol action.

**Rendering Guidelines:** Render as a native interactive button component. It must render its `child` component inside the button (usually a `Text` or `Icon`).
**Behavior & State:** When tapped, it dispatches the `action` back to the server, dynamically resolving the context variables at the moment of the interaction.
**Property Mapping:**

- `variant="default"`: Standard button with a subtle background and border.
- `variant="primary"`: Prominent call-to-action button using the theme's `primaryColor` for its background, and contrasting text.
- `variant="borderless"`: Button with no background or border, appearing like a clickable text link.

### TextField

A field for user text input.

**Rendering Guidelines:** Render using the platform's native text input control.
**Behavior & State:** Establishes **Two-Way Binding**. As the user types, immediately write the new string back to the local data model path bound to `value`.
**Property Mapping:**

- `variant="shortText"` (default): Standard single-line input field.
- `variant="longText"`: Render as a multi-line text area.
- `variant="number"`: Render as a numeric input field, typically showing a numeric keyboard on mobile.
- `variant="obscured"`: Render as an obscured password/secure field.

### CheckBox

A toggleable control with a label.

**Rendering Guidelines:** Render a native checkbox or toggle switch component alongside a text label.
**Behavior & State:** Triggers two-way binding on the `value` path, setting it to boolean `true` or `false` when interacted with.

### ChoicePicker

A component for selecting one or more options from a list.

**Rendering Guidelines:**

- `displayStyle="checkbox"` (default): Render as a dropdown menu, picker wheel, or an expanding vertical list of selectable options. A dropdown wrapper is preferred to save space.
- `displayStyle="chips"`: Render as a horizontal, wrapping row of selectable chips/pills. Selected chips should have a distinct background/border.
- If `filterable` is true, render a text input above the list of options. As the user types, filter the visible options using a case-insensitive substring match on the option labels.

**Behavior & State:** Binds to an array of strings in the data model representing the active selections. Toggle selections in the data model upon user interaction.

### Slider

A control for selecting a numeric value within a range.

**Rendering Guidelines:** Render using the platform's native slider or seek bar component. Optionally display the current numeric value next to the slider track.
**Behavior & State:** Set `min` and `max` limits. Perform two-way binding, updating the numeric `value` path as the user drags the slider. Note that the value is a `number` rather than an integer, allowing for decimal ranges (e.g., 0.0 to 1.0).

### DateTimeInput

An input for date and/or time.

**Rendering Guidelines:** Render using native date and time picker controls.

- If `enableDate` and `enableTime` are both true, show both date and time selection UI.
- If only `enableDate` is true, show only a date picker.
- If only `enableTime` is true, show only a time picker.

**Behavior & State:** The component must convert the platform's native date/time format into a standard ISO 8601 string before writing it to the A2UI data model, and correctly parse ISO 8601 strings coming from the model into the input field.

---

## 2. Client-Side Functions

Functions provide client-side logic for validation, interpolation, and operations. As defined in the Architecture Guide, the reactivity of function arguments is generally handled by the Core Data Layer (specifically the Binder/Context layer).

Core libraries for each language (such as `@a2ui/web_core` for TypeScript) typically provide a complete, framework-agnostic implementation of all the functions in the basic catalog. Developers are encouraged to utilize these shared implementations rather than writing their own.
When a function is called, the system resolves its arguments. If an argument is a static value, it is passed directly. If it is a dynamic binding, the Context layer handles the subscription. For most standard functions, the `execute` implementation simply receives a dictionary of static `args` and returns a static value. The Context layer wraps this execution in a reactive stream (e.g., a `computed` signal) so that the function re-runs whenever any of its dynamic arguments change.

However, complex functions like `formatString` must manually interact with the Context to parse and subscribe to nested dynamic dependencies.

### `formatString`

**Description:** The core interpolation engine. Parses the `args.value` string for `${expression}` blocks, combining literal strings, data paths, and other client-side function results.

**Architecture & Logic:**
Because `formatString` contains dynamic expressions embedded _within_ a string literal, the Context layer cannot pre-resolve them. The implementation must parse the string and manually create a reactive output.

1.  **Parser/Scanner:** Implement a parser that scans the input string (`args.value`) for `${...}` blocks. It must properly handle escaped markers (`\${`) which resolve to a literal `${`.
2.  **Expression Evaluation:** Inside the interpolation block, the parser must differentiate between:
    - **Literals:** Quoted strings (`'...'` or `"..."`), numbers, and keywords (`true`, `false`, `null`).
    - **Data Paths:** Identifiers starting with a slash (`/absolute/path`) or relative identifiers (`relative/path`).
    - **Function Calls:** Identifiers followed by parentheses, e.g., `funcName(argName: value)`.
3.  **Context Resolution:** For every parsed `DataPath` or `FunctionCall` token, use the `DataContext` (e.g., `context.resolveSignal(token)`) to turn it into a reactive stream/signal.
4.  **Reactive Return:** The function MUST return a computed reactive stream (e.g., a `computed(() => ...)` signal). Inside this computed stream, unwrap all the resolved signals, convert them to strings, and concatenate them with the literal string parts.

### `required`

**Description:** Validates that a given value is present.

**Logic:** Return `true` if `args.value` is strictly not `null`, not `undefined`, not an empty string `""`, and not an empty array `[]`. Otherwise, return `false`.

### `regex`

**Description:** Validates a value against a regular expression.

**Logic:** Instantiate a regular expression using `args.pattern`. Test the `args.value` string against it. Return `true` if it matches, `false` otherwise.

### `length`

**Description:** Validates string length constraints.

**Logic:** Ensure the length of the string `args.value` is `>= args.min` (if `min` is provided) and `<= args.max` (if `max` is provided).

### `numeric`

**Description:** Validates numeric range constraints.

**Logic:** Parse `args.value` as a number. Ensure it is `>= args.min` (if `min` is provided) and `<= args.max` (if `max` is provided). Return `true` if valid, `false` if invalid or if it cannot be parsed as a number.

### `email`

**Description:** Validates an email address.

**Logic:** Test `args.value` against a standard email regex pattern (e.g., `/^[^\s@]+@[^\s@]+\.[^\s@]+$/`).

### `formatNumber`

**Description:** Formats a numeric value.

**Logic:** Use the platform's native locale formatting (e.g., `Intl.NumberFormat` on the web or `NumberFormatter` natively) on `args.value`.

- If `args.decimals` is provided, force both the minimum and maximum fraction digits to that value.
- Enable grouping (e.g., thousands separators) unless `args.grouping` is explicitly set to `false`.

### `formatCurrency`

**Description:** Formats a number as a currency string.

**Logic:** Similar to `formatNumber`, but configured for currency style formatting. Apply the ISO 4217 currency code provided in `args.currency` (e.g., 'USD', 'EUR').

### `formatDate`

**Description:** Formats a timestamp into a date string.

**Logic:** Parse `args.value` into a native Date/Time object. Interpret the Unicode TR35 `args.format` string (e.g., `yyyy-MM-dd`, `HH:mm`) and construct the formatted date string. You will likely need a platform-specific date formatting library to parse the TR35 pattern.

### `pluralize`

**Description:** Returns a localized pluralized string.

**Logic:** Resolve the plural category for the numeric `args.value` based on the current locale (e.g., using `Intl.PluralRules` on the web). Map the resulting category (`zero`, `one`, `two`, `few`, `many`, `other`) to the corresponding string provided in the `args` object. If the specific category string is missing from `args`, fallback to `args.other`.

### `openUrl`

**Description:** Opens a URL.

**Logic:** Open `args.url` using the native platform's URL handler (e.g., opening in the system browser or deep-linking to an app). This function returns `void` and is executed as a side-effect.

**Security Constraints & Implementation Requirements (Mandatory):**
To prevent DOM-Based Cross-Site Scripting (XSS) via `javascript:`, `data:`, or other non-HTTP schemes:

1. **Resolve Relative URLs:** Before validation, resolve relative paths against the current environment context (e.g., `window.location.href` in browsers) using standard URL parsing.
2. **Enforce Scheme Allowlist:** Strictly validate that the resolved URL protocol/scheme is either `https:` or `http:`. Throw an execution or runtime error (such as `A2uiExpressionError`) and abort the action if any other scheme is used.
3. **Tab-Nabbing Protection:** When opening URLs in a new browser window/tab, always supply security attributes: `noopener,noreferrer` (e.g. `window.open(url, '_blank', 'noopener,noreferrer')`).

### `and`

**Description:** Logical AND operator.

**Logic:** Iterate through the boolean array `args.values`. Return `true` only if all values are true. Short-circuit evaluation is encouraged.

### `or`

**Description:** Logical OR operator.

**Logic:** Iterate through the boolean array `args.values`. Return `true` if at least one value is true. Short-circuit evaluation is encouraged.

### `not`

**Description:** Logical NOT operator.

**Logic:** Return the strict boolean negation of `args.value`.

---

## 3. Layout Spacing: Margins and Padding

A common challenge in dynamic UI frameworks is preventing "spacing multiplication," where nested containers (e.g., a `Text` inside a `Row` inside a `Column`) result in accumulated empty space that throws off the design.

To achieve a clean, consistent default spacing where elements feel naturally separated without stacking empty space, implementers should follow a **Leaf-Margin Strategy**:

1. **Invisible Containers have ZERO Spacing**: Structural, invisible layout containers (`Row`, `Column`, `List`) should have **no internal padding** and **no external margins**. They act purely as structural boundaries. This guarantees that wrapping an element in a `Row` or `Column` does not alter its spacing.
2. **Leaf Components carry the Margin**: All non-container, visual "leaf" elements (`Text`, `Image`, `Icon`, `Video`, `AudioPlayer`, `Slider`, etc.) should have a uniform default **external margin** applied to them (e.g., `8dp` on all sides).
3. **Visually Outlined Containers carry the Margin**: Containers and inputs that have a visible boundary (`Card`, `Button`, `TextField`, `CheckBox`, `ChoicePicker`) should also apply this same uniform default **external margin**.
   - _Note:_ These elements will naturally also need internal _padding_ to keep their content away from their own visible borders, but this padding is localized and does not affect the external layout.

**Why use Margins on Leaves?**
Applying margins directly to the visual elements—rather than relying on padding or gap properties on the parent containers—ensures predictable spacing. For example, if you have `Row(Item1, Item2)`, using margins on the items guarantees that there is space to the left of `Item1`, space to the right of `Item2`, and space between them. Because the invisible containers themselves contribute zero extra spacing, you can deeply nest your structural rows and columns without the spacing unexpectedly multiplying.

---

## 4. Color, Contrast, and Nesting

A common challenge in dynamically generated UI is ensuring proper contrast and visual hierarchy when components are nested. For example:

- A `Text` or `Icon` nested inside a `primary` `Button` must change its color to contrast with the button's background.
- A `Card` nested inside another `Card` should remain visually distinct.

To keep the A2UI rendering layer simple and performant, **do not manually calculate or pass color properties down the A2UI component tree**. Instead, rely entirely on the native context and theme inheritance mechanisms provided by your target UI framework.

### Text and Icon Contrast

When an element defines a strong background color (like a `primary` `Button` using the theme's `primaryColor`), it must also define the expected text color for its content. It should propagate this expectation implicitly.

- **Web (CSS):** The `Button` wrapper sets the standard CSS `color` property. Because `color` is inherited in CSS, any `Text` or `Icon` component rendered inside the button will automatically adapt.
- **Compose (Android):** The button wrapper should use `CompositionLocalProvider(LocalContentColor provides ...)`. Any nested `Text` and `Icon` components will automatically pick up this color without needing it explicitly passed to their A2UI classes.
- **SwiftUI (iOS):** Apply `.foregroundColor(...)` or `.environment(\.colorScheme, ...)` to the button wrapper.
- **Flutter:** Use `DefaultTextStyle.merge()` and `IconTheme.merge()` within the button wrapper. If using standard Material buttons (like `ElevatedButton`), this is often handled for you automatically.

_Rule of Thumb:_ Leaf components like `Text` and `Icon` should **never** hardcode their colors unless explicitly instructed by a property. They must always inherit from their environment.

### Nesting Containers (Cards)

When a `Card` is nested within another `Card`, or placed on different background surfaces, it needs to remain distinct. Attempting to alternate surface colors based on depth adds significant complexity to the renderer.

**Recommended Approach: Outlines and Transparent Surfaces**
The simplest, most robust starting approach is to give `Card` components a **transparent background** and a **visible outline/border** (e.g., a 1dp outline matching the theme's outline/border color).

- By using borders instead of opaque surface colors, nested cards will simply draw an inner boundary within the parent card.
- This guarantees a clear visual hierarchy regardless of how deeply they are nested, and it requires zero context-passing or depth-tracking in your code.
- If your design system requires opaque cards, consider using a framework-specific elevation system (e.g., standard Material elevation) which often handles shadow and surface tinting automatically, rather than building custom color-alternation logic into the A2UI adapters.

---

### Specification V0 9 Docs Evolution Guide (`specification/v0_9/docs/evolution_guide.md`)

# A2UI Protocol Evolution Guide: v0.8.1 to v0.9

This document serves as a comprehensive guide to the changes between A2UI version 0.8.1 and version 0.9. It details the shifts in philosophy, architecture, and implementation, providing a reference for stakeholders and developers migrating between versions.

## 1. Executive Summary

Version 0.9 represents a fundamental philosophical shift from "Structured Output First" to "Prompt First."

- **v0.8.1** was designed to be generated by an LLM using Structured Output above all else, optimized for LLMs that support strict JSON mode or function calling (which is also a form of Structured Output). It relied on deep nesting and specific wrapper structures that were definable in the limited schema features but often confusing for an LLM to generate.
- **v0.9** is designed to be **embedded directly in an LLM's system prompt**. The schema is refactored to be more human-readable and "token-efficient" for the model to understand. It prioritizes patterns that LLMs naturally excel at (like standard JSON objects for maps) over strict structured output-friendly structures (like arrays of key-value pairs).

### Summary Table

| Feature                  | v0.8.1                                   | v0.9                                                   |
| :----------------------- | :--------------------------------------- | :----------------------------------------------------- |
| **Philosophy**           | Structured Output / Function Calling     | Prompt-First / In-Context Schema                       |
| **Message Types**        | `beginRendering`, `surfaceUpdate`, ...   | `createSurface`, `updateComponents`, ...               |
| **Surface Creation**     | Explicit `beginRendering`                | Explicit `createSurface`                               |
| **Component Type**       | Key-based wrapper (`{"Text": ...}`)      | Property-based discriminator (`"component": "Text"`)   |
| **Data Model Update**    | Array of Key-Value Pairs                 | Standard JSON Object                                   |
| **Data Binding**         | `dataBinding` / `literalString`          | `path` / Native JSON types                             |
| **Button Context**       | Array of Key-Value pairs                 | Standard JSON Object                                   |
| **Button Variant**       | Boolean (`primary: true`)                | Enum (`variant: "primary"`)                            |
| **Catalog**              | Separate component and function catalogs | Unified Catalog (`catalogs/basic/catalog.json`)        |
| **Auxiliary Rules**      | N/A                                      | `basic_catalog_rules.txt`                              |
| **Validation**           | Basic Schema                             | Strict `ValidationFailed` feedback loop                |
| **Data Synchronization** | Implicit                                 | Explicit Client->Server data syncing (`sendDataModel`) |

## 2. Architectural & Schema Changes

### 2.1. Modular Schema Architecture

**v0.8.1:**

- Monolithic tendencies. `server_to_client.json` often contained deep definitions or relied on complex `oneOf` structures that were hard to decompose.
- `basic_catalog_definition.json` existed but was often implicitly coupled.

**v0.9:**

- **Modularization**: The schema is strictly split into:
  - `common_types.json`: Reusable primitives (IDs, paths) and logic/expression types.
  - `server_to_client.json`: The "envelope" defining the message types.
  - `catalogs/basic/catalog.json`: The unified catalog of UI components and functions.
- **Swappable Catalogs**: `server_to_client.json` now uses a relative reference to `catalog.json` as a placeholder. This allows developers to alias `catalog.json` to `catalogs/basic/catalog.json` (or any custom catalog) during validation, enabling the use of custom component sets without modifying the core envelope schema.
- **Unification**: Components and functions are now part of the same catalog object, simplifying capability negotiation and inline definitions.

### 2.2. Strict Message Typing

**v0.8.1:**

- Messages were objects where properties like `surfaceUpdate` were optional keys.
- Validation often relied on "minProperties: 1" constraints.

**v0.9:**

- Uses a top-level **`oneOf`** constraint in `server_to_client.json`.
- **Reason**: This is a more natural way to express the schema to an LLM, and easier for the LLM to reason about. It's also a more natural form for the developer to read.

### 2.3. Auxiliary Rules File

**v0.9:**

- **New Artifact**: `basic_catalog_rules.txt`.
- **Purpose**: A plain-text prompt fragment containing rules for using the catalog schema (e.g., "MUST provide 'action' for Button").
- **Usage**: Designed to be included in the system prompt alongside the catalog schema.
- **Reason**: Some constraints (like conditional requirements or specific property combinations) are difficult or verbose to express in JSON Schema but easy to express in natural language rules for an LLM, and it can be packaged with the catalog schema for ease of customizing the prompt for a particular catalog.

## 3. Protocol Lifecycle Changes

### 3.1. `beginRendering` Replaced by `createSurface`

**v0.8.1 (`beginRendering`):**

- **Explicit Signal**: The server sent a `beginRendering` message to tell the client "I am done sending the initial batch of components, you can draw now."
- **Root Definition**: The root component ID was defined in this message.
- **Style Information**: The message included style information for the surface.

**v0.9 (`createSurface`):**

- **Replacement**: `beginRendering` is **REPLACED** by `createSurface`.
- **Purpose**: `createSurface` signals the client to create a new surface and prepare for rendering.
- **Theme Information**: `createSurface` includes a `theme` property to specify theme parameters (like `primaryColor`). This replaces the `styles` property in v0.8.
- **Root Rule**: The rule is: "There must be exactly one component with the `ComponentId` 'root'." The "root" attribute that `beginRendering` had has been removed. The client is expected to render as soon as it has a valid tree with a root component.
- **New Requirement**: `createSurface` now requires a **`catalogId`** (string identifier) to explicitly state which unified catalog (components and functions) is being used.

**Example:**

**v0.8.1 (`beginRendering`)**:

```json
{
  "beginRendering": {
    "surfaceId": "user_profile_card",
    "root": "root",
    "styles": {
      "primaryColor": "#007bff"
    }
  }
}
```

**v0.9 (`createSurface`)**:

```json
{
  "version": "v0.9",
  "createSurface": {
    "surfaceId": "user_profile_card",
    "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
    "theme": {
      "primaryColor": "#007bff"
    }
  }
}
```

## 4. Message Structure Comparison

### 4.1. Component Updates

**v0.8.1 (`surfaceUpdate`)**:

- Components were wrapped in an object where the **key** was the component type.
- **Structure**: `{ "id": "...", "component": { "Text": { "text": "..." } } }`

**v0.9 (`updateComponents`)**:

- **Renamed**: `surfaceUpdate` -> `updateComponents`.
- **Refactored**: Components use a flattened structure with a const discriminator property `component`.
- **Structure**: `{ "id": "...", "component": "Text", "text": "..." }`
- **Reason**: This "flat" structure with a discriminator field (`component: "Text"`) is much easier for LLMs to generate consistently than a dynamic key (`"Text": {...}`). It also simplifies polymorphism in many JSON parsers.

Specifying an unknown surfaceId will cause an error. It is recommended that clients implement a namespacing scheme internally to prevent separate agents from creating surfaces with the same ID, and to prevent agents from modifying surfaces created by other agents.

#### Side-by-Side Example

**v0.8.1:**

```json
{
  "surfaceUpdate": {
    "surfaceId": "main",
    "components": [
      {
        "id": "title",
        "component": {
          "Text": {"text": {"literalString": "Hello"}}
        }
      }
    ]
  }
}
```

**v0.9:**

```json
{
  "version": "v0.9",
  "updateComponents": {
    "surfaceId": "main",
    "components": [
      {
        "id": "root",
        "component": "Column",
        "children": ["title"]
      },
      {
        "id": "title",
        "component": "Text",
        "text": "Hello"
      }
    ]
  }
}
```

### 4.2. Data Model Updates

**v0.8.1 (`dataModelUpdate`)**:

- **Adjacency List**: The `contents` property was an **array** of key-value pair objects.
- **Typed Values**: Each entry required explicit typing like `valueString`, `valueNumber`, `valueBoolean`.
- **Structure**: `[{ "key": "name", "valueString": "Alice" }]`

**v0.9 (`updateDataModel`)**:

- **Renamed**: `dataModelUpdate` -> `updateDataModel`.
- **Standard JSON**: The `value` property is now a standard **JSON object**.
- **Simplified**: The system relies on upsert semantics, so the client will create or update the data model at the specified path, or remove it if the value is null.
- **Structure**: `{ "name": "Alice" }`
- **Reason**: LLMs are trained to generate JSON objects. Forcing them to generate an "adjacency list" representation of a map was inefficient and error-prone.

## 5. Data Binding & State

### 5.1. Standardization of `path`

**v0.8.1:**

- Used `dataBinding` in `childrenProperty` templates.
- Used `path` in `BoundValue` objects.
- Inconsistent terminology.

**v0.9:**

- **Unified**: Everything is now a **`path`**.
- **Reason**: Reduces cognitive load for the LLM. "Path" always means "JSON Pointer to data."

### 5.2. Simplified Bound Values

**v0.8.1:**

- `{ "literalString": "foo" }` or `{ "path": "/foo" }`.
- Explicit typing in keys (`literalNumber`, `literalBoolean`).

**v0.9:**

- **Implicit Typing**: `DynamicString`, `DynamicNumber`, etc. are defined in `common_types.json`.
- **Structure**: The schema allows `string` OR `{ "path": "..." }`.
- **Reason**: Much more natural JSON. `{ "text": "Hello" }` is valid. `{ "value": { "path": "/msg" } }` is valid. No need for `{ "text": { "literalString": "Hello" } }`.

### 5.3. String Interpolation

**v0.8.1:**

- **Strict Envelopes**: Static text and data model references had to be separate or wrapped in explicit objects. Mixing literal text and dynamic values in a single string was not officially supported at the protocol level without custom logic.
- **Structure**: `{ "text": "static" }` OR `{ "text": { "path": "/var" } }`.

**v0.9:**

- **String Formatting**: Introduced the `formatString` function, which supports `${expression}` syntax for interpolation.
- **Unified Expression Language**: Allows embedding JSON Pointer paths (absolute and relative) and client-side function calls directly within the format string.
- **Nesting**: Supports recursive nesting of expressions (e.g., `${formatDate(value: ${/timestamp}, format: 'yyyy-MM-dd')}`).
- **Restriction**: String interpolation `${...}` is **ONLY** supported within the `formatString` function. It is not supported in general for string properties, in order to strictly separate data binding definitions from static content.
- **Reason**: Improves readability for complex strings. Instead of generating complex nested JSON objects (like chained concatenations) to combine strings and data, the model can write natural-looking template literals within the `formatString` function.

### 5.4. Data Synchronization

**v0.8.1:**

- Data synchronization was implicit and relied on ad-hoc mechanisms.

**v0.9:**

- **Explicit Client->Server Data Model Sync**: `createSurface` introduced `sendDataModel` (boolean).
- **Single-Path Updates**: Server pushes updates via `updateDataModel` using simple `path`/`value` pairs.
- **Client->Server Data Model Sync**: When `sendDataModel` is true, the client includes the full data model in every A2A message metadata.

## 6. Component-Specific Changes

### 6.1. Button Context

**v0.8.1:**

- **Array of Pairs**: `context: [{ "key": "id", "value": { "literalString": "123" } }]`
- **Reason**: Easy to parse, hard to generate.

**v0.9:**

- **Standard Map**: `context: { "id": "123" }`
- **Reason**: Token efficiency. LLMs understand JSON objects as maps natively.

### 6.2. Button Variant

**v0.8.1:**

- **Boolean**: `primary: true` or `primary: false`.
- **Limited**: Only two styles were explicitly supported.

**v0.9:**

- **Enum**: `variant: "primary"` or `variant: "borderless"`.
- **Reason**: More flexible and consistent with other components (like `Text` and `Image`) that use `variant` for styling hints. 'borderless' provides a standard way to represent clickable text or icons without a button-like frame.

### 6.3. TextField

**v0.8.1:**

- Property: `textFieldType` (e.g., "email", "password").
- Validation: `validationRegexp`.

**v0.9:**

- Property: **`variant`**.
- Validation: **`checks`** (generic list of function calls).
- **Reason**: Consistency with `Text` and `Image` components which already used `variant`. Validation is now more flexible and reusable. Also, `text` was renamed to **`value`** to match other input components.

### 6.4. ChoicePicker (vs MultipleChoice)

**v0.8.1:**

- Component: **`MultipleChoice`**.
- Properties: `selections` (typed wrapper), `maxAllowedSelections` (integer).

**v0.9:**

- Component: **`ChoicePicker`**.
- Properties: **`value`** (array), **`variant`** (enum: `multipleSelection`, `mutuallyExclusive`). The `maxAllowedSelections` property was removed.
- **Reason**: `ChoicePicker` is a more generic name that covers both radio buttons (mutually exclusive) and checkboxes (multiple selection). The `variant` controls the behavior, simplifying the component surface area.

### 6.5. Slider

**v0.8.1:**

- Properties: `minValue`, `maxValue`.

**v0.9:**

- Properties: **`min`**, **`max`**.
- **Reason**: Standardizing on shorter, more common property names.

## 7. Error Handling

**v0.9** introduces a strict **`ValidationFailed`** error format in `client_to_server.json`.

- **Purpose**: To allow the "Prompt-Generate-Validate" loop to work effectively.
- **Mechanism**: If the LLM generates invalid JSON, the system sends back a structured error:

  ```json
  {
    "error": {
      "code": "VALIDATION_FAILED",
      "surfaceId": "...",
      "path": "/components/0/text",
      "message": "Expected string, got number"
    }
  }
  ```

- **Result**: The LLM sees this and can "self-correct" in the next turn.

## 8. Property Rename Summary (Migration Quick Reference)

For developers migrating from earlier versions, here is a quick reference of property renaming:

| Component          | Old Name           | New Name    |
| :----------------- | :----------------- | :---------- |
| **Row / Column**   | `distribution`     | `justify`   |
| **Row / Column**   | `alignment`        | `align`     |
| **Modal**          | `entryPointChild`  | `trigger`   |
| **Modal**          | `contentChild`     | `content`   |
| **Tabs**           | `tabItems`         | `tabs`      |
| **TextField**      | `text`             | `value`     |
| **Many**           | `usageHint`        | `variant`   |
| **Client Message** | `userAction`       | `action`    |
| **Common Type**    | `childrenProperty` | `ChildList` |

---

### Specification V0 9 1 Docs A2ui Custom Functions (`specification/v0_9_1/docs/a2ui_custom_functions.md`)

# Defining Custom Functions

A2UI functions are defined inside a Catalog. When defining your own catalog, you can include custom functions that are specific to your application or design system.

This guide demonstrates how to define a string `trim` function and a hardware query function (`getScreenResolution`) in your catalog.

## 1. Define the Catalog

Create a JSON Schema file (e.g., `my_catalog.json`) that defines your
function parameters.

Use the `functions` property to define a map of function schemas.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## 2. Make the functions available

The `FunctionCall` definition refers to a [catalog-agnostic reference](a2ui_protocol.md#the-basic-catalog).
In your catalog, you simply need to define the `anyFunction` reference:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [{"$ref": "#/functions/trim"}, {"$ref": "#/functions/getScreenResolution"}]
    }
  }
}
```

If you want to incorporate functions defined in the [`catalogs/basic/catalog.json`],
those can be added too:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [
        {"$ref": "#/functions/trim"},
        {"$ref": "#/functions/getScreenResolution"},
        {"$ref": "catalogs/basic/catalog.json#/$defs/anyFunction"}
      ]
    }
  }
}
```

## How Validation Works

When a `FunctionCall` is validated:

1. **Discriminator Lookup:** The validator looks at the `call` property of the
   object.
2. **Schema Matching:**
   - If `call` is "length", it matches `Functions` -> `length`
     and validates the named arguments in `args` against the length rules.
   - If `call` is "trim", it matches `CustomFunctions` -> `trim` and
     validates against your custom rules.
   - If `call` is "unknownFunc", validation FAILS immediately (strict mode).

This strict-by-default approach ensures typos are caught early, while the
modular structure makes it easy to add new capabilities with full type safety.

---

### Specification V0 9 1 Docs A2ui Extension Specification (`specification/v0_9_1/docs/a2ui_extension_specification.md`)

# A2UI (Agent-to-Agent UI) Extension spec v0.9.1

## Overview

This document is intended for developers implementing the A2UI A2A extension. The extension adds A2UI v0.9.1 support to A2A, a format for agents to send streaming, interactive user interfaces to clients.

Note that A2UI extension activation is optional as clients and agents can negotiate A2UI support using A2A `message.metadata["a2uiClientCapabilities"]` which is attached to every A2A message from the client and contains the supported protocol version and catalogs. Agents advertising A2UI support in their AgentCard is encouraged as clients may rely on it to determine if they should send `message.metadata["a2uiClientCapabilities"]`, however it is not explicitly required.

## Extension URI

The URI of this extension is https://a2ui.org/a2a-extension/a2ui/v0.9.1

This URI is the canonical way to communicate protocol versioning between clients and agents. The extension URI explicitly encodes the version (e.g., `v0.9.1`). A client requesting this specific URI indicates it supports the v0.9.1 schema format.

## Agent Card

Agents are encouraged to advertise their A2UI capabilities in their AgentCard within the `AgentCapabilities.extensions` list. This advertisement is optional, but it informs the client whether to send `message.metadata["a2uiClientCapabilities"]`. The `params` object defines the agent's specific UI support and corresponds directly to the [Server Capabilities Schema](../json/server_capabilities.json).

Example AgentCard payload:

```json
{
  "name": "Dashboard Agent",
  "description": "Agent capable of generating dynamic UI dashboards.",
  "capabilities": {
    "extensions": [
      {
        "uri": "https://a2ui.org/a2a-extension/a2ui/v0.9.1",
        "description": "Ability to render A2UI v0.9.1",
        "required": false,
        "params": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v0.9/my_custom_catalog.json"
          ],
          "acceptsInlineCatalogs": true
        }
      }
    ]
  }
}
```

The `params` object corresponds to the `v0.9.1` object in the `server_capabilities.json` schema:

- `params.supportedCatalogIds` (optional): An array of strings, where each string is an ID identifying a Catalog Definition Schema that the agent can generate. This is not necessarily a resolvable URI.
- `params.acceptsInlineCatalogs` (optional): A boolean indicating if the agent can accept an `inlineCatalogs` array in the client's `a2uiClientCapabilities`. If omitted, this defaults to `false`.

## A2A Extension activation

Activating the A2UI extension is optional. Clients and agents can negotiate A2UI support using `message.metadata["a2uiClientCapabilities"]` A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`.

Specifically:

- If a client includes `message.metadata["a2uiClientCapabilities"]`, the agent can use this object to determine the supported A2UI protocol version and catalogs.
- If an agent returns A2A A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`, the client knows the payload contains A2UI messages.

While explicit activation is not required, clients can still explicitly activate the extension using the transport-defined A2A extension activation mechanism. The [A2A Extensions Guide](https://a2a-protocol.org/latest/topics/extensions/) defines this process.

Note: You should not use `accepted_output_modes: ['a2ui']` (which is not an A2UI standard) to trigger A2UI.

### JSON-RPC and HTTP transports

To activate the A2UI A2A Extension, the `X-A2A-Extensions` HTTP header includes the extension URI.

**Example HTTP `SendMessageRequest`:**

```http
POST /v1/messages HTTP/1.1
Host: agent.example.com
X-A2A-Extensions: https://a2ui.org/a2a-extension/a2ui/v0.9.1
Content-Type: application/json

{
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
      }
    ]
  }
}
```

To see how the agent parses the extension URI, see [`extension.py`](../../../python/a2ui_a2a/src/a2ui/a2a/extension.py).

### GRPC transport

To activate the A2UI A2A Extension, the client adds the extension URI to A2A `sendMessageParams.metadata["X-A2A-Extensions"]`.

**Example gRPC `SendMessageRequest`:**

```json
{
  "metadata": {
    "X-A2A-Extensions": "https://a2ui.org/a2a-extension/a2ui/v0.9.1"
  },
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
        }
      ]
    }
  }
}
```

## A2A Client to Server Metadata

Clients attach `a2uiClientCapabilities` and `a2uiClientDataModel` to A2A messages to communicate their state and supported catalogs.

### `a2uiClientCapabilities`

The client sends `sendMessageRequest.message["a2uiClientCapabilities"]` = [Client Capabilities Schema](../json/client_capabilities.json) to advertise which catalogs the renderer supports.

**Example `SendMessageRequest` with Capabilities:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Show me the dashboard."
      }
    ],
    "metadata": {
      "a2uiClientCapabilities": {
        "v0.9.1": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v0.9/my_custom_catalog.json"
          ]
        }
      }
    }
  }
}
```

### `a2uiClientDataModel`

When a surface enables Data Model Sync, the client sends `sendMessageRequest.message["a2uiClientDataModel"]` = [Client Data Model Schema](../json/client_data_model.json) on every message. This model provides the agent with the latest UI state. For more details, see the [Actions Guide](../../../docs/public/concepts/actions.md).

**Example `SendMessageRequest` with Data Model:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Submit the form."
      }
    ],
    "metadata": {
      "a2uiClientDataModel": {
        "version": "v0.9.1",
        "surfaces": {
          "main_surface_id": {
            "user_id": "12345",
            "email": "user@example.com"
          }
        }
      }
    }
  }
}
```

## Data encoding

Agents and clients encode A2UI messages as an A2A `DataPart`.

To identify a `DataPart` as containing A2UI data, it must have the following metadata:

- `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`

The `data` field of the `DataPart` contains a list of A2UI JSON messages (e.g., `createSurface`, `updateComponents`, `action`). It MUST be an array of messages.

### Processing Rules

The `data` field contains a list of messages. This list is NOT a transactional unit. Receivers (both Clients and Agents) MUST process messages in the list sequentially.

If a single message in the list fails to validate or apply (e.g., due to a schema violation or invalid reference), the receiver SHOULD report/log the error for that specific message and MUST continue processing the remaining messages in the list.

Atomicity is guaranteed only at the individual message level. However, for a better user experience, a renderer SHOULD NOT repaint the UI until all messages in the list have been processed. This prevents intermediate states from flickering to the user.

### Server-to-client messages

When an agent sends a message to a client (or another agent acting as a client/renderer), the `data` payload must validate against the [Server-to-Client Message List Schema](../json/server_to_client_list.json).

Example DataPart:

```json
{
  "data": [
    {
      "version": "v0.9.1",
      "createSurface": {
        "surfaceId": "example_surface",
        "catalogId": "https://a2ui.org/specification/v0_9/catalogs/basic/catalog.json"
      }
    },
    {
      "version": "v0.9.1",
      "updateComponents": {
        "surfaceId": "example_surface",
        "components": [
          {
            "Text": {
              "id": "root",
              "text": "Hello!"
            }
          }
        ]
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

### Client-to-server events

When a client (or an agent forwarding an event) sends a message to an agent, it also uses a `DataPart` with the same `application/a2ui+json` MIME type. However, the `data` payload must validate against the [Client-to-Server Message List Schema](../json/client_to_server_list.json).

Example `action` DataPart:

```json
{
  "data": [
    {
      "version": "v0.9.1",
      "action": {
        "name": "submit_form",
        "surfaceId": "contact_form_1",
        "sourceComponentId": "submit_button",
        "timestamp": "2026-01-15T12:00:00Z",
        "context": {
          "email": "user@example.com"
        }
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

---

### Specification V0 9 1 Docs A2ui Protocol (`specification/v0_9_1/docs/a2ui_protocol.md`)

<div style="text-align: center;">
  <div class="centered-logo-text-group">
    <img src="../../../docs/public/assets/A2UI_dark.svg" alt="A2UI Protocol Logo" width="100">
    <h1>A2UI (Agent to UI) Protocol v0.9.1</h1>
  </div>
</div>

A Specification for a JSON-Based, Streaming UI Protocol.

**Version:** 0.9.1
**Status:** Current Production
**Created:** Nov 20, 2025
**Last Updated:** Dec 3, 2025

A Specification for a JSON-Based, Streaming UI Protocol

## Introduction

The A2UI Protocol is designed for dynamically rendering user interfaces from a stream of JSON objects sent from a server (Agent). Its core philosophy emphasizes a clean separation of UI structure and application data, enabling progressive rendering as the client processes each message.

Communication occurs via a stream of JSON objects. The client parses each object as a distinct message and incrementally builds or updates the UI. The server-to-client protocol defines four message types:

- `createSurface`: Signals the client to create a new surface and begin rendering it.
- `updateComponents`: Provides a list of component definitions to be added to or updated in a specific surface.
- `updateDataModel`: Provides new data to be inserted into or to replace a surface's data model.
- `deleteSurface`: Explicitly removes a surface and its contents from the UI.

## Changes from previous versions

Version 0.9 introduced A2UI's prompt-first protocol family. While v0.8 was optimized for LLMs that support structured output, v0.9 is designed to be embedded directly within a model's prompt. The LLM is then asked to produce JSON that matches the provided examples and schema descriptions.

This "prompt-first" approach offers several advantages:

1.  **Richer schema:** The protocol is no longer limited by the constraints of structured output formats. This allows for more readable, complex, and expressive component catalogs.
2.  **Modularity:** The schema is now refactored into separate, more manageable components (e.g., [`common_types.json`], [`catalogs/basic/catalog.json`], [`server_to_client.json`]), improving maintainability and modularity.

The main disadvantage of this approach is that it requires more complex post-generation validation, as the LLM is not strictly constrained by the schema. This requires robust error handling and correction, so the system can identify discrepancies and attempt to fix them before rendering, or request a retry or correction from the LLM.

See [the evolution guide](evolution_guide.md) for a detailed explanation of the differences between v0.9 and v0.9.1.

## Protocol overview & data flow

The A2UI protocol uses a unidirectional stream of JSON messages from the server to the client to describe and update the UI. The client consumes this stream, builds the UI, and renders it. User interactions are handled separately, typically by sending events to a different endpoint, which may in turn trigger new messages on the UI stream.

Here is an example sequence of events (which don't have to be in exactly this order):

1.  **Create Surface:** The server sends a `createSurface` message to initialize the surface.
2.  **Update Surface:** Once a surface has been created, the server sends one or more `updateComponents` messages containing the definitions for all the components that will be part of the surface.
3.  **Update Data Model:** Once a surface has been created, the server can send `updateDataModel` messages at any time to populate or change the data that the UI components will display.
4.  **Render:** The client renders the UI for the surface, using the component definitions to build the structure and the data model to populate the content.
5.  **Dynamic updates:** As the user interacts with the application or as new information becomes available, the server can send additional `updateComponents` and `updateDataModel` messages to dynamically change the UI.
6.  **Delete Surface:** When a UI region is no longer needed, the server sends a `deleteSurface` message to remove it.

```mermaid
sequenceDiagram
    participant Server
    participant Client

    Server->>+Client: 1. createSurface(surfaceId: "main")
    Server->>+Client: 2. updateComponents(surfaceId: "main", components: [...])
    Server->>+Client: 3. updateDataModel(surfaceId: "main", path: "/user", value: "Alice")
    User->>+Client: Interact with UI (e.g. click button)
    Client->>+Server: action(name: "submit", context: {...})
    Client-->>-Server: (UI is displayed)

    Note over Client, Server: Time passes, user interacts, or new data arrives...

    Server->>+Client: 4. updateComponents or updateDataModel (Dynamic Update)
    Note right of Client: Client re-renders the UI to reflect changes
    Client-->>-Server: (UI is updated)

    Server->>+Client: 5. deleteSurface(surfaceId: "main")
    Note right of Client: Client removes the UI for the "main" surface
    Client-->>-Server: (UI is gone)
```

## Transport decoupling

The A2UI protocol is designed to be transport-agnostic. It defines the JSON message structure and the semantic contract between the server (Agent) and the client (Renderer), but it does not mandate a specific transport layer.

### The transport contract

To support A2UI, a transport layer must fulfill the following contract:

1.  **Reliable delivery**: Messages must be delivered in the order they were generated. A2UI relies on stateful updates (e.g., creating a surface before updating it), so out-of-order delivery can corrupt the UI state.
2.  **Message framing**: The transport must clearly delimit individual JSON envelope messages (e.g., using newlines in JSONL, WebSocket frames, or SSE events).
3.  **Metadata support**: The transport must provide a mechanism to associate metadata with messages. This is critical for:
    - **Data model synchronization**: The `sendDataModel` feature requires the client to send the current data model state as metadata alongside user actions.
    - **Capabilities exchange**: Client capabilities (supported catalogs, custom components) and Server capabilities are exchanged via metadata or transport-specific handshakes (like Agent Cards in A2A or initialization in MCP).
4.  **Bidirectional capability (optional)**: While the rendering stream is unidirectional (Server -> Client), interactive applications require a return channel for `action` messages (Client -> Server).

### Transport bindings

While A2UI is agnostic, it is most commonly used with the following transports.

#### A2A (Agent2Agent) binding

[A2A (Agent-to-Agent)](https://a2a-protocol.org/latest/) is an excellent transport option for A2UI in agentic systems, extending A2A with additional payloads.
A2A is uniquely capable of handling remote agent communication, and can also provide a secure and efficient transport between an agentic backend and front end application.

- **Message mapping**: Each A2UI envelope (e.g., `updateComponents`) corresponds to the payload of a single A2A message Part.
- **Metadata**:
  - **Data model**: When `sendDataModel` is active, the client's `a2uiClientDataModel` object is placed in the `metadata` field of the A2A message.
  - **Capabilities**: The `a2uiClientCapabilities` object is placed in the `metadata` field of every A2A `Message` sent from the client to the server.
- **Context**: A2UI sessions typically map to A2A `contextId`. All messages for a set of related surfaces should share the same `contextId`.

#### AG UI (Agent to User Interface) binding

**[AG-UI](https://docs.ag-ui.com/introduction)** is also an excellent transport option for A2UI Agent–User Interaction protocol.
AG UI provides convenient integrations into many agent frameworks and frontends. AG UI provides low latency and shared state message passing between front ends and agentic backends.

#### Other transports

A2UI can also be carried over:

- **[MCP (Model Context Protocol)](https://modelcontextprotocol.io/docs/getting-started/intro)**: Delivered as tool outputs or resource subscriptions.
- **[SSE](https://en.wikipedia.org/wiki/Server-sent_events) with [JSON RPC](https://www.jsonrpc.org/)**: Standard server-sent events for web integrations that support streaming, and JSON RPC for client-server communication.
- **[WebSockets](https://en.wikipedia.org/wiki/WebSocket)**: For bidirectional, real-time sessions.
- **[REST](https://cloud.google.com/discover/what-is-rest-api?hl=en)**: For simple use case, REST APIs will work but lack streaming capabilities.

## The protocol schemas

A2UI v0.9.1 is defined by three interacting JSON schemas.

### Common types

The [`common_types.json`] schema defines reusable primitives used throughout the protocol.

- **`DynamicString` / `DynamicNumber` / `DynamicBoolean` / `DynamicStringList`**: The core of the data binding system. Any property that can be bound to data is defined as a `Dynamic*` type. It accepts either a literal value, a `path` string ([JSON Pointer]), or a `FunctionCall` (function call).
- **`ChildList`**: Defines how containers hold children. It supports:
  - `array`: A static array of `ComponentId` component references.
  - `object`: A template for generating children from a data binding list (requires a template `componentId` and a data binding `path`).

- **`ComponentId`**: A reference to the unique ID of another component within the same surface.

### Server to client message structure: the envelope

The [`server_to_client.json`] schema is the top-level entry point. Every message streamed by the server must validate against this schema. It handles the message dispatching.

### The Basic Catalog

The [`catalogs/basic/catalog.json`] schema contains the definitions for all specific UI components (e.g., `Text`, `Button`, `Row`), functions (e.g., `required`, `email`), and the theme schema.

**Swappable Catalogs & Validation:**

The [`server_to_client.json`] envelope schema is designed to be catalog-agnostic. It references components and themes using a placeholder filename: `catalog.json` (specifically `$ref: "catalog.json#/$defs/anyComponent"` and `$ref: "catalog.json#/$defs/theme"`).

To validate A2UI messages:

1.  **Basic Catalog**: Map `catalog.json` to `catalogs/basic/catalog.json`.
2.  **Client Catalog**: Map `catalog.json` to your own catalog file (e.g., `my_company_catalog.json`).

This indirection allows the same core envelope schema to be used with any compliant component catalog without modification.

Defining your own catalog allows you to restrict the agent to using exactly the components and visual language that exist in your application. To use your own catalog, simply include it in the prompt in place of the basic catalog. It should have the same form as the basic catalog and use common elements in the [`common_types.json`] schema.

### Validator compliance when defining catalogs

To ensure that automated validators can verify the integrity of your UI tree (checking that parents reference existing children), any catalog you define MUST adhere to the following strict typing rules:

1.  **Single child references:** Any property that holds the ID of another component MUST use the `ComponentId` type defined in `common_types.json`.
    - Use: `"$ref": "common_types.json#/$defs/ComponentId"`
    - Do NOT use: `"type": "string"`

2.  **List references:** Any property that holds a list of children or a template MUST use the `ChildList` type.
    - Use: `"$ref": "common_types.json#/$defs/ChildList"`

Validators determine which fields represent structural links by looking for these specific schema references. If you use a raw string type for an ID, the validator will treat it as static text (like a URL or label) and will not check if the target component exists.

## Envelope message structure

The envelope defines four primary message types, and every message streamed by the server must be a JSON object containing exactly one of the following keys: `createSurface`, `updateComponents`, `updateDataModel`, or `deleteSurface`. The key indicates the type of message, and these are the messages that make up each message in the protocol stream.

### `createSurface`

This message signals the client to create a new surface and begin rendering it. A surface must be created before any `updateComponents` or `updateDataModel` messages can be sent to it. While typically achieved by the agent sending a `createSurface` message, an agent may skip this if it knows the surface has already been created (e.g., by another agent). Once a surface is created, its `surfaceId` and `catalogId` are fixed; to reconfigure them, the surface must be deleted and recreated. It is an error to send `createSurface` for a `surfaceId` that already exists without first deleting it. One of the components in one of the component lists MUST have an `id` of `root` to serve as the root of the component tree.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be rendered.
- `catalogId` (string, required): A string that uniquely identifies the catalog (components and functions) used for this surface. Note that `catalogId` is a string identifier, not a resolvable URI; while it is conventionally formatted as a URI (e.g., `https://mycompany.com/1.0/somecatalog`) to avoid naming collisions across organizations, it does not need to point to any deployed resource or downloadable file. Client and server developers must agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other.
- `theme` (object, optional): A JSON object containing theme parameters (e.g., `primaryColor`) defined in the catalog's theme schema.
- `sendDataModel` (boolean, optional): If true, the client will send the full data model of this surface in the metadata of every message sent to the server (via the Transport's metadata mechanism). This ensures the surface owner receives the full current state of the UI alongside the user's action or query. Defaults to false.

**Example:**

```json
{
  "version": "v0.9.1",
  "createSurface": {
    "surfaceId": "user_profile_card",
    "catalogId": "https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json",
    "theme": {
      "primaryColor": "#00BFFF"
    },
    "sendDataModel": true
  }
}
```

### `updateComponents`

This message provides a list of UI components to be added to or updated within a specific surface. The components are provided as a flat list, and their relationships are defined by ID references in an adjacency list. This message may only be sent to a surface that has already been created. Note that components may reference children or data bindings that do not yet exist; clients should handle this gracefully by rendering placeholders (progressive rendering).

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be updated. This is typically a name with meaning (e.g. "user_profile_card"), and it has to be unique within the context of the GenUI session.
- `components` (array, required): A list of component objects. The components are provided as a flat list, and their relationships are defined by ID references in an adjacency list.

**Example:**

```json
{
  "version": "v0.9.1",
  "updateComponents": {
    "surfaceId": "user_profile_card",
    "components": [
      {
        "id": "root",
        "component": "Column",
        "children": ["user_name", "user_title"]
      },
      {
        "id": "user_name",
        "component": "Text",
        "text": "John Doe"
      },
      {
        "id": "user_title",
        "component": "Text",
        "text": "Software Engineer"
      }
    ]
  }
}
```

### `updateDataModel`

This message is used to send or update the data that populates the UI components. It allows the server to change the UI's content without resending the entire component structure. The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface this data model update applies to.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, optional): The new value for the specified path. If omitted, the key at `path` is removed.

**Example:**

```json
{
  "version": "v0.9.1",
  "updateDataModel": {
    "surfaceId": "user_profile_card",
    "path": "/user/name",
    "value": "Jane Doe"
  }
}
```

### `deleteSurface`

This message instructs the client to remove a surface and all its associated components and data from the UI.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be deleted.

**Example:**

```json
{
  "version": "v0.9.1",
  "deleteSurface": {
    "surfaceId": "user_profile_card"
  }
}
```

## Example Stream

The following example demonstrates a complete interaction to render a Contact Form, expressed as a JSONL stream.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Component model

A2UI's component model is designed for flexibility, separating the protocol's structure from the set of available UI components.

### The component object

Each object in the `components` array of an `updateComponents` message defines a single UI component. It has the following structure:

- `id` (`ComponentId`, required): A unique string that identifies this specific component instance. This is used for parent-child references.
- `component` (string, required): Specifies the component's type (e.g., `"Text"`).
- **Component Properties**: Other properties relevant to the specific component type (e.g., `text`, `url`, `children`) are included directly in the component object.

This structure is designed to be both flexible and strictly validated.

### The component catalog

The set of available UI components and functions is defined in a **Catalog**. The basic catalog is defined in [`catalogs/basic/catalog.json`]. While the Basic Catalog is useful for starting out, most production applications will define their own catalog to reflect their specific design system. The server must generate messages that conform to the catalog understood by the client.

#### Catalog Identification & Compatibility

Each catalog is identified by a `catalogId` string. The `catalogId` is a string identifier used for matching catalogs between the client and server. While it is conventional to format catalog IDs as URIs (e.g., `https://mycompany.com/catalogs/v1`) to prevent naming collisions across organizations, a `catalogId` is not required to be a resolvable network resource.

Because A2UI catalogs are represented as JSON Schema documents, catalog definitions should include both `$id` (used by JSON Schema tooling) and `catalogId` (used by A2UI SDKs and catalog negotiation), and both fields should be set to the same URI.

It is up to client and server developers to agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other.

### UI composition: the adjacency list model

The A2UI protocol defines the UI as a flat list of components. The tree structure is built implicitly using ID references. This is known as an adjacency list model.

Container components (like `Row`, `Column`, `List`, and `Card`) have properties that reference the `id` of their child component(s). The client is responsible for storing all components in a map (e.g., `Map<String, Component>`) and recreating the tree structure at render time.

This model allows the server to send component definitions in any order. Rendering can begin as soon as the `root` component is defined, with the client filling in or updating the rest of the tree progressively as additional definitions arrive.

There must be exactly one component with the ID `root` in the component tree, acting as the root of the component tree. Until that component is defined, other component updates will have no visible effect, and they will be buffered until a root component is defined. Once a root component is defined, the client is responsible for rendering the tree in the best way possible based on the available data, skipping invalid references.

```mermaid
flowchart TD
    subgraph "Server Stream"
        A("<b>updateComponents</b><br>components: [root, title, button]")
    end

    subgraph "Client-Side Buffer (Map)"
        C("root: {id: 'root', component: 'Column', children: ['title', 'button']}")
        D("title: {id: 'title', component: 'Text', text: 'Welcome'}")
        E("button: {id: 'button', component: 'Button', child: 'button_label'}")
    end

    subgraph "Rendered Widget Tree"
        F(Column) --> G(Text: 'Welcome')
        F --> H(Button)
    end

    A -- "Parsed and stored" --> C
    A -- "Parsed and stored" --> D
    A -- "Parsed and stored" --> E

```

### Defining actions

Interactive components (like `Button`) use an `action` property to define what happens when the user interacts with them. Actions can either trigger an event sent to the server or execute a local client-side function.

#### Server actions

To send an event to the server, use the `event` property within the `action` object. It requires a `name` and an optional `context`.

```json
{
  "component": "Button",
  "text": "Submit",
  "action": {
    "event": {
      "name": "submit_form",
      "context": {
        "itemId": "123"
      }
    }
  }
}
```

#### Local actions

To execute a local function, use the `functionCall` property within the `action` object. This property references a standard `FunctionCall` object.

```json
{
  "component": "Button",
  "text": "Open Link",
  "action": {
    "functionCall": {
      "call": "openUrl",
      "args": {
        "url": "${/url}"
      }
    }
  }
}
```

## Data model representation: binding, scope

This section describes how UI components **represent** and reference data from the Data Model. A2UI relies on a strictly defined relationship between the UI structure (Components) and the state (Data Model), defining the mechanics of path resolution, variable scope during iteration.

### Path resolution & scope

Data bindings in A2UI are defined using **JSON Pointers** ([RFC 6901]). How a pointer is resolved depends on the current **Evaluation Scope**.

> [!NOTE]
> A2UI extends JSON Pointer to support **Relative Paths** that do not start with a forward slash `/`. This is a deviation from strict RFC 6901 to support template-based list rendering.

> **Note on progressive rendering:** During the initial streaming phase, data paths may resolve to `undefined` if the `updateDataModel` message containing that data has not yet arrived. Renderers should handle `undefined` values gracefully (e.g., by treating them as empty strings or showing a loading indicator) to support progressive rendering.

#### The root scope

By default, all components operate in the **Root Scope**.

- Paths starting with `/` (e.g., `/user/profile/name`) are **Absolute Paths**. They always resolve from the root of the Data Model, regardless of where the component is nested in the UI tree.

#### Collection scopes (relative paths)

When a container component (such as `Column`, `Row`, or `List`) utilizes the **Template** feature of `ChildList`, it creates a new **Child Scope** for each item in the bound array.

- **Template definition:** When a container binds its children to a path (e.g., `path: "/users"`), the client iterates over the array found at that location.
- **Scope instantiation:** For every item in the array, the client instantiates the template component.
- **Relative resolution:** Inside these instantiated components, any path that **does not** start with a forward slash `/` is treated as a **Relative Path**.
  - A relative path `firstName` inside a template iterating over `/users` resolves to `/users/0/firstName` for the first item, `/users/1/firstName` for the second, etc.
  - It is an error to use a non-numeric index on a path segment that refers to an array.

- **Mixing scopes:** Components inside a Child Scope can still access the Root Scope by using an Absolute Path.

#### Example: scope resolution

**Data model:**

```json
{
  "company": "Acme Corp",
  "employees": [
    {"name": "Alice", "role": "Engineer"},
    {"name": "Bob", "role": "Designer"}
  ]
}
```

**Component definition:**

```json
{
  "id": "employee_list",
  "component": "List",
  "children": {
    "path": "/employees",
    "componentId": "employee_card_template"
  }
},
{
  "id": "employee_card_template",
  "component": "Column",
  "children": ["name_text", "company_text"]
},
{
  "id": "name_text",
  "component": "Text",
  "text": { "path": "name" }
  // "name" is Relative. Resolves to /employees/N/name
},
{
  "id": "company_text",
  "component": "Text",
  "text": { "path": "/company" }
  // "/company" is Absolute. Resolves to "Acme Corp" globally.
}
```

#### Type conversion

When a non-string value is interpolated, the client converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **null/undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different client implementations.

### Two-way binding & input components

Interactive components that accept user input (`TextField`, `CheckBox`, `Slider`, `ChoicePicker`, `DateTimeInput`) establish a **Two-Way Binding** with the Data Model.

#### The read/write contract

Unlike static display components (like `Text`), input components modify the client-side data model immediately upon user interaction.

1.  **Read (Model -> View):** When the component renders, it reads its value from the bound `path`. If the Data Model is updated via `updateDataModel`, the component re-renders to reflect the new value.
2.  **Write (View -> Model):** When the user interacts with the component (e.g., types a character, toggles a box), the client **immediately** updates the value at the bound `path` in the local Data Model.

#### Reactivity

Because the local Data Model is the single source of truth, updates from input components are **reactive**.

- If a `TextField` is bound to `/user/name`, and a separate `Text` label is also bound to `/user/name`, the label must update in real-time as the user types in the text field.

#### Server synchronization

It is critical to note that Two-Way Binding is **local to the client**.

- User inputs (keystrokes, toggles) do **not** automatically trigger network requests to the server.
- The updated state is sent to the server only when a specific **User Action** is triggered (e.g., a `Button` click).
- When an `action` is dispatched, the `context` property of the action can reference the modified data paths to send the user's input back to the server.

#### Example: form submission pattern

1.  **Bind:** `TextField` is bound to `/formData/email`.
2.  **Interact:** User types "jane@example.com". The local model at `/formData/email` is updated.
3.  **Action:** A "Submit" button has the following action definition:

    ```json
    "action": {
      "event": {
        "name": "submit_form",
        "context": {
          "email": { "path": "/formData/email" }
        }
      }
    }
    ```

4.  **Send:** When clicked, the client resolves `/formData/email` (getting "jane@example.com") and sends it in the `action` payload.

## Data model updates: synchronization and convergence

While the sections above describe how components reference data, this section defines how the Data Model itself is **updated** and synchronized.

To support reliable data synchronization between the Renderer and the Agent that created the surface, the A2UI protocol uses a simple synchronization mechanism controlled by the `sendDataModel` property in the `createSurface` message.

### Server to client updates

The server sends `updateDataModel` messages to modify the client's data model. These updates follow strict upsert semantics:

- If the path exists, the value is updated.
- If the path does not exist, the value is created.
- If the value is omitted (or set to `undefined`), the key is removed. For arrays, the value at the index is set to `undefined`, preserving length.

The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The ID of the surface to update.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, optional): The new value for the specified path. If omitted, the key at `path` is removed.

**Examples:**

_Update a specific field:_

```json
{
  "version": "v0.9.1",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/firstName",
    "value": "Alice"
  }
}
```

_Remove a field:_

```json
{
  "version": "v0.9.1",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/tempData"
  }
}
```

_Replace the entire data model:_

```json
{
  "version": "v0.9.1",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "value": {
      "user": {"firstName": "Alice", "lastName": "Smith"},
      "preferences": {"theme": "dark"}
    }
  }
}
```

### Client to server updates

When `sendDataModel` is set to `true` for a surface, the client automatically appends the **entire data model** of that surface to the metadata of every message (such as `action` or user query) sent to the server that created the surface. The data model is included using the transport's metadata facility (e.g., the `metadata` field in A2A or a header in HTTP). The payload follows the schema in [`client_data_model.json`](../json/client_data_model.json).

- **Targeted Delivery**: The data model is sent exclusively to the server that created the surface. Data cannot leak to other agents or servers.
- **Trigger:** Data is sent only when a client-to-server message is triggered (e.g., by a user action like a button click). Passive data changes (like typing in a text field) do not trigger a network request on their own; they simply update the local state, which will be sent with the next action.
- **Payload:** The data model is included in the transport metadata, tagged by its `surfaceId`.
- **Convergence:** The server treats the received data model as the current state of the client at the time of the action.

## Client-side logic & validation

A2UI v0.9 generalizes client-side logic into **Functions**. These can be used for validation, data transformation, and dynamic property binding.

### Registered functions

The client supports a set of named **Functions** (e.g., `required`, `regex`, `email`, `add`, `concat`) which are defined in the JSON schema (e.g. `catalogs/basic/catalog.json`) alongside the component definitions. The server references these functions by name in `FunctionCall` objects. This avoids sending executable code. The client determines each function's execution boundary at runtime by reading its configuration from the active catalog definition.

Input components (like `TextField`, `CheckBox`) can define a list of checks. Each failure produces a specific error message that can be displayed when the component is rendered. Note that for validation checks, the function must return a boolean.

```json
"checks": [
  {
    "call": "required",
    "args": { "value": { "path": "/formData/zip" } },
    "message": "Zip code is required"
  },
  {
    "call": "regex",
    "args": {
      "value": { "path": "/formData/zip" },
      "pattern": "^[0-9]{5}$"
    },
    "message": "Must be a 5-digit zip code"
  }
]
```

### Example: button validation

Buttons can also define `checks`. If any check fails, the button is automatically disabled. This allows the button's state to depend on the validity of data in the model.

```json
{
  "component": "Button",
  "text": "Submit",
  "checks": [
    {
      "condition": {
        "call": "and",
        "args": {
          "values": [
            {
              "call": "required",
              "args": {"value": {"path": "/formData/terms"}}
            },
            {
              "call": "or",
              "args": {
                "values": [
                  {
                    "call": "required",
                    "args": {"value": {"path": "/formData/email"}}
                  },
                  {
                    "call": "required",
                    "args": {"value": {"path": "/formData/phone"}}
                  }
                ]
              }
            }
          ]
        }
      },
      "message": "You must accept terms AND provide either email or phone"
    }
  ]
}
```

## Basic Component Catalog

The [`catalogs/basic/catalog.json`] provides the baseline set of components and functions.

### Components

| Component         | Description                                                                                 |
| :---------------- | :------------------------------------------------------------------------------------------ |
| **Text**          | Displays text. Supports simple Markdown.                                                    |
| **Image**         | Displays an image from a URL.                                                               |
| **Icon**          | Displays a system-provided icon from a predefined list.                                     |
| **Video**         | Displays a video from a URL.                                                                |
| **AudioPlayer**   | A player for audio content from a URL.                                                      |
| **Row**           | A horizontal layout container.                                                              |
| **Column**        | A vertical layout container.                                                                |
| **List**          | A scrollable list of components.                                                            |
| **Card**          | A container with card-like styling.                                                         |
| **Tabs**          | A set of tabs, each with a title and child component.                                       |
| **Divider**       | A horizontal or vertical dividing line.                                                     |
| **Modal**         | A dialog that appears over the main content triggered by a button in the main content.      |
| **Button**        | A clickable button that dispatches an action. Supports 'primary' and 'borderless' variants. |
| **CheckBox**      | A checkbox with a label and a boolean value.                                                |
| **TextField**     | A field for user text input.                                                                |
| **DateTimeInput** | An input for date and/or time.                                                              |
| **ChoicePicker**  | A component for selecting one or more options.                                              |
| **Slider**        | A slider for selecting a numeric value within a range.                                      |

### Functions

| Function           | Description                                                              |
| :----------------- | :----------------------------------------------------------------------- |
| **required**       | Checks that the value is not null, undefined, or empty.                  |
| **regex**          | Checks that the value matches a regular expression string.               |
| **length**         | Checks string length constraints.                                        |
| **numeric**        | Checks numeric range constraints.                                        |
| **email**          | Checks that the value is a valid email address.                          |
| **formatString**   | Does string interpolation of data model values and registered functions. |
| **formatNumber**   | Formats a number with grouping and precision.                            |
| **formatCurrency** | Formats a number as a currency string.                                   |
| **formatDate**     | Formats a date/time using a pattern.                                     |
| **pluralize**      | Selects a localized string based on a numeric count.                     |
| **openUrl**        | Opens a URL in a browser.                                                |
| **and**            | Logical AND operation on a list of boolean values.                       |
| **or**             | Logical OR operation on a list of boolean values.                        |
| **not**            | Logical NOT operation on a boolean value.                                |

### Theme

The basic catalog defines the following theme properties that can be set in the `createSurface` message:

| Property             | Type   | Description                                                                                                                                                                                                               |
| :------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **primaryColor**     | String | The primary brand color used for highlights throughout the UI (e.g., primary buttons, active borders). The renderer may generate variants, such as lighter shades, as needed. Format: Hexadecimal code (e.g., '#00BFFF'). |
| **iconUrl**          | URI    | A URL for an image (e.g., logo or avatar) that identifies the agent or tool associated with the surface.                                                                                                                  |
| **agentDisplayName** | String | Text to be displayed next to the surface to identify the agent or tool that created it (e.g. "Weather Bot").                                                                                                              |

#### Identity and attribution

The `iconUrl` and `agentDisplayName` fields are used to provide attribution to the user, identifying which sub-agent or tool is responsible for a particular UI surface.

In multi-agent systems or orchestrators, the orchestrator is responsible for setting or validating these fields. This ensures that the identity displayed to the user matches the actual agent server being contacted, preventing malicious agents from impersonating trusted services. For example, an orchestrator might overwrite these fields with the verified identity of the sub-agent before forwarding the `createSurface` message to the client.

### The `formatString` function

The `formatString` function supports embedding dynamic expressions directly within string properties. This allows for mixing static text with data model values and function results.

#### `formatString` syntax

Interpolated expressions are enclosed in `${...}`. To include a literal `${` in a string, it must be escaped as `\${`.

#### `formatString` data model binding

Values from the data model can be interpolated using their JSON Pointer path.

- `${/user/profile/name}`: Absolute path.
- `${firstName}`: Relative path (resolved against the current collection scope).

**Example:**

```json
{
  "id": "user_welcome",
  "component": "Text",
  "text": {
    "call": "formatString",
    "args": {
      "value": "Hello, ${/user/firstName}! Welcome back to ${/appName}."
    }
  }
}
```

#### `formatString` client-side functions

Results of client-side functions can be interpolated. Function calls are identified by the presence of parentheses `()`.

- `${now()}`: A function with no arguments.
- `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`: A function with named arguments.

Arguments can be **Literals** (quoted strings, numbers, or booleans), or **Nested Expressions**.

#### `formatString` nested interpolation

Expressions can be nested using additional `${...}` wrappers inside an outer expression to make bindings explicit or to chain function calls.

- **Explicit Binding**: `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`
- **Nested Functions**: `${upper(${now()})}`

#### `formatString` type conversion

When a non-string value is interpolated, the client converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **Null/Undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different client implementations.

## Usage pattern: the prompt-generate-validate loop

The A2UI protocol is designed to be used in a three-step loop with a Large Language Model:

1.  **Prompt**: Construct a prompt for the LLM that includes:
    - The desired UI to be generated.
    - The A2UI JSON schema, including the component catalog.
    - Examples of valid A2UI JSON.

2.  **Generate**: Send the prompt to the LLM and receive the generated JSON output.

3.  **Validate**: Validate the generated JSON against the A2UI schema. If the JSON is valid, it can be sent to the client for rendering. If it is invalid, the errors can be reported back to the LLM in a subsequent prompt, allowing it to self-correct.

This loop allows for a high degree of flexibility and robustness, as the system can leverage the generative capabilities of the LLM while still enforcing the structural integrity of the UI protocol.

### Standard validation error format

If validation fails, the client (or the system acting on behalf of the client) should send an `error` message back to the LLM. To ensure the LLM can understand and correct the error, use the following standard format within the `error` message payload:

- `code` (string, required): Must be `"VALIDATION_FAILED"`.
- `surfaceId` (string, required): The ID of the surface where the error occurred.
- `path` (string, required): The JSON pointer to the field that failed validation (e.g. `/components/0/text`).
- `message` (string, required): A short one-sentence description of why validation failed.

**Example error message:**

```json
{
  "error": {
    "code": "VALIDATION_FAILED",
    "surfaceId": "user_profile_card",
    "path": "/components/0/text",
    "message": "Expected stringOrPath, got integer"
  }
}
```

## Client-to-server messages

The protocol also defines messages that the client can send to the server, which are defined in the [`client_to_server.json`] schema. These are used for handling user interactions and reporting client-side information.

### `action`

This message is sent when the user interacts with a component that has an `action` defined, such as a `Button`.

**Properties:**

- `name` (string, required): The name of the action.
- `surfaceId` (string, required): The ID of the surface where the action originated.
- `sourceComponentId` (string, required): The ID of the component that triggered the action.
- `timestamp` (string, required): An ISO 8601 timestamp.
- `context` (object, required): A JSON object containing any context provided in the component's `action` property.

### Capabilities & metadata

In A2UI v0.9, capabilities and other metadata are exchanged via **Transport metadata** or initialization payloads (e.g., A2A metadata, Agent Cards, or MCP initialization), rather than as first-class A2UI messages.

#### Server capabilities

A server (or agent) advertises its capabilities using the [`server_capabilities.json`] schema. This indicates which catalogs it can generate UI for, and whether it accepts inline catalogs from the client. The exact mechanism depends on the transport (e.g., the `params` object in an A2A AgentCard, or server capabilities in MCP).

#### Client capabilities

The `a2uiClientCapabilities` object in the A2A `Message`'s `metadata` field follows the [`client_capabilities.json`] schema.

**Properties:**

- `supportedCatalogIds` (array of strings, required): String identifiers of supported catalogs.
- `inlineCatalogs`: An array of inline catalog definitions provided directly by the client (useful for custom or ad-hoc components and functions).

#### Client data model

When `sendDataModel` is enabled for a surface, the client includes the `a2uiClientDataModel` object in the metadata, following the [`client_data_model.json`] schema.

**Properties:**

- `surfaces` (object, required): A map of surface IDs to their current data models.

### `error`

This message is used to report a client-side error to the server.

[`catalogs/basic/catalog.json`]: ../catalogs/basic/catalog.json
[`common_types.json`]: ../json/common_types.json
[`server_to_client.json`]: ../json/server_to_client.json
[`client_to_server.json`]: ../json/client_to_server.json
[`server_capabilities.json`]: ../json/server_capabilities.json
[`client_capabilities.json`]: ../json/client_capabilities.json
[`client_data_model.json`]: ../json/client_data_model.json
[JSON Pointer]: https://datatracker.ietf.org/doc/html/rfc6901
[RFC 6901]: https://datatracker.ietf.org/doc/html/rfc6901

---

### Specification V0 9 1 Docs Basic Catalog Implementation Guide (`specification/v0_9_1/docs/basic_catalog_implementation_guide.md`)

# A2UI Basic Catalog Implementation Guide

This guide is designed for renderer and client developers implementing the A2UI Basic Catalog (v0.9). It details how to visually present and functionally implement each component and client-side function defined in the catalog.

When building your framework-specific adapters (Layer 3) over the generic A2UI bindings, refer to this document for the expected visual behaviors, suggested layouts, and interaction patterns. This guide uses generic terminology applicable to Web, Mobile (iOS/Android), and Desktop platforms.

---

## 1. Components

### Text

Displays text content.

**Rendering Guidelines:** Text should be rendered using a Markdown parser when possible. If markdown rendering is unavailable or fails, gracefully fallback to rendering the raw text. In such cases, renderers should ideally attempt to strip common Markdown markers (like `**` or `#`) to ensure the text remains legible and aesthetically consistent with the intended presentation.
**Property Mapping:**

- `variant="h1"` through `h5"`: Apply heading styling. Suggested relative font sizes: `h1` (2.5x base), `h2` (2x base), `h3` (1.75x base), `h4` (1.5x base), `h5` (1.25x base).
- `variant="caption"`: Render as smaller text, typically italicized or in a lighter/muted color. Suggested font size: 0.8x base.
- `variant="body"` (default): Standard body text. Uses the base font size (e.g., 16dp/16px).

### Image

Displays an image from a URL.

**Rendering Guidelines:** Ensure the component defaults to a flexible width so it fills its container.
**Property Mapping:**

- `fit`: Map the property to the platform's equivalent content scaling mode (e.g., CSS `object-fit`, iOS `contentMode`, Android `ScaleType`).
- `variant="icon"`: Render very small and square (e.g., 24x24dp).
- `variant="avatar"`: Render small and rounded/circular (e.g., 40x40dp, fully rounded corners).
- `variant="smallFeature"`: Render as a small rectangle (e.g., 100x100dp).
- `variant="mediumFeature"` (default): Render as a medium rectangle (e.g., 100% width up to 300dp, or 200x200dp).
- `variant="largeFeature"`: Render as a large prominent image (e.g., 100% width, max height 400dp).
- `variant="header"`: Render as a full-width banner image, usually at the top of a surface (e.g., 100% width, height 200dp, scaling mode set to cover/crop).

### Icon

Displays a standard system icon.

**Rendering Guidelines:** Map the icon `name` to a system or bundled icon set (e.g., Material Symbols, SF Symbols). The string `name` from the data model (e.g., `accountCircle`) should be converted to the required format (like snake_case `account_circle`) if required by the icon engine. Suggested styling: 24dp size and inherit the current text color.

### Video

A video player.

**Rendering Guidelines:** Render using a native video player component with user controls enabled. Ensure the video container spans the full width of the parent's container for responsiveness. Scrubbing (seeking) should be supported if provided by the native control.

### AudioPlayer

An audio player.

**Rendering Guidelines:** Render using a native audio player component with user controls enabled. Like video, its container should span the full width of its parent. Scrubbing (seeking) should be supported if provided by the native control.

### Row

A horizontal layout container.

**Rendering Guidelines:** Implemented using a horizontal layout container (e.g., CSS Flexbox row, Compose `Row`, SwiftUI `HStack`). Ensure it fills the available width.
**Property Mapping:**

- `justify`: Maps to main-axis alignment (e.g., `justify-content` in CSS, `horizontalArrangement` in Compose). Use equivalents for pushing items to edges (`spaceBetween`) or packing them together (`start`, `center`, `end`).
- `align`: Maps to cross-axis alignment (e.g., `align-items` in CSS, `verticalAlignment` in Compose). Use equivalents for top (`start`), center, or bottom (`end`).

### Column

A vertical layout container.

**Rendering Guidelines:** Implemented using a vertical layout container (e.g., CSS Flexbox column, Compose `Column`, SwiftUI `VStack`).
**Property Mapping:**

- `justify`: Maps to main-axis alignment on the vertical axis.
- `align`: Maps to cross-axis alignment on the horizontal axis.

### List

A scrollable list of components.

**Rendering Guidelines:** Children of a horizontal list should typically have a constrained max-width so they do not stretch indefinitely.
**Property Mapping:**

- `direction="vertical"` (default): Implement as a vertically scrollable view (e.g., CSS `overflow-y: auto`, Compose `LazyColumn`, SwiftUI `ScrollView` vertical).
- `direction="horizontal"`: Implement as a horizontally scrollable view. Hide the scrollbar for a cleaner look if supported by the platform.

### Card

A container with card-like styling that visually groups its child.

**Rendering Guidelines:** Applies a background color distinct from the main surface, rounded corners (e.g., 8dp or 12dp), a subtle shadow or elevation, and inner padding (e.g., 16dp). Note that the card accepts exactly **one** child. If the user wants multiple elements inside a card, they must provide a container (like `Column`) as the single child.

### Tabs

A set of tabs, each with a title and a corresponding child component.

**Rendering Guidelines:** Render a horizontal row of interactive tab headers for the `titles`. Visually indicate the active tab (e.g., bold text, colored bottom border).
**Behavior & State:** Maintain a local `selectedIndex` state (defaulting to 0). When a tab header is tapped, update `selectedIndex` and render _only_ the `child` component that corresponds to that index.

### Divider

A dividing line to separate content.

**Property Mapping:**

- `axis="horizontal"` (default): Render a 1dp tall line spanning 100% width with a subtle border/outline color.
- `axis="vertical"`: Render a 1dp wide line with a set height, spanning the height of the container.

### Modal

A dialog window.

**Rendering Guidelines:**

- **Desktop UIs**: Render as a centered popup or native dialog window over the main content, typically with a dimmed backdrop.
- **Mobile UIs**: Render as a bottom sheet or full-screen dialog over the main content.
- You must provide a mechanism to close the modal (e.g., an "X" button, clicking/tapping the backdrop overlay, or a swipe-to-dismiss gesture).

**Behavior & State:** This component behaves differently than a standard container. It acts as a **Modal Entry Point**. When instantiated, the user only sees the `trigger` child component on the screen (which usually acts and looks like a Button). The modal logic intercepts interactions (taps/clicks) on the `trigger`. When the `trigger` is tapped, the modal opens and displays the `content` child component.

### Button

An interactive button that dispatches a protocol action.

**Rendering Guidelines:** Render as a native interactive button component. It must render its `child` component inside the button (usually a `Text` or `Icon`).
**Behavior & State:** When tapped, it dispatches the `action` back to the server, dynamically resolving the context variables at the moment of the interaction.
**Property Mapping:**

- `variant="default"`: Standard button with a subtle background and border.
- `variant="primary"`: Prominent call-to-action button using the theme's `primaryColor` for its background, and contrasting text.
- `variant="borderless"`: Button with no background or border, appearing like a clickable text link.

### TextField

A field for user text input.

**Rendering Guidelines:** Render using the platform's native text input control.
**Behavior & State:** Establishes **Two-Way Binding**. As the user types, immediately write the new string back to the local data model path bound to `value`.
**Property Mapping:**

- `variant="shortText"` (default): Standard single-line input field.
- `variant="longText"`: Render as a multi-line text area.
- `variant="number"`: Render as a numeric input field, typically showing a numeric keyboard on mobile.
- `variant="obscured"`: Render as an obscured password/secure field.

### CheckBox

A toggleable control with a label.

**Rendering Guidelines:** Render a native checkbox or toggle switch component alongside a text label.
**Behavior & State:** Triggers two-way binding on the `value` path, setting it to boolean `true` or `false` when interacted with.

### ChoicePicker

A component for selecting one or more options from a list.

**Rendering Guidelines:**

- `displayStyle="checkbox"` (default): Render as a dropdown menu, picker wheel, or an expanding vertical list of selectable options. A dropdown wrapper is preferred to save space.
- `displayStyle="chips"`: Render as a horizontal, wrapping row of selectable chips/pills. Selected chips should have a distinct background/border.
- If `filterable` is true, render a text input above the list of options. As the user types, filter the visible options using a case-insensitive substring match on the option labels.

**Behavior & State:** Binds to an array of strings in the data model representing the active selections. Toggle selections in the data model upon user interaction.

### Slider

A control for selecting a numeric value within a range.

**Rendering Guidelines:** Render using the platform's native slider or seek bar component. Optionally display the current numeric value next to the slider track.
**Behavior & State:** Set `min` and `max` limits. Perform two-way binding, updating the numeric `value` path as the user drags the slider. Note that the value is a `number` rather than an integer, allowing for decimal ranges (e.g., 0.0 to 1.0).

### DateTimeInput

An input for date and/or time.

**Rendering Guidelines:** Render using native date and time picker controls.

- If `enableDate` and `enableTime` are both true, show both date and time selection UI.
- If only `enableDate` is true, show only a date picker.
- If only `enableTime` is true, show only a time picker.

**Behavior & State:** The component must convert the platform's native date/time format into a standard ISO 8601 string before writing it to the A2UI data model, and correctly parse ISO 8601 strings coming from the model into the input field.

---

## 2. Client-Side Functions

Functions provide client-side logic for validation, interpolation, and operations. As defined in the Architecture Guide, the reactivity of function arguments is generally handled by the Core Data Layer (specifically the Binder/Context layer).

Core libraries for each language (such as `@a2ui/web_core` for TypeScript) typically provide a complete, framework-agnostic implementation of all the functions in the basic catalog. Developers are encouraged to utilize these shared implementations rather than writing their own.
When a function is called, the system resolves its arguments. If an argument is a static value, it is passed directly. If it is a dynamic binding, the Context layer handles the subscription. For most standard functions, the `execute` implementation simply receives a dictionary of static `args` and returns a static value. The Context layer wraps this execution in a reactive stream (e.g., a `computed` signal) so that the function re-runs whenever any of its dynamic arguments change.

However, complex functions like `formatString` must manually interact with the Context to parse and subscribe to nested dynamic dependencies.

### `formatString`

**Description:** The core interpolation engine. Parses the `args.value` string for `${expression}` blocks, combining literal strings, data paths, and other client-side function results.

**Architecture & Logic:**
Because `formatString` contains dynamic expressions embedded _within_ a string literal, the Context layer cannot pre-resolve them. The implementation must parse the string and manually create a reactive output.

1.  **Parser/Scanner:** Implement a parser that scans the input string (`args.value`) for `${...}` blocks. It must properly handle escaped markers (`\${`) which resolve to a literal `${`.
2.  **Expression Evaluation:** Inside the interpolation block, the parser must differentiate between:
    - **Literals:** Quoted strings (`'...'` or `"..."`), numbers, and keywords (`true`, `false`, `null`).
    - **Data Paths:** Identifiers starting with a slash (`/absolute/path`) or relative identifiers (`relative/path`).
    - **Function Calls:** Identifiers followed by parentheses, e.g., `funcName(argName: value)`.
3.  **Context Resolution:** For every parsed `DataPath` or `FunctionCall` token, use the `DataContext` (e.g., `context.resolveSignal(token)`) to turn it into a reactive stream/signal.
4.  **Reactive Return:** The function MUST return a computed reactive stream (e.g., a `computed(() => ...)` signal). Inside this computed stream, unwrap all the resolved signals, convert them to strings, and concatenate them with the literal string parts.

### `required`

**Description:** Validates that a given value is present.

**Logic:** Return `true` if `args.value` is strictly not `null`, not `undefined`, not an empty string `""`, and not an empty array `[]`. Otherwise, return `false`.

### `regex`

**Description:** Validates a value against a regular expression.

**Logic:** Instantiate a regular expression using `args.pattern`. Test the `args.value` string against it. Return `true` if it matches, `false` otherwise.

### `length`

**Description:** Validates string length constraints.

**Logic:** Ensure the length of the string `args.value` is `>= args.min` (if `min` is provided) and `<= args.max` (if `max` is provided).

### `numeric`

**Description:** Validates numeric range constraints.

**Logic:** Parse `args.value` as a number. Ensure it is `>= args.min` (if `min` is provided) and `<= args.max` (if `max` is provided). Return `true` if valid, `false` if invalid or if it cannot be parsed as a number.

### `email`

**Description:** Validates an email address.

**Logic:** Test `args.value` against a standard email regex pattern (e.g., `/^[^\s@]+@[^\s@]+\.[^\s@]+$/`).

### `formatNumber`

**Description:** Formats a numeric value.

**Logic:** Use the platform's native locale formatting (e.g., `Intl.NumberFormat` on the web or `NumberFormatter` natively) on `args.value`.

- If `args.decimals` is provided, force both the minimum and maximum fraction digits to that value.
- Enable grouping (e.g., thousands separators) unless `args.grouping` is explicitly set to `false`.

### `formatCurrency`

**Description:** Formats a number as a currency string.

**Logic:** Similar to `formatNumber`, but configured for currency style formatting. Apply the ISO 4217 currency code provided in `args.currency` (e.g., 'USD', 'EUR').

### `formatDate`

**Description:** Formats a timestamp into a date string.

**Logic:** Parse `args.value` into a native Date/Time object. Interpret the Unicode TR35 `args.format` string (e.g., `yyyy-MM-dd`, `HH:mm`) and construct the formatted date string. You will likely need a platform-specific date formatting library to parse the TR35 pattern.

### `pluralize`

**Description:** Returns a localized pluralized string.

**Logic:** Resolve the plural category for the numeric `args.value` based on the current locale (e.g., using `Intl.PluralRules` on the web). Map the resulting category (`zero`, `one`, `two`, `few`, `many`, `other`) to the corresponding string provided in the `args` object. If the specific category string is missing from `args`, fallback to `args.other`.

### `openUrl`

**Description:** Opens a URL.

**Logic:** Open `args.url` using the native platform's URL handler (e.g., opening in the system browser or deep-linking to an app). This function returns `void` and is executed as a side-effect.

**Security Constraints & Implementation Requirements (Mandatory):**
To prevent DOM-Based Cross-Site Scripting (XSS) via `javascript:`, `data:`, or other non-HTTP schemes:

1. **Resolve Relative URLs:** Before validation, resolve relative paths against the current environment context (e.g., `window.location.href` in browsers) using standard URL parsing.
2. **Enforce Scheme Allowlist:** Strictly validate that the resolved URL protocol/scheme is either `https:` or `http:`. Throw an execution or runtime error (such as `A2uiExpressionError`) and abort the action if any other scheme is used.
3. **Tab-Nabbing Protection:** When opening URLs in a new browser window/tab, always supply security attributes: `noopener,noreferrer` (e.g. `window.open(url, '_blank', 'noopener,noreferrer')`).

### `and`

**Description:** Logical AND operator.

**Logic:** Iterate through the boolean array `args.values`. Return `true` only if all values are true. Short-circuit evaluation is encouraged.

### `or`

**Description:** Logical OR operator.

**Logic:** Iterate through the boolean array `args.values`. Return `true` if at least one value is true. Short-circuit evaluation is encouraged.

### `not`

**Description:** Logical NOT operator.

**Logic:** Return the strict boolean negation of `args.value`.

---

## 3. Layout Spacing: Margins and Padding

A common challenge in dynamic UI frameworks is preventing "spacing multiplication," where nested containers (e.g., a `Text` inside a `Row` inside a `Column`) result in accumulated empty space that throws off the design.

To achieve a clean, consistent default spacing where elements feel naturally separated without stacking empty space, implementers should follow a **Leaf-Margin Strategy**:

1. **Invisible Containers have ZERO Spacing**: Structural, invisible layout containers (`Row`, `Column`, `List`) should have **no internal padding** and **no external margins**. They act purely as structural boundaries. This guarantees that wrapping an element in a `Row` or `Column` does not alter its spacing.
2. **Leaf Components carry the Margin**: All non-container, visual "leaf" elements (`Text`, `Image`, `Icon`, `Video`, `AudioPlayer`, `Slider`, etc.) should have a uniform default **external margin** applied to them (e.g., `8dp` on all sides).
3. **Visually Outlined Containers carry the Margin**: Containers and inputs that have a visible boundary (`Card`, `Button`, `TextField`, `CheckBox`, `ChoicePicker`) should also apply this same uniform default **external margin**.
   - _Note:_ These elements will naturally also need internal _padding_ to keep their content away from their own visible borders, but this padding is localized and does not affect the external layout.

**Why use Margins on Leaves?**
Applying margins directly to the visual elements—rather than relying on padding or gap properties on the parent containers—ensures predictable spacing. For example, if you have `Row(Item1, Item2)`, using margins on the items guarantees that there is space to the left of `Item1`, space to the right of `Item2`, and space between them. Because the invisible containers themselves contribute zero extra spacing, you can deeply nest your structural rows and columns without the spacing unexpectedly multiplying.

---

## 4. Color, Contrast, and Nesting

A common challenge in dynamically generated UI is ensuring proper contrast and visual hierarchy when components are nested. For example:

- A `Text` or `Icon` nested inside a `primary` `Button` must change its color to contrast with the button's background.
- A `Card` nested inside another `Card` should remain visually distinct.

To keep the A2UI rendering layer simple and performant, **do not manually calculate or pass color properties down the A2UI component tree**. Instead, rely entirely on the native context and theme inheritance mechanisms provided by your target UI framework.

### Text and Icon Contrast

When an element defines a strong background color (like a `primary` `Button` using the theme's `primaryColor`), it must also define the expected text color for its content. It should propagate this expectation implicitly.

- **Web (CSS):** The `Button` wrapper sets the standard CSS `color` property. Because `color` is inherited in CSS, any `Text` or `Icon` component rendered inside the button will automatically adapt.
- **Compose (Android):** The button wrapper should use `CompositionLocalProvider(LocalContentColor provides ...)`. Any nested `Text` and `Icon` components will automatically pick up this color without needing it explicitly passed to their A2UI classes.
- **SwiftUI (iOS):** Apply `.foregroundColor(...)` or `.environment(\.colorScheme, ...)` to the button wrapper.
- **Flutter:** Use `DefaultTextStyle.merge()` and `IconTheme.merge()` within the button wrapper. If using standard Material buttons (like `ElevatedButton`), this is often handled for you automatically.

_Rule of Thumb:_ Leaf components like `Text` and `Icon` should **never** hardcode their colors unless explicitly instructed by a property. They must always inherit from their environment.

### Nesting Containers (Cards)

When a `Card` is nested within another `Card`, or placed on different background surfaces, it needs to remain distinct. Attempting to alternate surface colors based on depth adds significant complexity to the renderer.

**Recommended Approach: Outlines and Transparent Surfaces**
The simplest, most robust starting approach is to give `Card` components a **transparent background** and a **visible outline/border** (e.g., a 1dp outline matching the theme's outline/border color).

- By using borders instead of opaque surface colors, nested cards will simply draw an inner boundary within the parent card.
- This guarantees a clear visual hierarchy regardless of how deeply they are nested, and it requires zero context-passing or depth-tracking in your code.
- If your design system requires opaque cards, consider using a framework-specific elevation system (e.g., standard Material elevation) which often handles shadow and surface tinting automatically, rather than building custom color-alternation logic into the A2UI adapters.

---

### Specification V0 9 1 Docs Evolution Guide (`specification/v0_9_1/docs/evolution_guide.md`)

# A2UI Protocol Evolution Guide: v0.9 to v0.9.1

This document describes the changes between A2UI version 0.9 and version 0.9.1. For changes from version 0.8 to 0.9, please refer to the [v0.9 Evolution Guide](../../v0_9/docs/evolution_guide.md).

## 1. Executive Summary

Version 0.9.1 is a minor refinement of the v0.9 specification. The key changes are:

1. **MIME Type Standardization**: Standardized all references to the A2UI message payload MIME type to `application/a2ui+json` (replacing the legacy `application/json+a2ui`).
2. **Surface ID Uniqueness Relaxation**: Relaxed the requirement for `surfaceId` to be globally unique for the renderer's lifetime. It must still be unique among currently active surfaces, and it remains an error to call `createSurface` on an existing surface without first deleting it, but the explicit lifetime uniqueness constraint is removed.

## 2. Detailed Changes

### 2.1. MIME Type Standardization

In previous draft iterations of the v0.9 extension specification, the legacy `application/json+a2ui` MIME type was referenced. Version 0.9.1 standardizes all specification guides and extension metadata examples to use `application/a2ui+json`.

### 2.2. Surface ID Requirements

In `a2ui_protocol.md`, the definition and requirements for `surfaceId` were updated:

- The restriction that `surfaceId` "must be globally unique for the renderer's lifetime" is removed.
- Instead, the uniqueness constraint is limited to active surfaces: it remains an error to send `createSurface` for a `surfaceId` that already exists without first deleting it.

## 3. Migration Guide

Since v0.9.1 is fully compatible with v0.9 payloads (the version fields in schemas accept both `"v0.9"` and `"v0.9.1"`), clients and servers can upgrade seamlessly.

- **Action for Implementers**: Update any hardcoded MIME type references from `application/json+a2ui` to `application/a2ui+json`.

---

### Specification V0 9 1 Docs Sdks Spec (`specification/v0_9_1/docs/sdks_spec.md`)

# A2UI Unified SDK Architecture

This document describes the unified architecture of the A2UI SDK ecosystem. To support modern, multi-paradigm generative UI applications, A2UI separates concerns into a modular, three-tiered structure: the **A2UI Core SDK**, the **Inference SDK**, and **Framework Adapters**. This structure is replicated across different languages.

This architecture enables high code reuse, strict conformance, and unified behavior across languages. Ensuring that we use a consistent codebase structure and terminology across languages also makes it easier to maintain the codebases together and add new features across languages using spec-driven development.

## 1. Ecosystem Dependency Structure

Framework adapter and inference SDKs depend on the core SDK as shown below:

```mermaid
flowchart TD
    FA[Framework Adapter<br>Renders surface state to pixels using a native UI] -->|Depends on| Core[A2UI Core SDK<br>Maintains surface state, message processing, and validation]
    Inference[Inference SDK<br>Generates serverToClient messages using LLM engines] -->|Depends on| Core
```

## 2. Library Responsibilities

### A2UI Core SDK (`a2ui_core` / `@a2ui/core`)

**Availability:** Every target language (TS, Dart, Python, Kotlin, Swift, C++).  
**Responsibility:** Provides the foundational, language-native representations of the official A2UI specifications.

- **Protocol Models:** Strongly-typed classes representing Catalog declarations (`Catalog`, `ComponentApi`, `FunctionApi`) and A2UI message types (`ClientToServer`, `ServerToClient`, etc.).
- **Surface State Management:** Mutable models representing active UI surfaces (`SurfaceModel`, `ComponentModel`, `DataModel`).
- **Processing Layer (`MessageProcessor`):** Evaluates incoming JSON message arrays, resolves relative JSON pointers, and updates surface state models.
- **Validation:** Performs strict validation of message schema structures and reference checks.
- **Incremental Snapshotting:** Supports tracking and collapsing incremental updates into flat snapshots (e.g., `ComponentNode` trees).

### Inference SDK (`a2ui_inference` / `@a2ui/inference`)

**Availability:** All supported agent languages and select client-side languages (for local inference).  
**Responsibility:** Guides Large Language Models (LLMs) to generate valid A2UI message payloads based on a defined component Catalog and active application context.

- **Inference Strategies:** Standard structured generation schemes.
- **Prompt Construction:** Building prompt buffers and feeding component capability schemas dynamically to LLM contexts.
- **Message Parsing:** Safely extracting and repairing raw JSON envelopes from LLM completion streams.
- **Error Repair & Retries:** Programmatic fixing of malformed or invalid schemas.

### Framework Adapters (`react_renderer`, `compose_renderer`, etc.)

**Availability:** Every supported UI framework across client platforms.  
**Responsibility:** Paints the state of a Core `SurfaceModel` onto physical screen pixels using native UI hierarchies.

- **Framework Entry View (`Surface`):** Observes Core state and boots the recursive layout loop.
- **Component Renderers (`ComponentImplementation`):** Individual native views implementing visual specs (e.g., standard layout, text, or inputs from the Basic Catalog).
- **Lifecycle Bindings:** Standardizes lazy-mounting, reactive value propagation, and memory leak prevention (`dispose`).

---

### Specification V1 0 Docs A2ui Custom Functions (`specification/v1_0/docs/a2ui_custom_functions.md`)

# Defining Custom Functions

A2UI functions are defined inside a Catalog. When defining your own catalog, you can include custom functions that are specific to your application or design system.

This guide demonstrates how to define a string `trim` function and a hardware query function (`getScreenResolution`) in your catalog.

## 1. Define the Catalog

Create a JSON Schema file (e.g., `my_catalog.json`) that defines your
function parameters.

Use the `functions` property to define a map of function schemas.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## 2. Make the functions available

The `FunctionCall` definition refers to a [catalog-agnostic reference](a2ui_protocol.md#the-basic-catalog).
In your catalog, you simply need to define the `anyFunction` reference:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [{"$ref": "#/functions/trim"}, {"$ref": "#/functions/getScreenResolution"}]
    }
  }
}
```

If you want to incorporate functions defined in the [`catalogs/basic/catalog.json`],
those can be added too:

```json
{
  "$defs": {
    "anyFunction": {
      "oneOf": [
        {"$ref": "#/functions/trim"},
        {"$ref": "#/functions/getScreenResolution"},
        {"$ref": "catalogs/basic/catalog.json#/$defs/anyFunction"}
      ]
    }
  }
}
```

## How Validation Works

When a `FunctionCall` is validated:

1. **Discriminator Lookup:** The validator looks at the `@call` property of the
   object.
2. **Schema Matching:**
   - If `@call` is `"length"`, it matches `Functions` -> `length`
     and validates the named arguments in `args` against the length rules.
   - If `@call` is `"trim"`, it matches `CustomFunctions` -> `trim` and
     validates against your custom rules.
   - If `@call` is `"unknownFunc"`, validation FAILS immediately (strict mode).

This strict-by-default approach ensures typos are caught early, while the
modular structure makes it easy to add new capabilities with full type safety.

---

### Specification V1 0 Docs A2ui Protocol (`specification/v1_0/docs/a2ui_protocol.md`)

<div style="text-align: center;">
  <div class="centered-logo-text-group">
    <img src="../../../docs/public/assets/A2UI_dark.svg" alt="A2UI Protocol Logo" width="100">
    <h1>A2UI (Agent to UI) Protocol v1.0</h1>
  </div>
</div>

A Specification for a JSON-Based, Streaming UI Protocol.

**Version:** 1.0
**Status:** Candidate
**Created:** Nov 20, 2025
**Last Updated:** Jun 8, 2026

A Specification for a JSON-Based, Streaming UI Protocol

## Introduction

The A2UI Protocol is designed for dynamically rendering user interfaces from a stream of JSON objects sent from an agent. Its core philosophy emphasizes a clean separation of UI structure and application data, enabling progressive rendering as the renderer processes each message.

Communication occurs via a stream of JSON objects. The renderer parses each object as a distinct message and incrementally builds or updates the UI. The agent-to-renderer protocol defines four message types:

- `createSurface`: Signals the renderer to create a new surface and begin rendering it.
- `updateComponents`: Provides a list of component definitions to be added to or updated in a specific surface.
- `updateDataModel`: Provides new data to be inserted into or to replace a surface's data model.
- `deleteSurface`: Explicitly removes a surface and its contents from the UI.

End of agent turn is signaled by [transport layer](../../../docs/public/concepts/transports.md).

## Changes from previous versions

The major differences between version 1.0 and 0.9 (including 0.9.1) are:

- **Bidirectional Function Calls**: Supports explicit, typed function invocation messages (`callRendererFunction`, `callAgentFunction`, `rendererFunctionResponse`, and `agentFunctionResponse`) verified against runtime catalog definitions.
- **Single-Message UI Instantiation**: Allows initial component trees and data models to be embedded directly within `createSurface`, enabling complete UI composition in a single payload.
- **Decoupled Branding**: Removes rigid theme properties (removing hardcoded brand colors) to defer visual styling entirely to the target framework's native theme.
- **Enhanced Catalog Schemas**: Refactors function definitions into object maps for direct O(1) lookups and supports standard JSON Schema metadata fields (`$schema`, `$id`) on inline catalogs.
- **Strict Identifier & Context Standards**: Enforces Unicode (UAX #31) naming rules across all catalog entities and reserves the `@` namespace for universal system context evaluations (such as `@index`).

See [the evolution guide](evolution_guide.md) for a detailed explanation of the differences between v0.9 and v1.0.

## Protocol overview & data flow

The A2UI protocol uses a unidirectional stream of JSON messages from the agent to the renderer to describe and update the UI. The renderer consumes this stream, builds the UI, and renders it. User interactions are handled separately, typically by sending events to a different endpoint, which may in turn trigger new messages on the UI stream.

Here is an example sequence of events (which don't have to be in exactly this order):

1.  **Create Surface:** The agent sends a `createSurface` message to initialize the surface.
2.  **Update Surface:** Once a surface has been created, the agent sends one or more `updateComponents` messages containing the definitions for all the components that will be part of the surface.
3.  **Update Data Model:** Once a surface has been created, the agent can send `updateDataModel` messages at any time to populate or change the data that the UI components will display.
4.  **Render:** The renderer renders the UI for the surface, using the component definitions to build the structure and the data model to populate the content.
5.  **Dynamic updates:** As the user interacts with the application or as new information becomes available, the agent can send additional `updateComponents` and `updateDataModel` messages to dynamically change the UI.
6.  **Delete Surface:** When a UI region is no longer needed, the agent sends a `deleteSurface` message to remove it.

```mermaid
sequenceDiagram
    participant Agent
    participant Renderer

    Agent->>+Renderer: 1. createSurface(surfaceId: "main")
    Agent->>+Renderer: 2. updateComponents(surfaceId: "main", components: [...])
    Agent->>+Renderer: 3. updateDataModel(surfaceId: "main", path: "/user", value: "Alice")
    User->>+Renderer: Interact with UI (e.g. click button)
    Renderer->>+Agent: action(name: "submit", context: {...})
    Renderer-->>-Agent: (UI is displayed)

    Note over Renderer, Agent: Time passes, user interacts, or new data arrives...

    Agent->>+Renderer: 4. updateComponents or updateDataModel (Dynamic Update)
    Note right of Renderer: Renderer re-renders the UI to reflect changes
    Renderer-->>-Agent: (UI is updated)

    Agent->>+Renderer: 5. deleteSurface(surfaceId: "main")
    Note right of Renderer: Renderer removes the UI for the "main" surface
    Renderer-->>-Agent: (UI is gone)
```

## Transport decoupling

The A2UI protocol is designed to be transport-agnostic. It defines the JSON message structure and the semantic contract between the Agent and the Renderer, but it does not mandate a specific transport layer.

### The transport contract

To support A2UI, a transport layer must fulfill the following contract:

1.  **Reliable delivery**: Messages must be delivered in the order they were generated. A2UI relies on stateful updates (e.g., creating a surface before updating it), so out-of-order delivery can corrupt the UI state.
2.  **Message framing**: The transport must clearly delimit individual JSON envelope messages (e.g., using newlines in JSONL, WebSocket frames, or SSE events).
3.  **Metadata support**: The transport must provide a mechanism to associate metadata with messages. This is critical for:
    - **Data model synchronization**: The `sendDataModel` feature requires the renderer to send the current data model state as metadata alongside user actions.
    - **Capabilities exchange**: Renderer capabilities (supported catalogs, custom components) and Agent capabilities are exchanged via metadata or transport-specific handshakes (like Agent Cards in A2A or initialization in MCP).
4.  **Bidirectional capability (optional)**: While the rendering stream is unidirectional (Agent -> Renderer), interactive applications require a return channel for `action` messages (Renderer -> Agent).

### Transport bindings

While A2UI is transport agnostic, it is most commonly used with the following transports.

#### AG-UI (Agent-to-User Interface) binding

**[AG-UI](https://docs.ag-ui.com/introduction)** is the standard transport binding for Agent-to-User Interaction. It provides convenient integrations into many agent frameworks and frontends, offering low-latency and shared-state message passing between frontends and agentic backends.

#### A2A (Agent-to-Agent) binding

The **[A2A Extension](../extensions/a2a/docs/a2ui_extension_specification.md)** maps A2UI over the **[A2A Protocol](https://a2a-protocol.org)**. It standardizes metadata placement, renderer-to-agent capability negotiation, and bidirectional data model synchronization for agent-to-agent interactions.

#### MCP (Model Context Protocol) binding

**[MCP](https://modelcontextprotocol.io/docs/getting-started/intro)** is a standard protocol for exposing data and tools to LLMs. A2UI can be carried over MCP tool calls, tool outputs, or resource subscriptions, allowing agents to dynamically render rich user interfaces for renderer-side applications.

#### Other transports

A2UI can also be carried over:

- **[SSE](https://en.wikipedia.org/wiki/Server-sent_events) with [JSON RPC](https://www.jsonrpc.org/)**: Standard server-sent events for web integrations that support streaming, and JSON RPC for renderer-agent communication.
- **[WebSockets](https://en.wikipedia.org/wiki/WebSocket)**: For bidirectional, real-time sessions.
- **[REST](https://cloud.google.com/discover/what-is-rest-api?hl=en)**: For simple use case, REST APIs will work but lack streaming capabilities.

## The protocol schemas

A2UI v1.0 is defined by three interacting JSON schemas.

### Common types

The [`common_types.json`] schema defines reusable primitives used throughout the protocol.

- **`DynamicString` / `DynamicNumber` / `DynamicBoolean` / `DynamicStringList`**: The core of the data binding system. Any property that can be bound to data is defined as a `Dynamic*` type. It accepts either a literal value, a `DataBinding` (`{"@path": "..."}` using [JSON Pointer]), or a `FunctionCall` (`{"@call": "...", "args": {...}}`). When a `DynamicBoolean` resolves to a `ValidationResult` object (an object with a boolean `valid` property), it is coerced to `result.valid`.
- **`ChildList`**: Defines how containers hold children. It supports:
  - `array`: A static array of `ComponentId` component references.
  - `object`: A template for generating children from a list in the data model (requires a template `componentId` and a JSON Pointer `path` string; note that `path` here is a plain string property on the template object, not a `DataBinding` `{"@path": "..."}` object).

- **`ComponentId`**: A reference to the unique ID of another component within the same surface.
- **`AccessibilityAttributes`**: Standardized accessibility properties attached via `ComponentCommon` to any component, supporting `label` (`DynamicString`), `description` (`DynamicString`), `live` (`"off"` | `"polite"` | `"assertive"`), and `hidden` (`DynamicBoolean`).

### Agent to renderer message structure: the envelope

The [`agent_to_renderer.json`] schema is the top-level entry point. Every message streamed by the agent must validate against this schema. It handles the message dispatching.

### The Basic Catalog

The [`catalogs/basic/catalog.json`] schema contains the definitions for all specific UI components (e.g., `Text`, `Button`, `Row`) and functions (e.g., `required`, `email`).

**Swappable Catalogs & Validation:**

The [`agent_to_renderer.json`] envelope schema is designed to be catalog-agnostic. Within its `Component` definition (referenced by `ComponentsList`), it validates base properties against `common_types.json#/$defs/ComponentCommon` and references components using a placeholder filename: `catalog.json` (specifically `$ref: "catalog.json#/$defs/anyComponent"`).

To validate A2UI messages:

1.  **Basic Catalog**: Map `catalog.json` to `catalogs/basic/catalog.json`.
2.  **Renderer Catalog**: Map `catalog.json` to your own catalog file (e.g., `my_company_catalog.json`).

This indirection allows the same core envelope schema to be used with any compliant component catalog without modification.

Defining your own catalog allows you to restrict the agent to using exactly the components and visual language that exist in your application. To use your own catalog, simply include it in the prompt in place of the basic catalog. It should have the same form as the basic catalog and use common elements in the [`common_types.json`] schema.

### Validator compliance when defining catalogs

To ensure that automated validators can verify the integrity of your UI tree (checking that parents reference existing children), any catalog you define MUST adhere to the following strict typing rules:

1.  **Single child references:** Any property that holds the ID of another component MUST use the `ComponentId` type defined in `common_types.json`.
    - Use: `"$ref": "common_types.json#/$defs/ComponentId"`
    - Do NOT use: `"type": "string"`

2.  **List references:** Any property that holds a list of children or a template MUST use the `ChildList` type.
    - Use: `"$ref": "common_types.json#/$defs/ChildList"`

Validators determine which fields represent structural links by looking for these specific schema references. If you use a raw string type for an ID, the validator will treat it as static text (like a URL or label) and will not check if the target component exists.

## Envelope message structure

The envelope defines several message types, and every message streamed by the agent must be a JSON object containing exactly one of the following keys: `createSurface`, `updateComponents`, `updateDataModel`, `deleteSurface`, `callRendererFunction`, or `agentFunctionResponse`. The key indicates the type of message, and these are the messages that make up each message in the protocol stream.

### `createSurface`

This message signals the renderer to create a new surface and begin rendering it. A surface must be created before any `updateComponents` or `updateDataModel` messages can be sent to it. While typically achieved by the agent sending a `createSurface` message, an agent may skip this if it knows of a preexisting surface that it has permission to modify. Once a surface is created, its `surfaceId` and default `catalogId` (if provided) are fixed; to reconfigure them, the surface must be deleted and recreated.

It is a state integrity error (`code: "INTEGRITY_ERROR"`) to try to create a surface with a `surfaceId` that already exists without first deleting it via `deleteSurface`; `surfaceId` must be globally unique for the renderer's lifetime. Orchestrators with subagents are empowered to manage surface IDs as needed to prevent conflicts (e.g., prefixing the subagent's name to the `surfaceId` or requiring subagents to use UUIDs).

The `createSurface` message implicitly instantiates the canonical `Surface` container component (`common_types.json#/$defs/Surface`). The `Surface` component always has `"child": "root"` and cannot be modified using `updateComponents`. To render the component tree, one of the components sent to the surface MUST have `"id": "root"`, which mounts as the child of `Surface`.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be rendered. This must be globally unique for the renderer's lifetime.
- `catalogId` (string, optional): A string that uniquely identifies the default catalog (components and functions) used for this surface. Note that `catalogId` is a string identifier, not a resolvable URI; while it is conventionally formatted as a URI (e.g., `https://mycompany.com/1.0/somecatalog`) to avoid naming collisions across organizations, it does not need to point to any deployed resource or downloadable file. Components and function calls on this surface that do not explicitly specify their own `catalogId` will use this surface-level default `catalogId`.
- `sendDataModel` (boolean, optional): If true, the renderer will send the full data model of this surface in the metadata of every message sent to the agent (via the Transport's metadata mechanism). This ensures the surface owner receives the full current state of the UI alongside the user's action or query. Defaults to false.
- `components` (array, optional): A list containing UI components for the surface, allowing the renderer to build and populate the UI tree immediately on surface creation. Conforms to the `ComponentsList` schema.
- `dataModel` (object, optional): A plain JSON object representing the initial root state of the data model.
- `metadata` (object, optional): Surface-level metadata containing an optional `extensions` map (`common_types.json#/$defs/Extensions`).

**Example:**

```json
{
  "version": "v1.0",
  "createSurface": {
    "surfaceId": "user_profile_card",
    "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
    "sendDataModel": true,
    "components": [
      {
        "id": "root",
        "component": "Column",
        "children": ["user_name"]
      },
      {
        "id": "user_name",
        "component": "Text",
        "text": {"@path": "/name"}
      }
    ],
    "dataModel": {
      "name": "John Doe"
    }
  }
}
```

### `updateComponents`

This message provides a flat list of UI components to add or update within a specific surface. Relationships between components are defined by ID references in an adjacency list. The component with `"id": "root"` mounts as the child of the surface's canonical `Surface` container. You cannot modify the `Surface` container itself using `updateComponents`. This message may only be sent to a surface that has already been created. Because components may reference children or data bindings that do not yet exist, renderers should handle missing references gracefully by rendering placeholders (progressive rendering).

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be updated. This must be globally unique for the renderer's lifetime.
- `components` (array, required): A list of component objects. The components are provided as a flat list, and their relationships are defined by ID references in an adjacency list.

**Example:**

```json
{
  "version": "v1.0",
  "updateComponents": {
    "surfaceId": "user_profile_card",
    "components": [
      {
        "id": "root",
        "component": "Column",
        "children": ["user_name", "user_title"]
      },
      {
        "id": "user_name",
        "component": "Text",
        "text": "John Doe"
      },
      {
        "id": "user_title",
        "component": "Text",
        "text": "Software Engineer"
      }
    ]
  }
}
```

### `updateDataModel`

This message is used to send or update the data that populates the UI components. It allows the agent to change the UI's content without resending the entire component structure. The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface this data model update applies to. This must be globally unique for the renderer's lifetime.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, required): The new value for the specified path. To delete the key/value at `path`, set `value` explicitly to `null`.

**Example:**

```json
{
  "version": "v1.0",
  "updateDataModel": {
    "surfaceId": "user_profile_card",
    "path": "/user/name",
    "value": "Jane Doe"
  }
}
```

### `deleteSurface`

This message instructs the renderer to remove a surface and all its associated components and data from the UI.

**Properties:**

- `surfaceId` (string, required): The unique identifier for the UI surface to be deleted. This must be globally unique for the renderer's lifetime.

**Example:**

```json
{
  "version": "v1.0",
  "deleteSurface": {
    "surfaceId": "user_profile_card"
  }
}
```

### `callRendererFunction`

This message is sent by the agent to execute a function registered on the renderer. Functions are catalog-defined abstractions that avoid sending raw executable code across the wire. Only functions which have `allowedCallers: "agentOnly"` or `allowedCallers: "rendererOrAgent"` in their catalog definition can be called by the agent. Renderer functions can only be called after a session has been initiated by the renderer. Functions are resolved by the specified `catalogId`. Upon completing execution of a `callRendererFunction` message, the renderer MUST always send a corresponding `rendererFunctionResponse` message (containing either `value` or `error`) back to the agent, even if the function's return type is `void`.

**Properties:**

- `callRendererFunction` (object, required):
  - `surfaceId` (string, optional): The unique identifier for the UI surface whose data model provides the evaluation context for this call. If omitted, the function executes in a surface-independent root context with an empty data model (`{}`).
  - `functionCallId` (string, required): A unique identifier for this invocation instance. The renderer MUST copy this ID verbatim into the subsequent `rendererFunctionResponse` message.
  - `callFunction` (object, required): The description of the function call.
    - `@call` (string, required): The registered name of the function to execute.
    - `catalogId` (string, required): The catalog ID defining the function to execute. `catalogId` MUST be specified on `callRendererFunction`; if omitted or unregistered, the renderer rejects the call with `code: "INVALID_FUNCTION_CALL"`.
    - `args` (object, optional): Arguments passed to the function, as defined by its schema in the catalog.

**Evaluation Scope and Ordering:**

- **Evaluation Scope**:
  - When `surfaceId` is specified, `callRendererFunction` executes against the root `DataContext` (`'/'`) of that surface's data model, allowing `DataBinding` (`{"@path": "..."}`) expressions inside `args` to read from the surface's data model. If no active surface with `surfaceId` exists, the renderer MUST reject the call and return a `rendererFunctionResponse` with `code: "INVALID_FUNCTION_CALL"`.
  - When `surfaceId` is omitted, `callRendererFunction` executes in a surface-independent root context with an isolated empty data model (`{}`). Renderers MUST NOT resolve it against any existing surface's data model; any `DataBinding` (`{"@path": "..."}`) inside `args` resolves against the empty root model (`null` / `undefined`).
  - In either context, calling `{"@call": "@index"}` outside a list template fails with `code: "EXECUTION_ERROR"`.
- **Envelope Dispatch Ordering**: Message envelopes in a stream or batch are dispatched in arrival order. Synchronous surface mutations (`createSurface`, `updateComponents`, `updateDataModel`, `deleteSurface`) that precede a `callRendererFunction` or `agentFunctionResponse` envelope take effect before that RPC envelope is dispatched, while asynchronous `callRendererFunction` execution completes without blocking subsequent envelopes in the stream.

**Security Boundaries and Verification:**

Execution boundary verification (`"rendererOnly"`, `"agentOnly"`, or `"rendererOrAgent"`) and user activation checks (`requiresUserActivation`) are enforced at runtime by the renderer application:

- When a renderer receives a `callRendererFunction` message, it determines the function's execution boundary (`allowedCallers`) and activation policy (`requiresUserActivation`) at runtime from the active catalog definition.
- If the requested function is configured in the catalog as `"rendererOnly"`, requires an active user gesture (`requiresUserActivation: true`) when none is present, fails argument schema validation, or is not registered at all, the renderer MUST immediately reject the call and return a `rendererFunctionResponse` message containing an `error` object with `code: "INVALID_FUNCTION_CALL"`.
- Note that `catalog_definition.json` requires functions declaring `requiresUserActivation: true` (such as `openUrl`) to set `allowedCallers: "rendererOnly"`, preventing agent-initiated remote invocation. Within the renderer, functions with `requiresUserActivation: true` MUST only execute when triggered by an active user gesture (such as a component `Action`). If referenced in a passive property binding or `CheckRule.condition`, the renderer MUST block execution and report a local evaluation error (`code: "EXPRESSION_ERROR"`).
- Functions marked as `"agentOnly"` or `"rendererOrAgent"` are authorized for agent invocation via `callRendererFunction`. Functions configured as `"agentOnly"` CANNOT be bound to UI component properties or executed by renderer UI actions; they are restricted exclusively to agent-initiated `callRendererFunction` execution.

**Example:**

Agent sends this message to the renderer:

```json
{
  "version": "v1.0",
  "callRendererFunction": {
    "functionCallId": "get_device_resolution_123",
    "callFunction": {
      "@call": "getScreenResolution",
      "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
      "args": {
        "screenIndex": 0
      }
    }
  }
}
```

If the function executes successfully, the renderer responds with a `rendererFunctionResponse`:

```json
{
  "version": "v1.0",
  "rendererFunctionResponse": {
    "functionCallId": "get_device_resolution_123",
    "value": [1920, 1080]
  }
}
```

If the agent attempts to call a `rendererOnly` function (e.g., a local-only component validator), the renderer responds with a `rendererFunctionResponse` containing an `error` payload:

```json
{
  "version": "v1.0",
  "rendererFunctionResponse": {
    "functionCallId": "get_device_resolution_123",
    "error": {
      "code": "INVALID_FUNCTION_CALL",
      "message": "Function 'validateLocalInput' cannot be called by agent (allowedCallers is rendererOnly)."
    }
  }
}
```

### `agentFunctionResponse`

This message is streamed by the agent to return the execution result or error of a renderer-initiated `callAgentFunction` request.

**Properties:**

- `agentFunctionResponse` (object, required):
  - `functionCallId` (string, required): The unique invocation ID matching the initiating `callAgentFunction` call.
  - `value` (any, optional): The returned execution value of the function call.
  - `error` (object, optional): An error object containing `code` (string) and `message` (string) describing execution failure.

The payload MUST include either `value` or `error`.

**Example (Success):**

```json
{
  "version": "v1.0",
  "agentFunctionResponse": {
    "functionCallId": "verify_provider_99",
    "value": {
      "valid": true,
      "name": "Acme Provider"
    }
  }
}
```

**Example (Failure):**

```json
{
  "version": "v1.0",
  "agentFunctionResponse": {
    "functionCallId": "verify_provider_99",
    "error": {
      "code": "PROVIDER_NOT_FOUND",
      "message": "Provider ID PRV-102 was not found."
    }
  }
}
```

## Transport Interaction Patterns

A2UI messages can be transported over both request-response channels (such as HTTP POST or polling) and bidirectional streaming channels (such as WebSockets, gRPC, or Server-Sent Events).

### 1. Request-Response Transport (e.g. HTTP POST)

In request-response environments, the agent cannot initiate an unprompted connection to the client. Agent-initiated function calls (`callRendererFunction`) and renderer-initiated calls (`callAgentFunction`) operate within the request-response cycle:

#### Agent-to-Renderer Function Call over HTTP

```mermaid
sequenceDiagram
    autonumber
    participant Client as Renderer (Client)
    participant Agent as Agent (Server)

    Client->>Agent: HTTP POST (Action / Event)
    Agent-->>Client: 200 OK (callRendererFunction)
    Client->>Agent: HTTP POST (rendererFunctionResponse)
    Agent-->>Client: 200 OK (updateComponents)
```

1. **Initiation:** The renderer sends a standard HTTP POST request (e.g., dispatching an event action or polling).
2. **Server Response:** The agent returns a `callRendererFunction` payload in the HTTP response.
3. **Execution & Delivery:** The renderer executes the function locally, then initiates a follow-up HTTP POST request delivering the `rendererFunctionResponse`.
4. **Completion:** The agent processes `rendererFunctionResponse` and returns updated UI components (`updateComponents`).

---

### 2. Bidirectional Streaming Transport (e.g. WebSockets / gRPC)

In streaming environments, either party can send protocol messages asynchronously over the active downstream/upstream connection:

#### Agent-to-Renderer Function Call over Stream

```mermaid
sequenceDiagram
    autonumber
    participant Client as Renderer (Client)
    participant Agent as Agent (Server)

    Agent->>Client: Stream Message (callRendererFunction)
    Client->>Agent: Stream Message (rendererFunctionResponse)
    Agent->>Client: Stream Message (updateComponents)
```

#### Renderer-to-Agent Function Call over Stream

```mermaid
sequenceDiagram
    autonumber
    participant Client as Renderer (Client)
    participant Agent as Agent (Server)

    Client->>Agent: Stream Message (callAgentFunction)
    Agent->>Client: Stream Message (agentFunctionResponse)
```

1. **Asynchronous Dispatch:** Messages flow over the established stream without requiring HTTP request-response wrapping.
2. **Correlation:** Every function call includes a `functionCallId` which is copied verbatim into the returning `rendererFunctionResponse` or `agentFunctionResponse` (`FunctionResponse` payload) message to correlate requests and responses asynchronously.

## Example Stream

The following example demonstrates a complete interaction to render a Contact Form, expressed as a JSONL stream.

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Component model

A2UI's component model is designed for flexibility, separating the protocol's structure from the set of available UI components.

### The component object

Each object in the `components` array of an `updateComponents` message defines a single UI component. It has the following structure:

- `id` (`ComponentId`, required): A unique string that identifies this specific component instance. This is used for parent-child references.
- `component` (string, required): Specifies the component's type (e.g., `"Text"`).
- `catalogId` (string, optional): A string that uniquely identifies the catalog for this component, overriding the surface's default `catalogId`. Useful when combining components from multiple catalogs in a single surface.
- **Component Properties**: Other properties relevant to the specific component type (e.g., `text`, `url`, `children`) are included directly in the component object.

This structure is designed to be both flexible and strictly validated.

#### Mixable catalogs and component resolution logic

Renderers can support components and functions from multiple catalogs simultaneously within a single surface (mixable catalogs). When a renderer advertises `supportedCatalogIds` in its capabilities, components from any of those catalogs can be combined in the same UI tree. The set of available catalogs for a surface includes both `supportedCatalogIds` and the `catalogId` of any inline catalog declared in `inlineCatalogs` (when supported by the agent). All catalog IDs specified at the component and function-call levels and at the surface-level must refer to catalogs which use the same A2UI specification version.

When resolving a component (or function call), the renderer evaluates catalog identity using the following strict resolution order:

1. **Explicit Component/Function-Level `catalogId`**: The renderer checks if the component or function call explicitly specifies a `catalogId`. If provided, the component or function is resolved against that catalog.
2. **Surface Default `catalogId`**: If the component or function call does not specify a `catalogId`, the renderer checks if a default `catalogId` was specified on the surface in the `createSurface` message. If provided, the component or function is resolved against that surface default catalog.
3. **Resolution Error**: If neither an explicit component/function-level `catalogId` nor a surface default `catalogId` is present, resolution fails immediately with an error and the component is not rendered (or the function call is rejected).

> [!IMPORTANT]
> There is **no fallback** to the list of catalogs declared in `rendererCapabilities` (even if the renderer only advertises a single supported catalog). Every component and function call must resolve through either its explicit `catalogId` or the surface default `catalogId`.

### Catalog-Agnostic Accessibility Requirements

Because JSON Schema cannot inspect arbitrary catalog component property semantics to infer which properties represent visible text labels or which components accept user interaction, accessibility rules are enforced through normative specification requirements and SDK tooling:

**Catalog and renderer implementations MUST:**

- **Plumb Accessibility Attributes**: Map all relevant A2UI `AccessibilityAttributes` (`label`, `description`, `live`, `hidden`) to the underlying UI framework's accessibility APIs (e.g., WAI-ARIA `aria-label`, `aria-describedby`, `aria-live`, and `aria-hidden` for web renderers; `Semantics` properties for Flutter; `AccessibilityNodeInfo` / `accessibilityLabel` for Android and iOS renderers).
- **Infer Default Semantics**: Use component types and non-accessibility properties (such as visible titles or text labels) to configure accessibility defaults automatically. When explicit `AccessibilityAttributes` (e.g., `label` or `description`) are provided, they MUST override inferred visual defaults. For example, a button component with a title of `"Submit"` and an explicit `accessibility.label` of `"Send Form"` must be announced by assistive technologies as `"Send Form"`.
- **SDK Linter Checks**: SDK tooling and catalog linters MUST verify that component schemas accepting actions or input bindings declare accessible label requirements or fallbacks.

### The component catalog

The set of available UI components and functions is defined in a **Catalog**. The basic catalog is defined in [`catalogs/basic/catalog.json`]. While the Basic Catalog is useful for starting out, most production applications will define their own catalog to reflect their specific design system. The agent must generate messages that conform to the catalog understood by the renderer.

#### Catalog structure

Every catalog follows the standard `Catalog` object definition:

- **catalogId** (string, required): A unique string identifier for this catalog. While conventionally formatted as a URI to avoid naming collisions across organizations, it is an arbitrary string ID and not a resolvable URI. Because A2UI catalogs are represented as JSON Schema documents, catalog definitions should include both `$id` (used by JSON Schema tooling) and `catalogId` (used by A2UI SDKs and catalog negotiation), setting both fields to the same URI. Renderer and agent developers must agree on shared catalogs with well-known IDs in order to build systems that are compatible with each other.
- **instructions** (string, optional): Markdown-formatted design principles, rules, or developer guidelines specific to this catalog. These rules guide LLMs when generating UI layouts under this catalog.
- **components** (object, optional): A map of supported UI components, where each key is the component type (e.g., `Text`) and its value is its JSON Schema definition. All keys MUST conform to the UAX #31 entity naming rules defined below.
- **functions** (object, optional): A map of renderer-side validation or utility functions supported by the catalog, where each key is the function name and its value is its definition. All function names MUST conform to the UAX #31 entity naming rules defined below. The renderer determines a function's execution boundary (e.g., rendererOnly status) at runtime by reading its configuration from the active catalog definition.

#### Catalog Entity Naming Rules

To ensure complete cross-language compatibility across renderer SDKs, parsers, and code generators, all catalog entity identifiers—specifically **component names**, **function names**, and **argument/property names**—MUST adhere strictly to [Unicode Standard Annex #31 (UAX #31)](https://www.unicode.org/reports/tr31/) variable naming rules.

1. **Permitted Characters**: Identifiers must begin with a character in the Unicode property class `XID_Start` or an underscore (`_`, `U+005F`). Subsequent characters must belong to the Unicode property class `XID_Continue`.
2. **Prohibited Initial Characters**: Identifiers MUST NOT begin with a decimal digit (Unicode general category `Nd`).
3. **Prohibited Symbols and Whitespace**: Identifiers MUST NOT contain any whitespace or symbols matching the Unicode character property classes `Pattern_Syntax` or `Pattern_White_Space`, other than underscores.
4. **Reserved Component Names**: The protocol reserves the component type name `"Surface"` for the canonical surface container created by `createSurface`. Catalogs MUST NOT define a standard UI component named `"Surface"`.

##### Canonical Regular Expression

```regex
^[\p{XID_Start}_][\p{XID_Continue}]*$
```

##### Examples

- **Valid**: `UserProfileCard`, `submit_form`, `item_id_1`, `_internal_state`
- **Invalid**:
  - `User Card` (violates `Pattern_White_Space`)
  - `1stItem` (violates initial `Nd`)
  - `submit-form`, `user#name`, `calc$val` (violates `Pattern_Syntax`)

#### Catalog Schema Rules and Conventions

To ensure catalog schemas can be translated reliably into alternative, LLM-friendly DSL formats (e.g., HTML-like XML, functional, or compact inline formats), cleanly mapped to type-safe renderer SDK representations, automatically parsed, and bound seamlessly across platforms, all v1.0 component and function catalog definitions MUST conform to the following strict structural constraints and conventions:

1. **Strict Top-Level vs. `$defs` Boundary:**
   - **Top-Level components and functions:** All component and function schemas MUST be declared directly under the top-level keys `"components"` and `"functions"` respectively.
   - **External References inside `$defs`:** Any definition referenced externally (e.g., from the envelope schema `agent_to_renderer.json` or `common_types.json`) MUST reside inside the `"$defs"` object at the catalog root. This strictly includes:
     - `anyComponent`: Referenced as `catalog.json#/$defs/anyComponent`.
     - `anyFunction`: Referenced as `catalog.json#/$defs/anyFunction`.
2. **No Custom `$defs` or Helpers:**
   - To prevent unconstrained branching, custom definitions or shared helper schemas inside a catalog are strictly prohibited under `"$defs"`.
   - The only allowed keys within the catalog's `"$defs"` object are `anyComponent` and `anyFunction`.
   - All helper properties (such as common properties factored out of catalog items) MUST be inlined directly inside the properties block of each supporting component schema rather than referenced from a shared helper.
3. **Restricted `$ref` Targets:**
   - Local `$ref` targets are restricted to referencing the catalog's top-level components or functions (e.g., `#/components/Text`, `#/functions/required`).
   - External `$ref` targets, other than references to peer catalogs (below), MUST reference the standard types inside `common_types.json` using the relative target format (`common_types.json#/$defs/...`). Allowed `$ref` targets are limited to the following schemas:
     - `ComponentId`
     - `Child`
     - `ChildList`
     - `DynamicString`
     - `DynamicNumber`
     - `DynamicBoolean`
     - `DynamicStringList`
     - `DynamicValue`
     - `AccessibilityAttributes`
     - `CheckRule`
     - `Checkable`
     - `Action`
     - `DataBinding`
     - `FunctionCall`
   - External `$ref` targets MAY also reference a **peer catalog**, as described in [Cross-Catalog References](#cross-catalog-references). These are the only other external targets allowed.

   > [!NOTE]
   > **Catalog Evolution and Protocol Compatibility**
   > While there are breaking changes to the catalog API between v0.9 and v1.0, v1.0 catalog definitions reference standard types using relative paths (`common_types.json#/$defs/<TypeName>`). This design allows v1.0 catalogs to potentially work against future protocol versions without requiring changes to catalog type paths.

4. **Component Discriminator Rule:**
   - Every component schema defined inside the `components` map must have a required property named `component` whose value is a constant (`const`) matching the key under which it is defined.
   - Example: The component defined at `components.Text` must declare:
     ```json
     "properties": {
       "component": {
         "const": "Text"
       }
     }
     ```
     This enables route-dispatch matching via the `discriminator` block inside `anyComponent` (designating `"propertyName": "component"`).
5. **Standard Component Structure:**
   - Catalog components define their discriminator (`component: { const: "<Name>" }`) and local properties (e.g., its children, variant, specific layouts), and can optionally import common property sets (such as `Checkable`) via `$ref`.
   - Base component envelope properties (`id`, `catalogId`, and `accessibility` via `ComponentCommon`) are composed at the envelope level in `agent_to_renderer.json` via `allOf` inside the `Component` definition (referenced by `ComponentsList`), and therefore MUST NOT be redundantly wrapped with `ComponentCommon` via `allOf` inside individual catalog component definitions.
6. **Strict Function Interface Pattern:**
   - Every function schema defined inside the `functions` map must validate a wire-level `FunctionCall` object. This requires:
     - A `properties` block with a `@call` property containing a constant of the function's name (e.g., `"@call": { "const": "email" }`).
     - An optional `args` property representing arguments (or absent if the function accepts no arguments).
     - Mandatory metadata fields outside the strict JSON validation properties to advertise interface details:
       - **`returnType`**: Must be a string enum indicating the return type (`string`, `number`, `boolean`, `array`, `object`, `validationResult`, `any`, or `void`).
       - **`allowedCallers`**: Must be a string enum indicating the authorized callers (`rendererOnly`, `agentOnly`, or `rendererOrAgent`). If omitted, it defaults to `rendererOnly`.
   - Base function envelope properties (`@call` and `catalogId` via `FunctionCommon`) are composed at the envelope level in `FunctionCall` (`common_types.json#/$defs/FunctionCall`) via `allOf`, and therefore MUST NOT be redundantly wrapped with `FunctionCommon` via `allOf` inside individual catalog function definitions.
7. **Strict Top-Level Schema Keys:**
   - To keep catalog schemas predictable and prevent custom extensions from polluting the global file space, a `catalog.json` file is restricted to the following root-level keys:
     - `$schema`
     - `$id`
     - `protocolVersion` (optional for backward compatibility; defaults to `"0.9"` if omitted, required for catalogs targeting `1.0` and beyond)
     - `title`
     - `description`
     - `catalogId`
     - `instructions`
     - `components`
     - `functions`
     - `$defs`
   - No other top-level keys are permitted.

8. **Deprecation Annotations:**
   - Components, functions, and individual properties may declare `deprecated: true` along with an optional human-readable `x-deprecated-reason` (string).

##### Example Schema Template

Below is an annotated, fully compliant `catalog.json` schema template (written in JSONC format with comments) representing a visual, complete model of these rules in action:

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### Cross-Catalog References

A catalog MAY reuse definitions from another catalog, its **peer**, through an external `$ref`. For example, a custom catalog can inherit the basic catalog's `Text` and add a property, or reuse the `action` property of another catalog's `Button`. Cross-catalog references are still local: the peer MUST be a catalog that the agent or renderer already holds, because it is registered with the agent or renderer or supplied together with the referencing catalog. An implementation MUST NOT fetch or download a peer catalog over the network to resolve a reference.

A cross-catalog `$ref` has the form `<peer document>#<pointer>`, and the pointer MUST address one of the peer's top-level components or functions, or a subschema inside one:

- `<peer document>#/components/<Name>` inherits a whole component, usually as an `allOf` entry. The peer's `component` discriminator, `id` envelope and closure keywords (`unevaluatedProperties`, `additionalProperties`) are not inherited; the referencing component declares its own discriminator.
- `<peer document>#/components/<Name>/properties/<property>` reuses the schema of one property.
- `<peer document>#/functions/<Name>` and pointers into a function, such as `#/functions/<Name>/properties/args/properties/<arg>`, do the same for functions.

`<peer document>` names the peer by its `catalogId` or `$id`, or by a path or file name that ends one of them. Implementations MUST resolve it against the peer catalogs they hold in this order, and the first catalog that matches wins:

1. A document named `common_types.json`, or a path ending in `/common_types.json`, refers to the protocol's common types and never to a peer.
2. A document named exactly `catalog.json` refers to the referencing catalog itself, as in the envelope schemas.
3. **Exact or path-suffix match:** a peer whose `catalogId` or `$id` equals the document, ends with `/` followed by the document, or is itself a path suffix of the document (the document ends with `/` followed by it).
4. A path ending in `/catalog.json` that no peer matches in step 3 refers to the referencing catalog itself.
5. **File name match:** a peer whose `$id` or `catalogId` has the same last path segment as the document.

Only a document named exactly `catalog.json` is generic. A file whose name merely ends in `catalog.json`, such as `mcp_catalog.json`, is matched like any other name, and a full URI such as `https://a2ui.org/specification/v1_0/catalogs/mcp/catalog.json` resolves to the peer with that `$id` before it is treated as the referencing catalog. When several peers match in the same step, the one listed or registered first wins; catalog authors SHOULD write references that match exactly one peer, for example by using the peer's full `$id`.

Inside the inherited content, the peer's own local references (`#/...`) resolve against the peer document, and its cross-catalog references resolve against the same set of peers. A catalog with a cross-catalog `$ref` that resolves to no peer the implementation holds is a catalog error. Implementations MUST NOT silently ignore such a reference or treat it as accepting any value; they report the error when the catalog is loaded or linked, or at the latest when a payload is validated against the affected component or function. The referencing catalog's own references MUST keep using local pointers (`#/components/...`) or `catalog.json`.

Catalog documents keep cross-catalog references as authored, for example in prompts and in `inlineCatalogs`. A renderer or agent that receives such a catalog MUST already hold its peers, or bundle them before validating.

#### Deprecating Catalog Properties

- **`deprecated`** (boolean, optional): Standard JSON Schema annotation indicating that a component, function, or property is deprecated.
- **`x-deprecated-reason`** (string, optional): Human-readable explanation of why the entity is deprecated and what to use instead.

### UI composition: the adjacency list model

The A2UI protocol defines the UI as a flat list of components. The tree structure is built implicitly using ID references. This is known as an adjacency list model.

Container components (like `Row`, `Column`, `List`, and `Card`) have properties that reference the `id` of their child component(s). The renderer is responsible for storing all components in a map (e.g., `Map<String, Component>`) and recreating the tree structure at render time.

This model allows the agent to send component definitions in any order. Rendering can begin as soon as the `root` component is defined, with the renderer filling in or updating the rest of the tree progressively as additional definitions arrive.

There must be exactly one component with the ID `root` in the component tree, acting as the root of the component tree. Until that component is defined, other component updates will have no visible effect, and they will be buffered until a root component is defined. Once a root component is defined, the renderer is responsible for rendering the tree in the best way possible based on the available data, skipping invalid references.

```mermaid
flowchart TD
    subgraph "Agent Stream"
        A("<b>updateComponents</b><br>components: [root, title, button]")
    end

    subgraph "Renderer-Side Buffer (Map)"
        C("root: {id: 'root', component: 'Column', children: ['title', 'button']}")
        D("title: {id: 'title', component: 'Text', text: 'Welcome'}")
        E("button: {id: 'button', component: 'Button', child: 'button_label'}")
    end

    subgraph "Rendered Widget Tree"
        F(Column) --> G(Text: 'Welcome')
        F --> H(Button)
    end

    A -- "Parsed and stored" --> C
    A -- "Parsed and stored" --> D
    A -- "Parsed and stored" --> E

```

#### Composition validation rules

To validate component nesting hierarchies, A2UI component catalogs support composition constraints via `allowedParents` and `allowedChildren`. You define these constraints on component type definitions in the catalog JSON Schema, and the renderer evaluates them against the component tree at runtime.

1. **Composition Constraints**:
   - `allowedParents` (array of strings, optional): The list of parent component type names that can contain this component type. If omitted, all parent component types are allowed.
   - `allowedChildren` (array of strings, optional): The list of child component type names allowed inside this container or slot. If omitted, all child component types are allowed.
2. **`"Surface"` Container Component**:
   - The protocol reserves the component type name `"Surface"` for the canonical surface container.
   - The `createSurface` message implicitly creates this container (`common_types.json#/$defs/Surface`) with `"child": "root"`. You cannot modify `Surface` using `updateComponents`.
   - Parent-child validation applies uniformly across the entire component tree, with `Surface` acting as the top-level container parent.
3. **Catalog Schema Examples**:
   - **Top-Level Component**: To restrict a component so it can appear only as the top-level component (`"id": "root"`) of a surface:
     ```json
     {
       "AppLayout": {
         "type": "object",
         "allowedParents": ["Surface"],
         "properties": {
           "component": {"const": "AppLayout"}
         }
       }
     }
     ```
   - **Top-Level or Container Union**: To allow a component as either the top-level component (`"id": "root"`) of a surface or a child of a specific container:
     ```json
     {
       "Card": {
         "type": "object",
         "allowedParents": ["Surface", "CanvasContainer"]
       }
     }
     ```
   - **Container-Restricted Components**: To restrict a child component so it can appear only within a specific parent container:
     ```json
     {
       "Menu": {
         "type": "object",
         "allowedChildren": ["MenuItem"]
       },
       "MenuItem": {
         "type": "object",
         "allowedParents": ["Menu"]
       }
     }
     ```
4. **Validation Error Codes**:
   - If a component is placed under an unallowed parent, the renderer emits a validation error message with `code` set to `"UNALLOWED_PARENT"`.
   - If an unallowed child component is placed inside a container, the renderer emits a validation error message with `code` set to `"UNALLOWED_CHILD"`.

### Defining actions

Interactive components (like `Button`) use an `action` property to define what happens when the user interacts with them. Actions can either trigger an event sent to the agent or execute a local renderer-side function.

#### Agent actions

To send an event to the agent, use the `event` property within the `action` object. It requires a `name` and supports an optional `userMessage` (`DynamicString`, resolved by the renderer into a human-readable string in the outbound `action` message) and an optional `context` object containing key-value parameters to dispatch to the agent.

```json
{
  "id": "submit_button",
  "component": "Button",
  "child": "submit_button_label",
  "action": {
    "event": {
      "name": "submit_form",
      "userMessage": "Submitted order #123",
      "context": {
        "itemId": "123"
      }
    }
  }
}
```

#### Local actions

To execute a local function, use the `functionCall` property within the `action` object. This property references a standard `FunctionCall` object. Functions declared with `requiresUserActivation: true` in their catalog definition (such as `openUrl`) MUST only execute when triggered by an active user gesture (e.g., inside an `action` handler); referencing them in a passive property binding or validation `CheckRule.condition` is blocked by the renderer (`code: "EXPRESSION_ERROR"`).

```json
{
  "id": "open_link_button",
  "component": "Button",
  "child": "open_link_button_label",
  "action": {
    "functionCall": {
      "@call": "openUrl",
      "args": {
        "url": {"@path": "/url"}
      }
    }
  }
}
```

## Data model representation: binding, scope

This section describes how UI components **represent** and reference data from the Data Model. A2UI relies on a strictly defined relationship between the UI structure (Components) and the state (Data Model), defining the mechanics of path resolution, variable scope during iteration.

### Path resolution & scope

Data bindings in A2UI are defined using **JSON Pointers** ([RFC 6901]). How a pointer is resolved depends on the current **Evaluation Scope**.

> **Note on progressive rendering:** During the initial streaming phase, data paths may resolve to `undefined` if the `updateDataModel` message containing that data has not yet arrived. Renderers should handle `undefined` values gracefully (e.g., by treating them as empty strings or showing a loading indicator) to support progressive rendering.

#### The root scope

By default, all components operate in the **Root Scope**.

- Paths starting with `/` (e.g., `/user/profile/name`) are **Absolute Paths**. They always resolve from the root of the Data Model, regardless of where the component is nested in the UI tree.

#### Collection scopes (relative paths)

When a container component (such as `Column`, `Row`, or `List`) utilizes the **Template** feature of `ChildList`, it creates a new **Child Scope** for each item in the bound array.

- **Template definition:** When a container binds its children to a path (e.g., `path: "/users"`), the renderer iterates over the array found at that location.
- **Scope instantiation:** For every item in the array, the renderer instantiates the template component.
- **Relative resolution:** Inside these instantiated components, any path that **does not** start with a forward slash `/` is treated as a **Relative Path**.
  - A relative path `firstName` inside a template iterating over `/users` resolves to `/users/0/firstName` for the first item, `/users/1/firstName` for the second, etc.

- **Mixing scopes:** Components inside a Child Scope can still access the Root Scope by using an Absolute Path.

#### Example: scope resolution

**Data model:**

```json
{
  "company": "Acme Corp",
  "employees": [
    {"name": "Alice", "role": "Engineer"},
    {"name": "Bob", "role": "Designer"}
  ]
}
```

**Component definition:**

```json
{
  "id": "employee_list",
  "component": "List",
  "children": {
    "path": "/employees",
    "componentId": "employee_card_template"
  }
},
{
  "id": "employee_card_template",
  "component": "Column",
  "children": ["name_text", "company_text"]
},
{
  "id": "name_text",
  "component": "Text",
  "text": { "@path": "name" }
  // "name" is Relative. Resolves to /employees/N/name
},
{
  "id": "company_text",
  "component": "Text",
  "text": { "@path": "/company" }
  // "/company" is Absolute. Resolves to "Acme Corp" globally.
}
```

#### Type conversion

When a non-string value is interpolated, the renderer converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **null/undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different renderer implementations.

### Two-way binding & input components

Interactive components that accept user input (`TextField`, `CheckBox`, `Slider`, `ChoicePicker`, `DateTimeInput`) establish a **Two-Way Binding** with the Data Model.

#### The read/write contract

Unlike static display components (like `Text`), input components modify the renderer-side data model immediately upon user interaction.

1.  **Read (Model -> View):** When the component renders, it reads its value from the bound `path`. If the Data Model is updated via `updateDataModel`, the component re-renders to reflect the new value.
2.  **Write (View -> Model):** When the user interacts with the component (e.g., types a character, toggles a box), the renderer **immediately** updates the value at the bound `path` in the local Data Model.

#### Reactivity

Because the local Data Model is the single source of truth, updates from input components are **reactive**.

- If a `TextField` is bound to `/user/name`, and a separate `Text` label is also bound to `/user/name`, the label must update in real-time as the user types in the text field.

#### Agent synchronization

It is critical to note that Two-Way Binding is **local to the renderer**.

- User inputs (keystrokes, toggles) do **not** automatically trigger network requests to the agent.
- The updated state is sent to the agent only when a specific **User Action** is triggered (e.g., a `Button` click).
- When an `action` is dispatched, the `context` property of the action can reference the modified data paths to send the user's input back to the agent.

#### Example: form submission pattern

1.  **Bind:** `TextField` is bound to `/formData/email`.
2.  **Interact:** User types "jane@example.com". The local model at `/formData/email` is updated.
3.  **Action:** A "Submit" button has the following action definition:

    ```json
    "action": {
      "event": {
        "name": "submit_form",
        "context": {
          "email": { "@path": "/formData/email" }
        }
      }
    }
    ```

4.  **Send:** When clicked, the renderer resolves `/formData/email` (getting "jane@example.com") and sends it in the `action` payload.

## Data model updates: synchronization and convergence

While the sections above describe how components reference data, this section defines how the Data Model itself is **updated** and synchronized.

To support reliable data synchronization between the Renderer and the Agent that created the surface, the A2UI protocol uses a simple synchronization mechanism controlled by the `sendDataModel` property in the `createSurface` message.

### Agent to renderer updates

The agent sends `updateDataModel` messages to modify the renderer's data model. These updates follow strict upsert semantics:

- If the path exists, the value is updated.
- If the path does not exist, the value is created.
- If the value is `null`, the key at that path is removed.

The `updateDataModel` message replaces the value at the specified `path` with the new content. If `path` is omitted (or is `/`), the entire data model for the surface is replaced.

**Properties:**

- `surfaceId` (string, required): The ID of the surface to update.
- `path` (string, optional): A JSON Pointer to the location in the data model to update. Defaults to `/`.
- `value` (any, required): The new value for the specified path. To delete the key/value at `path`, set `value` explicitly to `null`.

**Examples:**

_Update a specific field:_

```json
{
  "version": "v1.0",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/firstName",
    "value": "Alice"
  }
}
```

_Remove a field:_

```json
{
  "version": "v1.0",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "path": "/user/tempData",
    "value": null
  }
}
```

_Replace the entire data model:_

```json
{
  "version": "v1.0",
  "updateDataModel": {
    "surfaceId": "surface_123",
    "value": {
      "user": {"firstName": "Alice", "lastName": "Smith"},
      "preferences": {"theme": "dark"}
    }
  }
}
```

### Renderer to agent updates

When `sendDataModel` is set to `true` for a surface, the renderer automatically appends the **entire data model** of that surface to the metadata of every message (such as `action` or user query) sent to the agent that created the surface. The data model is included using the transport's metadata facility (the exact location and format are defined by the specific transport binding). The payload follows the schema in [`renderer_data_model.json`](../json/renderer_data_model.json).

- **Targeted Delivery**: The data model is sent exclusively to the agent that created the surface. Data cannot leak to other agents.
- **Trigger:** Data is sent only when a renderer-to-agent message is triggered (e.g., by a user action like a button click). Passive data changes (like typing in a text field) do not trigger a network request on their own; they simply update the local state, which will be sent with the next action.
- **Payload:** The data model is included in the transport metadata, tagged by its `surfaceId`.
- **Convergence:** The agent treats the received data model as the current state of the renderer at the time of the action.

## Renderer-side logic & validation

A2UI v1.0 generalizes renderer-side logic into **Functions**. These can be used for validation, data transformation, and dynamic property binding.

### Registered functions

The renderer supports a set of named **Functions** (e.g., `required`, `regex`, `email`, `add`, `concat`) which are defined in the JSON schema (e.g. `catalogs/basic/catalog.json`) alongside the component definitions. The agent references these functions by name in `FunctionCall` objects. This avoids sending executable code.

### Component Validation & Check Rules

Input components (like `TextField`, `ChoicePicker`) and interactive elements (like `Button`) can define a list of `checks` (`CheckRule` objects).

A `CheckRule` contains a `condition` (a `DataBinding` path or a `FunctionCall`) and an optional fallback `message` string. The `condition` evaluates to either a `ValidationResult` object (defined in [`catalog_definition.json#/$defs/ValidationResult`](../json/catalog_definition.json)) or a primitive `boolean`.

#### `ValidationResult` Structure

Validation functions (declared with `"returnType": "validationResult"`) or data model bindings evaluate directly to a `ValidationResult` object:

- **`valid`** (`boolean`, required): Whether the check passed.
- **`code`** (`string`, optional): Machine-readable error code (e.g., `EXPIRED_CARD`, `OUT_OF_RANGE`).
- **`message`** (`string`, optional): Human-readable error or warning message to display.
- **`severity`** (`"error" | "warning" | "info"`, optional, default `"error"`).

Because `ValidationResult` permits additional unconstrained properties, validation functions and specialized components can extend the object with custom domain-specific metadata (such as suggested fix values, field paths, or retry parameters).

#### `DynamicBoolean` and `CheckRule` Coercion

To allow validation functions (`required`, `email`, `regex`, `length`, `numeric`, which return `ValidationResult`) to compose with boolean properties and functions accepting `DynamicBoolean` arguments (such as `and`, `or`, and `not`, which return `boolean`), renderers apply two coercion rules:

1. **`ValidationResult` → `boolean` in `DynamicBoolean`**:
   - Schema validation of a `DynamicBoolean` occurs on the written wire payload (which accepts a literal `boolean`, any `DataBinding`, or any `FunctionCall`) before nested expressions are evaluated.
   - At runtime, whenever a `DynamicBoolean` (such as an argument to `and`, `or`, `not`, or a boolean component property) evaluates to a `ValidationResult` object (an object with a boolean `valid` property), the renderer extracts `result.valid` as its boolean value.
   - Functions with `DynamicBoolean` arguments (including `and`, `or`, and `not`) therefore receive and return plain booleans. When a boolean combinator is used as a `CheckRule.condition`, the enclosing `CheckRule.message` provides the user-facing error message when the combinator returns `false`.
2. **`boolean` → `ValidationResult` in `CheckRule.condition`**:
   - When a `CheckRule.condition` evaluates to `true`, the renderer coerces it to `{"valid": true}`.
   - When a `CheckRule.condition` evaluates to `false`, the renderer coerces it to `{"valid": false, "message": <CheckRule.message>, "severity": "error"}`.
   - When a `CheckRule.condition` evaluates to a `ValidationResult` with `valid: false`, `CheckRule.message` is used as a fallback if `ValidationResult.message` is omitted, and `severity` defaults to `"error"` if omitted.

_Example Component Definition:_

```json
"checks": [
  {
    "condition": {
      "@call": "validateCreditCard",
      "args": {
        "cardNumber": { "@path": "/payment/cardNumber" }
      }
    }
  }
]
```

_Example Dynamic `ValidationResult` Returned by `validateCreditCard`:_

```json
{
  "valid": false,
  "code": "EXPIRED_CARD",
  "message": "The card expiration date (05/24) has passed.",
  "severity": "error"
}
```

### Example: button validation

Buttons can also define `checks`. If any check fails, the button is automatically disabled. This allows the button's state to depend on the validity of data in the model.

```json
{
  "id": "submit_button",
  "component": "Button",
  "child": "submit_button_label",
  "action": {
    "event": {
      "name": "submit_form"
    }
  },
  "checks": [
    {
      "condition": {
        "@call": "and",
        "args": {
          "values": [
            {
              "@call": "required",
              "args": {"value": {"@path": "/formData/terms"}}
            },
            {
              "@call": "or",
              "args": {
                "values": [
                  {
                    "@call": "required",
                    "args": {"value": {"@path": "/formData/email"}}
                  },
                  {
                    "@call": "required",
                    "args": {"value": {"@path": "/formData/phone"}}
                  }
                ]
              }
            }
          ]
        }
      },
      "message": "You must accept terms AND provide either email or phone"
    }
  ]
}
```

## Basic Component Catalog

The [`catalogs/basic/catalog.json`] provides the baseline set of components and functions.

### Components

| Component         | Description                                                                                 |
| :---------------- | :------------------------------------------------------------------------------------------ |
| **Text**          | Displays text. Supports simple Markdown.                                                    |
| **Image**         | Displays an image from a URL.                                                               |
| **Icon**          | Displays a system-provided icon from a predefined list.                                     |
| **Video**         | Displays a video from a URL.                                                                |
| **AudioPlayer**   | A player for audio content from a URL.                                                      |
| **Row**           | A horizontal layout container.                                                              |
| **Column**        | A vertical layout container.                                                                |
| **List**          | A scrollable list of components.                                                            |
| **Card**          | A container with card-like styling.                                                         |
| **Tabs**          | A set of tabs, each with a title and child component.                                       |
| **Divider**       | A horizontal or vertical dividing line.                                                     |
| **Modal**         | A dialog that appears over the main content triggered by a button in the main content.      |
| **Button**        | A clickable button that dispatches an action. Supports 'primary' and 'borderless' variants. |
| **CheckBox**      | A checkbox with a label and a boolean value.                                                |
| **TextField**     | A field for user text input.                                                                |
| **DateTimeInput** | An input for date and/or time.                                                              |
| **ChoicePicker**  | A component for selecting one or more options.                                              |
| **Slider**        | A slider for selecting a numeric value within a range.                                      |

### Functions

> **Reserved Protocol Directives (`@` Prefix)**: The `@` prefix is strictly reserved for protocol-level directives and system context functions:
>
> - **`@path`**: Represents a dynamic data binding to a path in the data model (e.g. `{"@path": "/user/name"}`).
> - **`@call`**: Represents a catalog or system function invocation (e.g. `{"@call": "formatString", "args": {...}}`).
> - **`@index`**: Represents the universal system context function returning the 0-based iteration index during list template rendering (`{"@call": "@index"}`). Custom catalogs MUST NOT define functions prefixed with `@`.
>
> **Single-`@` Directive Rule**: Any key in a dynamic object matching `^@([^@]|$)` (a leading `@` that is not doubled, including a key consisting of `@` alone) that is not a recognized protocol directive is disallowed and rejected by renderers and validators. This reserves the single-`@` namespace for future protocol extensions without breaking backward compatibility.
>
> **Escaping via Prefix Doubling**: Plain objects that require literal property names starting with `@` must escape them by doubling the prefix: `"@@path"` evaluates to `"@path"`, `"@@type"` evaluates to `"@type"`, etc. Plain objects with `"path"` and `"call"` keys are literal objects and are never intercepted as dynamic bindings.

| Function           | Description                                                              |
| :----------------- | :----------------------------------------------------------------------- |
| **@index**         | Returns the 0-based index of the current item during template rendering. |
| **required**       | Checks that the value is not null, undefined, or empty.                  |
| **regex**          | Checks that the value matches a regular expression string.               |
| **length**         | Checks string length constraints.                                        |
| **numeric**        | Checks numeric range constraints.                                        |
| **email**          | Checks that the value is a valid email address.                          |
| **formatString**   | Does string interpolation of data model values and registered functions. |
| **formatNumber**   | Formats a number with grouping and precision.                            |
| **formatCurrency** | Formats a number as a currency string.                                   |
| **formatDate**     | Formats a date/time using a pattern.                                     |
| **pluralize**      | Selects a localized string based on a numeric count.                     |
| **openUrl**        | Opens a URL in a browser (requires user activation).                     |
| **and**            | Logical AND operation on a list of boolean values or validation results. |
| **or**             | Logical OR operation on a list of boolean values or validation results.  |
| **not**            | Logical NOT operation on a boolean value or validation result.           |

### The `formatString` function

The `formatString` function supports embedding dynamic expressions directly within string properties. This allows for mixing static text with data model values and function results.

#### `formatString` syntax

Interpolated expressions are enclosed in `${...}`. To include a literal `${` in a string, it must be escaped as `\${`.

#### `formatString` data model binding

Values from the data model can be interpolated using their JSON Pointer path.

- `${/user/profile/name}`: Absolute path.
- `${firstName}`: Relative path (resolved against the current collection scope).

**Example:**

```json
{
  "id": "user_welcome",
  "component": "Text",
  "text": {
    "@call": "formatString",
    "args": {
      "value": "Hello, ${/user/firstName}! Welcome back to ${/appName}."
    }
  }
}
```

#### `formatString` renderer-side functions

Results of renderer-side functions can be interpolated. Function calls are identified by the presence of parentheses `()`.

- `${now()}`: A function with no arguments.
- `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`: A function with named arguments.

Arguments can be **Literals** (quoted strings, numbers, or booleans), or **Nested Expressions**.

#### `formatString` nested interpolation

Expressions can be nested using additional `${...}` wrappers inside an outer expression to make bindings explicit or to chain function calls.

- **Explicit Binding**: `${formatDate(value:${/currentDate}, format:'yyyy-MM-dd')}`
- **Nested Functions**: `${upper(${now()})}`

#### `formatString` type conversion

When a non-string value is interpolated, the renderer converts it to a string:

- **Numbers/Booleans**: Standard string representation.
- **Null/Undefined**: An empty string `""`.
- **Objects/Arrays**: Stringified as JSON to ensure consistency across different renderer implementations.

### The `@index` function

The `@index` function returns the 0-based index of the current item when rendering a dynamic list from a template. It is a universal system function available across all catalogs.

#### `@index` scope restriction

The `@index` function MUST ONLY be available when evaluating template items within a list rendering context (Collection Scope). When an expression evaluator encounters `@index()`, it inspects the active Evaluation Context chain starting from the current scope and walking upward. If one or more Collection Scopes are present (such as in nested list templates), `@index` resolves to the **innermost** enclosing template's 0-based iteration index. If called outside of template iteration (e.g., directly in the Root Scope), the renderer MUST treat it as an error or evaluate it as invalid.

#### `@index` arguments

- `offset` (Optional, `number`): An offset added to the 0-based index. For example, `@index(offset: 1)` produces 1-based indexing (`1, 2, 3...`). Defaults to `0`.

#### Example usage

Displaying item positions inside a list row template:

```json
{
  "id": "todo-index",
  "component": "Text",
  "text": {
    "@call": "formatString",
    "args": {
      "value": "#${@index(offset: 1)}"
    }
  }
}
```

## Usage pattern: the prompt-generate-validate loop

The A2UI protocol is designed to be used in a three-step loop with a Large Language Model:

1.  **Prompt**: Construct a prompt for the LLM that includes:
    - The desired UI to be generated.
    - The A2UI JSON schema, including the component catalog.
    - Examples of valid A2UI JSON.

2.  **Generate**: Send the prompt to the LLM and receive the generated JSON output.

3.  **Validate**: Validate the generated JSON against the A2UI schema. If the JSON is valid, it can be sent to the renderer for rendering. If it is invalid, the errors can be reported back to the LLM in a subsequent prompt, allowing it to self-correct.

This loop allows for a high degree of flexibility and robustness, as the system can leverage the generative capabilities of the LLM while still enforcing the structural integrity of the UI protocol.

### Standard validation error format

If validation fails, the renderer (or the system acting on behalf of the renderer) should send an `error` message back to the LLM. To ensure the LLM can understand and correct the error, use the following standard format within the `error` message payload:

- `code` (string, required): Must be `"VALIDATION_FAILED"`, `"UNALLOWED_PARENT"`, or `"UNALLOWED_CHILD"`. Use `"UNALLOWED_PARENT"` if a component is placed under an unallowed parent, and `"UNALLOWED_CHILD"` if an unallowed child is placed inside a container.
- `surfaceId` (string, required): The ID of the surface where the error occurred.
- `path` (string, required): The JSON pointer to the field that failed validation (e.g. `/components/0/text`).
- `message` (string, required): A short one-sentence description of why validation failed.

**Example error message:**

```json
{
  "error": {
    "code": "VALIDATION_FAILED",
    "surfaceId": "user_profile_card",
    "path": "/components/0/text",
    "message": "Expected stringOrPath, got integer"
  }
}
```

## Renderer-to-agent event messages

The protocol defines messages that the renderer can send to the agent to report user interactions, execution results of agent-initiated function calls, or renderer-side runtime errors. Every renderer-to-agent message must validate against the [`renderer_to_agent.json`] schema and contain exactly one of the following top-level keys: `action`, `callAgentFunction`, `rendererFunctionResponse`, or `error`.

### `action`

This message is sent when a user interacts with a component that has an agent action defined (such as a `Button`).

**Properties:**

- `name` (string, required): The name of the action.
- `surfaceId` (string, required): The unique ID of the surface where the event originated.
- `sourceComponentId` (string, required): The ID of the component that triggered the interaction.
- `timestamp` (string, required): An ISO 8601 timestamp representing when the event occurred.
- `userMessage` (string, optional): A human-readable message describing the action performed by the user, resolved from `action.event.userMessage`.
- `context` (object, required): A JSON object containing the key-value pairs of the action's context parameters, after resolving all dynamic data bindings.
- `metadata` (object, optional): Action-level metadata containing an optional `extensions` map (`common_types.json#/$defs/Extensions`).

**Example:**

```json
{
  "version": "v1.0",
  "action": {
    "name": "submitForm",
    "surfaceId": "contact_form_1",
    "sourceComponentId": "submit_button",
    "timestamp": "2026-06-02T08:57:23Z",
    "userMessage": "Submitted contact form",
    "context": {
      "isSubscribed": true
    }
  }
}
```

### `callAgentFunction`

This message is sent by the renderer to execute a function remotely on the agent (e.g. verifying a provider ID or checking inventory availability).

**Function Location Resolution & Fallback Routing:**

When the renderer evaluates a `FunctionCall` (from an action handler, validation check, or dynamic value), it determines the execution target using implicit fallback routing:

1. **Local Lookup:** The renderer checks if a local renderer-side function with that name is registered in its local catalog/registry. If found, the renderer executes the function locally.
2. **Fallback to Agent RPC:** If the function is not registered in the local renderer catalog, the renderer assumes it is an agent-side function and dispatches a `callAgentFunction` message over the protocol.
3. **Agent Error Handling:** If the agent does not recognize the function name (or if parameter validation fails on the server), the agent MUST return an `agentFunctionResponse` message containing an `error` payload (`code: "UNKNOWN_FUNCTION"` or `"INVALID_FUNCTION_CALL"`). The renderer then handles the error state locally (e.g., via component error boundaries or fallbacks).

**Properties:**

- `callAgentFunction` (object, required):
  - `surfaceId` (string, required): The surface ID where the call originated.
  - `functionCallId` (string, required): A unique identifier for this invocation instance. The agent MUST copy this ID verbatim into the return `agentFunctionResponse`.
  - `callFunction` (object, required): The description of the function call (`@call`, `catalogId`, `args`).

**Example:**

```json
{
  "version": "v1.0",
  "callAgentFunction": {
    "surfaceId": "contact_form_1",
    "functionCallId": "verify_provider_99",
    "callFunction": {
      "@call": "verifyProvider",
      "args": {
        "providerId": "PRV-102"
      }
    }
  }
}
```

### `rendererFunctionResponse`

This message is sent by the renderer to return the execution result or error of an agent-initiated `callRendererFunction` request.

**Properties:**

- `rendererFunctionResponse` (object, required):
  - `functionCallId` (string, required): The unique invocation ID matching the initiating `callRendererFunction` call.
  - `value` (any, optional): The returned execution value of the function call.
  - `error` (object, optional): An error object containing `code` (string) and `message` (string) describing execution failure.

The payload MUST include either `value` or `error`.

**Example (Success):**

```json
{
  "version": "v1.0",
  "rendererFunctionResponse": {
    "functionCallId": "get_device_resolution_123",
    "value": [1920, 1080]
  }
}
```

**Example (Failure):**

```json
{
  "version": "v1.0",
  "rendererFunctionResponse": {
    "functionCallId": "get_device_resolution_123",
    "error": {
      "code": "EXECUTION_ERROR",
      "message": "Failed to query screen resolution."
    }
  }
}
```

### `error`

This message is sent by the renderer to report surface-level validation/integrity errors or envelope-level function invocation faults to the agent. (Standard `callRendererFunction` execution and boundary failures are returned via `rendererFunctionResponse.error`, as described above.)

**Properties:**

- `code` (string, required): The machine-readable error code (e.g., `"VALIDATION_FAILED"`, `"INTEGRITY_ERROR"`, `"INVALID_FUNCTION_CALL"`).
- `message` (string, required): A short, human-readable description of the error.
- `surfaceId` (string, optional): The unique ID of the surface where the error occurred. This field is mutually exclusive with `functionCallId`.
- `functionCallId` (string, optional): The unique ID of the function invocation that failed. This field is mutually exclusive with `surfaceId` and is used when reporting function invocation errors outside a `rendererFunctionResponse`.

**Example (Function Invocation Error):**

```json
{
  "version": "v1.0",
  "error": {
    "code": "INVALID_FUNCTION_CALL",
    "message": "Malformed callRendererFunction payload.",
    "functionCallId": "delete_file_call_9"
  }
}
```

## Functions in A2UI Content Execution

In addition to top-level protocol RPC messages (`callRendererFunction` and `callAgentFunction`), functions in A2UI can be embedded directly within UI component trees and content definitions.

### 1. Polymorphic Function Usage in UI Content

`FunctionCall` objects can be used interchangeably across UI content bindings regardless of whether the target function executes locally on the renderer or remotely on the agent:

- **Dynamic Value Bindings:** A `FunctionCall` can compute dynamic property values (e.g. formatting a timestamp or fetching calculated user statistics).
- **Validation Rules (`Checkable`):** Components that support client validation (such as input fields) use `FunctionCall` objects inside check rules to perform validation logic.
- **Action Handlers (`Action`):** Component interaction handlers can execute a `FunctionCall` directly on click or trigger.

The component tree syntax is completely uniform. The renderer evaluates whether to execute the function locally or route a `callAgentFunction` RPC to the agent based on function target resolution rules.

### 2. Asynchronous Evaluation & Pending States

When a UI component binding or validation rule depends on a function that routes remotely to the agent (or executes an asynchronous renderer function):

1. **Async Evaluation:** The renderer dispatches the function call (e.g. emitting `callAgentFunction`) and enters an asynchronous evaluation state.
2. **Pending UI State:** The renderer maintains a pending/loading state for the affected component binding (e.g., displaying a loading indicator or preserving existing component values) while awaiting `agentFunctionResponse`.
3. **Value Resolution:** Upon receiving `agentFunctionResponse`, the renderer updates the local dynamic value or validation state with the returned `value`.

### 3. Failure Propagation & Recovery Rules

If a function call within a content pipeline fails (returns an `agentFunctionResponse` containing an `error` payload, throws a local execution error, times out, or triggers a transport error), the renderer applies the following recovery rules:

- **Dynamic Value Binding Failure:** The property binding resolves to `null` (or a declared fallback value), and the renderer logs an evaluation error without crashing the surrounding component tree.
- **Validation Rule Failure (`Checkable`):** The check rule evaluates as invalid, displaying the rule's specified error message to the user.
- **Action Pipeline Failure:** Halts execution of any subsequent steps in the action execution pipeline and dispatches a local error boundary event or toast notification. Any side effects of previously executed steps are preserved.

---

## Capabilities and metadata

In A2UI v1.0, capabilities and other metadata are exchanged via **transport metadata** or initialization payloads (e.g., A2A metadata, Agent Cards, or MCP initialization) rather than as first-class A2UI messages.

### Agent capabilities

An agent advertises its capabilities using the [`agent_capabilities.json`] schema. This indicates which catalogs it can generate UI for, and whether it accepts inline catalogs from the renderer. The exact mechanism depends on the transport (e.g., the `params` object in an A2A AgentCard, or agent capabilities in MCP).

**Properties:**

- `v1.0` (object, required): The capability structure for version 1.0 of the A2UI protocol.
  - `supportedCatalogIds` (array of strings, required): An array of strings identifying the Catalog Definition Schemas the agent can generate.
  - `acceptsInlineCatalogs` (boolean, optional, default `false`): Indicates if the agent can accept custom inline component/function catalogs in the renderer's capabilities metadata.

### Renderer capabilities

The `a2uiRendererCapabilities` object in the transport metadata follows the [`renderer_capabilities.json`] schema to describe the renderer's capabilities.

If `a2uiRendererCapabilities` is carried on message metadata (eg, in A2A), it should be scoped to that conversation turn, and omitting it on subsequent messages should withdraw A2UI support for those turns. If `a2uiRendererCapabilities` is carried on session metadata (eg, in MCP initialize) it should be scoped to the session.

**Properties:**

- `v1.0` (object, required): The capability structure for version 1.0 of the A2UI protocol.
  - `supportedCatalogIds` (array of strings, required): The string identifiers of supported component and function catalogs.
  - `inlineCatalogs` (array, optional): An array of custom catalog definitions provided inline by the renderer. Functions defined within inline catalogs support declaring authorized callers (`allowedCallers: "rendererOnly" | "agentOnly" | "rendererOrAgent"`) to statically specify remote invocation safety.

### Renderer data model

When `sendDataModel` is enabled for a surface, the renderer includes the `a2uiRendererDataModel` object in the transport metadata, following the [`renderer_data_model.json`] schema.

**Properties:**

- `version` (string, required): Must be the constant `"v1.0"`.
- `surfaces` (object, required): A map of surface IDs to their current local data models.

### Extensions

In A2UI v1.0, strict schema validation (`additionalProperties: false`) protects components and wire messages from unrecognized fields. To enable non-visual metadata (such as access constraints, audit tags, and telemetry identifiers, etc.) without allowing arbitrary properties that would weaken schema validation, A2UI defines a centralized `Extensions` type in `common_types.json#/$defs/Extensions`.

#### Architectural Principles

1.  **Optional Schema Fields**: All `metadata.extensions` fields are strictly optional on the wire. When omitted, they incur zero token overhead.
2.  **Parser Conformance Rule**: Conformant renderers MUST NOT reject payloads containing extension keys within an `extensions` object. Renderers MAY inspect and process extension keys they recognize, and MUST ignore unrecognized extension keys without error.
3.  **Unicode Identifiers (UAX #31) and Prefix Reservation**: Extension names MUST be valid [Unicode UAX #31] identifiers (`^[\p{XID_Start}_][\p{XID_Continue}]*$`). To prevent key collisions:
    - Official A2UI extensions are strictly reserved under the prefix `a2ui_`.
    - Third-party extensions MUST be prefixed with a distinct organization or product identifier separated by an underscore (e.g. an extension from a company with the domain `company.com` might be named `com_company_extension`).
      - Use of names derived from reversed domain names is encouraged for public facing extensions.
    - Extension namespace uniqueness is self-managed by extension authors; no central registry is maintained.

#### Wire Containers

A2UI defines optional `metadata.extensions` containers across four scopes:

- **Surface Scope** (`createSurface.metadata.extensions` in [`agent_to_renderer.json`]): Attach surface-level security metadata, access policies, or telemetry session identifiers.
- **Component Scope** (`ComponentCommon.metadata.extensions` in [`common_types.json`]): Attach component-instance styling overrides, telemetry markers, or custom validation rules.
- **Catalog Component Definition Scope** (`ComponentDefinition.metadata.extensions` in [`catalog_definition.json`]): Attach static component metadata or default telemetry tagging directly to catalog component schemas.
- **Action Egress Scope** (`action.metadata.extensions` in [`renderer_to_agent.json`]): Send client-side action attestations, audit signatures, or authorization tokens back to the agent when user actions are triggered.

#### SDK Accessor Pattern

Renderers and client SDKs expose surface and component metadata using uniform accessors and change notification callbacks:

- `getMetadata()`: Retrieves the metadata object containing extensions.
- `setMetadata(metadata)`: Updates the metadata object and notifies listeners.
- `onMetadataChanged(callback)`: Registers a callback that fires whenever metadata updates.

[json pointer]: https://datatracker.ietf.org/doc/html/rfc6901
[rfc 6901]: https://datatracker.ietf.org/doc/html/rfc6901
[unicode uax #31]: https://www.unicode.org/reports/tr31/
[`agent_capabilities.json`]: ../json/agent_capabilities.json
[`agent_to_renderer.json`]: ../json/agent_to_renderer.json
[`catalog_definition.json`]: ../json/catalog_definition.json
[`catalogs/basic/catalog.json`]: ../../../catalogs/basic/v1/catalog.json
[`common_types.json`]: ../json/common_types.json
[`renderer_capabilities.json`]: ../json/renderer_capabilities.json
[`renderer_data_model.json`]: ../json/renderer_data_model.json
[`renderer_to_agent.json`]: ../json/renderer_to_agent.json

---

### Specification V1 0 Docs Evolution Guide (`specification/v1_0/docs/evolution_guide.md`)

# A2UI Protocol Evolution Guide: v0.9 to v1.0

This document serves as a comprehensive guide to the changes between A2UI version 0.9 (including 0.9.1) and version 1.0. It details the shifts in philosophy, architecture, and implementation, providing a reference for stakeholders and developers migrating between versions.

## 1. Executive summary

Version 1.0 differs from 0.9 in the following ways:

- Bidirectional RPC function calls are supported via explicit role-based messages: `callRendererFunction` for agent-initiated calls on the renderer (returning `rendererFunctionResponse`), and `callAgentFunction` for renderer-initiated calls on the agent (returning `agentFunctionResponse`). Execution results or errors are returned via shared `FunctionResponse` payloads. Runtime authorized callers (`allowedCallers`) and return types are defined in catalogs and verified at runtime.
- Catalogs can now be mixed within a single UI surface. Advertised `supportedCatalogIds` are mixable, allowing UI trees to combine components and functions from multiple catalogs simultaneously.
- Added `$defs/FunctionCommon` in `common_types.json` composed at the envelope level via `FunctionCall` for function-level catalog overrides, matching the `ComponentCommon` pattern.
- Added an optional `catalogId` property to `ComponentCommon` and `FunctionCall` to allow individual components and function calls to explicitly declare their source catalog.
- Retained `catalogId` on `createSurface` as an optional parameter that defines the default catalog for that surface.
- Added extensibility metadata support via `$defs/Extensions` in `common_types.json`, allowing `ComponentCommon`, `createSurface`, `ComponentDefinition`, and `action` to convey arbitrary extension key-value pairs (with Unicode UAX #31 keys and reserved `a2ui_` namespace).
- Defined explicit component and function call resolution logic: the renderer checks the component-level (or function call-level) `catalogId` first, then falls back to the surface default `catalogId`. If neither is defined, the renderer errors out and does not render the component (or rejects the function call). There is no fallback to catalogs declared in capabilities. Available catalogs for a surface include both `supportedCatalogIds` and any negotiated `inlineCatalogs`, and all mixed catalogs must use the same A2UI specification version.
- The `theme` property in the catalog and surface creation message is removed, along with `primaryColor`, to separate layout from branding.
- Components and initial data model states can be defined directly within the `createSurface` parameters. This allows for the creation of entire UIs in a single message, rather than a create followed by separate updates.
- The `functions` field in catalog meta-schemas (`catalog_definition.json`) is now formalized as a JSON object map of function name to its definition, matching the map structure used in catalog files.
- Standard JSON Schema metadata fields (`$schema`, `$id`, `title`, and `description`) are supported in catalogs, preventing validation failures on inline catalogs with strict property checks.
- Identifier naming rules across all catalog entities (component names, function names, and argument keys) must conform to Unicode Standard Annex #31 (UAX #31).
- Reserved `@` prefix across protocol keys (`@path` for data bindings, `@call` for function calls, `@index` for template iteration). Plain objects containing `"path"` or `"call"` keys are treated as literal dictionary values and are no longer intercepted as dynamic directives. Unknown single-`@` keys (`^@([^@]|$)`) in dynamic objects are disallowed, and literal `@` keys in plain objects are escaped via prefix doubling (`"@@path"` → `"@path"`).

  > [!WARNING]
  > Do not migrate v0.9 payloads with a blanket find-and-replace of `"path":` → `"@path":` or `"call":` → `"@call":`. Only `DataBinding` and `FunctionCall` positions take the prefix. These keep their unprefixed spelling in v1.0:
  >
  > - `ChildList` template objects: `{"componentId": "itemTemplate", "path": "/items"}`.
  > - The `updateDataModel` message envelope's `path` field, which is a message parameter rather than a data binding.
  > - Any `"call"` that is ordinary data rather than a directive, such as the `call` entry in the basic catalog's `Icon` name enum.
  >
  > Rewrite only the objects a renderer evaluates as a `DynamicValue`. In those objects, every key that needs a literal leading `@` must be escaped by doubling it, whatever follows the prefix: `"@@type"` for a literal `"@type"`, `"@@"` for a literal `"@"`. An unescaped leading `@` is reserved for protocol directives and is rejected.

- Standardized the names of core architectural components, renaming "client" to _renderer_ and "server" to _agent_ (e.g., `server_to_client` schemas are renamed to `agent_to_renderer`), because A2UI is sometimes generated on clients, and rendering sometimes happens on servers, making those terms ambiguous.
- Catalogs can now define composition constraints (`allowedParents` and `allowedChildren`) on component definitions, using `"Surface"` as the canonical root component type. Because JSON Schema cannot natively restrict child component types across a flat adjacency list of ID references, these rules allow catalogs to declare valid parent-child relationships without altering the wire format.
- `CheckRule` in `common_types.json` supports dynamic structured validation result objects (`ValidationResult`) returned directly by function evaluations or data bindings (containing `valid`, `code`, `message`, and `severity`) as well as booleans (coerced to `ValidationResult`), and `message` on `CheckRule` is made optional as a fallback error message. Conversely, `DynamicBoolean` coerces a `ValidationResult` object to its `valid` boolean property.
- Enhanced `AccessibilityAttributes` in `common_types.json` by adding WAI-ARIA `live` region support (`"off"`, `"polite"`, `"assertive"`) and `hidden` (`DynamicBoolean`) alongside the existing `label` (`DynamicString`) and `description` (`DynamicString`) properties, while setting `"additionalProperties": false`. Established normative specification prose requiring catalog and renderer implementations to plumb accessibility attributes, infer default screen reader semantics from visible text properties, and enforce SDK linter checks.

## 2. Changes

### 2.1. Catalog definition schema

- Removed the `$defs/theme` schema and the `primaryColor` property from the Catalog schema.
- Formalized the `functions` property in `catalog_definition.json` as a map object, keyed by function name.
- Added `allowedCallers` (enum: `rendererOnly`, `agentOnly`, `rendererOrAgent`, default: `rendererOnly`) to `FunctionDefinition` to restrict which roles can invoke a function.
- Added `requiresUserActivation` (boolean, default: `false`) to `FunctionDefinition` to declare if a function requires user gesture/activation context to execute, conditionally restricting `allowedCallers` to `rendererOnly`.
- Added `$defs/ValidationResult` schema (`valid`, `code`, `message`, `severity`) as the standard schema definition for validation function return payloads.
- Added an optional `instructions` field to the `Catalog` schema to embed design guidelines and component usage rules directly in the catalog, replacing the external `rules.txt` file.
- Supported standard JSON Schema metadata fields (`$schema`, `$id`, `title`, and `description`) in the Catalog object definition. Since the Catalog schema restricts properties with `additionalProperties: false`, this ensures inline catalogs containing standard schema metadata do not fail schema validation.
- Added a `protocolVersion` field (e.g., `"protocolVersion": "1.0"`) to catalog definition metadata (`catalog_definition.json`). If omitted, `protocolVersion` defaults to `"0.9"` for backward compatibility; catalog definitions targeting `1.0` and beyond MUST specify `"protocolVersion"`.
- Enforced Unicode Standard Annex #31 (UAX #31) identifier naming constraints (`XID_Start`, `XID_Continue`) across component names, function names, and argument keys.
- Added optional `allowedParents` and `allowedChildren` properties to catalog component definitions (`catalog_definition.json`) to define parent-child composition constraints. Because JSON Schema cannot natively restrict child component types across a flat adjacency list of ID references, these rules allow catalogs to declare valid component relationships.
- Added `"propertyNames": { "not": { "const": "Surface" } }` to the `components` map in `catalog_definition.json` to enforce reserving `"Surface"` at the schema validation level.
- Added the canonical `"Surface"` container component type in `common_types.json` to represent the top-level container of a surface for `"allowedParents": ["Surface"]` rules. The protocol reserves the `"Surface"` component name. The `createSurface` message implicitly creates `Surface` with `"child": "root"`, and you cannot modify `Surface` using `updateComponents`. These schema additions are catalog-level metadata and do not alter the wire format of component instances in `createSurface` or `updateComponents`.
- Added static `metadata` (containing `extensions`) property to `ComponentDefinition` inside `catalog_definition.json`.
- Introduced `x-deprecated-reason` as a human-readable explanation for a deprecated component, function, or property in addition to the standard JSON Schema `deprecated: true`.
- Allowed cross-catalog `$ref`s to peer catalogs that the agent or renderer already holds locally (for example `<peer catalog $id>#/components/Text`), alongside `common_types.json#/$defs/...`, and specified how the peer document is matched by `catalogId`, `$id` or file name. See "Cross-Catalog References" in the protocol specification.

### 2.2. Standard catalogs (basic)

- Added `posterUrl` property to the `Video` component in `catalogs/basic/catalog.json`, allowing a preview image to be displayed before the video plays.
- Added `placeholder` prop to the `TextField` component schema, and removed `TextField.validationRegexp` in favor of `checks` using the `regex` validation function.
- Added a `steps` property to the `Slider` component schema to snap values to discrete intervals.
- Updated `openUrl` function definition in `catalogs/basic/catalog.json` to set `"requiresUserActivation": true`.
- Refactored component definitions in `catalogs/basic/catalog.json` from `allOf: [ComponentCommon, ...]` and `unevaluatedProperties: false` to direct explicit property definitions (including explicit `component` const and `weight` props) or `$defs/Checkable`.
- Added an optional `instructions` field to the `Catalog` schema (`catalogs/basic/catalog.json`) to embed Markdown guidelines/rules directly, replacing the external `rules.txt` file.
- Updated return types on standard validation check functions (`required`, `regex`, `length`, `numeric`, `email`) in `catalogs/basic/catalog.json` from `"boolean"` to `"validationResult"`. When passed to `DynamicBoolean` parameters (such as in `and`, `or`, `not`), `ValidationResult` objects are coerced to their `valid` boolean.
- Updated external references to standard types in `catalogs/basic/catalog.json` to use relative paths (`common_types.json#/$defs/...`) instead of version-qualified URLs.
- Removed `$defs/theme` from the basic catalog.

### 2.3. Agent-to-renderer messages

- Replaced `callFunction` with `callRendererFunction` message structure (`CallRendererFunctionMessage`) to support agent-to-renderer function execution requests.
- Added `agentFunctionResponse` message structure (`AgentFunctionResponseMessage`) to `agent_to_renderer.json` so agents can return execution results or error payloads for renderer-initiated function calls (referencing `common_types.json#/$defs/FunctionResponse`).
- Updated the `createSurface` message (`CreateSurfaceMessage`) to remove the `theme` field, allowed passing initial `components` and `dataModel` directly inside the payload, made `catalogId` an optional parameter that acts as the surface's default catalog, and added optional surface-level `metadata` (containing `extensions`).
- Added an optional `catalogId` property to `ComponentCommon` and `FunctionCall` in `common_types.json` to enable mixing catalogs and explicitly designating the catalog on individual components or function calls.
- Added an optional `userMessage` (`DynamicString`) property to `Action.event` in `common_types.json`, resolved by the renderer into the outbound `action` message.
- Added `$defs/Extensions` to `common_types.json` and added optional `metadata` (containing `extensions`, `$ref: "#/$defs/Extensions"`) to `ComponentCommon`.
- Added `$defs/Child` (`"$ref": "#/$defs/ComponentId"`), `$defs/FunctionCommon`, and `$defs/IndexSystemFunction` to `common_types.json`.
- Added the `Component` definition in `agent_to_renderer.json` (referenced by `ComponentsList`) to compose `ComponentCommon` (`$ref: "common_types.json#/$defs/ComponentCommon"`) and updated `FunctionCall` in `common_types.json` to compose `FunctionCommon` (`$ref: "#/$defs/FunctionCommon"`), so base component and function call properties are validated at the envelope level regardless of catalog structure.
- Updated all protocol version references and envelopes from `v0.9` or `v0.9.1` to `v1.0`.

### 2.4. Renderer-to-agent events

- Added `callAgentFunction` message structure to support renderer-initiated remote function execution requests sent to the agent.
- Added `rendererFunctionResponse` renderer-to-agent message structure to return function execution results (`value`) or failure payloads (`error`), referencing `common_types.json#/$defs/FunctionResponse`.
- Added optional `userMessage` (string, resolved from `Action.event.userMessage`) and `metadata` (containing `extensions`, `$ref: "common_types.json#/$defs/Extensions"`) to the renderer-to-agent `action` message in `renderer_to_agent.json`.
- Updated renderer `error` messages to support `functionCallId` when reporting function execution failures, enforcing mutual exclusivity with `surfaceId`.
- Added `"UNALLOWED_PARENT"` and `"UNALLOWED_CHILD"` error code values to `renderer_to_agent.json` for reporting validation errors when a component is placed under an unallowed parent or an unallowed child is placed inside a container.
- Updated all protocol version references from `v0.9` or `v0.9.1` to `v1.0`.

### 2.5. Agent card and transport metadata

- Standardized the official MIME type to `application/a2ui+json` to conform to IANA media type guidelines.
- Updated capabilities namespace in transport metadata and A2A metadata parameters from `v0.9`/`v0.9.1` to `v1.0`.
- Clarified that `supportedCatalogIds` in `rendererCapabilities` and `agentCapabilities` are mixable within a single UI surface.
- Simplified `renderer_capabilities.json` by removing local inline catalog `$defs` (`Catalog`, `FunctionDefinition`) and replacing `inlineCatalogs` items with a direct `$ref` to `https://a2ui.org/specification/v1_0/catalog_definition.json`.
- Relocated extension specification from `v0_9_1/docs/a2ui_extension_specification.md` to `v1_0/extensions/a2a/docs/a2ui_extension_specification.md`.

### 2.6. Data encoding

- Standardized data deletion behavior in `updateDataModel` by making the `value` property required. Setting a path's value to `null` deletes the key at that path. Omitting the `value` property is now a schema validation error.
- Removed `allowedCallers` and `returnType` properties and validation constraints from `FunctionCall` and dynamic value schemas in `common_types.json`, deferring boundary checking and return type validation entirely to runtime execution.
- Added built-in `@index` function (with optional `offset` parameter) under `FunctionCall` to retrieve the iteration index during list template rendering. Reserved the `@` prefix for core system context evaluations.
- Updated `CheckRule` in `common_types.json` to support dynamic `ValidationResult` objects returned directly by function evaluations or data model bindings, adding the `$defs/ValidationResult` schema (`valid`, `code`, `message`, `severity`) and making `CheckRule.message` optional as a fallback message.

### 2.7. Processing rules

- Defined strict component and function catalog resolution logic:
  1. Check the component's (or function call's) explicit `catalogId`.
  2. If not present, check the surface's default `catalogId` provided in `createSurface`.
  3. If neither exists, report an error and do not render the component (or fail the function call). There is no fallback to catalogs advertised in capabilities. Available catalogs include `supportedCatalogIds` and negotiated `inlineCatalogs`, and all mixed catalogs must use the same A2UI specification version.
- Explicitly specified that `surfaceId` must be globally unique per renderer session. Creating a surface with an ID that already exists (without first deleting it) is an error.
- Enforced runtime lookup of function execution boundaries and return types. If a renderer receives a remote call to a function configured as `rendererOnly` or if the function is unregistered, it rejects the call and returns an error with the code `INVALID_FUNCTION_CALL`.
- Enforced catalog entity naming compliance with Unicode Standard Annex #31 (UAX #31).
- Restricted `@index` evaluation scope strictly to template instantiation loops (Collection Scope). Calling `@index` outside of template iteration results in an evaluation error.

### 2.8. Terminology standardization

- Renamed **client** to **renderer** and **server** to **agent** globally across all protocol schemas, capabilities, and message list definitions.
- Renamed all client-to-server and server-to-client JSON schema files to use renderer/agent filenames:
  - `server_to_client.json` -> `agent_to_renderer.json`
  - `client_to_server.json` -> `renderer_to_agent.json`
  - `client_capabilities.json` -> `renderer_capabilities.json`
  - `server_capabilities.json` -> `agent_capabilities.json`
  - `client_data_model.json` -> `renderer_data_model.json`
- Renamed batch message list and list wrapper schema files:
  - `server_to_client_list.json` -> `agent_to_renderer_list.json`
  - `server_to_client_list_wrapper.json` -> `agent_to_renderer_list_wrapper.json`
  - `client_to_server_list.json` -> `renderer_to_agent_list.json`
  - `client_to_server_list_wrapper.json` -> `renderer_to_agent_list_wrapper.json`

## 3. Migration guide

This section outlines the steps required to migrate existing applications and components from version 0.9 (including 0.9.1) to version 1.0.

### For agents

- Set the `version` field in all streamed JSON envelopes to `"v1.0"`.
- Change the MIME type of A2UI payloads in transport layers from `application/json+a2ui` to `application/a2ui+json`.
- Remove the `theme` field from `createSurface` messages. You can pass initial `components`, `dataModel`, and optional `metadata.extensions` directly in the `createSurface` payload, and `catalogId` is now optional (acting as the default catalog for that surface).
- When mixing components from multiple catalogs, specify the optional `catalogId` on individual components or function calls.
- Formalize the `functions` property in catalog definitions as a JSON object map keyed by function name.
- Remove the `$defs/theme` catalog definition and the `primaryColor` field.
- Ensure all generated catalog entity names conform to UAX #31 identifier rules.
- Do not include `allowedCallers` or `returnType` properties in wire-level `FunctionCall` payloads. Set static `allowedCallers`, `returnType`, and optional `requiresUserActivation` metadata in catalog function definitions where needed.
- Update `Video`, `TextField`, and `Slider` components to support optional `posterUrl`, `placeholder`, and `steps` properties, and migrate any `TextField.validationRegexp` usage to `checks` with the `regex` validation function. Update `openUrl` functions to specify `"requiresUserActivation": true`.
- Explicitly set values to `null` in `updateDataModel` messages to delete keys at specified paths. The `value` property is now required, and omitting it is a schema validation error.
- Handle remote function execution requests from renderers (`callAgentFunction`) and respond with `agentFunctionResponse` messages.
- Rename all references, constants, and endpoints mapping to `server_to_client.json` or `server_capabilities.json` to use `agent_to_renderer.json` and `agent_capabilities.json`.

### For renderers

- Implement multi-catalog mixing by supporting components and function calls from any catalog in `supportedCatalogIds` or negotiated `inlineCatalogs`. All catalogs mixed within a surface must use the same A2UI specification version.
- Implement component and function resolution order: (1) explicit component/call `catalogId`, (2) surface default `catalogId`, (3) error if neither exists (no fallback to capabilities).
- Implement function execution by adding support for parsing `callRendererFunction` messages from the agent, checking authorized callers in the catalog (`allowedCallers`), rejecting invalid calls with `INVALID_FUNCTION_CALL`, and returning `rendererFunctionResponse` messages.
- Implement renderer-initiated function calls by sending `callAgentFunction` messages to the agent and handling incoming `agentFunctionResponse` messages.
- Support simultaneous version handling during session initialization by inspecting the `version` property (e.g., `"v1.0"`) to route payloads to version-specific controllers.
- Enforce surface uniqueness by raising an error if `createSurface` is received for an existing `surfaceId`.
- Update error reporting to handle `functionCallId` and enforce mutual exclusivity with `surfaceId`.
- Enforce Unicode identifier naming by verifying that all catalog entity names (components, functions, prop keys) conform to UAX #31 identifier rules.
- Support built-in `@index` evaluation during list template rendering (Collection Scope) to provide the 0-based iteration index, adjusted by any `offset` parameter.
- Support dynamic `ValidationResult` objects (`valid`, `code`, `message`, `severity`) returned by component validation check conditions, falling back to static `CheckRule.message` if present.
- Rename all references, constants, and endpoints mapping to `client_to_server.json` or `client_capabilities.json` to use `renderer_to_agent.json` and `renderer_capabilities.json`.

### For catalog authors

- **Set catalog protocol version**: Catalogs targeting v1.0 must specify `"protocolVersion": "1.0"` in the catalog root.
- **Use relative standard type references**: Replace version-qualified schema URLs (`https://a2ui.org/specification/v1_0/common_types.json#/$defs/...`) with unversioned relative targets (`common_types.json#/$defs/...`).
- **Breaking changes from v0.9 to v1.0**: Catalogs authored for v0.9 cannot be used directly with v1.0 protocol runtimes due to breaking structural changes (such as composing `ComponentCommon` at the envelope level, returning `ValidationResult` objects from check functions, and declaring caller and composition constraints).
- **Future forward compatibility**: Using unversioned relative references allows v1.0 catalogs to potentially work against future protocol versions without requiring catalog authors to rewrite `$ref` URLs.

---

### Specification V1 0 Docs Sdks Spec (`specification/v1_0/docs/sdks_spec.md`)

# A2UI Unified SDK Architecture

This document describes the unified architecture of the A2UI SDK ecosystem. To support modern, multi-paradigm generative UI applications, A2UI separates concerns into a modular, three-tiered structure: the **A2UI Core SDK**, the **Inference SDK**, and **Framework Adapters**. This structure is replicated across different languages.

This architecture enables high code reuse, strict conformance, and unified behavior across languages. Ensuring that we use a consistent codebase structure and terminology across languages also makes it easier to maintain the codebases together and add new features across languages using spec-driven development.

## 1. Ecosystem Dependency Structure

Framework adapter and inference SDKs depend on the core SDK as shown below:

```mermaid
flowchart TD
    FA[Framework Adapter<br>Renders surface state to pixels using a native UI] -->|Depends on| Core[A2UI Core SDK<br>Maintains surface state, message processing, and validation]
    Inference[Inference SDK<br>Generates agentToRenderer messages using LLM engines] -->|Depends on| Core
```

## 2. Library Responsibilities

### A2UI Core SDK (`a2ui_core` / `@a2ui/core`)

**Availability:** Every target language (TS, Dart, Python, Kotlin, Swift, C++).  
**Responsibility:** Provides the foundational, language-native representations of the official A2UI specifications.

- **Protocol Models:** Strongly-typed classes representing Catalog declarations (`Catalog`, `ComponentApi`, `FunctionApi`) and A2UI message types (`RendererToAgent`, `AgentToRenderer`, etc.).
- **Surface State Management:** Mutable models representing active UI surfaces (`SurfaceModel`, `ComponentModel`, `DataModel`).
- **Processing Layer (`MessageProcessor`):** Evaluates incoming JSON message arrays, resolves relative JSON pointers, and updates surface state models.
- **Validation:** Performs strict validation of message schema structures, reference checks, and `AccessibilityAttributes` (`label`, `description`, `live`, `hidden`).
- **Catalog Linters:** Verifies component schemas accepting actions or input bindings declare accessible label requirements or fallbacks.
- **Incremental Snapshotting:** Supports tracking and collapsing incremental updates into flat snapshots (e.g., `ComponentNode` trees).

### Inference SDK (`a2ui_inference` / `@a2ui/inference`)

**Availability:** All supported agent languages and select renderer-side languages (for local inference).  
**Responsibility:** Guides Large Language Models (LLMs) to generate valid A2UI message payloads based on a defined component Catalog and active application context.

- **Inference Strategies:** Standard structured generation schemes.
- **Prompt Construction:** Building prompt buffers and feeding component capability schemas dynamically to LLM contexts.
- **Message Parsing:** Safely extracting and repairing raw JSON envelopes from LLM completion streams.
- **Error Repair & Retries:** Programmatic fixing of malformed or invalid schemas.

### Framework Adapters (`react_renderer`, `compose_renderer`, etc.)

**Availability:** Every supported UI framework across renderer platforms.  
**Responsibility:** Paints the state of a Core `SurfaceModel` onto physical screen pixels using native UI hierarchies.

- **Framework Entry View (`Surface`):** Observes Core state and boots the recursive layout loop.
- **Component Renderers (`ComponentImplementation`):** Individual native views implementing visual specs (e.g., standard layout, text, or inputs from the Basic Catalog).
- **Accessibility Plumbing & Semantic Inference:** Maps `AccessibilityAttributes` (`label`, `description`, `live`, `hidden`) to native UI framework accessibility APIs (Web ARIA, Flutter Semantics, Android/iOS accessibility nodes) and infers default screen reader semantics from visible text properties.
- **Lifecycle Bindings:** Standardizes lazy-mounting, reactive value propagation, and memory leak prevention (`dispose`).

---

### Specification V1 0 Extensions A2a Docs A2ui Extension Specification (`specification/v1_0/extensions/a2a/docs/a2ui_extension_specification.md`)

# A2UI (Agent-to-Agent UI) Extension spec v1.0

## Overview

This document is intended for developers implementing the A2UI A2A extension. The extension adds A2UI v1.0 support to A2A, a format for agents to send streaming, interactive user interfaces to renderers.

Note that A2UI extension activation is optional as renderers and agents can negotiate A2UI support using A2A `message.metadata["a2uiRendererCapabilities"]` which is attached to every A2A message from the renderer and contains the supported protocol version and catalogs. Agents advertising A2UI support in their AgentCard is encouraged as renderers may rely on it to determine if they should send `message.metadata["a2uiRendererCapabilities"]`, however it is not explicitly required.

## Extension URI

The URI of this extension is https://a2ui.org/a2a-extension/a2ui/v1.0

This URI is the canonical way to communicate protocol versioning between renderers and agents. The extension URI explicitly encodes the version (e.g., `v1.0`). A renderer requesting this specific URI indicates it supports the v1.0 schema format.

## Agent Card

Agents are encouraged to advertise their A2UI capabilities in their AgentCard within the `AgentCapabilities.extensions` list. This advertisement is optional, but it informs the renderer whether to send `message.metadata["a2uiRendererCapabilities"]`. The `params` object defines the agent's specific UI support and corresponds directly to the [Agent Capabilities Schema](../../../json/agent_capabilities.json).

Example AgentCard payload:

```json
{
  "name": "Dashboard Agent",
  "description": "Agent capable of generating dynamic UI dashboards.",
  "capabilities": {
    "extensions": [
      {
        "uri": "https://a2ui.org/a2a-extension/a2ui/v1.0",
        "description": "Ability to render A2UI v1.0",
        "required": false,
        "params": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v1.0/my_custom_catalog.json"
          ],
          "acceptsInlineCatalogs": true
        }
      }
    ]
  }
}
```

The `params` object corresponds to the `v1.0` object in the `agent_capabilities.json` schema:

- `params.supportedCatalogIds` (optional): An array of strings, where each string is an ID identifying a Catalog Definition Schema that the agent can generate. This is not necessarily a resolvable URI.
- `params.acceptsInlineCatalogs` (optional): A boolean indicating if the agent can accept an `inlineCatalogs` array in the renderer's `a2uiRendererCapabilities`. If omitted, this defaults to `false`.

## A2A Extension activation

Activating the A2UI extension is optional. Renderers and agents can negotiate A2UI support using `message.metadata["a2uiRendererCapabilities"]` A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`.

Specifically:

- If a renderer includes `message.metadata["a2uiRendererCapabilities"]`, the agent can use this object to determine the supported A2UI protocol version and catalogs.
- If an agent returns A2A A2A `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`, the renderer knows the payload contains A2UI messages.

While explicit activation is not required, renderers can still explicitly activate the extension using the transport-defined A2A extension activation mechanism. The [A2A Extensions Guide](https://a2a-protocol.org/latest/topics/extensions/) defines this process.

Note: You should not use `accepted_output_modes: ['a2ui']` (which is not an A2UI standard) to trigger A2UI.

### JSON-RPC and HTTP transports

To activate the A2UI A2A Extension, the `X-A2A-Extensions` HTTP header includes the extension URI.

**Example HTTP `SendMessageRequest`:**

```http
POST /v1/messages HTTP/1.1
Host: agent.example.com
X-A2A-Extensions: https://a2ui.org/a2a-extension/a2ui/v1.0
Content-Type: application/json

{
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
      }
    ]
  }
}
```

To see how the agent parses the extension URI, see [`extension.py`](../../../../../python/a2ui_a2a/src/a2ui/a2a/extension.py).

### GRPC transport

To activate the A2UI A2A Extension, the renderer adds the extension URI to A2A `sendMessageParams.metadata["X-A2A-Extensions"]`.

**Example gRPC `SendMessageRequest`:**

```json
{
  "metadata": {
    "X-A2A-Extensions": "https://a2ui.org/a2a-extension/a2ui/v1.0"
  },
  "message": {
    "parts": [
      {
        "text": "Hello, show me the dashboard"
        }
      ]
    }
  }
}
```

## A2A Renderer to Agent Metadata

Renderers attach `a2uiRendererCapabilities` and `a2uiRendererDataModel` to A2A messages to communicate their state and supported catalogs.

### `a2uiRendererCapabilities`

The renderer sends `sendMessageRequest.message["a2uiRendererCapabilities"]` = [Renderer Capabilities Schema](../../../json/renderer_capabilities.json) to advertise which catalogs the renderer supports.

Additionally, the renderer determines a function's execution boundary (e.g., `rendererOnly` status) at runtime by reading its configuration from the active catalog definition.

**Example `SendMessageRequest` with Capabilities:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Show me the dashboard."
      }
    ],
    "metadata": {
      "a2uiRendererCapabilities": {
        "v1.0": {
          "supportedCatalogIds": [
            "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
            "https://my-company.com/a2ui/v1.0/my_custom_catalog.json"
          ]
        }
      }
    }
  }
}
```

### `a2uiRendererDataModel`

When a surface enables Data Model Sync, the renderer sends `sendMessageRequest.message["a2uiRendererDataModel"]` = [Renderer Data Model Schema](../../../json/renderer_data_model.json) on every message. This model provides the agent with the latest UI state. For more details, see the [Actions Guide](../../../../../docs/public/concepts/actions.md).

**Example `SendMessageRequest` with Data Model:**

```json
{
  "message": {
    "parts": [
      {
        "text": "Submit the form."
      }
    ],
    "metadata": {
      "a2uiRendererDataModel": {
        "version": "v1.0",
        "surfaces": {
          "main_surface_id": {
            "user_id": "12345",
            "email": "user@example.com"
          }
        }
      }
    }
  }
}
```

## Data encoding

Agents and renderers encode A2UI messages as an A2A `DataPart`.

To identify a `DataPart` as containing A2UI data, it must have the following metadata:

- `DataPart.data.metadata["mimeType"] = "application/a2ui+json"`

The `data` field of the `DataPart` contains a list of A2UI JSON messages (e.g., `createSurface`, `updateComponents`, `action`). It MUST be an array of messages.

### Processing Rules

The `data` field contains a list of messages. This list is NOT a transactional unit. Receivers (both Renderers and Agents) MUST process messages in the list sequentially.

If a single message in the list fails to validate or apply (e.g., due to a schema violation or invalid reference), the receiver SHOULD report/log the error for that specific message and MUST continue processing the remaining messages in the list.

Atomicity is guaranteed only at the individual message level. However, for a better user experience, a renderer SHOULD NOT repaint the UI until all messages in the list have been processed. This prevents intermediate states from flickering to the user.

### Agent-to-renderer messages

When an agent sends a message to a renderer (or another agent acting as a renderer), the `data` payload must validate against the [Agent-to-Renderer Message List Schema](../../../json/agent_to_renderer_list.json).

Example DataPart:

```json
{
  "data": [
    {
      "version": "v1.0",
      "createSurface": {
        "surfaceId": "example_surface",
        "catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"
      }
    },
    {
      "version": "v1.0",
      "updateComponents": {
        "surfaceId": "example_surface",
        "components": [
          {
            "id": "root",
            "component": "Text",
            "text": "Hello!"
          }
        ]
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

### Renderer-to-agent events

When a renderer (or an agent forwarding an event) sends a message to an agent, it also uses a `DataPart` with the same `application/a2ui+json` MIME type. However, the `data` payload must validate against the [Renderer-to-Agent Message List Schema](../../../json/renderer_to_agent_list.json).

Example `action` DataPart:

```json
{
  "data": [
    {
      "version": "v1.0",
      "action": {
        "name": "submit_form",
        "surfaceId": "contact_form_1",
        "sourceComponentId": "submit_button",
        "timestamp": "2026-01-15T12:00:00Z",
        "context": {
          "email": "user@example.com"
        }
      }
    }
  ],
  "kind": "data",
  "metadata": {
    "mimeType": "application/a2ui+json"
  }
}
```

---

--- METRICS ---
- Files Extracted: 74
- Estimated Token Budget: ~192253 tokens
- Canonical Reference: https://codewiki.google/github.com/a2ui-project/a2ui
