> ## 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.

# Messaging

> Send, reply, react, edit, and delete messages across channels

**What it does:** Gives agents one unified API to send, reply to, react to, edit, delete, fetch, and attach messages on any connected channel.

**Who it's for:** Anyone building cross-channel agents -- alert routing, notification systems, multi-platform bots. The same `message` tool call works for Discord, Telegram, Slack, WhatsApp, Signal, iMessage, IRC, LINE, and Email.

<Warning>
  **Channel confinement (security).** When an agent is handling an inbound user message, its `message` calls are confined to the channel that conversation arrived on — a prompt-injected agent cannot read or post to a *different* channel the bot can reach (the confused-deputy / cross-channel exfiltration boundary in the [threat model](/security/threat-model)). Cross-channel delivery is available from **trusted contexts**: scheduled/heartbeat tasks (no originating channel) and operators calling the gateway with an admin-scoped token. Attempting a cross-channel operation from a confined context returns a `Channel access denied` error.
</Warning>

## message -- Cross-Channel Messaging

The `message` tool supports **7 actions** -- `send`, `reply`, `react`, `edit`, `delete`, `fetch`, and `attach`. Comis dispatches each call to the right channel adapter based on `channel_type`. Not every action is supported on every platform (see the [capability matrix](#per-channel-capability-matrix) below); the tool returns a structured error if you ask for something the channel cannot do.

All actions require the `channel_type` parameter to specify which platform adapter handles the request. This is a required string identifying the channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`, `signal`, `imessage`, `line`, `irc`, `email`).

### Quick Reference

| Action   | What It Does                            |
| -------- | --------------------------------------- |
| `send`   | Send a new message to a channel         |
| `reply`  | Reply to a specific message             |
| `react`  | Add an emoji reaction                   |
| `edit`   | Edit a previously sent message          |
| `delete` | Delete a message                        |
| `fetch`  | Retrieve recent messages from a channel |
| `attach` | Send a message with a file attachment   |

### Actions

<AccordionGroup>
  <Accordion title="send -- Send a new message">
    Sends a new message to a channel. From a **trusted context** (a scheduled/heartbeat task, or an operator using an admin-scoped gateway token) the agent can send to any channel it has access to. When **handling an inbound user message**, sends are confined to that conversation's channel (see the channel-confinement note above).

    **Parameters:**

    | Parameter      | Type    | Required | Description                                                                                                                                                                        |
    | -------------- | ------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `action`       | string  | Yes      | Must be `send`                                                                                                                                                                     |
    | `channel_type` | string  | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`)                                                                                                                    |
    | `channel_id`   | string  | Yes      | The target channel identifier                                                                                                                                                      |
    | `text`         | string  | Yes      | The message content                                                                                                                                                                |
    | `buttons`      | array   | No       | Button rows for interactive messages. Each inner array is one row of buttons with `text`, optional `callback_data`, `url`, and `style` (`primary`, `secondary`, `danger`, `link`). |
    | `cards`        | array   | No       | Rich card embeds. Renders as embeds on Discord, blocks on Slack, HTML on Telegram. Each card has optional `title`, `description`, `image_url`, `color`, and `fields`.              |
    | `effects`      | array   | No       | Message delivery effects: `spoiler` (wraps text in spoiler) or `silent` (suppresses notification)                                                                                  |
    | `thread_reply` | boolean | No       | Create or continue a thread from this message. Discord creates thread, Slack uses thread\_ts.                                                                                      |

    **Example -- Send a notification:**

    ```yaml theme={null}
    action: send
    channel_type: discord
    channel_id: "general"
    text: "The daily report is ready. Check the #reports channel for details."
    ```

    <Tip>
      Use `send` for proactive messages like notifications, alerts, and announcements. Cross-channel coordination (sending to a channel the agent is not currently conversing in) works from scheduled tasks and operator-initiated (admin) contexts; an agent answering an inbound message stays confined to that channel.
    </Tip>
  </Accordion>

  <Accordion title="reply -- Reply to a specific message">
    Replies to an existing message, creating a threaded response on platforms that support threading (like Discord and Slack). On platforms without threading, this sends a regular message.

    **Parameters:**

    | Parameter      | Type    | Required | Description                                                     |
    | -------------- | ------- | -------- | --------------------------------------------------------------- |
    | `action`       | string  | Yes      | Must be `reply`                                                 |
    | `channel_type` | string  | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`) |
    | `channel_id`   | string  | Yes      | The channel containing the message                              |
    | `message_id`   | string  | Yes      | The ID of the message to reply to                               |
    | `text`         | string  | Yes      | The reply content                                               |
    | `buttons`      | array   | No       | Button rows for interactive messages (same format as `send`)    |
    | `cards`        | array   | No       | Rich card embeds (same format as `send`)                        |
    | `effects`      | array   | No       | Message delivery effects: `spoiler` or `silent`                 |
    | `thread_reply` | boolean | No       | Create or continue a thread from this message                   |

    **Example -- Reply to a user's question:**

    ```yaml theme={null}
    action: reply
    channel_type: slack
    channel_id: "support"
    message_id: "msg_abc123"
    text: "Great question! Here's what I found..."
    ```
  </Accordion>

  <Accordion title="react -- Add an emoji reaction">
    Adds an emoji reaction to an existing message. This is a lightweight way for agents to acknowledge messages without sending a full reply.

    **Parameters:**

    | Parameter      | Type   | Required | Description                                                                                                                                                                                   |
    | -------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `action`       | string | Yes      | Must be `react`                                                                                                                                                                               |
    | `channel_type` | string | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`)                                                                                                                               |
    | `channel_id`   | string | Yes      | The channel containing the message                                                                                                                                                            |
    | `message_id`   | string | Yes      | The ID of the message to react to                                                                                                                                                             |
    | `emoji`        | string | Yes      | The emoji to add. Provide the literal Unicode emoji character (e.g., the thumbs-up character) or a platform-recognized shortcode; per-platform translation is handled by the channel adapter. |

    **Example -- Acknowledge a request:**

    ```yaml theme={null}
    action: react
    channel_type: telegram
    channel_id: "requests"
    message_id: "msg_def456"
    emoji: "thumbsup"
    ```

    <Info>
      Emoji names vary by platform. Discord uses custom emoji names, Telegram uses Unicode emoji, and Slack uses shortcodes like `:thumbsup:`. The agent handles the translation automatically.
    </Info>
  </Accordion>

  <Accordion title="edit -- Edit a sent message">
    Edits a message that the agent previously sent. Useful for updating status messages or correcting errors.

    **Parameters:**

    | Parameter      | Type   | Required | Description                                                     |
    | -------------- | ------ | -------- | --------------------------------------------------------------- |
    | `action`       | string | Yes      | Must be `edit`                                                  |
    | `channel_type` | string | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`) |
    | `channel_id`   | string | Yes      | The channel containing the message                              |
    | `message_id`   | string | Yes      | The ID of the message to edit                                   |
    | `text`         | string | Yes      | The new message content                                         |

    <Warning>
      Not all platforms support message editing. Telegram supports editing within 48 hours. Discord supports editing with no time limit. Some platforms (like IRC) do not support editing at all. The tool will return an error if editing is not supported.
    </Warning>
  </Accordion>

  <Accordion title="delete -- Delete a message">
    Deletes a message from a channel. The agent can only delete messages it has permission to delete -- typically its own messages or, on platforms with moderation rights, other users' messages.

    **Parameters:**

    | Parameter      | Type   | Required | Description                                                     |
    | -------------- | ------ | -------- | --------------------------------------------------------------- |
    | `action`       | string | Yes      | Must be `delete`                                                |
    | `channel_type` | string | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`) |
    | `channel_id`   | string | Yes      | The channel containing the message                              |
    | `message_id`   | string | Yes      | The ID of the message to delete                                 |

    <Info>
      Platform permissions apply. On Discord, the bot needs "Manage Messages" permission to delete other users' messages. On Telegram, the bot needs admin rights. Check your platform's documentation for permission requirements. This is a destructive action that requires user confirmation via the `_confirmed` parameter.
    </Info>
  </Accordion>

  <Accordion title="fetch -- Retrieve recent messages">
    Fetches recent messages from a channel. Useful when the agent needs to review recent conversation history or catch up on messages it may have missed.

    **Parameters:**

    | Parameter      | Type    | Required | Description                                                     |
    | -------------- | ------- | -------- | --------------------------------------------------------------- |
    | `action`       | string  | Yes      | Must be `fetch`                                                 |
    | `channel_type` | string  | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`) |
    | `channel_id`   | string  | Yes      | The channel to fetch messages from                              |
    | `limit`        | integer | No       | Maximum number of messages to return (default: 20)              |
    | `before`       | string  | No       | Fetch messages before this message ID (for pagination)          |

    Returns a list of messages including their IDs, authors, timestamps, and content.

    **Example -- Get the last 5 messages:**

    ```yaml theme={null}
    action: fetch
    channel_type: discord
    channel_id: "general"
    limit: 5
    ```
  </Accordion>

  <Accordion title="attach -- Send a message with a file">
    Sends a message with a file attachment. The agent can attach images, documents, audio files, or any other file type supported by the target platform.

    **Parameters:**

    | Parameter         | Type   | Required | Description                                                                               |
    | ----------------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
    | `action`          | string | Yes      | Must be `attach`                                                                          |
    | `channel_type`    | string | Yes      | Channel type (e.g., `telegram`, `discord`, `slack`, `whatsapp`)                           |
    | `channel_id`      | string | Yes      | The target channel                                                                        |
    | `attachment_url`  | string | Yes      | URL or workspace path of file to send: `http://`, `https://`, `file://`, or absolute path |
    | `attachment_type` | string | No       | Attachment media type: `image`, `file`, `audio`, or `video` (default: `file`)             |
    | `mime_type`       | string | No       | MIME type of attachment                                                                   |
    | `file_name`       | string | No       | Display filename for the attachment                                                       |
    | `caption`         | string | No       | Caption text for the attachment                                                           |

    **Example -- Send a generated report:**

    ```yaml theme={null}
    action: attach
    channel_type: telegram
    channel_id: "reports"
    attachment_url: "https://example.com/weekly-report.pdf"
    attachment_type: file
    file_name: "weekly-report.pdf"
    caption: "Here's the weekly summary report."
    ```

    <Info>
      File size limits vary by platform. Discord allows up to 25 MB (or 100 MB with Nitro). Telegram allows up to 50 MB for most files. Check your platform's limits if sending large files.
    </Info>
  </Accordion>
