Channels
OpenParallax supports multi-channel messaging, allowing you to interact with your agent through various platforms beyond the CLI and web UI. Each channel connects to the same engine and goes through the same pipeline — Shield evaluation, audit logging, and memory persistence apply identically regardless of the channel.
Architecture
Every channel adapter implements the same pattern:
- Receive a message from the external platform
- Normalize it into a standard format (sender, session ID, message content)
- Call
engine.ProcessMessageForWeb(ctx, sender, sessionID, messageID, content, mode) - Receive pipeline events via the
EventSenderinterface - Format events back into the platform's message format and send to the user
Each channel maintains independent sessions. A Telegram conversation and a Discord conversation are separate sessions with separate histories.
Supported Channels
WhatsApp (Cloud API)
Connect your agent to WhatsApp via the Meta Cloud API.
Configuration:
channels:
whatsapp:
enabled: true
phone_number_id: "1234567890"
access_token_env: WHATSAPP_ACCESS_TOKEN
verify_token: "your-verify-token"
webhook_port: 8443
allowed_numbers: ["+1234567890"]| Field | Description |
|---|---|
phone_number_id | WhatsApp Business phone number ID from Meta Developer Portal |
access_token_env | Environment variable containing the permanent access token |
verify_token | Token for webhook verification (you choose this value) |
webhook_port | TCP port the adapter binds for incoming webhook requests |
allowed_numbers | List of phone numbers permitted to message the bot. Empty list allows all numbers |
Setup steps:
- Create a Meta Developer account and a WhatsApp Business app
- In the WhatsApp product settings, get your Phone Number ID and generate a permanent access token
- Set the access token as an environment variable:
export WHATSAPP_ACCESS_TOKEN="..." - Configure the webhook URL in Meta Developer Portal:
https://your-domain:3100/webhooks/whatsapp - Enter the verify token you chose in step 3
- Subscribe to the
messageswebhook field - Enable the channel in config.yaml and restart
The agent needs to be reachable from the internet for WhatsApp webhooks. Use a reverse proxy (nginx, Caddy) or a tunnel (ngrok, Cloudflare Tunnel) to expose the webhook endpoint.
Telegram (Bot API)
Connect via a Telegram bot.
Configuration:
channels:
telegram:
enabled: true
token_env: TELEGRAM_BOT_TOKEN
allowed_users: [123456789]
allowed_groups: []
private_only: true
polling_interval: 1| Field | Description |
|---|---|
token_env | Environment variable containing the bot token from @BotFather |
allowed_users | List of Telegram user IDs (numeric) that can interact with the bot. Empty list allows all users. |
allowed_groups | List of Telegram group chat IDs (numeric) where the bot is permitted to respond. Empty list allows all groups. |
private_only | When true, the bot only responds to private (direct) messages and ignores group chats. Defaults to true for security. |
polling_interval | Long-polling interval in seconds. Defaults to 1. |
The Telegram adapter uses long polling — no public URL or webhook is needed.
Setup steps:
- Create a bot via @BotFather on Telegram
- Copy the bot token and set it:
export TELEGRAM_BOT_TOKEN="..." - Find your Telegram user ID (send a message to @userinfobot)
- Add your user ID to
allowed_usersto restrict access - Optionally set a webhook URL for push-based delivery, or leave empty for long polling
- Enable the channel and restart
Long polling mode does not require a public URL, making it easier to set up for personal use.
Discord (Bot)
Connect via a Discord bot.
Configuration:
channels:
discord:
enabled: true
token_env: DISCORD_BOT_TOKEN
allowed_guilds: ["9876543210"]
allowed_channels: []
allowed_users: []
respond_to_mentions: true| Field | Description |
|---|---|
token_env | Environment variable containing the Discord bot token |
allowed_guilds | List of Discord server (guild) IDs where the bot is permitted to operate. Required — the bot refuses to respond in unlisted guilds. |
allowed_channels | Optional channel ID allowlist within those guilds. Empty list allows all channels. |
allowed_users | Optional user ID allowlist. Empty list allows all members of the allowed guilds. |
respond_to_mentions | When true, the bot replies to @mentions in addition to direct messages. |
Setup steps:
- Create an application in the Discord Developer Portal
- Create a bot user and copy the token:
export DISCORD_BOT_TOKEN="..." - Enable the
MESSAGE CONTENTprivileged gateway intent - Generate an invite URL with
botandapplications.commandsscopes - Invite the bot to your server
- Add the guild ID to
guild_idsfor server-specific slash commands - Enable the channel and restart
The bot responds to direct messages and mentions in channels. Each Discord user gets their own session.
Slack (App)
Planned — Not Yet Implemented
The Slack adapter is on the roadmap but not yet implemented. The configuration schema is defined, but enabling it has no effect at runtime.
Will connect via a Slack app using Socket Mode.
Configuration:
channels:
slack:
enabled: true
bot_token_env: SLACK_BOT_TOKEN
app_token_env: SLACK_APP_TOKEN| Field | Description |
|---|---|
bot_token_env | Bot User OAuth Token (xoxb-...) |
app_token_env | App-Level Token (xapp-...) for Socket Mode |
Setup steps:
- Create a new app at api.slack.com
- Enable Socket Mode in the app settings
- Generate an App-Level Token with
connections:writescope - Under OAuth & Permissions, add bot token scopes:
chat:write,app_mentions:read,im:history,im:read,im:write - Install the app to your workspace
- Set environment variables:
SLACK_BOT_TOKEN,SLACK_APP_TOKEN - Enable the channel and restart
The bot responds to direct messages and @mentions. Socket Mode means no public URL is required.
Signal (signal-cli)
Connect via Signal using signal-cli as the transport layer.
Configuration:
channels:
signal:
enabled: true
cli_path: "/usr/local/bin/signal-cli"
account: "+1234567890"
allowed_numbers: ["+1987654321"]| Field | Description |
|---|---|
cli_path | Path to the signal-cli binary |
account | The phone number registered with Signal for the bot |
allowed_numbers | List of phone numbers allowed to message the bot. Empty list allows all. |
Setup steps:
- Install signal-cli
- Register or link a phone number:
signal-cli -u +1234567890 registerand verify - Set the path and phone number in config.yaml
- Add trusted phone numbers to
allowed_numbers - Enable the channel and restart
Signal provides end-to-end encrypted messaging. All messages between you and the agent are encrypted in transit.
Microsoft Teams (Graph API)
Planned — Not Yet Implemented
The Microsoft Teams adapter is on the roadmap but not yet implemented. The configuration schema is defined, but enabling it has no effect at runtime.
Will connect via Microsoft Teams using the Microsoft Graph API and Bot Framework.
Configuration:
channels:
teams:
enabled: true
app_id_env: TEAMS_APP_ID
password_env: TEAMS_APP_PASSWORD| Field | Description |
|---|---|
app_id_env | Environment variable for the Azure AD application (client) ID |
password_env | Environment variable containing the client secret |
Setup steps:
- Register an application in Azure AD
- Add Microsoft Graph API permissions:
ChatMessage.Read,ChatMessage.Send - Create a client secret and set it:
export TEAMS_APP_PASSWORD="..." - Create a Bot Channel Registration in Azure
- Configure the messaging endpoint URL
- Add the bot to your Teams workspace
- Enable the channel and restart
iMessage (macOS only)
Connect via iMessage using the AppleScript bridge to Messages.app.
macOS Only
iMessage integration requires macOS with Messages.app configured. It is not available on Linux or Windows.
Configuration:
channels:
imessage:
enabled: true
apple_id: "you@icloud.com"| Field | Description |
|---|---|
apple_id | The Apple ID email address configured in Messages.app |
Setup steps:
- Sign in to Messages.app with your Apple ID
- Grant Full Disk Access to the OpenParallax process in System Settings > Privacy & Security > Full Disk Access
- Set your Apple ID email in
config.yaml - Enable the channel and restart
The adapter uses AppleScript to poll for new messages and send responses through Messages.app. A GUI session is required -- headless servers are not supported. Text messages only; attachments are not processed in the initial implementation.
See the iMessage adapter documentation for full details.
Message Normalization
Regardless of the source channel, messages are normalized into a common format before entering the pipeline:
- Sender — channel-specific user identifier
- Session ID — unique per user per channel
- Message content — text content extracted from platform-specific formatting
- Mode — normal or OTR
Platform-specific features (reactions, threads, attachments) are handled by each channel adapter as appropriate. Text content is always extracted and passed through.
Dynamic Channel Management
Channels can be connected and disconnected at runtime without restarting the engine.
attach connects a channel to a running agent:
openparallax attach telegram
openparallax attach discord myagentdetach disconnects a channel from a running agent:
openparallax detach telegram
openparallax detach discord myagentThe channel must be configured in config.yaml with valid credentials. attach starts the adapter and begins processing messages; detach gracefully shuts it down and stops accepting new messages.
Security Across Channels
All channels go through the identical Shield pipeline. There is no bypass for any channel:
- Every tool call is evaluated by Shield
- Every action is logged in the audit trail
- Every channel respects the active policy file
- OTR mode works in all channels (the agent checks session mode, not channel type)
The allowed_users / allowed_numbers fields on Telegram, Signal, and other channels provide an additional access control layer that restricts who can interact with the bot.
Security defaults by channel:
- Discord — requires a guild allowlist (
allowed_guilds). The bot refuses to respond in unlisted guilds. - Telegram — defaults to private-chat-only (
private_only: true). Group chat responses require explicitly settingprivate_only: falseand configuringallowed_groups.
Tier 3 human approval:
When Shield escalates an action to Tier 3, approval requests are broadcast to all connected channels:
- Web UI — inline approval card with Approve/Deny buttons and countdown timer.
- Telegram — inline keyboard buttons. Tap to approve or deny.
- Discord — message component buttons. Click to approve or deny.
- WhatsApp, Signal, iMessage — notification only. Approve or deny on the web UI, Telegram, or Discord.
Multiple Channels Simultaneously
You can enable multiple channels at the same time. The engine handles all channel adapters concurrently:
channels:
telegram:
enabled: true
token_env: TELEGRAM_BOT_TOKEN
allowed_users: ["123456789"]
discord:
enabled: true
token_env: DISCORD_BOT_TOKEN
slack:
enabled: true
bot_token_env: SLACK_BOT_TOKEN
app_token_env: SLACK_APP_TOKEN
signing_secret_env: SLACK_SIGNING_SECRETEach channel maintains its own sessions. The web UI and CLI are always available alongside any configured messaging channels.
Next Steps
- Configuration — full channel configuration reference
- Security — how Shield protects across channels
- Sessions — how cross-channel sessions work