blocks. Each block has a stable id, a kind from the closed set below, and a set of kind‑specific fields. A VIEWER MUST render every kind it claims to support and MUST render a fallback for kinds it does not (see Fallback).
The source of truth for the field set on every block is the Block interface in apps/hub/src/types.ts.
Common fields
Every block carries:id(string, required) — stable across edits; survives patches; URLs anchor on it.kind(string, required) — one of the kinds below, or a vendor extension shapedvendor.kind(see conformance.mdx#extension-namespaces).title(string, optional)metadata(object, optional) — extension data; viewers MUST ignore unknown keys.
Kinds
| Kind | Purpose | Notable fields |
|---|---|---|
heading | Section heading | text, level (1–6) |
markdown | Prose / mixed content | markdown |
image | Image asset | assetId OR url, alt, caption |
terminal | A command and its output | command, output, exitCode, language |
diff | Unified diff | diff (string of the diff body), language |
chart | Data visualization | chart: ChartSpec (type, axes, series) |
checklist | Items that can be checked off | items: ChecklistItem[] |
decision | A prompt for a human to pick from options | prompt, options |
link | External or internal URL card | url, title, caption, thumbnailUrl, thumbnailAssetId |
metadata | A small grid of key/value rows | metadata map |
video | Embedded video | assetId OR url, platform, duration, thumbnailUrl, thumbnailAssetId, posterAlt |
html | Free‑form rendered HTML | html (inline body, sandboxed) OR screenshotAssetId (rendered fallback image); optional sandbox, height, caption |
collection | A list of mixed items | items: ChecklistItem[] (used as item rows), pageSize |
form | A small input form | fields: FormField[] |
orderable-list | A list with drag‑to‑reorder | orderableItems: OrderableItem[], optional itemEditor: FormSchema, optional total |
split | Weighted split into named slices | slices: SplitSlice[] |
rule-builder | A typed rule builder | ruleSchema: RuleSchema, clauses: RuleClause[] |
ChartSpec.series[].data[], FormField.type) is normative and lives in apps/hub/src/types.ts. A future MINOR bump MAY add new kinds; viewers MUST forward‑compatibly fall back to a labeled placeholder.
Fallback
When a VIEWER encounters ablock.kind it does not support, it MUST:
- Render a visually distinct placeholder that includes the
kindvalue and the blockid. - Preserve the block in the document model so that round‑trips do not drop it.
- Not block the rest of the canvas from rendering.
<UnknownBlock> card with the kind label visible.
Edit ops and block kinds
POST /v1/canvases/:id/edits (see lifecycle.mdx#canvas-edits) carries ops that target specific block kinds. The HUB MUST validate kind/op compatibility via opRequiresBlockKind. A consumer that authors edits MUST consult apps/hub/src/validation.ts for the current op→kind mapping; a future MINOR bump SHOULD lift that mapping into this document.
HTML blocks
Thehtml kind lets an agent emit a free‑form rendered view — a small report, a chart, an annotated screenshot, or any HTML fragment a reviewer should see verbatim. Two carriers are supported, and a block MAY include either or both:
html— an inline HTML body, capped at 256 KiB. VIEWERS MUST render it inside a sandboxed iframe usingsrcdoc. The defaultsandboxisstrict(no allowances).sandbox: "relaxed"MAY grantallow-scripts; a VIEWER MUST NOT grantallow-same-originorallow-top-navigationfor either mode.screenshotAssetId— an image asset (typically a PNG/JPEG of the rendered HTML). The HUB MUST validate that the asset exists in the bound canvas’s workspace and SHOULD decorate the block with a publicscreenshotUrlwhen an asset CDN is configured. VIEWERS MUST display this image as a fallback whenhtmlis absent or when execution is blocked by viewer policy.
title,caption— same conventions asimage.height— initial iframe height in CSS pixels, 1–1600; VIEWERS MAY clamp.
html nor screenshotAssetId is invalid and the HUB MUST reject it with HTTP 400.
Agents SHOULD prefer html when reviewers benefit from interactive content (sortable tables, hover details, sparklines) and SHOULD include screenshotAssetId whenever a frozen visual record is also useful — for example, post‑run reports archived after the live session ends.
Assets
Blocks that reference assets do so byassetId. The HUB MUST validate that any viewer session with asset.read can only fetch assets referenced by its bound canvas (see auth.mdx#viewer-links).
A canvas MAY embed asset bodies inline by base64 only inside an exported CanvasBundle (bundle.assets[].bodyBase64). Top‑level canvases delivered through GET /v1/canvases/:id MUST reference assets by id, never by inline body.