</AccordionGroup>

## Per-channel capability matrix

Channel adapters declare what they can do via a `ChannelCapability` schema, and the `message` tool checks support before dispatching. Asking for an unsupported action returns a structured error with `errorKind: "platform"` -- it does not silently no-op.

| Channel  | Send | Reply                  | React               | Edit            | Delete   | Fetch History | Attachments | Streaming method | Max chars |
| -------- | ---- | ---------------------- | ------------------- | --------------- | -------- | ------------- | ----------- | ---------------- | --------- |
| Discord  | Yes  | Yes                    | Yes                 | Yes             | Yes      | Yes           | Yes         | edit (500ms)     | 2000      |
| Telegram | Yes  | Yes                    | Yes (limited emoji) | Yes             | Yes      | No            | Yes         | edit (300ms)     | 4096      |
| Slack    | Yes  | Yes (thread\_ts)       | Yes (shortnames)    | Yes             | Yes      | Yes           | Yes         | edit (400ms)     | 4000      |
| WhatsApp | Yes  | Yes (quoted)           | Yes (Unicode)       | Yes (overwrite) | Own only | No            | Yes         | block (600ms)    | 65536     |
| Signal   | Yes  | Yes (quoted)           | Yes (Unicode)       | No              | Yes      | No            | Yes         | block (500ms)    | 65536     |
| iMessage | Yes  | No                     | No                  | No              | No       | Yes           | Yes         | none             | 20000     |
| LINE     | Yes  | Yes (push)             | No                  | No              | No       | No            | Yes         | none             | 5000      |
| IRC      | Yes  | Mention prefix         | No                  | No              | No       | No            | No          | none             | 512       |
| Email    | Yes  | Yes (RFC 5322 headers) | No                  | No              | No       | No            | Yes         | none             | 100000    |

