> ## Documentation Index
> Fetch the complete documentation index at: https://comis-feature-skill-archive-import.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Rich Messages

> Buttons, cards, and effects across Discord, Telegram, Slack, and more

**Can my agent send buttons people can click? A poll? A pretty card with an
image?** On the platforms that support those, yes — your agent describes
them once in a platform-neutral way and Comis renders them natively
per-channel. On platforms that do not (IRC, Email, Signal, iMessage), Comis
falls back to plain text so the message still gets through.

Your agents can send more than just text. Rich messages include interactive
buttons, styled cards with images and fields, and special effects like spoiler
text. Comis provides a unified way to create these -- your agent writes them
once, and Comis renders them correctly on each platform using that platform's
native features.

Polls are also available, but they are dispatched through the
`platform_action` tool (action: `poll`) rather than as part of a normal
`message` send. See [Platform Actions](/agent-tools/platform-actions) for the
full poll parameters.

<Info>
  You don't need to understand the technical details to use this feature. The configuration examples below are copy-paste ready.
</Info>

## What Your Agent Can Send

Comis supports three types of rich messages plus polls via platform actions:

* **Buttons** -- Clickable actions that appear below a message. Users tap a
  button instead of typing a response. Great for choices like "Yes/No,"
  "Approve/Reject," or navigation menus.

* **Cards (Embeds)** -- Styled message blocks with a title, description, optional
  image, color accent, and structured fields. Think of them like a mini web page
  embedded in the chat.

* **Effects** -- Special delivery modifiers like spoiler (content hidden until
  tapped) and silent (no notification sound).

* **Polls** -- Question + 2-10 options, dispatched via `platform_action` (not
  the `message` tool). Available on Discord, Telegram, and WhatsApp.

## Platform Support

Not every platform supports every rich message type. The table below shows what
works where.

| Feature                       | Discord | Telegram    | Slack | LINE | WhatsApp            | Signal | iMessage | IRC | Email |
| ----------------------------- | ------- | ----------- | ----- | ---- | ------------------- | ------ | -------- | --- | ----- |
| Buttons                       | Yes     | Yes         | Yes   | No   | Stubbed (text only) | No     | No       | No  | No    |
| Cards/Embeds                  | Yes     | Styled text | Yes   | No   | No                  | No     | No       | No  | No    |
| Spoiler                       | Yes     | Yes         | No    | No   | No                  | No     | No       | No  | No    |
| Silent                        | Yes     | Yes         | No    | No   | No                  | No     | No       | No  | No    |
| Polls (via `platform_action`) | Yes     | Yes         | No    | No   | Yes                 | No     | No       | No  | No    |

<Info>
  When your agent tries to send a rich message to a platform that does not support
  it, Comis gracefully falls back to plain text. Buttons become a numbered list,
  cards become formatted text, and polls are not sent. Your agent's message always
  gets through.
</Info>

## Buttons

Buttons give users a quick way to respond without typing. Your agent defines the
button labels and what happens when each is clicked. Buttons are the most commonly
used rich message type -- they work on the most platforms and provide a simple,
intuitive interaction.

### Button Types

There are two kinds of buttons:

* **Action buttons** use `callback_data` -- when a user clicks the button, the
  identifier is sent back to the agent so it knows which button was pressed.
* **Link buttons** use `url` -- clicking the button opens a web page in the
  user's browser. No data is sent back to the agent.

### Button Properties

| Property        | Type   | Description                                                               |
| --------------- | ------ | ------------------------------------------------------------------------- |
| `text`          | string | The label shown on the button                                             |
| `callback_data` | string | Identifier sent back when the button is clicked                           |
| `url`           | string | URL to open (for link buttons -- mutually exclusive with `callback_data`) |
| `style`         | string | Visual hint: `primary`, `secondary`, `danger`, or `link`                  |

