# A2UI Architecture Explained: Stream-Oriented UI Generation for LLM Agents

> Discover the A2UI architecture for stream-oriented, declarative UI generation. LLM agents create native interfaces with JSON message streams and a reactive client.

- Repository: [Google/A2UI](https://github.com/google/A2UI)
- Tags: architecture
- Published: 2026-03-13

---

**A2UI is a stream-oriented, declarative UI framework that enables LLM agents to generate native user interfaces by emitting JSON message streams processed through a reactive client-side pipeline.**

The google/A2UI repository implements a message-driven architecture where agents construct interfaces incrementally via JSON-Lines streams. This Agent-to-UI (A2UI) architecture separates message generation from rendering, enabling transport-agnostic communication between LLM backends and frontend clients. The high-level concepts are documented in [`docs/concepts/overview.md`](https://github.com/google/A2UI/blob/main/docs/concepts/overview.md).

## End-to-End A2UI Architecture and Data Flow

The A2UI architecture follows a linear pipeline from agent to native UI:

```

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

```

The **A2UI Generator** formats UI descriptions as self-contained JSON objects according to the A2UI schema. These messages travel through any transport layer—Server-Sent Events, WebSockets, the A2A protocol, or plain HTTP—before reaching the client-side **Message Processor**.

According to [`docs/concepts/data-flow.md`](https://github.com/google/A2UI/blob/main/docs/concepts/data-flow.md), this streaming approach allows the client to render UI components progressively as the agent generates them, rather than waiting for complete page definitions.

## Message Schema Evolution (v0.8 vs. v0.9)

The A2UI architecture supports two active message protocol versions with distinct lifecycle approaches:

| Version | Surface Creation | Component Update | Data Model Update | Surface Deletion |
|---------|------------------|------------------|-------------------|------------------|
| **v0.8 (stable)** | Implicit via `surfaceUpdate`/`beginRendering` | `surfaceUpdate` | `dataModelUpdate` | `deleteSurface` |
| **v0.9 (draft)** | Explicit `createSurface` (catalog required) | `updateComponents` | `updateDataModel` | `deleteSurface` |

In v0.9, surfaces require explicit initialization with a catalog reference:

```json
{
  "version": "v0.9",
  "createSurface": { 
    "surfaceId": "main", 
    "catalogId": "https://a2ui.org/specification/v0_9/basic_catalog.json" 
  }
}

```

The full message specifications live in [`docs/reference/messages.md`](https://github.com/google/A2UI/blob/main/docs/reference/messages.md), which defines the JSON schema for all server-to-client communications.

## Declarative Component Architecture

A2UI adopts an **adjacency-list model** where components exist in a flat array and reference children by string `id`. This architecture eliminates hierarchy constraints during streaming, allowing LLMs to generate components in any order while the client resolves relationships post-receipt.

As documented in [`docs/concepts/components.md`](https://github.com/google/A2UI/blob/main/docs/concepts/components.md), each component definition includes:
- A unique `id` for referencing
- A `component` type from the registered catalog
- Optional `children` arrays or single `child` references
- Style and property definitions

Example v0.9 component tree:

```json
{
  "version": "v0.9",
  "updateComponents": {
    "surfaceId": "main",
    "components": [
      { "id": "root", "component": "Column", "children": ["header", "body"] },
      { "id": "header", "component": "Text", "text": "Welcome", "variant": "h1" },
      { "id": "body", "component": "Card", "child": "content" },
      { "id": "content", "component": "Text", "text": { "path": "/message" } }
    ]
  }
}

```

### Data Binding and Reactive Updates

Components declare dynamic values via **JSON Pointer paths** (e.g., `{ "path": "/user/name" }`). When the server emits `updateDataModel` (v0.9) or `dataModelUpdate` (v0.8) messages, the client updates only the specified data subtree, triggering reactive re-renders in bound components.

This binding mechanism, detailed in [`docs/concepts/data-binding.md`](https://github.com/google/A2UI/blob/main/docs/concepts/data-binding.md), enables real-time UI updates without requiring complete component re-transmission.

## Client-Side Processing Architecture

The browser-side architecture centers on the **Message Processor**, implemented in [`renderers/lit/src/0.8/data/signal-model-processor.ts`](https://github.com/google/A2UI/blob/main/renderers/lit/src/0.8/data/signal-model-processor.ts). This processor consumes JSONL streams and maintains an in-memory model using reactive signals.

Key implementation details:
- Uses **signal-utils** (array, map, object, set) for fine-grained reactivity
- Exposes surfaces as reactive objects compatible with Lit's rendering engine
- Supports incremental message processing via `processMessages()`

Implementation in a Lit component:

```typescript
import { v0_8 } from "@a2ui/lit";

class MyA2UIWidget extends LitElement {
  #processor = v0_8.Data.createSignalA2uiMessageProcessor();

  async handleMessages(messages: v0_8.Types.ServerToClientMessage[]) {
    this.#processor.clearSurfaces();
    this.#processor.processMessages(messages);
  }

  render() {
    const surfaces = this.#processor.getSurfaces();
    return html`
      ${repeat(
        surfaces,
        ([surfaceId]) => surfaceId,
        ([, surface]) => html`<a2ui-surface .surface=${surface}></a2ui-surface>`
      )}
    `;
  }
}

```

The processor relies on the generic `A2uiMessageProcessor` class from `@a2ui/web_core/data/model-processor`, enabling renderer-agnostic message handling.

## Handshake and Capability Negotiation

Before streaming begins, the A2UI architecture requires a **capability handshake**. The client transmits its supported component catalog to the agent, ensuring the LLM generates only compatible UI elements.

The handshake implementation in [`tools/editor/client.ts`](https://github.com/google/A2UI/blob/main/tools/editor/client.ts) demonstrates this initialization:

```typescript
await this.#send({
  clientUiCapabilities: {
    dynamicCatalog: catalog,
  },
});

```

After handshake completion, the client can send multipart requests containing images and instructions:

```typescript
import { A2UIClient } from "./client.ts";

const client = new A2UIClient();
await client.ready;

const response = await client.sendMultipart(
  undefined,
  "Create a simple login form"
);

```

## Extensibility and Renderer Abstraction

The A2UI architecture supports pluggable renderers through the `@a2ui/web_core` abstraction layer. Developers can implement React, Vue, or custom native renderers while reusing the same message processor core.

Extension points include:
- **Custom components**: Advertised via the dynamic catalog in the initial handshake
- **Transport layers**: Any stream-capable protocol can carry A2UI messages
- **Data processors**: The signal-based processor can be replaced with alternative reactive implementations

The reference implementation in [`tools/editor/editor.ts`](https://github.com/google/A2UI/blob/main/tools/editor/editor.ts) and consumer samples like [`samples/personalized_learning/src/a2ui-renderer.ts`](https://github.com/google/A2UI/blob/main/samples/personalized_learning/src/a2ui-renderer.ts) demonstrate production usage patterns.

## Summary

- **A2UI architecture** employs a stream-oriented pipeline where LLM agents emit JSON-Lines messages that clients render incrementally
- The framework supports two protocol versions (v0.8 stable and v0.9 draft) with explicit surface lifecycle management in the newer version
- Components use a flat adjacency-list structure with ID references, optimized for LLM generation patterns
- Data binding uses JSON Pointer paths for reactive updates without full component re-transmission
- Client-side processing relies on signal-based reactivity in [`signal-model-processor.ts`](https://github.com/google/A2UI/blob/main/signal-model-processor.ts) to transform messages into UI
- Initial handshake exchanges capability catalogs to ensure component compatibility between agent and client
- The renderer abstraction in `@a2ui/web_core` enables framework-agnostic implementations while maintaining consistent message semantics

## Frequently Asked Questions

### How does A2UI handle real-time streaming of UI components?

A2UI processes UI generation as a **JSON-Lines stream**, allowing the client to parse and render components incrementally as the LLM generates them. The [`signal-model-processor.ts`](https://github.com/google/A2UI/blob/main/signal-model-processor.ts) implementation uses reactive signals to update the DOM immediately when new messages arrive, without waiting for the complete stream to finish. This architecture supports Server-Sent Events, WebSockets, or any transport capable of delivering ordered JSON objects.

### What is the difference between v0.8 and v0.9 in A2UI's message architecture?

Version 0.8 creates surfaces implicitly through `surfaceUpdate` or `beginRendering` messages, while **v0.9 requires explicit surface creation** via `createSurface` with a mandatory catalog reference. Version 0.9 also renames key message types (`updateComponents` instead of `surfaceUpdate`, `updateDataModel` instead of `dataModelUpdate`) to better reflect their atomic operations. Both versions maintain the same flat component adjacency-list structure and JSON Pointer data binding.

### How do LLM agents know which UI components the client supports?

Before generating UI, agents receive a **dynamic catalog** through the initial handshake protocol defined in [`client.ts`](https://github.com/google/A2UI/blob/main/client.ts). The client sends its `clientUiCapabilities` including available component types, which constrains the agent's generation to compatible elements. This capability negotiation ensures that generated JSON messages reference only components the client can actually render.

### Can A2UI work with frontend frameworks other than Lit?

Yes. While the reference implementation uses Lit (`@a2ui/lit`), the **renderer abstraction** in `@a2ui/web_core` provides framework-agnostic message processing. The `A2uiMessageProcessor` class handles the core state management, allowing developers to implement React, Vue, or vanilla JavaScript renderers that consume the same surface objects and data bindings emitted by the processor.