Skip to content

Channels

PRX communicates through channels — messaging integrations that implement a common Channel trait. Each channel runs its own listener loop, maintains per-sender conversation history, and enforces independent access policies.

ChannelBackendProtocolNotes
Signal (CLI)signal-cliD-Bus / JSON-RPCCLI-based Signal client
Signal (native)libsignalSignal protocolNative Rust implementation
WhatsApp (whatsmeow)whatsmeow bridgeWebSocketGo-based WhatsApp Web bridge
WhatsApp (wacli)wacliCLILightweight WhatsApp CLI
WhatsApp (wa-rs)wa-rsNativePure Rust WhatsApp client
TelegramteloxideBot APIFull bot API support
DiscordserenityGateway WebSocketSlash commands and message events
Slackslack-morphismEvents API + WebSocketBolt-compatible event handling
Matrixmatrix-sdkClient-Server APIFull E2EE support via vodozemac
iMessageapplescript / imessage-rsAppleScript / BlueBubblesmacOS only
IRCirc crateIRC protocolStandard IRC with TLS
EmailIMAP + SMTPIMAP IDLE / pollingSupports HTML and attachments
DingTalkDingTalk Open APIHTTP webhook + WebSocketChina enterprise messaging
Lark / FeishuLark Open APIHTTP webhook + WebSocketBytedance enterprise suite
QQOpenShamrock / LagrangeOneBot v11QQ Bot via reverse WebSocket
MattermostMattermost APIWebSocket + RESTSelf-hosted team chat
Nextcloud TalkNextcloud Talk APIPollingSelf-hosted collaboration
LinQLinQ protocolCustomInternal messaging protocol
CLIstdin/stdoutTTYLocal interactive mode

Each channel is configured independently with access control policies:

[channels.telegram]
enabled = true
token = "BOT_TOKEN"
# DM policy: who can message the bot directly
dm_policy = "allowlist" # "allowlist" | "open" | "disabled"
dm_allowlist = [123456789, 987654321]
# Group policy: which groups the bot responds in
group_policy = "allowlist" # "allowlist" | "open" | "disabled"
group_allowlist = [-1001234567890]
# Sender allowlist (applies to both DM and group)
sender_allowlist = ["user_id_1", "user_id_2"]
PolicyBehavior
allowlistOnly explicitly listed users/groups can interact
openAnyone can interact (use with caution)
disabledChannel direction (DM or group) is turned off entirely

Every incoming message follows this pipeline:

Channel Listener Loop
├─ 1. Receive message from platform
├─ 2. Policy check (dm_policy / group_policy / sender_allowlist)
│ Denied → silently drop
├─ 3. Per-sender history lookup
│ Each sender maintains a rolling window of 50 messages
├─ 4. Concurrency control
│ Max 4 parallel requests per channel
│ Excess requests are queued
├─ 5. Timeout budget
│ Per-request timeout to prevent LLM hangs
├─ 6. Route to LLM via Router
│ Intent classification → model selection → generation
├─ 7. Send response back to channel
├─ 8. Memory auto-save
│ Significant conversations are persisted to prx-memory
└─ 9. History compaction
When history exceeds 50 messages, older entries are
summarized and compressed to maintain context quality

PRX maintains a per-sender conversation buffer of the last 50 messages. This is not a simple truncation:

  • Messages are stored with timestamps, role (user/assistant), and channel metadata
  • When the buffer is full, the oldest messages are compacted into a summary
  • The summary is prepended to the history so context is preserved without consuming the full token window
  • History is isolated per sender — conversations do not leak between users

Each channel enforces a maximum of 4 parallel LLM requests. This prevents:

  • Rate limit exhaustion on LLM providers
  • Memory pressure from too many concurrent context windows
  • Platform-side throttling from rapid response bursts

Requests beyond the concurrency limit are held in a FIFO queue and processed as slots free up.

PRX exposes an HTTP gateway for channels that communicate via webhooks rather than persistent connections. This is used by:

  • DingTalk (event subscription callbacks)
  • Lark / Feishu (event subscription callbacks)
  • Slack (Events API mode)
  • Custom integrations posting to PRX via HTTP

The gateway validates incoming webhook signatures, maps payloads to the internal message format, and feeds them into the same message flow pipeline.