Text
model or codeMarkdown text. The default, and what every other component falls back to.
{
"type": "Text",
"markdown": "Traffic was **normal** this week."
}Traffic was **normal** this week.@intui/core · protocol v1
Interactive answers from agents, drawn on any surface.
An agent answers with a component tree (charts, tables, flows, buttons, forms) instead of only text. A renderer for each surface draws it: a terminal, a web page, an email, later native apps. Every tree also has a Markdown text form, so the model can read back what it showed, and every surface has a fallback.
tool call ──► Tree.parse ──► component tree ──► renderer: Claude Code
or code (validate, (Chart, Table, ├─► renderer: web
Tree.of check who Flow, Choice…) ├─► renderer: email
wrote it) │ └─► later: Swift, Kotlin
└──► toText(): what the model reads back
Chart and Stat are built by code from a query, never typed by the model. The model calls a tool that returns them.Choice or submitting a Form sends an IntuiEvent to the agent, naming the tree it came from."v": 1. Changes are additive, so trees in old transcripts and emails keep working.import { Tree, IntuiEvent, core } from "@intui/core";
// A tool's input schema: only what the model may write.
const inputSchema = core.writableBy("model").jsonSchema();
// Validate what the model sent. Throws IntuiError listing every problem.
const tree = Tree.parse(input, { author: "model" });
tree.toText(); // Markdown, returned as the tool result
// When the person presses a button:
const event = IntuiEvent.press(toolUseId, "next", "park");
tree.verify(event);
tree.describe(event); // 'Pressed "Park" in next (from toolu_1).'
Not on npm yet. For now, clone the repo.
Markdown text. The default, and what every other component falls back to.
{
"type": "Text",
"markdown": "Traffic was **normal** this week."
}Traffic was **normal** this week.Holds other components in a row or a column.
{
"type": "Group",
"direction": "row",
"children": [
{
"type": "Text",
"markdown": "**Ideas inbox**"
},
{
"type": "Label",
"text": "3 open",
"tone": "neutral"
}
]
}**Ideas inbox** · [3 open]A short tag with a tone, such as a status.
{
"type": "Label",
"text": "parked",
"tone": "muted"
}[parked]Rows and columns of short values. For comparisons and lists of records.
{
"type": "Table",
"columns": [
{
"key": "option",
"label": "Option"
},
{
"key": "streams",
"label": "Streams?"
}
],
"rows": [
{
"option": "Tool calls",
"streams": "No"
},
{
"option": "Markup in text",
"streams": "Yes"
}
]
}| Option | Streams? |
| --- | --- |
| Tool calls | No |
| Markup in text | Yes |A line or bar chart of one or more series, with optional markers.
{
"type": "Chart",
"kind": "line",
"title": "Visitors",
"unit": "visitors",
"series": [
{
"label": "This week",
"role": "primary",
"points": [
{
"x": "Mon",
"y": 120
},
{
"x": "Tue",
"y": 180
},
{
"x": "Wed",
"y": 90
}
]
},
{
"label": "Usual",
"role": "baseline",
"points": [
{
"x": "Mon",
"y": 110
},
{
"x": "Tue",
"y": 115
},
{
"x": "Wed",
"y": 105
}
]
}
],
"annotations": [
{
"at": "Tue",
"label": "New pricing page"
}
]
}**Visitors** (line chart, visitors)
| | This week | Usual (baseline) |
| --- | --- | --- |
| Mon | 120 | 110 |
| Tue | 180 | 115 |
| Wed | 90 | 105 |
Markers: Tue: New pricing pageOne number with a label, and optionally its change.
{
"type": "Stat",
"label": "Visitors",
"value": 1204,
"change": {
"value": 18,
"as": "percent"
},
"tone": "positive"
}**Visitors:** 1,204 (+18%)Steps joined by arrows: a process, a pipeline, how parts of a system connect.
{
"type": "Flow",
"steps": [
{
"id": "model",
"label": "Model tokens"
},
{
"id": "tree",
"label": "Component tree",
"detail": "Validated against the core schemas"
},
{
"id": "render",
"label": "Renderer",
"detail": "One per surface"
}
],
"links": []
}Model tokens → Component tree → Renderer
- **Component tree:** Validated against the core schemas
- **Renderer:** One per surfaceButtons. Pressing one sends an event back to the agent.
{
"type": "Choice",
"id": "next-step",
"prompt": "What next?",
"options": [
{
"id": "explore",
"label": "Start exploring",
"emphasis": "primary"
},
{
"id": "park",
"label": "Park"
}
],
"repeat": "once"
}What next?
[Start exploring] [Park]A few inputs and a submit button. Submitting sends the values back to the agent.
{
"type": "Form",
"id": "new-idea",
"fields": [
{
"id": "title",
"label": "Title",
"input": "text",
"required": true
},
{
"id": "source",
"label": "Source",
"input": "select",
"options": [
"self",
"client"
],
"required": false
}
],
"submitLabel": "Add idea"
}Form:
- Title (text, required)
- Source (select: self, client)
[Add idea]Agents add to IntUI while working on specific products. These rules keep core general.
series, tone, annotation: yes. pageviews, client, deal: no.tone: "warning" and role: "baseline", never colors or dash styles. Each renderer decides the look.proposals/.show tool that draws trees in the transcript.