Skip to content

Connect a Telegram bot and one of your agents will reply to direct messages and group chats. The agent uses every tool, skill, and memory it would in the web UI.

What you need

  • A bot created with @BotFather on Telegram
  • The bot's API token (issued by BotFather, looks like 123456:ABC-DEF...)
  • A publicly reachable URL for the engine. See server.external_url. For local development, ngrok works.

Creating the bot

  1. Open a chat with @BotFather.
  2. Send /newbot and follow the prompts to set the name and username.
  3. Copy the API token from the confirmation message.
  4. (Optional) Send /setprivacy and disable privacy mode if you want the bot to read every message in groups, not just ones that mention it.

Connecting the channel

Connection happens in two stages. A short dialog creates the channel, then the channel's detail page is where you paste the bot token (via Frona's vault).

Step 1: Create the channel

  1. In Frona, open Settings → Channels and click Add channel.
  2. Pick Telegram Bot from the provider list. The create dialog opens.
  3. Fill in the dialog:
    • Space. Defaults to Telegram Bot. This is the space the conversation will live in. Keep the default to create a new space with that name, type any other name to create a different one, or pick an existing space from the dropdown. A space can host only one channel, so spaces already bound to another channel are hidden.
    • Agent. The agent that reads every incoming message and sends the reply.
    • When a message arrives. How inbound messages are handled:
      • Treat as a message from you (default). The agent runs full inference and replies.
      • Hand off to a waiting agent. The message goes to whichever task is currently waiting on a signal (e.g., a 2FA code). The agent does not reply on this channel. See Signals.
  4. Click Create.

You land on the channel detail page. The status is Setup until the bot token is configured.

Step 2: Configure the bot token

Open the Config tab on the channel detail page. The Provider Config panel lists bot_token. It's a secret, so it's set via Frona's credential picker rather than a raw text field.

  1. Click Configure next to bot_token.
  2. Pick a vault connection. You can use a configured password manager (1Password, Bitwarden, HashiCorp Vault, KeePass) or Local to keep the secret in Frona's encrypted store.
  3. Either pick an existing vault item, or click New credential to create one. For Local, choose API key, name it (e.g., telegram-bot-token), and paste the 123456:ABC-DEF… value from BotFather.
  4. Pick the field on the item that holds the token.
  5. Click Save in the dialog.

After the token is configured, click Save at the top of the channel page. Frona registers a webhook with Telegram pointing at your engine, and the channel transitions to Connected.

Step 3: Pair your Telegram account

By default the channel doesn't trust any sender, so even your own messages are ignored. Pair the channel to your Telegram account so the agent treats you as a self-source:

  1. On the channel detail page, click Pair. A short code appears (e.g. XYZ-123).
  2. Send the code as a regular message to the bot from your own Telegram account.
  3. The channel records your Telegram address as a paired address and the conversation goes live.

From then on, messages from that account pass the default receive_message policy and the agent replies. To pair another account, click Re-pair and repeat. Paired addresses accumulate. To let unpaired senders through (e.g., friends, group members), add a policy.

Configuration fields

FieldRequiredDescription
bot_tokenYesThe token issued by BotFather. Stored encrypted at rest.

How messages flow

  • Direct messages to the bot land in a chat tagged as direct.
  • Group messages that the bot can see (mentions, replies, or any message if privacy mode is disabled) land in a chat tagged as group.
  • Replies are sent back to the same Telegram chat. The adapter renders Markdown into Telegram's MarkdownV2 format when possible and falls back to plain text otherwise. Markdown tables are rendered as monospace code blocks since Telegram has no native table support.
  • Replies longer than 4,096 characters split across multiple messages at paragraph, line, or word boundaries — code fences are never broken across messages.
  • Tool calls are streamed as separate Telegram messages so you can watch progress, then the final reply is sent as one bubble.

Approvals and questions

When the agent needs your input — an app deploy approval, a question with multiple choices — Telegram renders it as an inline keyboard right under the prompt. Tap a button and the agent resumes. Until you respond, the chat stays paused.

Allowlisting senders

By default only paired-address senders pass receive_message. For a personal bot this means just you. To open the bot up to specific contacts or groups, add a policy. For example, allowing one Telegram username:

cedar
permit(
  principal == Policy::Agent::"assistant",
  action == Policy::Action::"receive_message",
  resource in Policy::Channel::"telegram"
) when { resource.sender.address == "@friend_username" };

See Policies for more patterns (channel-wide allows, blocking spammers, quiet mode).

Tips

  • One bot per agent. Telegram tokens cannot be shared across applications, and giving each agent its own bot keeps personalities clean.
  • Disable privacy mode for group bots. Otherwise the bot only sees @mentions and replies to its own messages.
  • Use Markdown in agent prompts. The adapter renders standard Markdown (bold, italic, links, code blocks) into Telegram's format.
  • Public URL is required. Telegram won't deliver webhooks to localhost. Use ngrok for local testing.

Troubleshooting

SymptomLikely cause
Channel marked Failed right after creationBad token, the token already in use elsewhere, or the engine's external URL isn't reachable from Telegram
Bot receives messages but you don't see themThe agent doesn't have receive_message permission for that sender. Check the agent's policies.
Bot doesn't reply in groupsPrivacy mode is on. Disable it via /setprivacy in BotFather.

Next steps

  • Channels. How channels work in general.
  • Policies. Allow specific senders or groups.