Skip to content

Channels let an agent receive and send messages outside the web UI. Connect Telegram, Slack, Discord, WhatsApp, Signal, SMS, or any of the other supported providers, and the agent can reply to incoming messages just like it does in chat, with tools, memory, delegation, and signals all working the same way.

Spaces and agents

Each channel belongs to a space and is bound to a single agent. Conversations on the channel live inside that space, so the agent has access to the same memory and context it would have in the web UI for that space.

You can connect multiple channels to the same agent (for example, your personal assistant on both Telegram and SMS). You can also split channels by space: a finance space with its own SMS channel for bank alerts, a personal space with Telegram for everyday chat.

Dispatch modes

A channel can run in one of two modes:

ModeWhat it doesWhen to use
Message (default)Inbound messages run full inference. The agent reads, replies, and uses tools.Normal conversation channels.
SignalInbound messages do tag-only inference and feed the signal matcher. The agent doesn't reply.Channels for ingesting alerts, 2FA codes, or events that other agents are waiting on.

A channel can be flipped from one mode to the other in its settings. The two-tier authorization (see below) lets you mix the behaviors per sender.

Pairing and self-source

Channels require pairing before they accept inbound messages. The flow is:

  1. After connecting, the channel goes to Pairing state and shows a one-time code.
  2. You text the code from the address you want to use to the channel's number (or send the code from the linked account, depending on the provider).
  3. The platform records that address as a paired address on the channel.
  4. From then on, messages from any paired address are treated as you (self-source) and pass the default receive_message policy.

Messages from non-paired addresses are dropped by default. If you want the agent to talk to other people on the channel, you add a policy that allows specific contacts or addresses.

Authorization

Two policy actions gate every inbound:

ActionEffect
receive_messageAllows the agent to read and reply to the message
receive_signalAllows the message to be evaluated against active signal watches

The dispatcher evaluates both:

  • Both allowed → full inference. The agent replies and may use tools.
  • receive_signal allowed but receive_message denied → tag-only inference. The agent annotates the message for signal matching but cannot reply or use general tools.
  • Both denied → the message is discarded. No DB record, no broadcast.

This is how you get behaviors like "the finance agent never sees SMS at all" or "this channel is for ingesting bank 2FA codes only".

See Policies for the full action reference.

Interactive prompts on channels

When an agent needs your input (an app deploy approval, a multiple-choice question, a credential pick), it pauses the chat and asks. How that prompt arrives depends on the channel:

Channel kindRender
Telegram, Discord, Slack, WhatsApp CloudReal buttons (inline keyboard, Block Kit, interactive message). Tap one and the agent resumes.
Signal, WhatsApp Personal, SMSA prompt followed by "Reply YES or NO". Quote-reply with yes, y, ok, 👍, no, n, nope, (and many variants). The parser is generous.

The chat resumes the moment all pending prompts on the latest turn are resolved. Until then, the agent doesn't generate or call other tools.

For credential picks, channels don't render the vault picker inline. The prompt links to a web page where you choose the entry — same chat-pause behavior.

Message length and formatting

Each adapter splits long replies at safe boundaries — paragraph breaks, then line breaks, then word boundaries — so a single agent turn that exceeds a platform limit arrives as a sequence of clean chunks rather than getting truncated:

ChannelPer-message limitNotes
Telegram4,096 charsMarkdown is rendered into MarkdownV2. Tables render as monospace code blocks.
Discord2,000 charsMarkdown is rendered into Discord's flavor. Tables render as monospace code blocks.
SlackPlain textThe adapter multi-chunks silently.
SMS1,600 charsLong replies are truncated and finished with Full reply: {short-link} pointing at a share URL for the full conversation.
WhatsApp (both)Per-message limitMarkdown is converted to WhatsApp's inline styles.
SignalPer-message limitMarkdown is converted to Signal's BodyRange format.

Splitters never break inside a code fence or between escape character and the character it escapes, so syntax stays intact.

Available adapters

ChannelConnectionPublic URL?Best for
TelegramWebhook from TelegramYesPersonal assistants, group bots
SlackSocket Mode (outbound WebSocket)NoTeam workspaces
DiscordGateway WebSocketNoCommunity servers, gaming groups
WhatsApp (Cloud API)Meta webhookYesBusiness numbers, customer-facing
WhatsApp (Personal)QR linked deviceNoPersonal use, testing
SignalQR linked deviceNoPersonal use, 2FA capture
SMSTwilio webhookYesMobile assistants, 2FA capture, notifications

Channel statuses

StatusMeaning
SetupThe channel is created but is waiting for an interactive step: for example scanning a QR code (Signal, WhatsApp Personal) or verifying a webhook in the provider's dashboard (WhatsApp Cloud API).
PairingWaiting for the user to complete address pairing (e.g., text the pairing code to the bot)
ConnectingThe adapter is starting and registering with the provider
ConnectedThe channel is live and receiving messages
DisconnectedThe channel is stopped (you turned it off)
FailedThe adapter could not start. See the error message on the channel page.

Retry policy

When a channel fails to start or its connection drops, Frona retries automatically with exponential backoff. The default policy lives in channel.retry in the config file:

FieldDefaultMeaning
max_retriesunlimitedTotal retry attempts before the channel is marked Failed for good.
initial_backoff_ms1000Delay before the first retry.
backoff_multiplier2.0Delay multiplier between attempts.
max_backoff_ms60000Cap on the delay between attempts.

Every channel can override these defaults on its detail page (Retry policy section). Per-channel values take precedence over the server default. If you want a channel to fail fast (say, a Slack bot that should never silently retry), set max_retries to a small number for that channel.

Tips

  • Start in Message mode. Switch to Signal mode only when you specifically want passive watching, not conversation.
  • Pair from the address you'll use. The pairing code locks the channel to that wire address. If you want to add another, repeat pairing.
  • Use a separate agent per channel if the channels have different audiences. The agent's specialty is what people on the other end interact with.
  • Use spaces to scope memory. A channel for work and a channel for personal life should live in different spaces so memory doesn't leak between them.
  • Watch the status. A channel stuck in Failed won't receive anything. Check the error message before debugging at the provider.

Next steps

  • Telegram. Connect a bot.
  • Slack. Wire up a workspace bot via Socket Mode.
  • Discord. Connect a Discord bot.
  • WhatsApp. Cloud API or personal account.
  • Signal. Link as a secondary device.
  • SMS. Send and receive SMS via Twilio.
  • Signals. What channels in Signal mode feed.
  • Policies. Allowlists, blocks, quiet mode.