Channel Adapters

OpenFang connects to messaging platforms through 40 channel adapters, allowing users to interact with their agents across every major communication platform. Adapters span consumer messaging, enterprise collaboration, social media, community platforms, privacy-focused protocols, and generic webhooks.

All adapters share a common foundation: graceful shutdown via watch::channel, exponential backoff on connection failures, Zeroizing<String> for secrets, automatic message splitting for platform limits, per-channel model/prompt overrides, DM/group policy enforcement, per-user rate limiting, and output formatting (Markdown, TelegramHTML, SlackMrkdwn, PlainText).

All 40 Channels

Core (7)

Channel Protocol Env Vars ChannelType Variant
Telegram Bot API long-polling TELEGRAM_BOT_TOKEN Telegram
Discord Gateway WebSocket v10 DISCORD_BOT_TOKEN Discord
Slack Socket Mode WebSocket SLACK_BOT_TOKEN, SLACK_APP_TOKEN Slack
WhatsApp Cloud API webhook WA_ACCESS_TOKEN, WA_PHONE_ID, WA_VERIFY_TOKEN WhatsApp
Signal signal-cli REST/JSON-RPC (system service) Signal
Matrix Client-Server API /sync MATRIX_TOKEN Matrix
Email IMAP + SMTP EMAIL_PASSWORD Email

Enterprise (8)

Channel Protocol Env Vars ChannelType Variant
Microsoft Teams Bot Framework v3 webhook + OAuth2 TEAMS_APP_ID, TEAMS_APP_SECRET Teams
Mattermost WebSocket + REST v4 MATTERMOST_TOKEN, MATTERMOST_URL Mattermost
Google Chat Service account webhook GOOGLE_CHAT_SA_KEY, GOOGLE_CHAT_SPACE Custom("google_chat")
Webex Bot SDK WebSocket WEBEX_BOT_TOKEN Custom("webex")
Feishu / Lark Open Platform webhook FEISHU_APP_ID, FEISHU_APP_SECRET Custom("feishu")
Rocket.Chat REST polling ROCKETCHAT_TOKEN, ROCKETCHAT_URL Custom("rocketchat")
Zulip Event queue long-polling ZULIP_EMAIL, ZULIP_API_KEY, ZULIP_URL Custom("zulip")
XMPP XMPP protocol (stub) XMPP_JID, XMPP_PASSWORD, XMPP_SERVER Custom("xmpp")

Social (8)

Channel Protocol Env Vars ChannelType Variant
LINE Messaging API webhook LINE_CHANNEL_SECRET, LINE_CHANNEL_TOKEN Custom("line")
Viber Bot API webhook VIBER_AUTH_TOKEN Custom("viber")
Facebook Messenger Platform API webhook MESSENGER_PAGE_TOKEN, MESSENGER_VERIFY_TOKEN Custom("messenger")
Mastodon Streaming API WebSocket MASTODON_TOKEN, MASTODON_INSTANCE Custom("mastodon")
Bluesky AT Protocol WebSocket BLUESKY_HANDLE, BLUESKY_APP_PASSWORD Custom("bluesky")
Reddit OAuth2 polling REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, REDDIT_USERNAME, REDDIT_PASSWORD Custom("reddit")
LinkedIn Messaging API polling LINKEDIN_ACCESS_TOKEN Custom("linkedin")
Twitch IRC gateway TWITCH_TOKEN, TWITCH_CHANNEL Custom("twitch")

Community (6)

Channel Protocol Env Vars ChannelType Variant
IRC Raw TCP PRIVMSG IRC_SERVER, IRC_NICK, IRC_PASSWORD Custom("irc")
Guilded WebSocket GUILDED_BOT_TOKEN Custom("guilded")
Revolt WebSocket REVOLT_BOT_TOKEN Custom("revolt")
Keybase Bot API polling KEYBASE_USERNAME, KEYBASE_PAPERKEY Custom("keybase")
Discourse REST polling DISCOURSE_API_KEY, DISCOURSE_URL Custom("discourse")
Gitter Streaming API GITTER_TOKEN Custom("gitter")

Self-hosted (1)

Channel Protocol Env Vars ChannelType Variant
Nextcloud Talk REST polling NEXTCLOUD_TOKEN, NEXTCLOUD_URL Custom("nextcloud")

Privacy (3)

Channel Protocol Env Vars ChannelType Variant
Threema Gateway API webhook THREEMA_ID, THREEMA_SECRET Custom("threema")
Nostr NIP-01 relay WebSocket NOSTR_PRIVATE_KEY, NOSTR_RELAY Custom("nostr")
Mumble TCP text protocol MUMBLE_SERVER, MUMBLE_USERNAME, MUMBLE_PASSWORD Custom("mumble")

Workplace (4)

Channel Protocol Env Vars ChannelType Variant
Pumble Webhook PUMBLE_WEBHOOK_URL, PUMBLE_TOKEN Custom("pumble")
Flock Webhook FLOCK_TOKEN Custom("flock")
Twist API v3 polling TWIST_TOKEN Custom("twist")
DingTalk Robot API webhook DINGTALK_TOKEN, DINGTALK_SECRET Custom("dingtalk")

Notification (2)

Channel Protocol Env Vars ChannelType Variant
ntfy SSE pub/sub NTFY_TOPIC, NTFY_SERVER Custom("ntfy")
Gotify WebSocket GOTIFY_TOKEN, GOTIFY_URL Custom("gotify")

Integration (1)

Channel Protocol Env Vars ChannelType Variant
Webhook Generic HTTP with HMAC-SHA256 WEBHOOK_URL, WEBHOOK_SECRET Custom("webhook")

Channel Configuration

All channel configurations live in ~/.openfang/config.toml under the [channels] section. Each channel is a subsection:

