Skip to content
On this page

A2UI v0.9.1 Message Templates

Small, versioned A2UI v0.9.1 JSONL examples for creating, updating, and deleting a surface safely.

Updated: 8/24/2026 Reviewed by: HIA2UI editorial team v0.9.1

A2UI v0.9.1 Message Templates

These examples show the shape and ordering of a small A2UI v0.9.1 message stream. They are starting points for learning and tests, not universal production payloads. Component properties depend on the catalog selected by your renderer, and the protocol may evolve. Pin the version, use a host-approved catalog, and validate every line against the exact official v0.9.1 schema before rendering it.

A2UI messages are commonly streamed as JSON Lines: each line is one complete JSON object. Do not wrap the lines in an array unless your transport explicitly requires that. The v0.9 lifecycle consists of createSurface, updateComponents, updateDataModel, and deleteSurface. Do not mix them with the v0.8 names beginRendering, surfaceUpdate, or dataModelUpdate.

Template 1: a static status card

This minimal sequence creates a surface and adds a root column containing a heading and status text. Replace the example catalog URL with an identifier your host recognizes; do not allow an agent to load arbitrary executable code from a catalog URL.

{"version":"v0.9.1","createSurface":{"surfaceId":"service-status","catalogId":"https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"}}
{"version":"v0.9.1","updateComponents":{"surfaceId":"service-status","components":[{"id":"root","component":"Column","children":["title","status"]},{"id":"title","component":"Text","text":"Service status","variant":"h2"},{"id":"status","component":"Text","text":"All systems operational"}]}}

The component list is flat: the root refers to child IDs rather than nesting complete component objects. This makes incremental replacement possible. Component names and properties still have to exist in the selected catalog. If the catalog uses different text or layout fields, adapt the payload and revalidate it.

Use stable component IDs within a surface. An update with the same component ID replaces that definition, so random IDs make targeted updates harder and can leave stale components in memory.

Template 2: data-bound content

Keep changing business data in the data model rather than regenerating the whole component graph. The following stream creates a simple order summary whose text reads from data paths. Confirm the binding syntax against your catalog and renderer version.

{"version":"v0.9.1","createSurface":{"surfaceId":"order-summary","catalogId":"https://a2ui.org/specification/v0_9_1/catalogs/basic/catalog.json"}}
{"version":"v0.9.1","updateComponents":{"surfaceId":"order-summary","components":[{"id":"root","component":"Column","children":["heading","order-id","state"]},{"id":"heading","component":"Text","text":"Order summary","variant":"h2"},{"id":"order-id","component":"Text","text":{"path":"/order/id"}},{"id":"state","component":"Text","text":{"path":"/order/status"}}]}}
{"version":"v0.9.1","updateDataModel":{"surfaceId":"order-summary","path":"/","value":{"order":{"id":"A-1042","status":"Awaiting review"}}}}

Later, update only the value that changed:

{"version":"v0.9.1","updateDataModel":{"surfaceId":"order-summary","path":"/order/status","value":"Approved"}}

Restrict writable paths in the host. A valid JSON Pointer is not automatically an authorized data destination. Set limits for data-model size and text length, and reject values that do not match the application’s expected type.

Template 3: a host-authorized action

Interactive components may request an action, but the payload must never grant permission by itself. This example adds a button that asks the host to refresh an order. The exact button and action fields are catalog-specific, so validate the example in the A2UI Composer using the same catalog as your application.

{"version":"v0.9.1","updateComponents":{"surfaceId":"order-summary","components":[{"id":"root","component":"Column","children":["heading","order-id","state","refresh"]},{"id":"refresh","component":"Button","child":"refresh-label","action":{"event":{"name":"refreshOrder","context":{"orderId":{"path":"/order/id"}}}}},{"id":"refresh-label","component":"Text","text":"Refresh status"}]}}

Map refreshOrder to a host-owned function. Check the user’s authorization on the server and validate orderId before making any request. For operations that spend money, disclose data, send messages, or make irreversible changes, show a precise confirmation and protect against duplicate submission. Never evaluate code supplied in an action name or parameter.

When replacing the root component, include every child that should remain visible. An incremental component update replaces definitions with matching IDs; it does not infer your intended merge from omitted fields.

Template 4: deterministic cleanup

Delete a surface when the conversation, modal, route, or task no longer needs it:

{"version":"v0.9.1","deleteSurface":{"surfaceId":"order-summary"}}

The renderer should release component state, bindings, pending callbacks, media, and subscriptions associated with the surface. An update received after deletion should fail rather than silently recreate the surface. A surfaceId may be reused only after the previous surface has been deleted and fully cleaned up.

Validation workflow

Use this short workflow for every template you adapt:

  1. Choose one protocol version and one catalog version.
  2. Validate each JSON object against the matching official schema.
  3. Reject unknown components, properties, paths, URLs, and actions at the host boundary.
  4. Preview normal, empty, long, malformed, and incremental data in Composer or your renderer test harness.
  5. Test duplicate, reordered, truncated, and post-deletion messages.
  6. Test keyboard navigation, focus behavior, labels, narrow screens, and safe failure states.
  7. Store the validated payload as a fixture so dependency upgrades reveal breaking changes.

Common adaptation mistakes

Do not remove the version field when copying a line. The v0.9.1 schema accepts the current patch identifier, while older articles may show v0.9 or the structurally different v0.8 format. Keep the message and Catalog versions aligned.

Do not rename root, wrap component properties under a type name, or change a fixed children array back to explicitList. Those shapes come from earlier protocol examples. Likewise, a Button event belongs under action.event; the renderer resolves allowed context bindings before sending the resulting action to the server.

Examples also omit product-specific constraints. A real order surface should define maximum text length, permitted status values, URL policy, authorization, localization, empty states, and accessible announcements. Replace demonstration identifiers and content, but preserve the verified envelope shape unless the matching official schema requires a change.

Test fixtures, not prompt decoration

Keep a small set of known-valid and known-invalid streams in the application test suite. Run them through the same validator and renderer used in production. A prompt can include concise schema guidance, but the model’s compliance is never the enforcement boundary. Runtime validation remains required even when the same template has worked repeatedly.

The official message reference defines the lifecycle. The renderer development guide explains host responsibilities. Treat those sources and the versioned schema as authoritative when they differ from an example on this site.