Flutter GenUI SDK — Conversational AI-Driven UI
Tech Stack: Flutter 3.41.x / Dart 3.10.9, genui package (experimental/alpha), A2UI Protocol v0.8+, Riverpod 3.x
What is GenUI?
GenUI is Flutter's official SDK for generative UI — it turns text-based LLM conversations into interactive native Flutter widgets at runtime. Instead of receiving walls of text from an AI agent, users interact with dynamically rendered graphical interfaces composed from a developer-defined widget catalog.
Key principle: The AI agent generates structured JSON (A2UI protocol); the Flutter client validates against an approved catalog and renders native widgets. Agents never generate Dart code — they describe intent via JSON, the client renders it safely.
Status: Highly experimental / alpha. API will change. Pin to a specific commit or version.
Iron Law
GENUI PAYLOADS ARE UNTRUSTED. VALIDATE COMPONENT TYPES AGAINST THE CATALOG BEFORE RENDERING. NEVER EXECUTE AGENT-PROVIDED CODE. NEVER RENDER UNREGISTERED WIDGET TYPES.
Core Concepts (6 Pillars)
| Concept |
Class/Type |
Role |
| Catalog |
Catalog (list of CatalogItem) |
Defines which widgets the AI is allowed to use — schemas + builders |
| Conversation |
Conversation |
Manages history, sends user input, invokes the model, drives the UI generation loop |
| A2UI Transport |
A2uiTransportAdapter, A2uiMessage |
Translates streamed model output into UI commands (GenUI uses A2UI under the hood) |
| DataModel |
DataModel |
Central observable state store — data binding and update flow |
| SurfaceController |
SurfaceController |
Processes messages, manages surfaces, keeps generated UI in sync |
| CatalogItem |
CatalogItem |
Individual widget registration — JSON schema + Dart builder function |
Package Structure
| Package |
Purpose |
genui |
Core framework — Catalog, Conversation, SurfaceController, rendering |
genui_a2a |
A2UI protocol connector for custom agent backends (ADK, REST, etc.) |
genai_primitives |
Technology-agnostic AI application types |
json_schema_builder |
Dart JSON Schema validation for widget definitions |
Prerequisites
Before Writing Any GenUI Code
- Read
reference/genui-catalog-design.md — how to define Catalog, CatalogItem, JSON schemas, builder functions
- Read
reference/genui-conversation-orchestration.md — Conversation lifecycle, model adapters, streaming loop
- Read
reference/genui-state-binding.md — DataModel, SurfaceController, reactive state, surface rendering
- Read
reference/genui-a2ui-transport.md — A2uiTransportAdapter, A2uiMessage, SSE streaming, JSONL parsing
- Read
reference/genui-functions.md — A2UIFunctionEvaluator, declarative functions (formatCurrency, required, email, and/or/not), integration pattern
- Read
reference/genui-custom-widgets.md — custom widget integration, Slider/AudioPlayer/Video, custom triage widgets
- Read
reference/genui-security.md — catalog allowlist enforcement, input sanitization, payload limits
- Verify Flutter/Dart APIs — Use
dart-mcp-server or Context7 MCP before using any API
Process
- Define the Catalog — Register all allowed widget types as
CatalogItem objects with JSON schemas and builder functions
- Configure Transport — Set up
A2uiTransportAdapter to connect to your AI agent backend (ADK SSE endpoint)
- Create Conversation — Initialize
Conversation with the catalog, transport adapter, and model configuration
- Build Surface Rendering — Use
SurfaceController to process incoming A2UI messages and render surfaces
- Implement DataModel Binding — Bind widget state to
DataModel for reactive updates
- Handle User Input — Wire user interactions back to the Conversation as structured events
- Add Custom Widgets — Register app-specific widgets (photo_upload, dropdown, rating, etc.)
- Write Tests — Unit tests for catalog validation, surface building, input handling
- Verify Build — Run
melos run test and flutter analyze
Reference Files
Detailed patterns are in reference/:
Core SDK
genui-catalog-design.md — Catalog, CatalogItem, JSON schema definition, builder patterns, widget registration
genui-conversation-orchestration.md — Conversation lifecycle, model adapter setup, message history, streaming loop
genui-state-binding.md — DataModel observable state, SurfaceController, surface management, reactive rendering
genui-a2ui-transport.md — A2uiTransportAdapter, A2uiMessage types, SSE/JSONL streaming, backend integration
genui-functions.md — A2UIFunctionEvaluator: validation (required, regex, email), formatting (formatCurrency, formatDate, pluralize), logical (and, or, not), navigation (openUrl) — full Dart implementation
Integration
genui-custom-widgets.md — Custom widget registration, extended A2UI catalog (Slider, AudioPlayer, Video), custom triage widgets (photo_upload, dropdown, free_text, rating, confirmation)
genui-security.md — Catalog allowlist enforcement, untrusted payload handling, input sanitization, size limits
A2UI Protocol (shared with Angular skill)
- See
../a2ui-angular/reference/a2ui-protocol.md for the full A2UI protocol spec (5 message types, JSONL format)
- See
../a2ui-angular/reference/a2ui-protocol-advanced.md for streaming, action model, Gemini quirks
Example Integration: Conversational Triage Flow
GenUI can power a triage flow — the conversational UI that replaces static request forms.
Flow:
- User describes issue (voice/text) ->
POST /triage/start returns { job_id }
- Flutter opens
GET /triage/{job_id}/stream SSE
- Agent streams
{ response, category, widgets[] } via A2UI protocol
GenUIRenderer renders widgets as native Flutter widgets
- User interacts -> next question streams -> repeat until triage complete
Fallback: If GenUI/ADK unavailable -> standard form fields shown; record needs_classification = true
File location in monorepo:
packages/shared_ui/
lib/
widgets/
gen_ui/
gen_ui_renderer.dart # SurfaceController + rendering logic
widget_catalog.dart # Catalog with all registered CatalogItems
widget_types.dart # Custom widget builders (PhotoUpload, etc.)
triage_conversation.dart # Conversation setup for triage flow
Anti-Patterns
// FORBIDDEN: Rendering arbitrary widget types from agent
Widget buildFromAgent(Map<String, dynamic> spec) {
// Agent controls what gets rendered — XSS/injection vector
return widgetRegistry[spec['type']]!(spec);
}
// REQUIRED: Validate against Catalog before rendering
Widget buildFromAgent(Map<String, dynamic> spec) {
final item = catalog.findByType(spec['type']);
if (item == null) {
logger.warning('Unknown GenUI type rejected: ${spec['type']}');
return const SizedBox.shrink(); // Skip unknown types
}
return item.builder(spec);
}
// FORBIDDEN: Executing agent-provided code
eval(spec['script']); // Dart doesn't have eval, but don't try alternatives
// FORBIDDEN: Using dynamic widget creation from agent strings
Function.apply(spec['handler'], []); // Never
// REQUIRED: Declarative catalog-based rendering only
// FORBIDDEN: Accepting unbounded payloads
final widgets = parseWidgets(response); // No size check
// REQUIRED: Enforce limits
final widgets = parseWidgets(response);
if (widgets.length > kMaxWidgets) {
widgets.removeRange(kMaxWidgets, widgets.length);
logger.warning('GenUI: payload truncated — exceeded $kMaxWidgets widgets');
}
Error Handling
- Agent returns unknown widget type -> skip silently (log warning), render remaining widgets
- Agent payload is malformed JSON -> show error state to user, log full error
- Agent connection drops mid-stream -> render what was received, show reconnect option
- User action dispatch fails -> show error snackbar, do NOT silently swallow
- GenUI SDK unavailable or fails to initialize -> fall back to static form fields
Common Commands
# Add GenUI dependency (from packages/shared_ui/)
# Note: GenUI is git-sourced, add to pubspec.yaml manually
# Bootstrap after adding dependency
melos bootstrap
# Run tests
melos run test
# Analyze
flutter analyze packages/shared_ui/
# Run specific GenUI tests
flutter test packages/shared_ui/test/widgets/gen_ui/
Documentation Sources
| Source |
URL / Tool |
Purpose |
| Flutter GenUI Docs |
https://docs.flutter.dev/ai/genui |
Official overview, concepts |
| GenUI Components |
https://docs.flutter.dev/ai/genui/components |
Catalog, CatalogItem, Conversation, DataModel, SurfaceController |
| GenUI Get Started |
https://docs.flutter.dev/ai/genui/get-started |
Setup, initialization, first app |
| GenUI Input Events |
https://docs.flutter.dev/ai/genui/input-events |
User interaction handling |
| GenUI GitHub |
https://github.com/flutter/genui |
Source code, examples, packages |
| A2UI Protocol |
https://a2ui.org/ |
Underlying protocol spec |
| A2UI GitHub |
https://github.com/google/A2UI |
Reference implementations |
| Dart MCP |
dart-mcp-server MCP |
Dart/Flutter API verification |
| Context7 |
Context7 MCP |
Library docs fallback |
1---2name: flutter-genui3description: Flutter GenUI SDK — conversational AI-driven UI using A2UI protocol. Use when building GenUI renderers, widget catalogs, Conversation orchestration, DataModel binding, SurfaceController setup, or SSE-streamed agent-to-UI flows in Flutter. Covers catalog design, A2UI transport, state binding, custom widgets, and triage integration.4---56# Flutter GenUI SDK — Conversational AI-Driven UI78> **Tech Stack**: Flutter 3.41.x / Dart 3.10.9, `genui` package (experimental/alpha), A2UI Protocol v0.8+, Riverpod 3.x910## What is GenUI?1112GenUI is Flutter's official SDK for **generative UI** — it turns text-based LLM conversations into interactive native Flutter widgets at runtime. Instead of receiving walls of text from an AI agent, users interact with dynamically rendered graphical interfaces composed from a developer-defined widget catalog.1314**Key principle:** The AI agent generates structured JSON (A2UI protocol); the Flutter client validates against an approved catalog and renders native widgets. Agents never generate Dart code — they describe intent via JSON, the client renders it safely.1516**Status:** Highly experimental / alpha. API will change. Pin to a specific commit or version.1718## Iron Law1920**GENUI PAYLOADS ARE UNTRUSTED. VALIDATE COMPONENT TYPES AGAINST THE CATALOG BEFORE RENDERING. NEVER EXECUTE AGENT-PROVIDED CODE. NEVER RENDER UNREGISTERED WIDGET TYPES.**2122## Core Concepts (6 Pillars)2324| Concept | Class/Type | Role |25|---------|-----------|------|26| **Catalog** | `Catalog` (list of `CatalogItem`) | Defines which widgets the AI is allowed to use — schemas + builders |27| **Conversation** | `Conversation` | Manages history, sends user input, invokes the model, drives the UI generation loop |28| **A2UI Transport** | `A2uiTransportAdapter`, `A2uiMessage` | Translates streamed model output into UI commands (GenUI uses A2UI under the hood) |29| **DataModel** | `DataModel` | Central observable state store — data binding and update flow |30| **SurfaceController** | `SurfaceController` | Processes messages, manages surfaces, keeps generated UI in sync |31| **CatalogItem** | `CatalogItem` | Individual widget registration — JSON schema + Dart builder function |3233## Package Structure3435| Package | Purpose |36|---------|---------|37| `genui` | Core framework — Catalog, Conversation, SurfaceController, rendering |38| `genui_a2a` | A2UI protocol connector for custom agent backends (ADK, REST, etc.) |39| `genai_primitives` | Technology-agnostic AI application types |40| `json_schema_builder` | Dart JSON Schema validation for widget definitions |4142## Prerequisites4344- Flutter >= 3.35.7 (3.41.x recommended)45- Add to `pubspec.yaml` in the package that uses GenUI (e.g., `packages/shared_ui/`):46 ```yaml47 dependencies:48 genui:49 git:50 url: https://github.com/flutter/genui.git51 path: packages/genui52 genui_a2a:53 git:54 url: https://github.com/flutter/genui.git55 path: packages/genui_a2a56 ```5758## Before Writing Any GenUI Code59601. **Read `reference/genui-catalog-design.md`** — how to define Catalog, CatalogItem, JSON schemas, builder functions612. **Read `reference/genui-conversation-orchestration.md`** — Conversation lifecycle, model adapters, streaming loop623. **Read `reference/genui-state-binding.md`** — DataModel, SurfaceController, reactive state, surface rendering634. **Read `reference/genui-a2ui-transport.md`** — A2uiTransportAdapter, A2uiMessage, SSE streaming, JSONL parsing645. **Read `reference/genui-functions.md`** — A2UIFunctionEvaluator, declarative functions (formatCurrency, required, email, and/or/not), integration pattern656. **Read `reference/genui-custom-widgets.md`** — custom widget integration, Slider/AudioPlayer/Video, custom triage widgets667. **Read `reference/genui-security.md`** — catalog allowlist enforcement, input sanitization, payload limits678. **Verify Flutter/Dart APIs** — Use `dart-mcp-server` or Context7 MCP before using any API6869## Process70711. **Define the Catalog** — Register all allowed widget types as `CatalogItem` objects with JSON schemas and builder functions722. **Configure Transport** — Set up `A2uiTransportAdapter` to connect to your AI agent backend (ADK SSE endpoint)733. **Create Conversation** — Initialize `Conversation` with the catalog, transport adapter, and model configuration744. **Build Surface Rendering** — Use `SurfaceController` to process incoming A2UI messages and render surfaces755. **Implement DataModel Binding** — Bind widget state to `DataModel` for reactive updates766. **Handle User Input** — Wire user interactions back to the Conversation as structured events777. **Add Custom Widgets** — Register app-specific widgets (photo_upload, dropdown, rating, etc.)788. **Write Tests** — Unit tests for catalog validation, surface building, input handling799. **Verify Build** — Run `melos run test` and `flutter analyze`8081## Reference Files8283Detailed patterns are in `reference/`:8485### Core SDK86- `genui-catalog-design.md` — Catalog, CatalogItem, JSON schema definition, builder patterns, widget registration87- `genui-conversation-orchestration.md` — Conversation lifecycle, model adapter setup, message history, streaming loop88- `genui-state-binding.md` — DataModel observable state, SurfaceController, surface management, reactive rendering89- `genui-a2ui-transport.md` — A2uiTransportAdapter, A2uiMessage types, SSE/JSONL streaming, backend integration90- `genui-functions.md` — `A2UIFunctionEvaluator`: validation (required, regex, email), formatting (formatCurrency, formatDate, pluralize), logical (and, or, not), navigation (openUrl) — full Dart implementation9192### Integration93- `genui-custom-widgets.md` — Custom widget registration, extended A2UI catalog (Slider, AudioPlayer, Video), custom triage widgets (photo_upload, dropdown, free_text, rating, confirmation)94- `genui-security.md` — Catalog allowlist enforcement, untrusted payload handling, input sanitization, size limits9596### A2UI Protocol (shared with Angular skill)97- See `../a2ui-angular/reference/a2ui-protocol.md` for the full A2UI protocol spec (5 message types, JSONL format)98- See `../a2ui-angular/reference/a2ui-protocol-advanced.md` for streaming, action model, Gemini quirks99100## Example Integration: Conversational Triage Flow101102GenUI can power a **triage flow** — the conversational UI that replaces static request forms.103104**Flow:**1051. User describes issue (voice/text) -> `POST /triage/start` returns `{ job_id }`1062. Flutter opens `GET /triage/{job_id}/stream` SSE1073. Agent streams `{ response, category, widgets[] }` via A2UI protocol1084. `GenUIRenderer` renders widgets as native Flutter widgets1095. User interacts -> next question streams -> repeat until triage complete110111**Fallback:** If GenUI/ADK unavailable -> standard form fields shown; record `needs_classification = true`112113**File location in monorepo:**114```115packages/shared_ui/116 lib/117 widgets/118 gen_ui/119 gen_ui_renderer.dart # SurfaceController + rendering logic120 widget_catalog.dart # Catalog with all registered CatalogItems121 widget_types.dart # Custom widget builders (PhotoUpload, etc.)122 triage_conversation.dart # Conversation setup for triage flow123```124125## Anti-Patterns126127```dart128// FORBIDDEN: Rendering arbitrary widget types from agent129Widget buildFromAgent(Map<String, dynamic> spec) {130 // Agent controls what gets rendered — XSS/injection vector131 return widgetRegistry[spec['type']]!(spec);132}133134// REQUIRED: Validate against Catalog before rendering135Widget buildFromAgent(Map<String, dynamic> spec) {136 final item = catalog.findByType(spec['type']);137 if (item == null) {138 logger.warning('Unknown GenUI type rejected: ${spec['type']}');139 return const SizedBox.shrink(); // Skip unknown types140 }141 return item.builder(spec);142}143```144145```dart146// FORBIDDEN: Executing agent-provided code147eval(spec['script']); // Dart doesn't have eval, but don't try alternatives148149// FORBIDDEN: Using dynamic widget creation from agent strings150Function.apply(spec['handler'], []); // Never151152// REQUIRED: Declarative catalog-based rendering only153```154155```dart156// FORBIDDEN: Accepting unbounded payloads157final widgets = parseWidgets(response); // No size check158159// REQUIRED: Enforce limits160final widgets = parseWidgets(response);161if (widgets.length > kMaxWidgets) {162 widgets.removeRange(kMaxWidgets, widgets.length);163 logger.warning('GenUI: payload truncated — exceeded $kMaxWidgets widgets');164}165```166167## Error Handling168169- Agent returns unknown widget type -> skip silently (log warning), render remaining widgets170- Agent payload is malformed JSON -> show error state to user, log full error171- Agent connection drops mid-stream -> render what was received, show reconnect option172- User action dispatch fails -> show error snackbar, do NOT silently swallow173- GenUI SDK unavailable or fails to initialize -> fall back to static form fields174175## Common Commands176177```bash178# Add GenUI dependency (from packages/shared_ui/)179# Note: GenUI is git-sourced, add to pubspec.yaml manually180181# Bootstrap after adding dependency182melos bootstrap183184# Run tests185melos run test186187# Analyze188flutter analyze packages/shared_ui/189190# Run specific GenUI tests191flutter test packages/shared_ui/test/widgets/gen_ui/192```193194## Documentation Sources195196| Source | URL / Tool | Purpose |197|--------|-----------|---------|198| Flutter GenUI Docs | `https://docs.flutter.dev/ai/genui` | Official overview, concepts |199| GenUI Components | `https://docs.flutter.dev/ai/genui/components` | Catalog, CatalogItem, Conversation, DataModel, SurfaceController |200| GenUI Get Started | `https://docs.flutter.dev/ai/genui/get-started` | Setup, initialization, first app |201| GenUI Input Events | `https://docs.flutter.dev/ai/genui/input-events` | User interaction handling |202| GenUI GitHub | `https://github.com/flutter/genui` | Source code, examples, packages |203| A2UI Protocol | `https://a2ui.org/` | Underlying protocol spec |204| A2UI GitHub | `https://github.com/google/A2UI` | Reference implementations |205| Dart MCP | `dart-mcp-server` MCP | Dart/Flutter API verification |206| Context7 | `Context7` MCP | Library docs fallback |