Documentation Index
Fetch the complete documentation index at: https://prefab.prefect.io/docs/llms.txt
Use this file to discover all available pages before exploring further.
The Prefab protocol defines the JSON wire format exchanged between a server (Python SDK) and a client (renderer). A server returns a UIResponse that serializes to the envelope below. The renderer parses it, resolves templates, interpolates state, and renders the component tree.
Envelope
Every response is a JSON object with clean top-level keys:
{
"version": "0.2",
"view": { ... },
"defs": { ... },
"state": {
"count": 42,
"name": "Alice"
}
}
| Key | Type | Description |
|---|
version | string | Protocol version (currently "0.2") |
view | Component | The root component tree to render |
defs | object | Optional map of template name to component subtree (see Define/Use below) |
state | object | Optional client-side state, accessible via {{ key }} interpolation |
State keys must not start with $ (reserved for interpolation builtins like $event and $error).
Components
Every component is a JSON object with a type discriminator:
{
"type": "Badge",
"label": "Active",
"variant": "success"
}
All components share these optional base fields:
| Field | Type | Description |
|---|
id | string | HTML id attribute, applied to the outermost element |
cssClass | string | Additional Tailwind CSS classes |
Container components (Row, Column, Card, etc.) also have a children array of nested components.
For conditional rendering, use the Condition component with cases and an optional else branch.
Actions
Actions define what happens on user interaction. They appear in event handler fields like onClick, onChange, and onSubmit. An action uses an action discriminator instead of type:
{
"action": "toolCall",
"tool": "get_weather",
"arguments": { "city": "{{ city }}" }
}
Action fields accept a single action, an array of actions (executed sequentially), or null:
{
"type": "Button",
"label": "Submit",
"onClick": [
{ "action": "setState", "key": "loading", "value": true },
{ "action": "toolCall", "tool": "process" }
]
}
Available action types:
| Action | Discriminator | Description |
|---|
| SetState | setState | Set a client-side state variable |
| ToggleState | toggleState | Flip a boolean state variable |
| CallTool | toolCall | Call a server-side tool |
| SendMessage | sendMessage | Send a message to the chat |
| UpdateContext | updateContext | Silently update model context |
| OpenLink | openLink | Open a URL |
| ShowToast | showToast | Display a toast notification |
Interpolation
All string properties support {{ key }} placeholders that resolve against client-side state at render time. The special value {{ $event }} captures the triggering interaction’s value (slider position, input text, checkbox state, etc.).
{
"type": "P",
"content": "Hello, {{ name }}! You have {{ count }} items."
}
Define / Use (Templates)
Templates let you define a component subtree once and reference it multiple times with different data.
Defining a template — entries in defs map a name to a component subtree:
{
"defs": {
"user-card": {
"type": "Card",
"children": [
{ "type": "CardTitle", "content": "{{ name }}" },
{ "type": "CardDescription", "content": "{{ role }}" }
]
}
}
}
Using a template — a $ref node references a definition by name:
With scoped data — add let bindings to the $ref node:
{
"$ref": "user-card",
"let": { "name": "Alice", "role": "Engineer" }
}
The renderer resolves $ref nodes by looking up the definition and rendering it with the current interpolation context. Circular references are detected and short-circuited.