Each button is either an **action button** (sends `callback_data` back to the
agent when clicked) or a **link button** (opens a URL in the user's browser).
You cannot have both `callback_data` and `url` on the same button.

### Platform Limits

<AccordionGroup>
  <Accordion title="Discord">
    Buttons appear in "action rows." Maximum 5 buttons per row and 5 rows per
    message (25 buttons total). Supports all 4 styles: primary (blue), secondary
    (gray), danger (red), and link (opens a URL).
  </Accordion>

  <Accordion title="Telegram">
    Buttons appear as inline keyboards below the message. Maximum `callback_data`
    length is 64 bytes -- longer values are silently truncated. URL buttons and
    callback buttons are both supported. Styles are not visually distinct (Telegram
    shows all buttons the same way regardless of the `style` property).
  </Accordion>

  <Accordion title="Slack">
    Buttons appear in actions blocks. Only `primary` and `danger` styles are
    supported -- other styles fall back to the default appearance. Each button
    needs a unique identifier internally.
  </Accordion>

  <Accordion title="LINE">
    The LINE adapter ships a Flex Message builder (`flex-builder.ts`) for
    rich-menu actions, but its `sendMessage` path does not currently render
    `RichButton` rows -- buttons are not delivered when sent through the
    `message` tool. The plugin self-declares `buttons: false`. The Flex
    builder limits action labels to 20 characters and postback data to 300
    characters when used directly through internal APIs.
  </Accordion>

  <Accordion title="WhatsApp">
    The WhatsApp plugin self-declares `buttons: true`, but the current
    adapter implementation logs button payloads and falls back to plain text
    \-- the buttons themselves are not yet rendered to the WhatsApp Business
    API. Treat WhatsApp button support as not yet implemented for end users.
  </Accordion>
</AccordionGroup>

<Warning>
  Keep `callback_data` short (under 64 bytes) and button labels under 20 characters
  for maximum cross-platform compatibility.
</Warning>

## Cards and Embeds

Cards are styled message blocks that stand out from regular text. They can include
a title, description, image, color accent, and structured fields. Cards are the
most visually rich message type and are ideal for displaying structured
information like status reports, product listings, or summaries.

### Card Properties

| Property      | Type   | Description                                                        |
| ------------- | ------ | ------------------------------------------------------------------ |
| `title`       | string | Card title (bold, larger text)                                     |
| `description` | string | Card body text                                                     |
| `image_url`   | string | URL for a thumbnail or hero image                                  |
| `color`       | number | Accent color as integer (e.g., `0x0099FF` for blue)                |
| `fields`      | array  | Structured key-value pairs with `name`, `value`, and `inline` flag |
| `buttons`     | array  | Button rows attached to the card                                   |

Fields are key-value pairs that appear inside the card. Each field has a `name`
(the label), a `value` (the content), and an `inline` flag. When `inline` is
true, fields are displayed side by side rather than stacked vertically.

### How Cards Render on Each Platform

<AccordionGroup>
  <Accordion title="Discord">
    Full embed support. Supports title, description, color sidebar, up to 25
    fields (inline or stacked), thumbnail image, and footer. Discord provides the
    richest card experience with native embed styling, color accents, and image
    previews.
  </Accordion>

  <Accordion title="Telegram">
    No native embed format. Cards are rendered as HTML-formatted text with bold
    titles, italic descriptions, and an invisible link for image previews. The
    result is functional but less visually striking than Discord embeds.
  </Accordion>

  <Accordion title="Slack">
    Uses Block Kit section blocks. Title becomes a header block, description
    becomes markdown text, fields render as two-column sections, and images
    become accessory elements. Slack's block layout provides a clean, structured
    appearance.
  </Accordion>

  <Accordion title="LINE">
    The LINE adapter does not render `RichCard` from the `message` tool today
    \-- the plugin self-declares `cards: false`. Cards sent to LINE fall back to
    the plain-text equivalent.
  </Accordion>
</AccordionGroup>

## Polls (via `platform_action`)

Polls let your agent ask a question and collect votes. Users click to select
their answer, and results are visible to everyone in the chat.

Polls are dispatched through the `platform_action` tool with `action: "poll"`,
not as part of a normal `message` send. See
[Platform Actions](/agent-tools/platform-actions) for the full tool reference.

### Poll Input Properties

| Property        | Type   | Description                                                                              |
| --------------- | ------ | ---------------------------------------------------------------------------------------- |
| `question`      | string | The poll question (required, non-empty)                                                  |
| `options`       | array  | 2 to 10 answer choices                                                                   |
| `maxSelections` | number | Maximum selections per voter (default: 1, must not exceed number of options)             |
| `durationHours` | number | How long the poll stays open. Clamped to 1-168 hours; defaults to 24 hours when omitted. |

The `maxSelections` property controls whether users can pick one answer or
multiple answers. Set it to 1 for single-choice polls (like "Which day works
best?") or higher for multi-select polls (like "Which features do you want?").

### Platform Support

<AccordionGroup>
  <Accordion title="Discord">
    Native poll support via `platform_action` (action: "poll"). Duration is
    clamped to 1-168 hours (1 hour to 7 days). Polls appear as a dedicated
    message type with clickable options and a live vote count.
  </Accordion>

  <Accordion title="Telegram">
    Native poll support via `platform_action`. Polls appear below the chat
    message with radio buttons (single-select) or checkboxes (multi-select).
    Results update in real time as users vote.
  </Accordion>

  <Accordion title="WhatsApp">
    Polls are sent through the WhatsApp adapter's `platform_action` handler
    using Baileys' poll-message support. Vote-result normalization is not yet
    wired (see code TODO), so the agent receives the poll-creation
    confirmation but does not yet receive vote callbacks.
  </Accordion>

  <Accordion title="Other platforms">
    Polls are not supported on Slack, LINE, Signal, iMessage, IRC, or Email.
    Calling `platform_action` with `action: "poll"` on these platforms returns
    an error. The accompanying text message (if any) is still sent through the
    normal `message` path.
  </Accordion>
</AccordionGroup>

## Effects

Effects are delivery modifiers that change how a message appears or is delivered.
They do not change the message content itself. Effects can be combined with any
other rich message type -- for example, you can send a card with a spoiler effect.

### Spoiler

Content is hidden behind a spoiler tag. Users must tap or click to reveal it.
Supported on Discord (spoiler markdown formatting) and Telegram (spoiler entity).

Common uses:

* Hiding quiz answers until the user is ready
* Concealing plot spoilers in entertainment channels
* Masking sensitive information that should not be visible at a glance

### Silent

The message is delivered without triggering a notification sound. Supported on
Discord (silent message flag) and Telegram (notification disabled).

Common uses:

* Low-priority status updates or periodic reports
* Automated messages that should not interrupt the user
* Batch notifications where only the first should make a sound

Effects are ignored on platforms that do not support them. The message is still
delivered normally -- it just does not have the spoiler or silent behavior.

## How Agents Create Rich Messages

Agents create rich messages through the `message` tool. The agent specifies
buttons, cards, polls, or effects as part of the message action. For example, an
agent might send a card with a summary and a row of buttons for the user to choose
from.

The agent does not need to know the specifics of each platform's message format.
Comis handles the conversion automatically. A single rich message definition works
across all connected platforms, with Comis adapting it to each platform's native
capabilities.

For the full tool reference and usage examples, see
[Messaging Tools](/agent-tools/messaging).

<Tip>
  Your agent does not need to know which platform the user is on. Comis
  automatically adapts the rich message format. The agent writes one message, and
  it renders correctly everywhere it is supported.
</Tip>

## Fallback Behavior

When a rich message is sent to a platform that does not support it, Comis
converts it to the closest plain text equivalent:

| Rich Type                     | Fallback                                                                           |
| ----------------------------- | ---------------------------------------------------------------------------------- |
| Buttons                       | Plain text only (button rows are dropped on unsupported platforms)                 |
| Cards                         | Plain text only (cards are dropped on unsupported platforms)                       |
| Spoiler                       | Content shown without hiding                                                       |
| Silent                        | Normal notification behavior                                                       |
| Polls (via `platform_action`) | Action returns an error on unsupported platforms; no fallback message is generated |

This means your agent can always use rich messages without worrying about
platform compatibility. Users on platforms with full support get the native
interactive experience, while users on simpler platforms still receive the
essential information as plain text.

<Note>
  Fallback conversion is automatic. You do not need to define separate message
  formats for different platforms. Comis detects the target platform and chooses the
  best rendering approach available.
</Note>

## Related

<CardGroup cols={2}>
  <Card title="Messaging Tools" icon="paper-plane" href="/agent-tools/messaging">
    message tool reference with rich message examples
  </Card>

  <Card title="Channels Overview" icon="comments" href="/channels/index">
    Platform-specific capabilities and limits
  </Card>

  <Card title="Media Overview" icon="photo-film" href="/media/index">
    Back to media overview
  </Card>

  <Card title="Platform Actions" icon="gavel" href="/agent-tools/platform-actions">
    Platform-specific moderation tools
  </Card>
</CardGroup>
