Catalog composition
The package intentionally does not ship an "all-in-one" catalog constant. A top-level array referencing every built-in defeats tree-shaking — every consumer of such an aggregate would bundle every component, even the components you don't use. Composition is per-component, and the cost is visible at the import site.
The minimum a renderer needs
If your app only renders, names alone are enough. Pass bare components —
the protocol name comes from displayName ?? component.name.
⚠️ Production minifiers will rename function declarations, which breaks the
component.namefallback. For production safety, set an explicitdisplayNameon every custom component (the string literal survives minification), or pair the component with itscatalog.jsonmanifest using the tuple form below — the manifest key is authoritative.
Bundlers tree-shake unused components — pulling Text does not drag in
Button, Card, etc.
Adding schemas for the agent handshake
If you want serializeCatalog(...) to emit JSON Schema for each component
(for the agent to know what props to send), pair each component with the
JSON the extractor emitted at dist/catalog/<Name>/catalog.json:
The protocol name lives in the JSON as the top-level key, so the runtime never duplicates it.
"I really want every built-in" - the paste-able recipe
This includes every built-in component and the A2UI v0.9 basic-catalog
function entries. The package intentionally does not export this as
catalog/all; keep the list at the integration site so the bundle cost stays
visible.
Drop the manifest import + tuple form for any component whose schema you
don't need to ship to the agent. Keep ...basicFunctions if your A2UI
messages use function calls in dynamic props, actions, or validation checks.
Custom components
A component is anything that takes a single props object and returns a
ReactNode. The function's name (or displayName) is the protocol name the
agent will use:
If you want schema introspection for a custom component, generate the
manifest with @lynx-js/genui/a2ui-catalog-extractor against your interface and
pair it the same way:
API surface
defineCatalog(inputs)— builds the runtime catalog. Inputs can mix bare components,[component, manifest]tuples, and already-resolved entries (e.g. frommergeCatalogs).mergeCatalogs(...catalogs)— last-write-wins on duplicate names.serializeCatalog(catalog)— emits the JSON manifest for the agent handshake. Components without an attached schema serialize to{ name }only.resolveCatalog(catalog)— name → component map (used internally by the renderer; exposed for advanced cases).

