Channels overview
The channel trait model, delivery modes, allowlist semantics, and the build feature-flag matrix.
A channel is how your Revka agent reaches people on a messaging platform, a voice system, or an automation endpoint. Revka connects to 37 channels through a single unified subsystem: every channel implements one Channel trait, is configured under the [channels_config] namespace in ~/.revka/config.toml, and is managed by a supervisor that provides per-sender conversation history, concurrent message processing, and exponential-backoff reconnection.
This page is the reference hub for that subsystem. It covers the channel trait and its optional capabilities, how each channel receives messages (and which ones need a public address), how allowlists gate inbound senders, the in-chat commands users can run, and the Cargo feature flags that gate the optional channels at build time.
If you just want to wire up your first channel, start with Connect a messaging channel. For per-platform setup, jump to the catalog pages linked at the bottom of this page.
The channel model
Section titled “The channel model”Every channel is enabled by adding its sub-table under [channels_config] in ~/.revka/config.toml. The simplest possible channel is the built-in CLI channel, which needs no credentials:
[channels_config]cli = trueEach platform adds its own table — for example [channels_config.telegram] — with the credentials and options for that platform:
[channels_config.telegram]bot_token = "123456:TELEGRAM-TOKEN"allowed_users = ["myusername"]stream_mode = "off"mention_only = falseChannels run inside revka daemon (gateway + channels + heartbeat + cron) or can be started on their own with revka channel start. They do not run under a bare revka gateway, which serves only the dashboard and API. The supervisor restarts a crashed channel task automatically and applies exponential backoff on reconnection.
Channel trait capabilities
Section titled “Channel trait capabilities”All channels implement the Channel trait. Beyond the two mandatory methods (send and listen), every capability is optional and defaults to a no-op, so a channel only advertises what its platform supports. This is why streaming, reactions, and pinning work on Discord and Slack but are silently absent on, say, IRC or email.
| Capability | Purpose | Channels that implement it |
|---|---|---|
send() | Outbound message delivery | All |
listen() | Inbound message loop | All (keepalive no-op for webhook channels) |
health_check() | Liveness probe for revka channel doctor | Selected (Discord, Slack, Mattermost, etc.) |
start_typing() / stop_typing() | Typing indicator | Telegram, Discord, Slack, Mattermost, Matrix |
supports_draft_updates() | Progressive edit streaming | Telegram (partial), Discord, Slack, Matrix |
supports_multi_message_streaming() | Paragraph-split delivery | Discord, Matrix |
send_draft() / update_draft() / finalize_draft() / cancel_draft() | Draft lifecycle | Telegram, Discord, Slack, Matrix |
update_draft_progress() | Tool-execution status updates | Slack, Matrix |
add_reaction() / remove_reaction() | Emoji reactions | Discord, Telegram (ack), Slack, Matrix |
pin_message() / unpin_message() | Message pinning | Matrix (Voice Call) |
redact_message() | Message deletion | Matrix |
Streaming (delivery) modes
Section titled “Streaming (delivery) modes”Channels that support draft updates expose a stream_mode config key with up to three values. Not every channel supports every mode. Note that Slack is an exception: it uses a boolean stream_drafts key (not stream_mode) and supports only off/partial-style draft streaming — there is no multi_message mode for Slack.
stream_mode | Behavior | Supported on |
|---|---|---|
off | The full reply is sent once, when generation completes. | All streaming-capable channels (default for Telegram) |
partial | An editable draft message is posted and updated token-by-token as the model streams, then finalized. Edit throttle is draft_update_interval_ms. | Telegram, Discord, Slack, Matrix |
multi_message | The reply is delivered as separate messages, split at paragraph boundaries (\n\n) as tokens arrive. Code fences are never split. Pacing is multi_message_delay_ms. | Discord, Matrix |
[channels_config.discord]bot_token = "DISCORD-BOT-TOKEN"stream_mode = "multi_message" # off | partial | multi_messagedraft_update_interval_ms = 1000 # edit throttle for partial modemulti_message_delay_ms = 800 # delay between paragraph sends in multi_message modeDelivery mode summary
Section titled “Delivery mode summary”How a channel receives inbound messages determines whether it needs a public address. Polling / outbound-connection channels dial out from Revka (long-poll, WebSocket/gateway, periodic REST) and work behind NAT with no public port. Webhook / push channels need the platform to POST events to a reachable HTTPS callback URL.
| Channel | Receive mode | Public inbound port? | Feature flag |
|---|---|---|---|
| CLI | stdin | No | — |
| Telegram | long-polling | No | — |
| Discord | Gateway WebSocket | No | — |
| Slack | Socket Mode / polling | No | — |
| Mattermost | REST polling | No | — |
| Matrix | sync API (E2EE) | No | channel-matrix |
| Signal | signal-cli SSE bridge | No | — |
| WhatsApp Cloud API | webhook (push) | Yes | — |
| WhatsApp Web | WebSocket (wa-rs) | No | whatsapp-web |
| IRC | TLS socket | No | — |
| Nostr | relay WebSocket | No | channel-nostr |
| Bluesky | polling | No | — |
| Twitter / X | filtered stream | No | — |
| polling | No | — | |
| Notion | polling | No | — |
| Lark / Feishu | WebSocket (default) or webhook | Webhook mode only | channel-lark |
| DingTalk | Stream Mode WS | No | — |
| WeCom | outbound-only (webhook) | No | — |
| WATI | webhook (push) | Yes | — |
| bot gateway WS | No | — | |
| Mochat | polling | No | — |
| Nextcloud Talk | webhook (push) | Yes | — |
| Linq | webhook (push) | Yes | — |
| iMessage | macOS AppleScript | No (macOS only) | — |
| Email (IMAP) | IMAP IDLE | No | — |
| Gmail Push | Pub/Sub webhook | Yes | — |
| Generic Webhook | HTTP server | Usually yes | — |
| MQTT | broker subscriber | No (outbound conn) | — |
| Voice Call | telephony webhook | Yes | — |
| Voice Wake | microphone capture | No | voice-wake |
| ACP Server | stdio JSON-RPC | No | — |
Allowlist field reference
Section titled “Allowlist field reference”Every inbound channel applies a sender allowlist, and the semantics are uniform across platforms:
- Empty list
[]→ deny all. This is the default — a freshly added channel connects and listens but ignores everyone until you add an identity. - Single entry
"*"→ allow all senders. Use only for temporary verification. - Explicit list → allow only the listed senders.
The field name differs by channel because each platform identifies senders differently:
| Channels | Allowlist field |
|---|---|
| Telegram, Discord, Slack, Mattermost, Matrix, IRC, Lark, Feishu, DingTalk, QQ, Nextcloud Talk, WeCom, Mochat, Twitter | allowed_users |
| Signal | allowed_from |
| WhatsApp (Cloud API & Web), WATI | allowed_numbers |
| Email, Linq, Gmail Push | allowed_senders |
| iMessage | allowed_contacts |
| Nostr | allowed_pubkeys |
| ClawdTalk | allowed_destinations |
For Telegram there is a CLI helper that appends to the allowlist for you:
revka channel bind-telegram revka_user # by username (no leading @)revka channel bind-telegram 123456789 # by numeric user IDFor every other channel, edit the appropriate allowlist field in config.toml. Tighten from "*" to explicit identities once you have confirmed a reply arrives.
In-chat runtime commands
Section titled “In-chat runtime commands”On channels that accept text commands (notably Telegram and Discord), allowlisted users can steer the session inline — no CLI, no restart. These are chat commands, not revka subcommands.
| Command | Effect |
|---|---|
/models | Show the available providers and current selection |
/models <provider> | Switch the provider for the current sender session |
/model | Show the current model (and cached model IDs, if available) |
/model <model-id> | Switch the model for the current sender session |
/new | Clear conversation history and start a fresh session |
Switching provider or model clears only that sender’s in-memory conversation history, to avoid cross-model context contamination. /new clears history without changing the provider or model. Model previews come from revka models refresh --provider <ID>. The CLI channel additionally supports /quit and /exit to leave an interactive terminal session.
Build feature flags
Section titled “Build feature flags”Most channels are compiled into every build. A handful of channels pull in heavy dependencies and are therefore gated behind Cargo features — they are not present in lean default builds and must be enabled at compile time.
| Feature flag | Enables | Notes |
|---|---|---|
channel-matrix | Matrix (Client-Server API, E2EE) | Pulls in matrix-sdk. |
channel-lark | Lark and Feishu | channel-feishu is an alias for channel-lark — Lark and Feishu are the same platform. |
channel-nostr | Nostr (NIP-04 / NIP-17) | Pulls in nostr-sdk. |
whatsapp-web | WhatsApp Web mode (wa-rs) | WhatsApp Cloud API mode needs no flag; only the native Web client is gated. |
voice-wake | Local microphone wake-word detection | Uses cpal; needs libasound2-dev on Linux. |
Enable them with --features at build or check time:
# Matrixcargo build --release --locked --features channel-matrix
# Matrix + Lark togethercargo build --release --locked --features channel-matrix,channel-lark
# WhatsApp Web modecargo build --release --locked --features whatsapp-web# Quick local check with only hardware supportcargo check --features hardware
# Add Matrix when neededcargo check --features hardware,channel-matrixsetup.bat --minimal :: default featuressetup.bat --standard :: Matrix + Lark/Feishusetup.bat --full :: all featuresFor the full Cargo feature catalog and architecture decision records, see Cargo feature flags & ADRs.
The CLI channel
Section titled “The CLI channel”revka channel is the command-line surface for managing channels without hand-editing config.toml. The subcommands:
| Subcommand | What it does |
|---|---|
revka channel list | List all configured channels |
revka channel start | Start all configured channels |
revka channel doctor | Run health_check() for every configured channel |
revka channel add <type> <config_json> | Add a channel from an inline JSON config blob |
revka channel remove <name> | Remove a channel by its config name |
revka channel bind-telegram <identity> | Add a Telegram username (no @) or numeric user ID to the allowlist |
revka channel send <message> --channel-id <NAME> --recipient <TARGET> | Send a one-off message |
revka channel add supports the types telegram, discord, slack, whatsapp, matrix, imessage, and email; every other channel is configured by editing config.toml directly or via the onboarding wizard (revka onboard --channels-only).
# Inspect, then start, the configured channelsrevka channel listrevka channel start
# Add a Telegram bot and allowlist yourselfrevka channel add telegram '{"bot_token":"123456:TELEGRAM-TOKEN","name":"my-bot"}'revka channel bind-telegram 123456789
# Health-check everything when a channel looks stuckrevka channel doctor
# Send a scripted alert through a channel and exitrevka channel send 'Nightly backup completed.' --channel-id slack --recipient C1234567890revka channel send delivers a single message and exits — built for scripted notifications (sensor alerts, cron results, deploy notices). --channel-id is the channel’s config name; --recipient is the platform-specific target. For the complete CLI reference see revka channel & integrations.
Hot-reload
Section titled “Hot-reload”When channels are running, the channel runtime watches config.toml and applies a defined set of changes live, on the next inbound message, with no daemon restart:
default_providerdefault_modeldefault_temperatureapi_key/api_urlreliability.*
Other changes — adding or removing a channel, rotating tokens, editing allowlists — are not hot-reloaded; restart the channels (revka channel start) or the daemon to apply them. Hot-reload applies to the channel runtime under the daemon, not to interactive revka agent sessions.
Validate a channel
Section titled “Validate a channel”If a channel connects but never replies, the cause is almost always one of: the sender is not on the correct allowlist field; the bot lacks membership/permissions in the target room or channel; a token is invalid or expired; a webhook channel has no reachable HTTPS callback; or the daemon was not restarted after a config change. Run revka channel doctor for per-channel health and revka doctor for whole-system diagnostics.
Channel catalog
Section titled “Channel catalog”The per-platform setup details, config keys, and platform-specific notes live on the catalog pages below.
Related pages
Section titled “Related pages”- Connect a messaging channel — end-to-end guide to wiring up your first channel.
- revka channel & integrations — full CLI reference for the channel subcommands.
- Config: channels, tools & integrations — config keys for channels.
- Cargo feature flags & ADRs — the full build feature catalog.
- Expose your gateway with a tunnel — for webhook channels that need a public callback.
- Webhook ingress — the gateway webhook API.
- revka gateway, daemon & service — run channels as part of the always-on daemon.
- Security model — the trust model behind allowlist defaults.