Skip to Content
GuidesProteus

Proteus

Proteus is a JSON-based UI specification for building interactive tool interfaces. You define your UI as a JSON document, and the Proteus renderer (@optiaxiom/proteus) turns it into interactive Axiom components.

Document structure

A Proteus document is a JSON object with $type: "Document". At minimum it needs a body:

{ "$type": "Document", "body": [ { "$type": "Heading", "children": "Hello World" }, { "$type": "Text", "children": "Welcome to Proteus." } ] }

Every element has a $type that identifies the component. The children property holds nested content: a string, number, another element, or an array of elements.

Documents also support title, subtitle, appName, appIcon, and actions (buttons rendered at the bottom). Set blocking to true to hide the chat input and force the user to interact with the UI before continuing.

{ "$type": "Document", "appName": "Task Manager", "title": "Create Task", "subtitle": "Fill out the form below", "body": [ { "$type": "Field", "label": "Task Name", "children": { "$type": "Input", "name": "task_name", "placeholder": "Enter task name", "required": true } } ], "actions": [ { "$type": "Action", "children": "Create", "appearance": "primary" }, { "$type": "CancelAction", "children": "Cancel" } ], "blocking": true }

Components

Use Group as a flexbox container to arrange child elements. It supports flexDirection, gap, alignItems, and justifyContent. Card, CardHeader, and CardLink provide card-based layouts. Separator adds a visual divider.

{ "$type": "Group", "flexDirection": "column", "gap": "12", "children": [ { "$type": "Card", "children": [ { "$type": "CardHeader", "children": "Settings" }, { "$type": "Text", "children": "Configure your preferences below." } ] }, { "$type": "Separator" }, { "$type": "Text", "children": "More content here." } ] }

Heading renders section headings, Text renders inline or block text, and Link renders a hyperlink with an href prop.

[ { "$type": "Heading", "children": "Welcome" }, { "$type": "Text", "children": "Get started by filling out the form.", "fontSize": "sm", "color": "fg.secondary" }, { "$type": "Link", "href": "https://example.com", "children": "Learn more" } ]

DataTable renders structured data with columns, sorting, and pagination. Chart renders bar or line charts. Image and ImageCarousel display images. Avatar, Badge, and Time handle user avatars, status tags, and formatted timestamps.

{ "$type": "DataTable", "columns": [ { "header": "Name", "accessorKey": "name" }, { "header": "Status", "accessorKey": "status" } ], "rows": { "$type": "Value", "path": "/items" } }

Wrap inputs with Field to add a label. Available inputs include Input, Textarea, Select (composed from SelectTrigger and SelectContent), Switch, Range, and Question (a multi-question dynamic form).

[ { "$type": "Field", "label": "Email", "children": { "$type": "Input", "name": "email", "placeholder": "you@example.com", "required": true } }, { "$type": "Field", "label": "Category", "children": { "$type": "Select", "name": "category", "children": [ { "$type": "SelectTrigger", "children": "Choose a category" }, { "$type": "SelectContent" } ] } }, { "$type": "Field", "label": "Notifications", "children": { "$type": "Switch", "name": "notifications" } } ]

Action renders a button with an onClick handler (see Interactions below). CancelAction renders a cancel button that abandons the current interaction.

[ { "$type": "Action", "children": "Submit", "appearance": "primary", "onClick": { "interaction": "submit_form" } }, { "$type": "CancelAction", "children": "Cancel" } ]

All components accept Axiom styling props for spacing, colors, layout, and typography:

{ "$type": "Group", "flexDirection": "column", "gap": "8", "p": "12", "bg": "bg.error.subtle", "rounded": "md", "maxH": "sm", "children": { "$type": "Text", "children": "Styled container", "color": "fg.error", "fontSize": "sm", "fontWeight": "500" } }

Available props include p, px, py, m, mb, mt, bg, color, fontSize, fontWeight, rounded, display, gap, flexDirection, alignItems, justifyContent, maxH, maxW, overflow, and objectFit.

Data binding

Reads a field from the tool response using a JSON Pointer path:

{ "$type": "Value", "path": "/title" }

Paths starting with / are absolute (from the root of the tool response). Paths without a leading / are relative (resolved from the current context, like inside a Map).

Iterates over an array, rendering children once per item. Inside a Map, relative paths resolve against the current item:

{ "$type": "Map", "path": "/results", "children": { "$type": "Text", "children": { "$type": "Value", "path": "name" } } }

MapIndex gives you the current iteration index inside a Map. Concat joins multiple values into a single string. Zip combines parallel arrays into an array of objects.

{ "$type": "Concat", "children": [ "Item #", { "$type": "MapIndex" }, ": ", { "$type": "Value", "path": "name" } ] }

Given this tool response:

{ "title": "Search Results", "results": [ { "name": "Widget A", "price": 9.99 }, { "name": "Widget B", "price": 14.99 } ] }

This template renders the results dynamically:

{ "$type": "Document", "title": { "$type": "Value", "path": "/title" }, "body": { "$type": "Map", "path": "/results", "children": { "$type": "Card", "children": [ { "$type": "Heading", "children": { "$type": "Value", "path": "name" } }, { "$type": "Text", "children": { "$type": "Concat", "children": ["$", { "$type": "Value", "path": "price" }] } } ] } } }

Conditional rendering

Use Show to render content only when a condition is met:

{ "$type": "Show", "when": { "!!": { "$type": "Value", "path": "/error" } }, "children": { "$type": "Text", "children": "An error occurred", "color": "fg.error" } }

Supported operators: ==, !=, <, <=, >, >=, !! (truthy), ! (falsy). Combine conditions with and and or:

{ "$type": "Show", "when": { "and": [ { "!!": { "$type": "Value", "path": "/items" } }, { "!=": [{ "$type": "Value", "path": "/status" }, "loading"] } ] }, "children": { "$type": "Text", "children": "Items loaded" } }

Interactions

Calls a server-side interaction handler registered with the SDK:

{ "$type": "Action", "children": "Submit", "appearance": "primary", "onClick": { "interaction": "submit_form" } }

Sends a text message back to the LLM:

{ "$type": "Action", "children": "Continue", "onClick": { "message": "User confirmed the selection" } }

Triggers a file download:

{ "$type": "Action", "children": "Download Report", "onClick": { "action": "download", "url": { "$type": "Value", "path": "/download_url" } } }

When blocking is set to true on the Document, the chat input is hidden and the user must click an Action or CancelAction to continue. Use this for forms that require explicit user input before proceeding.

Proteus Designer

The Proteus Designer is a visual editor for building Proteus documents. You can build a component tree, edit properties in the inspector, see a live preview of how the document renders, and copy the final JSON into your resource handler. You can also provide sample data to test how dynamic values resolve.

Last updated on