Flab × A2UIv0.0.2
Flab UI docs

Agent Integration

How to make your AI agent aware of the Flab A2UI component catalog — the JSON Schema contract that constrains what the agent can generate. This page covers catalog structure, prompt injection patterns, CLI export, token optimization, and protocol-level negotiation.

The Installation page covers the renderer side (React, theme, transport). This page covers the agent side — teaching an LLM what components it can emit.

What is the catalog?

The Flab A2UI catalog is a JSON Schema document that enumerates every component the renderer can draw and the properties each accepts. It is the design-system boundary: an agent cannot ask for a component that is not in the catalog, which is what keeps the renderer from ever executing arbitrary UI. The catalog currently contains 36 components (from layout primitives like Column and Row to complex widgets like TaskBoard, Calendar, and AgentLegion), 8 validation functions, and a discriminated union definition.

FieldPurpose
instructionsNatural-language guidance written for LLM consumption. Tells the agent how to compose layouts, pick variants, and respect the theme boundary.
componentsA map of component names → JSON Schema objects. Each entry declares the accepted properties, required fields, and enum constraints. This is the core of the contract.
functionsRenderer-side validation and utility functions the agent can reference in checks (required, email, regex, numeric, length) and logical combinators (and, or, not).
$defs.anyComponentA oneOf union of all component refs with a discriminator on the "component" property. Tells the agent (and JSON Schema validators) how to disambiguate component types.
$id / catalogIdThe canonical identifier for this catalog version. The renderer uses it to match incoming surfaces to the correct component set.

The instructions field is specifically designed for LLM consumption — it reads: “Compose layouts from Column and Row; wrap grouped content in a Card. Text renders a typographic primitive; set variant to pick the scale step. Do not send colours — visual styling is owned by the Flab theme.”

Integration methods

1

System prompt injection (JS/TS agents)

Import flabCatalog from the dedicated entry point and serialise it into the LLM's system prompt. The catalog is a plain JavaScript object, so JSON.stringify is all you need.

import { flabCatalog } from '@flabbergasted-ai/a2ui/catalog';
const systemPrompt = [  'You are an AI agent that generates A2UI surfaces.',  'Here is the component catalog you MUST follow:',  JSON.stringify(flabCatalog, null, 2),  '',  'Rules:',  '- ' + flabCatalog.instructions,  '- Every component object must have a "component" discriminator field.',  '- Only use components listed in the catalog.',  '- Data bindings use { path: "/pointer/to/data" } syntax.',].join('\n');
const response = await openai.chat.completions.create({  model: 'gpt-4o',  messages: [    { role: 'system', content: systemPrompt },    { role: 'user', content: userQuery },  ],});
2

CLI export (Python / Go / any stack)

If the agent is not written in JavaScript, use the flab CLI to export the catalog as a static JSON file, then load it in whatever prompt pipeline you use.

# Print to stdoutflab a2ui catalog
# Write to a fileflab a2ui catalog --out flab-a2ui-catalog.json

Then load it in Python:

import json
with open("flab-a2ui-catalog.json") as f:    catalog = json.load(f)
system_prompt = f"""You generate A2UI surfaces. Follow this catalog:{json.dumps(catalog, indent=2)}
Rules: {catalog['instructions']}Only use components listed in the catalog.Every component must have a "component" discriminator field.Data bindings use {{ "path": "/pointer/to/data" }} syntax."""
response = client.chat.completions.create(    model="gpt-4o",    messages=[        {"role": "system", "content": system_prompt},        {"role": "user", "content": user_query},    ],)
3

Token-optimised injection

The full catalog is ~650 lines of JSON. For token-constrained prompts, you can send only the components and instructions fields — this preserves all component definitions and generation guidance while cutting token usage by roughly 40%.

import { flabCatalog } from '@flabbergasted-ai/a2ui/catalog';
// Lean version — only what the agent needs to generate UIconst leanCatalog = {  instructions: flabCatalog.instructions,  components: flabCatalog.components,};
const systemPrompt =  'Generate A2UI surfaces using these components:\n' +  JSON.stringify(leanCatalog, null, 2);
4

Protocol-level catalogId negotiation

Beyond prompt injection, the A2UI protocol has first-class catalog support. When the agent sends a createSurface message it can declare which catalog it generated against via catalogId. The renderer matches this against its known catalogs and rejects surfaces with unknown IDs.

{  "version": "v1.0",  "createSurface": {    "surfaceId": "main",    "catalogId": "urn:flab-ui:a2ui:catalog:v1"  }}

Individual components can also carry a catalogId to support mixed-catalog surfaces — for example a Flab base catalog plus a domain-specific extension catalog:

{  "id": "custom-widget",  "component": "DealPipeline",  "catalogId": "https://acme.com/a2ui/crm-catalog.json",  "deals": { "path": "/deals" }}
5

End-to-end example

A complete loop: the agent receives the catalog in its system prompt, generates A2UI messages, and the renderer turns them into live Flab components.

// agent-side: build the prompt with the catalogimport { flabCatalog, FLAB_CATALOG_ID } from '@flabbergasted-ai/a2ui/catalog';
async function runAgent(userMessage: string) {  const response = await llm.chat({    system: [      'You are an A2UI agent. Respond ONLY with a JSON array of A2UI messages.',      'Catalog: ' + JSON.stringify(flabCatalog, null, 2),      'Every envelope MUST set "version" to "v1.0".',      'createSurface MUST set catalogId to ' + FLAB_CATALOG_ID + '.',    ].join('\n'),    user: userMessage,  });
  // Parse the LLM output as A2UI messages  const messages = JSON.parse(response.text);  return messages;  // → [  //   { version: "v1.0", createSurface: { surfaceId: "main", catalogId: FLAB_CATALOG_ID } },  //   { version: "v1.0", updateComponents: { surfaceId: "main", components: [...] } },  //   { version: "v1.0", updateDataModel: { surfaceId: "main", value: {...} } },  // ]}
// renderer-side: feed the messages through a transportimport { A2uiClient, A2UISurface, createMemoryTransport } from '@flabbergasted-ai/a2ui';
const transport = createMemoryTransport();const client = new A2uiClient(transport);client.connect();
const messages = await runAgent('Show a dashboard with 3 KPI stats');for (const msg of messages) {  transport.push(msg);}
// In your React tree:// <A2UISurface//   surface={client.surfaces.getSurface('main')!}//   onAction={(action) => {//     void client.onAction(action).catch((error) => console.error('A2UI action failed', error));//   }}// />

Tips

Use the discriminator

The catalog's $defs.anyComponent declares discriminator: { propertyName: 'component' }. Tell the agent to always set the component field first — it's the type tag the renderer switches on.

No colours, no CSS

The agent describes structure and data; visual styling is owned by the Flab theme. Instruct the agent to never emit colour values, class names, or inline styles. Use tone and variant enums instead.

Catalog drift protection

The package ships a catalog-drift.test.ts snapshot test that fails when the catalog changes unexpectedly. Re-export the JSON after component changes to keep agent prompts in sync.

Data bindings are JSON Pointers

Teach the agent that { "path": "/users/0/name" } binds a property to the surface data model. This is how components stay reactive — the renderer resolves pointers and re-renders when the model updates.

See the catalog in action: the showcases are real A2UI message streams generated against this catalog, rendered live into Flab components.