Skip to main content
A formatting component is a block in the agent’s reply text that starts with ::: <name> and ends with :::. The model writes the block as plain text; each channel then turns it into what that channel can show: cards in the web widget, an interactive list on WhatsApp, an Adaptive Card in Teams, an attachment in email. Components exist so one agent can answer every channel from one persona and one set of skills without your code knowing where a reply is displayed.

From reply text to rendered message

The reply is ordinary Markdown with blocks embedded in it:
Before delivery, a messaging channel extracts every block it knows, sends each in its native form, and sends the remaining text as the message body. The same extraction runs for replies in a conversation and for messages you send with Channels.send to WhatsApp, Messenger, Instagram, and MessageBird. The web widget parses blocks in the browser and renders them while the reply streams. A channel that can’t render a block drops it or sends it as raw text; the matrix under Rendering by channel says which.

Taught blocks and instructed blocks

On every text channel the platform prompt teaches the model the syntax for list-item, horizontal-list-item, actions, links, images, and payment; on every channel except web it also teaches flow (WhatsApp only) and reaction. The model decides when to use them, so for predictable output say when and how in the persona or a skill’s context. Two blocks are never taught: documents and navigate appear only when your instructions include their syntax. Two cases change the rules. On the web channel (Lua Desktop and the admin dashboard’s chat) the model is told to prefer plain Markdown, to use cards only for options the end user picks from, and never to emit flow; the web widget is not on that channel (it reports pop) and gets the same rulebook as the messaging channels. A client that declares the plain-markdown capability gets plain Markdown and no blocks at all: lua chat declares it, and the HTTP chat API accepts it as clientCapabilities: ["plain-markdown"]. Voice turns get no blocks either; the same data goes through tools that show it on screen.

Rendered previews before release

Nothing shows a sandbox version with its blocks rendered. lua chat declares plain-markdown in both environments, so it prints Markdown and never a card, and lua chat --agent-version runs against production. Two clients render blocks, and both talk to the agent’s production version: the web widget, and the chat panel in the admin dashboard’s agent workspace, which is on the web channel and so gets the plain-Markdown-first rulebook; a block your instructions ask for still renders there. To see a reply on a real messaging app, test on Lua’s channels over WhatsApp, Messenger, Instagram, or Slack, which also deliver production. The HTTP chat API returns blocks as raw markers for your own client to render.

Rendering by channel

Three terms recur in the matrix. The messaging channels are WhatsApp, Messenger, Instagram, Slack, Teams, RCS, MessageBird, and iMessage; they share one extractor. Email has two forms: a generated inbox is the address Lua issues, and your own address is a mailbox you connected. A block a channel can’t render is either dropped, meaning the block is removed and the surrounding text is still sent, or reaches the reader as raw text, meaning the ::: lines are sent as written. SMS and Front have no extractor: a reaction block becomes its emoji, and every other block reaches the reader as raw text, so keep instructions for those channels to plain text. Your own address renders blocks into HTML; a generated inbox runs the messaging channels’ extraction, sends images and documents as attachments, and drops the rest.

Channel-scoped instructions

A block that works on one channel can leak on another, so scope the instruction: “On WhatsApp, send the verification flow …”, or in a tool read Lua.request.channel and return the block only where it renders (see Lua). When in doubt, list-item, actions, images, and payment travel furthest; every other block has a channel list to check first.

Limits

Next steps

list-item

The component most replies start with.

Write skill context

Where component instructions belong.

Send proactive messages

Blocks in messages the agent starts.

Channels

Every channel and its inbound and outbound names.