Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 5 additions & 18 deletions specification/v1_0/docs/a2ui_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The envelope defines several message types, and every message streamed by the se

### `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.
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. Once a surface is created, its `surfaceId` is fixed; to reconfigure it, 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).

Expand All @@ -181,7 +181,6 @@ One of the components in one of the component lists MUST have an `id` of `root`
**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.
- `surfaceProperties` (object, optional): A JSON object containing surface properties (e.g., `agentDisplayName`) defined in the catalog's surfaceProperties 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.
- `components` (array, optional): A list containing UI components for the surface, allowing the client to build and populate the UI tree immediately on surface creation. Conforms to the `ComponentsList` schema.
Expand All @@ -194,7 +193,6 @@ One of the components in one of the component lists MUST have an `id` of `root`
"version": "v1.0",
"createSurface": {
"surfaceId": "user_profile_card",
"catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
"surfaceProperties": {
"agentDisplayName": "Weather Bot"
},
Expand Down Expand Up @@ -354,6 +352,7 @@ This message is sent by the server to execute a function registered on the clien
- `wantResponse` (boolean, optional, default `false`): Specifies whether the server expects a response payload back from the client. If set to `true`, the client MUST reply with either a `functionResponse` or an `error` 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 for this function.
- `args` (object, optional): Arguments passed to the function, as defined by its schema in the catalog.

**Security Boundaries and Verification:**
Expand All @@ -374,6 +373,7 @@ Server sends this message to the client:
"wantResponse": true,
"callFunction": {
"call": "getScreenResolution",
"catalogId": "https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json",
"args": {
"screenIndex": 0
}
Expand Down Expand Up @@ -412,8 +412,8 @@ If the server attempts to call a `clientOnly` function (e.g., a local-only compo
The following example demonstrates a complete interaction to render a Contact Form, expressed as a JSONL stream.

```jsonl
{"version": "v1.0", "createSurface":{"surfaceId":"contact_form_1","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"}}
{"version": "v1.0", "updateComponents":{"surfaceId":"contact_form_1","components":[{"id":"root","component":"Card","child":"form_container"},{"id":"form_container","component":"Column","children":["header_row","name_row","email_group","phone_group","pref_group","divider_1","newsletter_checkbox","submit_button"],"justify":"start","align":"stretch"},{"id":"header_row","component":"Row","children":["header_icon","header_text"],"align":"center"},{"id":"header_icon","component":"Icon","name":"mail"},{"id":"header_text","component":"Text","text":"# Contact Us"},{"id":"name_row","component":"Row","children":["first_name_group","last_name_group"],"justify":"spaceBetween"},{"id":"first_name_group","component":"Column","children":["first_name_label","first_name_field"],"weight":1},{"id":"first_name_label","component":"Text","text":"First Name","variant":"caption"},{"id":"first_name_field","component":"TextField","label":"First Name","value":{"path":"/contact/firstName"},"variant":"shortText"},{"id":"last_name_group","component":"Column","children":["last_name_label","last_name_field"],"weight":1},{"id":"last_name_label","component":"Text","text":"Last Name","variant":"caption"},{"id":"last_name_field","component":"TextField","label":"Last Name","value":{"path":"/contact/lastName"},"variant":"shortText"},{"id":"email_group","component":"Column","children":["email_label","email_field"]},{"id":"email_label","component":"Text","text":"Email Address","variant":"caption"},{"id":"email_field","component":"TextField","label":"Email","value":{"path":"/contact/email"},"variant":"shortText","checks":[{"call":"required","args":{"value":{"path":"/contact/email"}},"message":"Email is required."},{"call":"email","args":{"value":{"path":"/contact/email"}},"message":"Please enter a valid email address."}]},{"id":"phone_group","component":"Column","children":["phone_label","phone_field"]},{"id":"phone_label","component":"Text","text":"Phone Number","variant":"caption"},{"id":"phone_field","component":"TextField","label":"Phone","value":{"path":"/contact/phone"},"variant":"shortText","checks":[{"call":"regex","args":{"value":{"path":"/contact/phone"},"pattern":"^\\d{10}$"},"message":"Phone number must be 10 digits."}]},{"id":"pref_group","component":"Column","children":["pref_label","pref_picker"]},{"id":"pref_label","component":"Text","text":"Preferred Contact Method","variant":"caption"},{"id":"pref_picker","component":"ChoicePicker","variant":"mutuallyExclusive","options":[{"label":"Email","value":"email"},{"label":"Phone","value":"phone"},{"label":"SMS","value":"sms"}],"value":{"path":"/contact/preference"}},{"id":"divider_1","component":"Divider","axis":"horizontal"},{"id":"newsletter_checkbox","component":"CheckBox","label":"Subscribe to our newsletter","value":{"path":"/contact/subscribe"}},{"id":"submit_button_label","component":"Text","text":"Send Message"},{"id":"submit_button","component":"Button","child":"submit_button_label","variant":"primary","action":{"event":{"name":"submitContactForm","context":{"formId":"contact_form_1","clientTime":{"call":"formatDate","args":{"value": "2026-02-02T15:17:00Z", "format": "E MMM d, YYYY h:mm a"}},"isNewsletterSubscribed":{"path":"/contact/subscribe"}}}}}]}}
{"version":"v1.0","createSurface":{"surfaceId":"contact_form_1"}}
{"version":"v1.0","updateComponents":{"surfaceId":"contact_form_1","components":[{"id":"root","component":"Card","child":"form_container","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"form_container","component":"Column","children":["header_row","name_row","email_group","phone_group","pref_group","divider_1","newsletter_checkbox","submit_button"],"justify":"start","align":"stretch","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"header_row","component":"Row","children":["header_icon","header_text"],"align":"center","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"header_icon","component":"Icon","name":"mail","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"header_text","component":"Text","text":"# Contact Us","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"name_row","component":"Row","children":["first_name_group","last_name_group"],"justify":"spaceBetween","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"first_name_group","component":"Column","children":["first_name_label","first_name_field"],"weight":1,"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"first_name_label","component":"Text","text":"First Name","variant":"caption","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"first_name_field","component":"TextField","label":"First Name","value":{"path":"/contact/firstName"},"variant":"shortText","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"last_name_group","component":"Column","children":["last_name_label","last_name_field"],"weight":1,"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"last_name_label","component":"Text","text":"Last Name","variant":"caption","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"last_name_field","component":"TextField","label":"Last Name","value":{"path":"/contact/lastName"},"variant":"shortText","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"email_group","component":"Column","children":["email_label","email_field"],"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"email_label","component":"Text","text":"Email Address","variant":"caption","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"email_field","component":"TextField","label":"Email","value":{"path":"/contact/email"},"variant":"shortText","checks":[{"call":"required","args":{"value":{"path":"/contact/email"}},"message":"Email is required."},{"call":"email","args":{"value":{"path":"/contact/email"}},"message":"Please enter a valid email address."}],"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"phone_group","component":"Column","children":["phone_label","phone_field"],"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"phone_label","component":"Text","text":"Phone Number","variant":"caption","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"phone_field","component":"TextField","label":"Phone","value":{"path":"/contact/phone"},"variant":"shortText","checks":[{"call":"regex","args":{"value":{"path":"/contact/phone"},"pattern":"^\\d{10}$"},"message":"Phone number must be 10 digits."}],"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"pref_group","component":"Column","children":["pref_label","pref_picker"],"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"pref_label","component":"Text","text":"Preferred Contact Method","variant":"caption","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"pref_picker","component":"ChoicePicker","variant":"mutuallyExclusive","options":[{"label":"Email","value":"email"},{"label":"Phone","value":"phone"},{"label":"SMS","value":"sms"}],"value":{"path":"/contact/preference"},"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"divider_1","component":"Divider","axis":"horizontal","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"newsletter_checkbox","component":"CheckBox","label":"Subscribe to our newsletter","value":{"path":"/contact/subscribe"},"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"submit_button_label","component":"Text","text":"Send Message","catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"},{"id":"submit_button","component":"Button","child":"submit_button_label","variant":"primary","action":{"event":{"name":"submitContactForm","context":{"formId":"contact_form_1","clientTime":{"call":"formatDate","args":{"value":"2026-02-02T15:17:00Z","format":"E MMM d, YYYY h:mm a"}},"isNewsletterSubscribed":{"path":"/contact/subscribe"}}}},"catalogId":"https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json"}]}}
{"version": "v1.0", "updateDataModel":{"surfaceId":"contact_form_1","path":"/contact","value":{"firstName":"John","lastName":"Doe","email":"john.doe@example.com","phone":"1234567890","preference":["email"],"subscribe":true}}}
{"version": "v1.0", "deleteSurface":{"surfaceId":"contact_form_1"}}
```
Expand All @@ -428,19 +428,6 @@ Each object in the `components` array of an `updateComponents` message defines a

- `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 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. Client and server 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 client-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 client determines a function's execution boundary (e.g., clientOnly status) at runtime by reading its configuration from the active catalog definition.
Expand Down
8 changes: 7 additions & 1 deletion specification/v1_0/docs/evolution_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Version 1.0 differs from 0.9 in the following ways:
- 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).
- The `@index` built-in function dynamically retrieves iteration indices during list template rendering. The `@` prefix is reserved for core system context evaluations.
- The `supportedCatalogIds` in `a2uiClientCapabilities` are all mixable, meaning a client can updateComponents with components from multiple catalogs simultaneously.
- Components now require a `catalogId` property so they can be unambiguously resolved across catalogs, since we now allow mixing catalogs. The `catalogId` property on `createSurface` has been removed.

## 2. Changes

Expand All @@ -39,7 +41,10 @@ Version 1.0 differs from 0.9 in the following ways:

- Added `actionResponse` message structure (`ActionResponseMessage`) to allow the server to respond to a specific action call using a unique `actionId` with a `value` or `error`.
- Added `callFunction` message structure (`CallFunctionMessage`) to support server-initiated function execution. Removed `callableFrom` and `returnType` properties from the wire payload, relying on runtime catalog verification.
- Updated the `createSurface` message (`CreateSurfaceMessage`) to rename the `theme` field to `surfaceProperties`, and allowed passing initial `components` and `dataModel` directly inside the payload.
- Updated the `createSurface` message (`CreateSurfaceMessage`) to rename the `theme` field to `surfaceProperties`, allowed passing initial `components` and `dataModel` directly inside the payload, and removed `catalogId`.
- Added a required `catalogId` to the base component definition (`ComponentCommon`) to cleanly isolate component namespaces.
- Added a required `catalogId` to the `FunctionCall` definition so functions can be unambiguously resolved across catalogs.
- Added a `rootOnly` boolean (default: false) to `ComponentCommon` to indicate if a component must be the top-level element. This allows restricting top-level components (like a Canvas) from being nested inside a `ChildList`.
Comment thread
wrenj marked this conversation as resolved.
Outdated
Comment thread
wrenj marked this conversation as resolved.
Outdated
- Updated all protocol version references and envelopes from `v0.9` or `v0.9.1` to `v1.0`.

### 2.4. Client-to-server events
Expand All @@ -59,6 +64,7 @@ Version 1.0 differs from 0.9 in the following ways:

- 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`.
- Explicitly defined that `supportedCatalogIds` in `a2uiClientCapabilities` are mixable.

### 2.7. Data encoding

Expand Down
2 changes: 1 addition & 1 deletion specification/v1_0/json/client_capabilities.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"properties": {
"supportedCatalogIds": {
"type": "array",
"description": "An array of string identifiers for each of the component and function catalogs supported by the client.",
"description": "An array of string identifiers for each of the component and function catalogs supported by the client. Multiple catalogs can be mixed in a surface.",
"items": {"type": "string"}
},
"inlineCatalogs": {
Expand Down
17 changes: 15 additions & 2 deletions specification/v1_0/json/common_types.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,20 @@
"id": {
"$ref": "#/$defs/ComponentId"
},
"catalogId": {
"type": "string",
"description": "The catalog ID for this component."
},
"rootOnly": {
"type": "boolean",
"description": "If true, this component must be the top-level element and cannot be placed inside a ChildList.",
"default": false
},
"accessibility": {
"$ref": "#/$defs/AccessibilityAttributes"
}
},
"required": ["id"]
"required": ["id", "catalogId"]
},
"ChildList": {
"oneOf": [
Expand Down Expand Up @@ -188,6 +197,10 @@
"type": "string",
"description": "The name of the function to call."
},
"catalogId": {
"type": "string",
"description": "The catalog ID for this function."
},
"args": {
"type": "object",
"description": "Arguments passed to the function.",
Expand All @@ -204,7 +217,7 @@
}
}
},
"required": ["call"],
"required": ["call", "catalogId"],
"oneOf": [
{"$ref": "catalog.json#/$defs/anyFunction"},
{"$ref": "#/$defs/IndexSystemFunction"}
Expand Down
Loading
Loading