Overview and architecture
This page explains what @lynx-js/genui/openui is, how OpenUI Lang maps to a
trusted ReactLynx component tree, and what happens between a streamed Agent
response and the rendered UI.
What this package is
@lynx-js/genui/openui is the ReactLynx client runtime for OpenUI Lang
v0.5. It combines the framework-agnostic parser and evaluator from
@openuidev/lang-core with a ReactLynx renderer and a built-in mobile component
library.
The package provides:
<OpenUiRenderer>for raw or pre-parsed OpenUI input;createOpenUiLibrary()and 26 trusted component implementations;- incremental parsing for model streams;
- reactive
$variables, expression evaluation, and form state; Query(),Mutation(), and multi-stepAction([...])execution;- structured parser, runtime, render, and tool errors;
- prompt builders that describe the matching component contract to an Agent.
It does not host an Agent, call an LLM, define your network transport, or provide backend tools. Your application owns those pieces.
Quick start
Install the package and optional default theme in a ReactLynx app:
The simplest valid response is:
OpenUI uses positional arguments. The parser maps them to named props in the order of each component's Zod schema. Forward references are allowed, so the root can refer to statements that appear later in the response.
The mental model
In ordinary React, your source code chooses a component and passes props:
In OpenUI, the Agent writes the same intent as declarative assignments:
The renderer never evaluates generated JavaScript. It parses the text against
the JSON Schema produced by your Library, turns valid component calls into an
element tree, and looks up each element's trusted ReactLynx implementation by
name. A component that is not in the Library cannot be rendered.
The Library is therefore the contract on both sides:
Keep the prompt Library and renderer Library aligned whenever you add or override a component. A name or prop-order mismatch can produce text that the client cannot validate.
OpenUI Lang v0.5 in one minute
An OpenUI program contains one assignment per line. There are three statement families:
Expressions can contain primitives, arrays, objects, references, member access,
operators, ternaries, and built-ins such as @Count(...). The renderer needs a
statement named root; by default its component must be Stack because that is
the default Library root.
State values are reactive. When $status changes, expressions that read it are
evaluated again and Queries whose arguments depend on it are refreshed.
For the complete language grammar and built-ins, read the OpenUI Lang v0.5 specification.
The end-to-end picture
OpenUI is a loop between an Agent that writes declarative UI and a client that parses, evaluates, and renders it.
- Your transport sends the user request to an Agent service.
- The service calls a model with an OpenUI system prompt built from the same component contract the client supports.
- The transport appends chunks to one accumulated
responsestring and passes it to<OpenUiRenderer>. - The streaming parser validates completed statements and resolves references.
- The runtime initializes state, evaluates expressions, and runs complete
Queries through your
toolProvider. - The renderer walks the evaluated root and mounts trusted ReactLynx components from the Library.
- User interactions execute action steps. Host-facing actions leave through
onAction; state and tool steps stay inside the runtime.
Inside the client
The raw response path creates the complete v0.5 runtime:
Important runtime behavior:
- Incremental parsing. The parser caches completed statements while the accumulated response grows. Forward references become renderable when their targets arrive.
- Stable Library. Create the Library once with
useMemoor outside the component. Changing its identity creates a new parser and can reset parsing work. - Streaming guard. Pass
isStreamingwhile generation is active. Query and mutation execution waits for stable output, and built-in interactions are disabled. - Reactive state.
$variablesand form values live in one external Store.onStateUpdatecan persist its snapshots;$-prefixed values ininitialStatehydrate reactive declarations. - Queries and mutations. Queries execute when their statements are complete
and re-run when referenced state changes. Mutations are registered but run
only when an action calls
@Run(mutationRef). - Sequential actions.
@Run,@Set,@Reset,@ToAssistant, and@OpenUrlexecute in order. A failed mutation stops the remaining steps. - Soft component failure. An element whose component name is not registered
renders nothing.
onErrorreceives other parse, evaluation, render, and tool failures after streaming settles.
Who owns what
<OpenUiRenderer> props
Use the raw response form for all new integrations.
<OpenUiRenderer result={parseResult} library={library}> remains available for
legacy/static callers. It can render a pre-parsed element tree and forward
simple actions, but it does not create the v0.5 QueryManager or fully execute
@Run, @Set, and @Reset. Do not use it for a new v0.5 integration.
Tool providers
For local functions, pass a name-to-function map:
You may also pass an MCP-compatible object with
callTool({ name, arguments }). The runtime extracts structured MCP tool
results before expression evaluation. Missing tools and tool failures are
reported through onError.
Exports
Component styles, the core renderer stylesheet, and the Material Icons font are
implementation details imported by the relevant modules. Do not import private
files under styles/catalog or dist/core.