**Streaming methods:**

* `edit` -- the agent posts a placeholder, then edits it in place as content streams in. Supported on Discord, Telegram, Slack.
* `block` -- the agent buffers chunks and emits complete blocks (no edit). Used by WhatsApp and Signal where edits are unreliable or unsupported.
* `none` -- no streaming; the agent waits for the full reply before sending.

The throttle column is the minimum delay between consecutive edits/blocks during streaming, configured per adapter to respect each platform's rate limits.

<Note>
  The **React** column above is the *outbound* capability — whether the agent can **add** an emoji via `message` `action: react`. It is independent of inbound-reaction **capture** (below): a channel can support sending reactions while not exposing inbound ones, and vice versa.
</Note>

## Inbound reactions: corroborating learning signal

Beyond **sending** reactions (the `react` action above, plus the `removeReaction` lifecycle), Comis also **captures** reactions that other people add to the agent's **own outbound messages** — turning a 👍 / 👎 into a lightweight, corroborating outcome signal for [Verified Learning](/reference/config-yaml#learning-outcome-agents-learningoutcome).

This is **off by default** and only does anything when `learningOutcome.enabled` is set for the agent (and the master `memory.enabled` switch is on). When enabled, a reaction is matched against the agent's `reactionMap` (`👍`/`✅` → success, `👎`/`❌` → failure by default) and recorded through the `reaction` source. It is strictly a **corroborating** signal: it can only weight an outcome the deterministic tool/pipeline signal already resolved, never override it. The captured event carries ids / emoji / counts only — never a message body or a sender display name. See the [`learningOutcome`](/reference/config-yaml#learning-outcome-agents-learningoutcome) config for the trust-weighting and rate-limit behavior.