[channels.telegram]
bot_token_env = "TELEGRAM_BOT_TOKEN"
default_agent = "assistant"
allowed_users = ["123456789"]

[channels.discord]
bot_token_env = "DISCORD_BOT_TOKEN"
default_agent = "coder"

[channels.slack]
bot_token_env = "SLACK_BOT_TOKEN"
app_token_env = "SLACK_APP_TOKEN"
default_agent = "ops"

# Enterprise example
[channels.teams]
app_id_env = "TEAMS_APP_ID"
app_secret_env = "TEAMS_APP_SECRET"
default_agent = "ops"

# Social example
[channels.mastodon]
token_env = "MASTODON_TOKEN"
instance = "https://mastodon.social"
default_agent = "social-media"

Common Fields

  • bot_token_env / token_env – The environment variable holding the bot/access token. OpenFang reads the token from this env var at startup. All secrets are stored as Zeroizing<String> and wiped from memory on drop.
  • default_agent – The agent name (or ID) that receives messages when no specific routing applies.
  • allowed_users – Optional list of platform user IDs allowed to interact. Empty means allow all.
  • overrides – Optional per-channel behavior overrides.

Environment Variables Reference (Core Channels)

Channel Required Env Vars
Telegram TELEGRAM_BOT_TOKEN
Discord DISCORD_BOT_TOKEN
Slack SLACK_BOT_TOKEN, SLACK_APP_TOKEN
WhatsApp WA_ACCESS_TOKEN, WA_PHONE_ID, WA_VERIFY_TOKEN
Matrix MATRIX_TOKEN
Email EMAIL_PASSWORD

Channel Overrides

Every channel adapter supports ChannelOverrides, which let you customize behavior per channel without modifying the agent manifest. Add an [channels.<name>.overrides] section in config.toml:

[channels.telegram.overrides]
model = "gemini-2.5-flash"
system_prompt = "You are a concise Telegram assistant. Keep replies under 200 words."
dm_policy = "respond"
group_policy = "mention_only"
rate_limit_per_user = 10
threading = true
output_format = "telegram_html"
usage_footer = "compact"

Override Fields

Field Type Default Description
model Option<String> Agent default Override the LLM model for this channel.
system_prompt Option<String> Agent default Override the system prompt for this channel.
dm_policy DmPolicy Respond How to handle direct messages.
group_policy GroupPolicy MentionOnly How to handle group/channel messages.
rate_limit_per_user u32 0 (unlimited) Max messages per minute per user.
threading bool false Send replies as thread responses (platforms that support it).
output_format Option<OutputFormat> Markdown Output format for this channel.
usage_footer Option<UsageFooterMode> None Whether to append token usage to responses.

Formatter, Rate Limiter, and Policies

Output Formatter

The formatter module (openfang-channels/src/formatter.rs) converts Markdown output from the LLM into platform-native formats:

OutputFormat Target Notes
Markdown Standard Markdown Default; passed through as-is.
TelegramHtml Telegram HTML subset Converts **bold** to <b>, code to <code>, etc.
SlackMrkdwn Slack mrkdwn Converts **bold** to *bold*, links to `<url
PlainText Plain text Strips all formatting.

Per-User Rate Limiter

The ChannelRateLimiter (openfang-channels/src/rate_limiter.rs) uses a DashMap to track per-user message counts.

DM Policy

Controls how the adapter handles direct messages:

DmPolicy Behavior
Respond Respond to all DMs (default).
AllowedOnly Only respond to DMs from users in allowed_users.
Ignore Silently drop all DMs.

Group Policy

Controls how the adapter handles messages in group chats, channels, and rooms:

GroupPolicy Behavior
All Respond to every message in the group.
MentionOnly Only respond when the bot is @mentioned (default).
CommandsOnly Only respond to /command messages.
Ignore Silently ignore all group messages.

Telegram

Prerequisites

Setup

  1. Open Telegram and message @BotFather.
  2. Send /newbot and follow the prompts to create a new bot.
  3. Copy the bot token.
  4. Set the environment variable:
export TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
  1. Add to config:
[channels.telegram]
bot_token_env = "TELEGRAM_BOT_TOKEN"
default_agent = "assistant"
  1. Restart the daemon:
openfang start

How It Works

The Telegram adapter uses long-polling via the getUpdates API. It polls every few seconds with a 30-second long-poll timeout. On API failures, it applies exponential backoff (starting at 1 second, up to 60 seconds). Shutdown is coordinated via a watch::channel.

Discord

Prerequisites

Setup

  1. Go to Discord Developer Portal.
  2. Click "New Application" and name it.
  3. Go to the Bot section and click "Add Bot".
  4. Copy the bot token.
  5. Enable Message Content Intent required to read message content.
  6. Set the environment variable:
export DISCORD_BOT_TOKEN=MTIzNDU2Nzg5.ABCDEF.ghijklmnop
  1. Add to config:
[channels.discord]
bot_token_env = "DISCORD_BOT_TOKEN"
default_agent = "coder"
  1. Restart the daemon.

How It Works

The Discord adapter connects to the Discord Gateway via WebSocket (v10) and routes messages to the configured agent.

Slack

Prerequisites

  • A Slack app with Socket Mode enabled

Setup

  1. Go to Slack API and click "Create New App" > "From Scratch".
  2. Copy the token.
  3. Set the environment variables:
export SLACK_APP_TOKEN=xapp-1-...
export SLACK_BOT_TOKEN=xoxb-...
  1. Add to config:
[channels.slack]
bot_token_env = "SLACK_BOT_TOKEN"
app_token_env = "SLACK_APP_TOKEN"
default_agent = "ops"
  1. Restart the daemon.

How It Works

The Slack adapter uses Socket Mode to receive events and routes them to the configured agent.