Configuration for all 45 channel adapters, per-channel behavior overrides, and sidecar channel integration.
[channels]
All 45 channel adapters are configured under [channels.<name>]. Each channel is Option<T> -- omitting the section disables the adapter entirely. Including the section header (even empty) enables it with default values.
Universal channel fields: Every channel adapter supports the following common fields in addition to its own specific fields:
Field
Type
Default
Description
default_agent
string or null
null
Agent name to route messages to by default.
account_id
string or null
null
Unique identifier for this bot instance. Used for multi-bot routing via [[bindings]] match rules.
Header present but signature mismatched, replayed, or expired
401 Unauthorized
HMAC verification covers the raw wire bytes (not bytes round-tripped through serde_json::Value), so the signing key set in the platform portal must match the env var configured below. Comparison runs in constant time.
Channels with a per-secret env var (Messenger app_secret_env, Teams security_token_env) fall back to "skip verification + log a startup warning" when the env var is unset — this preserves backwards compatibility but should never be left unset in production.
Outbound webhook URLs (callback_url on [channels.webhook]) are run through an SSRF guard at adapter construction: any private (10/8, 172.16/12, 192.168/16), CGN (100.64/10), loopback (127/8, ::1), link-local (169.254/16, fe80::/10), unique-local (fc00::/7), multicast, or cloud-metadata (169.254.169.254, metadata.google.internal, metadata.azure.com) target — including IPv6-bracket forms like [::], [::ffff:127.0.0.1], NAT64 [64:ff9b::7f00:1], and trailing-dot FQDNs — is rejected with a startup error.
Upgrading from earlier versions
If you are upgrading from a release before this contract was introduced:
Operating Messenger? Copy your App Secret from the Facebook app dashboard and export it as MESSENGER_APP_SECRET (or whatever name you set app_secret_env to). Without it, inbound webhooks still work but are unauthenticated — a warning is logged once at startup.
Operating Teams? Copy the outgoing-webhook security token (base64) from the Teams portal and export it as TEAMS_SECURITY_TOKEN (or whatever you set security_token_env to). Same fallback semantics — warning once, no verification.
Operating LINE / Viber / DingTalk? No new env var to set, but probes/health-checks that hit the webhook path without the platform's signature header now return 400/401. Real platform traffic always carries a signature, so genuine inbound is unaffected; only direct probes break.
Using [channels.webhook] with callback_url pointing at a private address? The most common case is a local dev setup with callback_url = "http://127.0.0.1/...". The adapter now refuses to start with that. Switch to a public tunnel (e.g. ngrok, cloudflared) or omit callback_url entirely if you don't need outbound delivery.
If you operate none of the channels above, no action is required — your existing config keeps working unchanged.
[channels.telegram]
[channels.telegram]bot_token_env = "TELEGRAM_BOT_TOKEN"allowed_users = []# default_agent = "assistant"poll_interval_secs = 1# api_url = "https://api.telegram.org" # override for local Bot API server# account_id = "my-telegram-bot"
Field
Type
Default
Description
bot_token_env
string
"TELEGRAM_BOT_TOKEN"
Env var holding the Telegram Bot API token.
allowed_users
list of i64
[]
Telegram user IDs allowed to interact. Empty = allow all.
default_agent
string or null
null
Agent name to route messages to.
poll_interval_secs
u64
1
Long-polling interval in seconds.
account_id
string or null
null
Unique bot instance identifier for multi-bot routing.
api_url
string or null
null
Override the Telegram Bot API base URL. Useful for local Bot API server instances. Defaults to https://api.telegram.org.
Env var holding the email password or app password.
poll_interval_secs
u64
30
IMAP polling interval in seconds.
folders
list of strings
["INBOX"]
IMAP folders to monitor.
allowed_senders
list of strings
[]
Only process emails from these senders. Empty = all.
default_agent
string or null
null
Agent name to route messages to.
[channels.teams]
[channels.teams]app_id = ""app_password_env = "TEAMS_APP_PASSWORD"security_token_env = "TEAMS_SECURITY_TOKEN"# webhook_port = 3978 # Deprecated: webhooks now share the API portallowed_tenants = []
Field
Type
Default
Description
app_id
string
""
Azure Bot App ID.
app_password_env
string
"TEAMS_APP_PASSWORD"
Env var holding the Azure Bot Framework app password.
security_token_env
string
"TEAMS_SECURITY_TOKEN"
Env var holding the outgoing webhook security token (base64-encoded, copied from the Teams portal). Used for HMAC-SHA256 verification of every inbound Authorization: HMAC <…> header. If unset or non-base64, signature verification is skipped and a warning is logged once at startup — production deployments should always set this.
webhook_port
u16
3978
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
IRC channels to join (e.g., ["#librefang", "#general"]).
use_tls
bool
false
Use TLS for the connection.
default_agent
string or null
null
Agent name to route messages to.
[channels.google_chat]
[channels.google_chat]service_account_env = "GOOGLE_CHAT_SERVICE_ACCOUNT"space_ids = []# webhook_port = 8444 # Deprecated: webhooks now share the API port
Field
Type
Default
Description
service_account_env
string
"GOOGLE_CHAT_SERVICE_ACCOUNT"
Env var holding the service account JSON key.
space_ids
list of strings
[]
Google Chat space IDs to listen in.
webhook_port
u16
8444
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
XMPP server hostname. Defaults to the JID domain if empty.
port
u16
5222
XMPP server port.
rooms
list of strings
[]
MUC (multi-user chat) rooms to join.
default_agent
string or null
null
Agent name to route messages to.
[channels.line]
[channels.line]channel_secret_env = "LINE_CHANNEL_SECRET"access_token_env = "LINE_CHANNEL_ACCESS_TOKEN"# webhook_port = 8450 # Deprecated: webhooks now share the API port
Field
Type
Default
Description
channel_secret_env
string
"LINE_CHANNEL_SECRET"
Env var holding the LINE channel secret. Required — every inbound webhook must carry a matching X-Line-Signature; missing → 400, mismatched → 401.
access_token_env
string
"LINE_CHANNEL_ACCESS_TOKEN"
Env var holding the LINE channel access token.
webhook_port
u16
8450
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
default_agent
string or null
null
Agent name to route messages to.
[channels.viber]
[channels.viber]auth_token_env = "VIBER_AUTH_TOKEN"webhook_url = ""# webhook_port = 8451 # Deprecated: webhooks now share the API port
Field
Type
Default
Description
auth_token_env
string
"VIBER_AUTH_TOKEN"
Env var holding the Viber Bot auth token. Required — also used as the HMAC-SHA256 key to verify every inbound X-Viber-Content-Signature; missing → 400, mismatched → 401.
webhook_url
string
""
Public URL for the Viber webhook endpoint.
webhook_port
u16
8451
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
default_agent
string or null
null
Agent name to route messages to.
[channels.messenger]
[channels.messenger]page_token_env = "MESSENGER_PAGE_TOKEN"verify_token_env = "MESSENGER_VERIFY_TOKEN"app_secret_env = "MESSENGER_APP_SECRET"# webhook_port = 8452 # Deprecated: webhooks now share the API port
Field
Type
Default
Description
page_token_env
string
"MESSENGER_PAGE_TOKEN"
Env var holding the Facebook page access token.
verify_token_env
string
"MESSENGER_VERIFY_TOKEN"
Env var holding the webhook verify token.
app_secret_env
string
"MESSENGER_APP_SECRET"
Env var holding the Facebook App Secret. Used for HMAC-SHA1 verification of every inbound X-Hub-Signature header. If unset, signature verification is skipped and a warning is logged once at startup — production deployments should always set this.
webhook_port
u16
8452
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
Supports two modes: stream (default, recommended) and webhook (legacy).
# Stream mode (recommended — no public IP needed)[channels.dingtalk]receive_mode = "stream"app_key_env = "DINGTALK_APP_KEY"app_secret_env = "DINGTALK_APP_SECRET"# Webhook mode (legacy)[channels.dingtalk]receive_mode = "webhook"access_token_env = "DINGTALK_ACCESS_TOKEN"secret_env = "DINGTALK_SECRET"# webhook_port = 8457 # Deprecated: webhooks now share the API port
Field
Type
Default
Description
receive_mode
string
"stream"
Connection mode: "stream" or "webhook".
app_key_env
string
"DINGTALK_APP_KEY"
Env var holding the DingTalk App Key (stream mode).
app_secret_env
string
"DINGTALK_APP_SECRET"
Env var holding the DingTalk App Secret (stream mode).
access_token_env
string
"DINGTALK_ACCESS_TOKEN"
Env var holding the DingTalk webhook access token (webhook mode).
secret_env
string
"DINGTALK_SECRET"
Env var holding the DingTalk signing secret (webhook mode). Required — webhook mode rejects requests without a numeric timestamp header (400), with a stale or mismatched signature (401).
webhook_port
u16
8457
Deprecated. Previously used for standalone webhook server; now ignored. All webhooks share the API port.
robot_code
string or null
null
Robot code for stream mode replies (defaults to app_key).
Env var holding the HMAC signing secret for verifying incoming webhooks.
listen_port
u16
8460
Port to listen for incoming webhook requests.
callback_url
string or null
null
URL to POST outgoing messages to. SSRF-guarded: the daemon refuses to start the adapter if this resolves to a private, loopback, link-local, multicast, or cloud-metadata range (e.g. 127.0.0.1, 10.0.0.1, 169.254.169.254, [::1], [::ffff:127.0.0.1]). Public hostnames only.
default_agent
string or null
null
Agent name to route messages to.
[channels.voice]
WebSocket-based voice channel with STT (Speech-to-Text) and TTS (Text-to-Speech) support.
Model override for this channel. Uses the agent's default model when null.
system_prompt
string or null
null
System prompt override for this channel.
dm_policy
string
"respond"
How the bot handles direct messages. See below.
group_policy
string
"mention_only"
How the bot handles group messages. See below.
rate_limit_per_minute
u32
0
Global rate limit for this channel (messages per minute). 0 = unlimited.
rate_limit_per_user
u32
0
Maximum messages per user per minute. 0 = unlimited.
threading
bool
false
Enable thread replies (where supported by the platform).
output_format
string or null
null
Override output formatting. See below.
usage_footer
string or null
null
Override usage footer mode for this channel. Values: off, tokens, cost, full.
typing_mode
string or null
null
Typing indicator behavior. See below. Defaults to instant.
disable_commands
bool
false
Disable all built-in slash commands. See Command Policy.
allowed_commands
list of strings
[]
Whitelist of command names (no leading /). When non-empty, only these commands work.
blocked_commands
list of strings
[]
Blacklist of command names (no leading /). Applied when allowed_commands is empty.
dm_policy values:
Value
Description
respond
Respond to all direct messages (default).
allowed_only
Only respond to DMs from users in the allowed list.
ignore
Ignore all direct messages.
group_policy values:
Value
Description
all
Respond to all messages in group chats.
mention_only
Only respond when the bot is @mentioned (default).
commands_only
Only respond to slash commands.
ignore
Ignore all group messages.
output_format values:
Value
Description
markdown
Standard Markdown (default).
telegram_html
Telegram HTML subset (<b>, <i>, <code>, etc.).
slack_mrkdwn
Slack mrkdwn format (*bold*, _italic_, `code`).
plain_text
No formatting markup.
typing_mode values:
Value
Description
instant
Send typing indicator immediately on message receipt (default).
message
Send typing indicator only when the first text delta arrives from the LLM.
thinking
Send typing indicator only during LLM reasoning/thinking phase.
never
Never send typing indicators.
Command Policy
Every channel ships with a set of built-in slash commands (/agent, /new, /reboot, /model, /usage, etc.) that let users switch agents, fork into a fresh session, inspect usage, and trigger workflows. On public-facing bots (customer support, community assistants), exposing these to arbitrary users is a security hole — anyone can type /agent admin to switch to an internal agent, /new to fork off into a new session (the prior conversation stays resumable on the channel), or /model to change the model.
The three command-policy fields gate the built-in commands per channel. Precedence:disable_commands > allowed_commands (whitelist) > blocked_commands (blacklist).
Blocked commands are forwarded to the agent as plain text — they are not rejected with an error. So a public bot with disable_commands = true will respond conversationally when a user types /agent admin, and the user never learns that any command system exists.
Recipe: locked-down public bot (no commands at all)
Command names are the bare tokens used internally — either "agent" or "/agent" in TOML works, the leading slash is stripped on match. The full list of built-in commands is in /help.
[[sidecar_channels]]
Sidecar channel adapters allow external processes (written in any language) to act as channel adapters. Communication uses newline-delimited JSON over stdin/stdout.