Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dallay/corvus/llms.txt

Use this file to discover all available pages before exploring further.

Channels are Corvus’s messaging interfaces that allow your AI agent to communicate across multiple platforms simultaneously. Each channel implements a common Channel trait, providing a unified API for sending and receiving messages.

Channel Trait Interface

All channels implement the core Channel trait defined in clients/agent-runtime/src/channels/traits.rs:
pub trait Channel: Send + Sync {
    /// Human-readable channel name
    fn name(&self) -> &str;

    /// Send a message through this channel
    async fn send(&self, message: &SendMessage) -> anyhow::Result<()>;

    /// Start listening for incoming messages (long-running)
    async fn listen(&self, tx: tokio::sync::mpsc::Sender<ChannelMessage>) -> anyhow::Result<()>;

    /// Check if channel is healthy
    async fn health_check(&self) -> bool;

    /// Signal that the bot is processing (typing indicator)
    async fn start_typing(&self, recipient: &str) -> anyhow::Result<()>;

    /// Stop typing indicator
    async fn stop_typing(&self, recipient: &str) -> anyhow::Result<()>;

    /// Whether this channel supports progressive message updates
    fn supports_draft_updates(&self) -> bool;

    /// Send an initial draft message
    async fn send_draft(&self, message: &SendMessage) -> anyhow::Result<Option<String>>;

    /// Update a previously sent draft message
    async fn update_draft(&self, recipient: &str, message_id: &str, text: &str) -> anyhow::Result<()>;

    /// Finalize a draft with the complete response
    async fn finalize_draft(&self, recipient: &str, message_id: &str, text: &str) -> anyhow::Result<()>;
}

Message Types

ChannelMessage

Represents an incoming message from a channel:
pub struct ChannelMessage {
    pub id: String,           // Unique message ID
    pub sender: String,       // Sender identifier
    pub reply_target: String, // Where to send the reply
    pub content: String,      // Message text content
    pub channel: String,      // Channel name (e.g., "telegram")
    pub timestamp: u64,       // Unix timestamp
}

SendMessage

Represents an outgoing message to send:
pub struct SendMessage {
    pub content: String,         // Message content
    pub recipient: String,       // Recipient identifier
    pub subject: Option<String>, // Optional subject (for email)
}

Supported Channels

Corvus supports a wide variety of messaging platforms:

Real-Time Channels

  • CLI - Command-line interface (stdin/stdout)
  • Telegram - Telegram bot via long-polling
  • Discord - Discord bot via WebSocket Gateway
  • Slack - Slack bot via WebSocket API
  • iMessage - macOS iMessage integration
  • Matrix - Matrix protocol client

Webhook-Based Channels

  • WhatsApp - WhatsApp Business Cloud API (Meta)
  • Webhook - Generic HTTP webhook receiver

Enterprise Channels

  • Lark - ByteDance Lark/Feishu
  • DingTalk - Alibaba DingTalk
  • QQ - Tencent QQ
  • Mattermost - Self-hosted Mattermost

Legacy Channels

  • IRC - Internet Relay Chat
  • Signal - Signal messaging via signal-cli
  • Email - SMTP/IMAP email integration

Allowlist Security Model

All channels use an allowlist-based security model to control who can interact with your agent:

Configuration Pattern

Each channel has an allowed_users or allowed_numbers field:
[channels_config.telegram]
bot_token = "YOUR_BOT_TOKEN"
allowed_users = ["alice", "bob", "123456789"]  # Usernames or user IDs

[channels_config.discord]
bot_token = "YOUR_BOT_TOKEN"
allowed_users = ["987654321098765432"]  # Discord user IDs

[channels_config.whatsapp]
access_token = "YOUR_ACCESS_TOKEN"
phone_number_id = "YOUR_PHONE_ID"
allowed_numbers = ["+1234567890"]  # E.164 format

Wildcard Access

Use "*" to allow all users (not recommended for production):
allowed_users = ["*"]

Empty Allowlist

An empty allowlist denies everyone by default - you must explicitly add users.

Identity Formats

  • Telegram: Username (without @) or numeric user ID
  • Discord: Numeric user ID (snowflake ID)
  • WhatsApp: Phone number in E.164 format (+1234567890)
  • Slack: User ID from Slack API
  • CLI: Always allows "user"

Common Patterns

Starting Channels

Start all configured channels in daemon mode:
corvus channel start
This starts a long-running process that listens to all configured channels and processes messages.

Health Checks

Verify channel connectivity and authentication:
corvus channel doctor
Output shows health status for each channel:
🩺 Corvus Channel Doctor

  ✅ Telegram  healthy
  ✅ Discord   healthy
  ❌ Slack     unhealthy (auth/config/network)
  ⏱️  WhatsApp  timed out (>10s)

Listing Channels

See which channels are configured:
corvus channel list

Binding Users (Telegram)

For Telegram, you can bind a user from the CLI:
corvus channel bind-telegram alice
Or users can bind themselves with a pairing code:
/bind <pairing-code>

Channel-Specific Features

Draft Updates

Some channels support progressive message updates (streaming):
  • Telegram: Supported (editable messages)
  • Discord: Limited (typing indicator only)
  • CLI: No (instant output)
  • WhatsApp: No (webhook-based)
Configure streaming for Telegram:
[channels_config.telegram]
bot_token = "YOUR_TOKEN"
stream_mode = "full"  # Options: "off", "full"
draft_update_interval_ms = 1000  # Throttle edit frequency

Typing Indicators

Channels send typing indicators while processing:
  • Telegram: sendChatAction with "typing"
  • Discord: POST /channels/{id}/typing
  • Slack: Slack WebSocket typing event

Message Splitting

Long messages are automatically split to respect platform limits:
  • Telegram: 4096 characters
  • Discord: 2000 characters
  • WhatsApp: 4096 characters
The runtime automatically chunks messages at word boundaries.

Configuration Example

Complete multi-channel configuration in ~/.corvus/config.toml:
[channels_config.telegram]
bot_token = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
allowed_users = ["alice", "bob"]
stream_mode = "full"
draft_update_interval_ms = 1000

[channels_config.discord]
bot_token = "MTE1..."
guild_id = "123456789012345678"
allowed_users = ["987654321098765432"]
listen_to_bots = false
mention_only = true

[channels_config.whatsapp]
access_token = "EAAxxxx"
phone_number_id = "123456789"
verify_token = "my-secret-verify-token"
allowed_numbers = ["+1234567890"]

Next Steps

Reference

  • Source: clients/agent-runtime/src/channels/
  • Trait definition: clients/agent-runtime/src/channels/traits.rs
  • Channel implementations: clients/agent-runtime/src/channels/{telegram,discord,whatsapp,cli}.rs

Build docs developers (and LLMs) love