Blocks
Structured, typed visual outputs for agent work — DataSpec, MCP Apps, apps, and 13 show primitives.
Blocks are typed outputs that make agent work inspectable. Alumia ships 16 registered runtime block definitions and 13 showable system primitives. MCP App blocks render hand-coded connector UIs in sandboxed iframes. Every canvas block is created through one of four paths — the agent picks the right one based on what it's emitting.
The four block paths
| Path | Block type | When |
|---|---|---|
data_block tool | type: "data" | Default for any structured data display. The agent emits a typed DataSpec; the renderer builds 100% shadcn UI from it. |
show tool | one of 13 system primitives | Interactive primitives with their own state and behaviour — see below. |
| MCP App reference | type: "mcp-app" | Real connector outputs (Gmail, Slack, GitHub, Notion, Linear, Stripe, etc.). Created by connector flows. Renders a hand-coded ui.tsx in a sandboxed iframe. |
app_create | type: "app" | Multi-file mini-app the user explicitly asked for. Multi-file project + sqlite. |
The AI never writes UI code outside of apps. DataSpec is typed JSON the agent fills; MCP App ui.tsx is hand-coded by humans; apps are explicit user request only.
DataSpec sub-types (the data_block catalog)
A data block's data field is a DataSpec. Pick the right type:
type | Use for |
|---|---|
markdown | Long-form prose, notes, summaries |
callout | Highlighted info/warning/success/danger bands |
metric | One headline number with delta + label |
kpi-grid | A small grid of metrics |
card | A single rich card with title, body, image, actions |
table | Rows × columns — sortable, filterable, sticky header, drag-reorder columns, resizable columns |
list | Vertical list of titled items with optional images, statuses, actions |
form | An input form with typed fields and submission |
chart | Line, bar, area, pie, or scatter |
timeline | Dated events down a left rail |
kanban | Columns of cards (drag between columns) |
dashboard | A composition of metrics, charts, and lists |
gallery | Images, videos, audio — single or multi |
app-view | App-shaped previews via named presets (tweets, emails, products, calendar events, contacts, files, etc.) |
map | A pannable map with markers |
steps | A numbered sequence |
comparison | Side-by-side comparison of options |
calendar | Calendar grid with events |
pdf | A rendered PDF preview |
Each sub-type has a strict Zod schema. The agent fills the fields; the renderer is hand-built with shadcn primitives.
Variant whitelists
The agent picks from these — never invents values:
- Buttons / badges:
default | secondary | destructive | outline | ghost | muted - Status:
default | success | warning | destructive | info | muted - Trend:
up | down | neutral - Chart kind:
line | bar | area | pie | scatter
Colors
When a DataSpec field accepts a hex (e.g. a chart series colour, callout marker, badge accent), the AI picks from a curated 12-colour 2026 palette: slate, azure, iris, emerald, sage, amber, honey, rose, violet, teal, fuchsia, plus cloud (Pantone 2026). No neon, no fully-saturated CSS named colours, no invented hexes.
The 13 show primitives
Use the show tool only for interactive primitives that have their own state and behaviour. Plain data displays belong in data_block.
document, review, code, spreadsheet, google-workspace, draw, browser, sandbox, terminal, timer, stopwatch, swarm, chat.
draw (Excalidraw), browser (live Browserbase session), and google-workspace (linked Google Docs/Sheets/Slides) are "native interactive" blocks — their content is always interactive, never a drag target.
Workboards are grouped blocks
A workboard is a grouped composition of normal blocks, not a separate runtime block definition. The registry still has 16 registered runtime block definitions; workboard membership is stored on each block's persisted canvas position as groupId, groupLabel, and groupKind.
Agents use compose_canvas when the answer needs several related blocks to land as one coherent surface. compose_canvas accepts ordered sections, item refs, and 1–12 column spans; the deterministic layout engine computes coordinates, inserts headings, and writes the full group atomically. The group can include data blocks and valid show primitives, but it cannot invent UI code, raw JSX, or a new block type.
Agents use recompose_canvas when a workboard already exists. It replaces the existing group under the same durable groupId, preserves the group's identity, and avoids leaving stale blocks beside the new version. For small edits inside one existing block, agents still use search_block plus update_block.patch.
App-view presets
app-view is the DataSpec sub-type for generated drafts and previews that should look like a recognizable app surface. Examples:
- Social:
social-post,social-thread,social-poll,social-profile— Twitter / X / LinkedIn / Bluesky / Threads. Threads render with a continuous left connector line linking avatars. - Messaging:
message-thread,message-direct— Slack-style with avatars (themed viabg+colorhex on the avatar spec), timestamps, hover rows. - Email:
email-draft,email-inbox— Gmail-style. - Work items:
issue-task,pull-request— GitHub / Linear style. - Commerce:
product-card,cart,checkout,order— Shopify style with line items, totals, statuses. - Calendar:
calendar-event,calendar-agenda. - Media:
audio-track,audio-playlist,video-clip,video-playlist— ElevenLabs-style pill audio player; playlists auto-fit to their content height. - Files:
file-preview,pdf-preview. - Generic web:
bookmark,link-preview,news-article,quote. - Domain-specific: weather, sports, finance, food, healthcare, real-estate, gaming, science, info.
Real connector outputs still become mcp-app blocks via connector flows. app-view is for the agent's own drafts and previews.
Social posts must include media
When drafting a tweet, X / LinkedIn / Bluesky / Threads post, or any app-view with surface: "social", the agent fetches or generates a relevant image, saves it via image_save, and attaches it on media.fileId. A tweet without media looks unfinished. The only exception is when the user explicitly says "text only".
Images on the canvas
Never put external https:// URLs directly in DataSpec image fields — browsers will block them with CORS errors. The agent always calls image_save first, gets a file id, and references it via fileId (preferred) or src: "file:<id>". The renderer resolves file ids to a canvas-safe URL automatically.
Why blocks matter
- They keep long-running work visible
- They make apps easier to review than raw JSON
- They give agents a stable object to update (via
update_blockpatches) instead of rewriting whole conversations
Use blocks whenever the output has structure, needs revision, or should remain visible after the chat moves on.
How agents discover and edit blocks
search_blocks— list/search canvas blocks by query and typecompose_canvas— create a grouped multi-block workboard atomicallyrecompose_canvas— replace an existing grouped workboard under the same group idsearch_block— find exact JSON Pointer paths inside one block's data (for patch operations)read_block/narrate_block— read full data; narrate for voice modesupdate_block— acceptstitle,patch(array of JSON Pointer ops), or both. Preferpatchover replacing wholedatadelete_block— soft-deletecanvas_inspect— schema/render validation after creating or patchingcanvas_screenshot— visual verification when layout matters
Two workflow rules the agent follows:
- Search before creating. If a block of the same purpose exists,
update_blockit instead of creating a duplicate. - Patch, don't replace. Use
search_blockto find JSON Pointer paths (e.g./content,/rows/2/status), thenupdate_blockwithpatchfor surgical edits. - Compose related surfaces. If the answer naturally needs three or more related blocks, use
compose_canvasinstead of emitting one block at a time.