Let AI agents answer with interfaces, not just text.
An agent emits a small declarative JSON document. A runtime validates it, and a renderer draws it with your own components. No HTML, CSS or JavaScript from the model, so there is nothing to execute.
git clone https://github.com/Pranavtej/GenUI-Protocol.git && cd GenUI-Protocol && pnpm install && pnpm buildA document in, an interface out
This is a miniature of what the renderers do: inputs bound to a data model, templates that update as you type, and a submit action that sends an event to the agent.
{
"version": "1.0.0",
"data": {
"form": {
"name": ""
}
},
"root": {
"t": "card",
"p": {
"title": "Sign up"
},
"c": [
{
"t": "input",
"p": {
"label": "Name",
"value": {
"$bind": "form.name"
}
}
},
{
"t": "text",
"p": {
"content": {
"$tpl": "Hello {{form.name}}"
}
}
},
{
"t": "button",
"p": {
"label": "Send",
"onClick": {
"do": "submit",
"name": "signup",
"from": "form"
}
}
}
]
}
}Hello
Define, validate, render
Define or generate
An agent (or your code) emits a small declarative JSON document: nodes, data, bindings and actions. Build it with the JS or Python SDK, or let a model write it from the generated prompt.
import { ui, bind, actions, document, assertValid } from "@genui-protocol/sdk-js";
assertValid(document(
ui.card({ title: "Sign up" },
ui.input({ label: "Name", value: bind("form.name") }),
ui.button({ label: "Send", onClick: actions.submit("signup", "form") })),
{ form: { name: "" } },
));Validate
The runtime enforces size and depth limits, URL checks, allow-lists and duplicate-id rules. Invalid documents fail with readable errors, so a validate-and-repair loop can fix them.
$ genui validate doc.json # exit 1 + readable errors when invalid $ genui prompt # LLM system prompt, generated from the registry
Render
A renderer draws the document with your own components. UI events flow back to the agent, which replies with RFC 6902 patches or sequenced stream frames.
import { GenUiRenderer, createSession } from "@genui-protocol/renderer-react";
const session = createSession({ document, onEmit: (event) => agent.send(event) });
<GenUiRenderer session={session} />;A protocol, a hardened runtime, renderers and agent tooling
Nothing to execute
The model never writes HTML, CSS or JavaScript. It describes a document; your renderer decides how it looks.
Data binding and actions
$bind and $tpl expressions with two-way inputs, plus declarative actions: setData, toggle, navigate, emit and submit.
Patches and streaming
Atomic RFC 6902 patches, an id-keyed diff, and an ordered stream consumer that resyncs when it falls behind.
Agent tooling
An MCP server (stdio and REST/SSE), a prompt kit generated from the registry, JS and Python SDKs, a CLI, and genui-eval.
Your components
Theme through CSS variables, or register custom namespaced components alongside the 23 built-ins.
Conformance fixtures
Language-neutral test vectors for patches, validation, bindings, actions and rendering. TypeScript and Python both pass.
23 built-in components
The same set is implemented by the React and Angular renderers. Agents discover them through the registry, so the prompt never goes stale.
pagesectiongridflexstackdashboardcardtextheadingbuttontabsinputtextareaselectcheckboxtablechartkpitimelinedialogdrawerworkflowexecutionGraphRecorded from the real apps
Every clip comes from the playground and example apps in the repository.




Early, and honest about it
GenUI is 0.x. This is what exists today and what does not.
- Protocol, spec and JSON Schemas
- Validator, patches, streaming with resync
- React and Angular renderers (all 23 components)
- MCP server, JS and Python SDKs, CLI, prompt kit
- Shared conformance fixtures
- Packages are not published to npm or PyPI yet
- genui-eval has never run against a real model
- Vue, Svelte, React Native, SwiftUI, Flutter renderers
- Remote data sources, form validation rules, WebSocket transport
Want to help? Read CONTRIBUTING.md.