| name | rich-output |
| description | Rich content blocks for the ClawDad web UI. Use when responding to web channels (folder starts with "web_") to emit structured blocks — code, cards, tables, stats, progress bars, diffs, alerts, action buttons, files, forms — alongside standard markdown. |
Rich Output — Web UI Content Blocks
Critical syntax rules
Non-negotiable. Violations render as broken JSON in the chat.
- Only
:::blocks works — never :::card, :::alert, etc.
- Content MUST be a JSON array —
[{ ... }], even for a single block. Never a bare { ... } object.
- No prose inside the fence — only valid JSON between
:::blocks and :::.
- Closing
::: required — every :::blocks must have a matching ::: on its own line.
- Prose goes outside fences — text before/after the fence is markdown, not JSON.
Web only: if the channel isn't web (Slack, Discord, Telegram), don't use blocks — they render as raw JSON.
Block protocol
Wrap a JSON array in :::blocks / ::: fences. Mix prose and block fences freely.
Here's what I found:
:::blocks
[
{ "type": "alert", "level": "success", "body": "All checks passed." }
]
:::
Let me know if you want details.
Block type quick reference
For full field tables, JSON examples, and per-block guidance: Read references/block-types.md.
| Type | Key Fields | Use for |
|---|
text | content | Markdown prose (rarely needed — text outside fences is already markdown) |
code | content, language?, filename? | Code snippets with syntax highlighting and copy button |
card | title, body, icon?, footer?, rows?, status? | Status reports, summaries, self-contained info panels |
table | columns, rows | Structured data grids (cleaner than markdown tables) |
stats | stats: [{ icon?, label, value }] | Metric badges, counters, quick readouts |
progress | label, value, max, color? | Task completion, build progress |
alert | level (success/warn/error/info), body, title? | Important status changes, errors, warnings |
diff | content, filename? | Unified diffs with colored add/remove lines |
action | buttons: [{ id, label, style?, url?, target? }] | Clickable buttons — open URL, run portal specialist, or send [action: id] |
form | id, fields, title?, submitLabel? | Multi-field input collection — submits send [form: id] |
image | src, alt?, caption? | Inline images |
file | src, filename, mimeType?, caption? | Download card for non-image artifacts (PDF, CSV, JSON, txt, docx) |
sound | tone, label? | Notification tones |
Combining blocks
Multiple blocks per fence; multiple fences interleaved with prose:
I've analyzed your deployment:
:::blocks
[
{ "type": "alert", "level": "success", "body": "Deployment completed." },
{ "type": "stats", "stats": [{ "icon": "⏱️", "label": "Duration", "value": "3m 42s" }] }
]
:::
Want me to run the smoke tests?
:::blocks
[{ "type": "action", "buttons": [{ "id": "run_tests", "label": "Run Tests", "style": "primary" }] }]
:::
Updating blocks after emission
You can update a previously-emitted block in place — change a button's status to "Done", advance a progress bar, replace a stale stat. Lets you close the loop on actions instead of emitting a new message every change.
Two requirements:
- Give the block an explicit
id field when you emit it. Blocks without an id are not addressable.
- Call
mcp__nanoclaw__update_block({ message_id, block_id, state }) later. message_id is the host-assigned id on the <message> element in your conversation context.
For full state contracts (per-block-type fields, examples, ordering rules): Read references/update-block.md.
Common mistakes
- Bare objects without
[...] wrapper — always wrap in an array, even for one block.
- Using
:::card or :::alert — only :::blocks is the correct fence name.
- Mixing prose and JSON inside the same fence — prose goes OUTSIDE.
- Forgetting the closing
::: — every :::blocks must have a matching ::: on its own line.
- Broken markdown links inside blocks — use
[Title](url) not *[Title (url)*.
- Invalid JSON — missing commas, trailing commas, unquoted keys, unescaped newlines in strings.
Field naming
body and content are interchangeable on all block types. Use whichever feels natural.
- Array fields are named after what they contain:
stats, buttons, fields, rows, columns.
Guidelines
- Don't overuse blocks. A simple text answer doesn't need blocks. Use them when structure adds value.
- Mix prose and blocks. Blocks work best as visual anchors within a conversational response, not as a replacement for explanation.
- Keep JSON valid. Invalid JSON falls back to plain text rendering — the user sees raw JSON.
- Action buttons are for real choices. Don't present actions for trivial things.
- Cards for self-contained info. If the content makes sense as a standalone panel with a title, use a card.
- One alert per concern. Don't stack 5 alerts — combine related info into a single alert.