### Which channels capture inbound reactions

| Channel                                           | Inbound reaction capture | Notes                                                                                                                                                                                                              |
| ------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Discord                                           | Yes                      | Binds `MessageReactionAdd`; the required gateway intents are already held.                                                                                                                                         |
| Slack                                             | Yes                      | Binds the `reaction_added` event; **requires operator setup** (below).                                                                                                                                             |
| Telegram                                          | Yes                      | Binds `message_reaction`; **requires operator setup** for a webhook deployment (below).                                                                                                                            |
| WhatsApp / Signal / iMessage / LINE / IRC / Email | No                       | These platforms' inbound APIs expose no per-reaction event carrying the reactor's identity. This is an honest no-op, not a gap — the agent can still *send* reactions where the capability matrix above allows it. |

### Operator setup

The reaction-capable platforms need a one-time setup so the platform actually delivers reaction events:

* **Slack** — add the `reactions:read` OAuth scope to the app and subscribe to the `reaction_added` event in the app's Event Subscriptions. Without both, Slack silently delivers no reaction events and the signal stays dark with no error.
* **Telegram** — the bot opts into `message_reaction` updates automatically when Comis runs it in polling mode (the default). If you instead run Telegram via a **webhook**, you must include `message_reaction` in the `allowed_updates` list you pass to `setWebhook` (alongside `message`, `edited_message`, `callback_query`, and `poll`) — omitting it stops reaction delivery to the webhook.
* **Discord** — no developer-portal change. Comis already holds the `GuildMessageReactions` / `DirectMessageReactions` intents.

## Cross-Channel Messaging

The `message` tool works across all connected channels. The `channel_type` and `channel_id` parameters together identify which channel to target. Agents can send messages to channels they are not currently conversing in -- this is a key capability for building notification systems, alert pipelines, and cross-channel coordination workflows.

**Example -- mirror an alert to Discord and Email:**

A finance agent watching a market trigger needs to fan out the same alert to two channels at once. The agent makes two consecutive `message` calls with the same body but different targets:

```yaml theme={null}
# First call: high-priority Discord notification
action: send
channel_type: discord
channel_id: "ops-alerts"
text: "ALERT: NVDA crossed below 450 -- review position."

# Second call: email for permanent record
action: send
channel_type: email
channel_id: "trading-team@example.com"
text: "ALERT: NVDA crossed below 450 -- review position."
```

For a monitoring agent reacting to its own heartbeat check, the typical pattern is:

1. Detect an issue through its heartbeat check.
2. Send an alert to the `#ops-alerts` Discord channel using `channel_type: discord`.
3. Send a summary to the Telegram admin group using `channel_type: telegram`.
4. React with a warning emoji on the original message that triggered the check.

All of this happens through the same `message` tool with different `channel_type` and `channel_id` values.

## notify\_user -- Proactive Notifications

The `notify_user` tool delivers proactive notifications outside the normal request-response flow. The daemon applies rate limiting, dedup, quiet-hours suppression, and channel-resolution guards before enqueueing the notification.

| Parameter      | Type   | Required | Description                                                                            |
| -------------- | ------ | -------- | -------------------------------------------------------------------------------------- |
| `message`      | string | Yes      | Notification text to send to the user                                                  |
| `priority`     | string | No       | One of `low`, `normal` (default), `high`, `critical`. `critical` bypasses quiet hours. |
| `channel_type` | string | No       | Target channel type (e.g., `telegram`, `discord`). Omit for auto-resolution.           |
| `channel_id`   | string | No       | Target channel/chat ID. Required when `channel_type` is specified.                     |

**Example -- Critical alert that bypasses quiet hours:**

```yaml theme={null}
message: "Production deploy failed -- rolling back."
priority: critical
```

Use `notify_user` for agent-initiated communication (alerts, reminders, task-completion notices) when you want platform-level guards. Use `message` (action: `send`) for direct messaging to a specific channel without the notification guard pipeline.

## Related

<CardGroup cols={2}>
  <Card title="Channels Overview" icon="messages" href="/channels/index">
    Connect Discord, Telegram, Slack, and 5 more platforms
  </Card>

  <Card title="Sessions" icon="users" href="/agent-tools/sessions">
    Sub-agents, pipelines, and session management
  </Card>

  <Card title="Agent Tools Overview" icon="toolbox" href="/agent-tools/index">
    Master reference table of all tools
  </Card>

  <Card title="Platform Actions" icon="gavel" href="/agent-tools/platform-actions">
    Moderation actions for Discord, Telegram, Slack, and WhatsApp
  </Card>
</CardGroup>
