Open protocols: AG-UI · A2UI
Generative UI without the stack
AG-UI and generative-UI interfaces render in ~9 KB, with no React, no build step, no cloud. The lightweight render target for agent-driven UI.
- Zero dependencies
- MIT licensed
- No build step
What is generative UI?
Generative UI is interface an AI agent produces at runtime instead of text. Rather than returning a markdown table, the agent streams UI (values, components, whole forms) into a running app while the human watches and approves. Two open protocols standardize it, and they stack with MCP:
How an agent calls tools and reads resources on a backend: the action layer.
How an agent drives the frontend live over an event stream, human in the loop: the interaction layer.
How an agent declares UI against a host app's catalog of components: what the user touches.
AG-UI and A2UI list renderers for React, Angular, Lit, Flutter. None is lightweight, framework-agnostic, or build-free. That slot is the point of this page.
Render AG-UI in ~9 KB
An AG-UI stream is typed events over SSE. The client is a reducer: one event, one state mutation. LemonadeJS reactivity does the rest: the DOM patches delta-only as the agent streams. The demo below replays a real AG-UI event sequence, ending in a human-in-the-loop approval.
import { html, mount } from 'lemonadejs';
// AG-UI is an SSE stream of typed events. The client is a reducer:
// one event -> one state mutation. That is the entire integration.
const AgentView = (props, { state }) => {
const status = state('idle'); // run lifecycle
const log = state(''); // streamed tokens
const fields = state([]); // the UI the agent builds, live
const apply = (ev) => {
if (ev.type === 'RUN_STARTED') status.value = 'running';
else if (ev.type === 'TEXT_MESSAGE_CONTENT') log.value += ev.delta;
else if (ev.type === 'STATE_DELTA') {
const next = fields.value.slice();
const i = next.findIndex(f => f.key === ev.key);
i < 0 ? next.push(ev) : (next[i] = ev);
fields.value = next; // assignment notifies, DOM patches delta-only
}
else if (ev.type === 'AWAIT_APPROVAL') status.value = 'awaiting';
else if (ev.type === 'RUN_FINISHED') status.value = 'done';
};
// Production: const es = new EventSource('/agui');
// es.onmessage = (e) => apply(JSON.parse(e.data));
return html`<div>
<p>status: ${status}</p>
<pre>${log}</pre>
${() => fields.value.map(f => html`<div><b>${f.key}</b> ${f.value}</div>`)}
${() => status.value === 'awaiting' &&
html`<button onclick="${() => apply({ type: 'RUN_FINISHED' })}">Approve</button>`}
</div>`;
};
mount(AgentView, document.getElementById('agent')); ● live: a replayed AG-UI stream, rendering on this page
Swap the canned stream for new EventSource('/agui') and the same
reducer renders a real agent. Same pattern feeds STATE_DELTA into
a Studio datagrid, the grid agents render into.
You don't need the whole stack
AG-UI is an open protocol. You don't need a funded platform to render it; you need a renderer. Here is one in 9 KB.
| The enterprise agentic frontend stack | A 9 KB file |
|---|---|
| React + RSC + a build pipeline | Framework-agnostic, zero build |
| Cloud, Slack, Teams surfaces | Self-host, any backend, no cloud |
| The platform | The render primitive |
| Adopt a stack to ship | One script tag, one file |
A generative UI framework without React or a build step
Drop it into any page or any framework. Interop is built in, with no rewrite to adopt one piece.
Zero build
One <script> tag, working app. The whole renderer is one file an agent can ship.
Framework-agnostic
adaptReact(C) makes a component a real React component; createWebComponent(C) makes it a custom element.
Verified, not assumed
Components publish a typed contract; verify() proves conformance. Agents read interfaces, not source.