Skip to main content
Connect your Comis agent to Telegram groups, channels, forum topics, and private chats. Telegram supports reactions, inline buttons, HTML formatting, file attachments up to 50 MB, and live-streaming responses that update in real time as your agent thinks.
You don’t need to understand the technical details to use this feature. The configuration examples below are copy-paste ready.

Prerequisites

  • A Telegram account
This page covers three Telegram chat types: direct messages (1:1), groups (multi-party conversation), and channels (broadcast feeds). Each has its own section below; the Setup flow gets the bot online for DMs, then the Groups and Channels sections add the chat-type specifics.
Setting this up for several people or a team? See Multiple users and teams for the privacy and isolation model - DMs are private per person, but a shared agent shares its learned memory, so route each person or group to their own agent for full separation.
Group privacy mode is ON by default. With the default in place, Telegram only forwards group messages to your bot when the message @-mentions it, replies to one of its messages, or is a /cmd@<botname> command. Plain group chatter never reaches Comis. If you want the bot to respond freely (or use groupActivation: "always" | "custom"), follow the Disable BotFather privacy mode procedure - toggling the setting alone is not enough, you must kick and re-add the bot afterwards because Telegram caches the privacy flag at the moment the bot joins.

Setup

1

Create a bot with BotFather

Open Telegram and search for @BotFather (the official bot for creating bots - verified with a blue check).Send /newbot and follow the prompts:
  1. Choose a display name for your bot (for example, MyTeamBot)
  2. Choose a username ending in bot (for example, my_team_comis_bot)
BotFather will confirm creation and display your bot token.
2

Copy the bot token

BotFather replies with a token that looks like 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11. Copy it immediately and store it somewhere safe.This token is your bot’s password. Anyone who has it can control your bot.
3

Configure Comis

Add the Telegram channel to your Comis configuration file (~/.comis/config.yaml):
channels:
  telegram:
    enabled: true
    botToken: "${TELEGRAM_BOT_TOKEN}"
Set the TELEGRAM_BOT_TOKEN environment variable in your ~/.comis/.env file:
TELEGRAM_BOT_TOKEN=your-token-from-step-2
Never store API keys, tokens, or passwords directly in config.yaml. Use the .env file or Secret Manager for credential management.
4

Restart and verify

Restart the Comis daemon to pick up the new configuration:
comis daemon stop && comis daemon start
Check the logs for a successful connection:
comis daemon logs
Look for a line containing “Telegram adapter connected” or “channel-telegram activated”. If you see this, your bot is online.Open Telegram, find your bot by its username, and send it a message to confirm it responds.

Configuration

These options go under channels.telegram in your config.yaml:
OptionTypeDefaultWhat it does
enabledbooleanfalseTurns on the Telegram adapter
botTokenstring / SecretRef(required)Bot authentication token from BotFather (env: TELEGRAM_BOT_TOKEN)
webhookUrlstring(optional)Public webhook URL. When set, Telegram pushes updates over HTTPS instead of long-polling.
allowFromstring[][] (all)Restrict to specific Telegram user IDs. Empty means all users can talk to the bot.
mediaProcessing.transcribeAudiobooleantrueTranscribe voice messages to text before passing to the agent
mediaProcessing.analyzeImagesbooleantrueDescribe images sent to the bot using AI vision
mediaProcessing.describeVideosbooleantrueExtract descriptions from video content
mediaProcessing.extractDocumentsbooleantrueExtract text from PDFs, DOCX, and other documents
mediaProcessing.understandLinksbooleantrueFetch and summarize URLs included in messages
By default the adapter uses long-polling (Grammy runner with auto-retry on HTTP 429). Set TELEGRAM_WEBHOOK_SECRET in your .env if you switch to webhook delivery — Comis uses it to verify the X-Telegram-Bot-Api-Secret-Token header on incoming requests.

What your agent can do

Once connected to Telegram, your agent can:
  • Send, edit, and delete messages in any chat it has access to
  • React to messages with emoji (Telegram limits the supported emoji set)
  • Send inline buttons for user choices
  • Send rich cards with formatted content
  • Use HTML formatting (bold, italic, code, links, spoilers, blockquotes, custom emoji)
  • Apply message effects (spoiler reveal, silent send)
  • Send file attachments up to 50 MB
  • Send native voice messages (audio attachments uploaded as Telegram voice notes)
  • Stream responses with live editing (updates every 300 ms)
  • Mention users in group chats
  • Send native polls and stickers via platform actions (poll, sticker)
  • Receive location and venue messages — coordinates appear in the agent’s message metadata so the agent can react to “I’m at the office now”
  • Pin and unpin messages, set chat title and description, ban or promote members, and manage forum topics (create, edit, close, reopen)
Telegram supports native forum topics (threads) in supergroups. It does not support fetching message history (Bot API limitation) or read receipts.
File reference guard. Markdown like config.go or README.md looks like a domain name to Telegram’s link previewer, which generates broken preview cards. Comis automatically wraps such filenames in <code> tags before sending so your messages never contain phantom link cards. No configuration is needed.

Platform limits

LimitValueWhat Comis does about it
Message length4,096 charactersAutomatically splits long responses into multiple messages at paragraph boundaries
Attachment size50 MBFiles over 50 MB are rejected with a user-friendly error message

Groups

Telegram groups (and supergroups) are multi-party chats where many users talk together. The bot is just another member, and Telegram applies an extra filter - privacy mode - that determines which messages the bot can see at all. The Comis activation policy then decides which of those messages should trigger a reply. Both layers matter; misconfiguring either one results in the bot looking “broken.”

How addressing works (default)

Out of the box, your agent activates in a group when any of these is true:
  • The message contains @<your_bot_username> parsed as a Telegram mention entity
  • The message is a reply to one of the bot’s previous messages
  • The message is a slash command targeted at the bot: /cmd@<your_bot_username>
Plain group chatter (no mention, no reply, no command) is silently recorded as history context but does not activate the agent. This is the mention-gated activation mode and is the default for autoReplyEngine.groupActivation.

Setting up a Telegram group

1

Complete the base Setup section first

Confirm the bot is online and replying to DMs (the Setup flow above). Group setup builds on a working DM bot.
2

Add the bot to your group

In Telegram, open the group → tap the group name → Add Members → search for @<your_bot_username> → tap the bot → Add. The bot does not need to be an administrator unless you turn off privacy mode (next step) or your agent uses platform actions like ban/promote/pin that require admin rights.
3

(Recommended) Disable BotFather privacy mode

Required only if you want the bot to see all group messages - for example, when running with groupActivation: "always" or "custom", or when your agent passively monitors group chatter. If you only need mention-gated behavior, skip this step and leave privacy on.See Disable BotFather privacy mode immediately below for the full procedure (including the mandatory kick-and-readd step).
4

Restrict who can talk to the bot (optional)

By default, any user in the group can activate the bot. To restrict it to specific Telegram user IDs, add them to allowFrom in ~/.comis/config.yaml:
channels:
  telegram:
    enabled: true
    botToken: "${TELEGRAM_BOT_TOKEN}"
    allowFrom:
      - "678314278"      # Alice
      - "5900067809"     # Bob
allowFrom is sender-keyed, not chat-keyed. Adding the group’s chat ID to allowFrom does not whitelist the group - every individual user you want to enable must be listed by their Telegram user ID. To find a user’s ID, ask them to send any message in the group while you tail pm2 logs comis (the senderId field is logged on every inbound). Leave allowFrom: [] (or omit it) to allow all users.
5

Restart the daemon and verify

Restart the Comis daemon to pick up the new configuration:
comis daemon stop && comis daemon start
Check the logs for a successful connection:
comis daemon logs
Look for a line containing “Telegram adapter connected” or “channel-telegram activated”. In the group, send a fresh @<your_bot_username> hello (when typing @, tap the suggestion popup so Telegram parses it as a mention entity - typing the text alone is not enough). The bot should reply within seconds.

Disable BotFather privacy mode

Permanently disable privacy mode so the bot sees all group messages reliably.
1

Toggle the setting in BotFather

Open Telegram, message @BotFather, then:/mybots → select @<your_bot_username>Bot SettingsGroup PrivacyTurn offBotFather confirms Privacy mode is disabled for <bot>.
2

Kick and re-add the bot in every existing group

This step is mandatory. Telegram caches the privacy flag at the moment the bot joins a group. Toggling the setting in BotFather does not retroactively unlock messages in groups the bot is already in.For every group where you want the bot to see all messages:
  1. Open the group → tap the group name → Members
  2. Find the bot → swipe (iOS) or long-press (Android) → Remove
  3. Re-add the bot via Add Members@<your_bot_username>Add
From this point on, the bot receives every message in those groups.
3

Verify the flag is off

Confirm via the Bot API directly:
TOKEN=$(grep '^TELEGRAM_BOT_TOKEN' ~/.comis/.env | cut -d= -f2- | tr -d '"')
curl -s "https://api.telegram.org/bot${TOKEN}/getMe" | python3 -m json.tool
Look for "can_read_all_group_messages": true. If it still says false, BotFather hasn’t propagated the change yet - wait a minute and try again.
Privacy off = bot sees everything. Once disabled, the bot receives every message in the group, including DMs between members that get quoted, file attachments, location pins, and so on. Comis still applies its own activation policy (so it doesn’t reply to everything), but the data flows into the agent’s history buffer. Only disable privacy if you need it.

Group activation modes

Comis decides whether to activate the agent based on the autoReplyEngine.groupActivation config (top level of config.yaml):
autoReplyEngine:
  enabled: true
  groupActivation: mention-gated   # default - recommended
  customPatterns: []               # used only when groupActivation: custom
  historyInjection: true           # silently buffer non-trigger messages as context
  maxHistoryInjections: 50
  maxGroupHistoryMessages: 20
ModeWhen the agent activatesPrivacy mode requirement
mention-gated (default)Message @-mentions the bot, replies to it, or uses /cmd@<botname>Privacy on is fine
alwaysEvery group messagePrivacy must be off
customMessage text matches one of customPatterns (regex)Privacy must be off
historyInjection: true silently records non-trigger group messages into a ring buffer per session, so when the agent does activate, it has the recent context. Set to false to drop them entirely. custom example - wake the agent on either a regex trigger or any question:
autoReplyEngine:
  groupActivation: custom
  customPatterns:
    - "^hey bot\\b"
    - "\\?$"

Routing different groups to different agents

If you want a single bot to serve multiple agents - one per group, or one per user - use top-level routing bindings. The Multi-agent routing section below has the full schema and examples.

Finding a group’s chat ID

You’ll need the group’s numeric chat ID (looks like -1001234567890 or -5152588116) for routing bindings, log filters, or sending posts programmatically.
# Send any message in the group with the bot present, then:
pm2 logs comis --lines 50 --nostream | grep -E '"chatId":"-[0-9]+"' | tail -3
Or via the API:
TOKEN=$(grep '^TELEGRAM_BOT_TOKEN' ~/.comis/.env | cut -d= -f2- | tr -d '"')
curl -s "https://api.telegram.org/bot${TOKEN}/getUpdates" \
  | python3 -m json.tool | grep -A1 '"chat":' | head -20
Group chat IDs are negative; supergroup IDs are large negative numbers (typically starting with -100).

Channels

Telegram channels are one-way broadcast feeds: one or more administrators post; subscribers read. Channels are not chats - there are no member messages to respond to. Use a channel when you want the agent to publish status updates, daily summaries, monitoring alerts, or any kind of scheduled feed. Use a group instead if you want a conversational bot.

Setting up a Telegram channel

1

Create the channel in Telegram

iOS / Android: tap the pencil icon (top right on iOS, ✏️ floating button on Android) → New Channel. Desktop / Web: click the menu icon (☰) → New Channel.Set channel name, optional description and photo, then choose Public (gets a t.me/<handle> link, anyone can find it) or Private (invite-only via link).
2

Add the bot as an administrator

Channels do not have plain “members” for bots - bots must be administrators or they cannot post.Open the channel → tap the channel name (header) → AdministratorsAdd Administrator → search @<your_bot_username> → tap to select. Grant at minimum Post Messages. For richer behavior also enable Edit Messages, Delete Messages, and (if your agent manages subscribers) Add Subscribers. Save.
3

Find the channel's chat ID

Post any message in the channel as the bot’s owner, then check logs or hit the API:
TOKEN=$(grep '^TELEGRAM_BOT_TOKEN' ~/.comis/.env | cut -d= -f2- | tr -d '"')
curl -s "https://api.telegram.org/bot${TOKEN}/getUpdates" \
  | python3 -m json.tool | grep -B1 -A2 '"type": "channel"' | head -20
Channel chat IDs are large negative numbers, typically -1001234567890.
4

Have the agent post into the channel

Comis treats channels as ordinary delivery targets. Your agent can post via the messaging tool (message skill), background tasks, or the gateway HTTP API. Use the channel’s numeric chat ID as the target:
# Manual test from the host:
TOKEN=$(grep '^TELEGRAM_BOT_TOKEN' ~/.comis/.env | cut -d= -f2- | tr -d '"')
CHANNEL_ID="-1001234567890"
curl -s "https://api.telegram.org/bot${TOKEN}/sendMessage" \
  -d "chat_id=${CHANNEL_ID}" \
  -d "text=Hello from the bot!"
For scheduled posts, wire a heartbeat or cron task that calls the messaging tool with channelType: "telegram" and channelId: "<channel-id>".
Channel privacy mode does not apply. The BotFather privacy toggle governs groups, not channels. Bot admins in channels see exactly the posts you’d expect to see - there’s nothing extra to enable.

Inbound from channels

Telegram emits channel_post updates for messages authored in the channel. Comis normalizes these the same way as group messages: chatType: "channel" in the prompt context, telegramChatType: "channel" in metadata. The auto-reply gate also applies, so if you want the agent to react to channel posts (rare - usually channels are write-only from the agent’s perspective), set groupActivation: "always" or "custom" and target the channel’s chat ID in your routing bindings.

Multi-agent routing

A single Telegram bot can serve multiple agents. Comis resolves which agent handles a given message via the top-level routing config, with bindings ranked by specificity (peerId 8 > channelId 4 > guildId 2 > channelType 1).
agents:
  default:
    model: claude-opus-4-7
  research:
    model: claude-sonnet-4-6
  ops:
    model: claude-haiku-4-5

routing:
  defaultAgentId: default
  bindings:
    # Per-chat: this group always routes to research agent
    - channelType: telegram
      channelId: "-5152588116"
      agentId: research

    # Per-user: Alice always hits ops agent (in any chat)
    - channelType: telegram
      peerId: "678314278"
      agentId: ops

    # Per-user-in-chat: Bob in the research group goes to default
    - channelType: telegram
      channelId: "-5152588116"
      peerId: "111222333"
      agentId: default
mention-gated and allowFrom apply per resolved agent - first the bot receives the message, then the router picks the agent, then the agent’s gate runs. Multi-agent setups don’t change addressing rules; they just change which agent answers. Routing to separate agents is also how you isolate memory between people: each agent keeps its own long-term memory, secrets, and budget, so two users on different agents never share learned facts. For the full multi-user model - what is private by default and what isn’t - see Multiple users and teams. If you need a literally separate bot identity per agent (different @username, different command menus), run one Comis daemon per bot:
mkdir -p ~/.comis-research && cp ~/.comis/config.yaml ~/.comis-research/config.yaml
# Edit to use a different TELEGRAM_BOT_TOKEN and a single agent
COMIS_CONFIG_PATHS="$HOME/.comis-research/config.yaml" \
  pm2 start packages/daemon/dist/daemon.js --name comis-research
The schema currently allows one channels.telegram entry per daemon, so multi-bot in a single daemon is not yet supported.

Forum Topics

Telegram supergroups can enable forum mode, which organizes conversations into topics — similar to channels within a Discord server. Each topic is a separate conversation thread with its own name, icon, and message history. When forum mode is enabled, your agent automatically detects which topic a message came from and routes its replies to the same topic.

Setting up forum topics

1

Enable forum mode in your Telegram group

Open your Telegram supergroup, go to Settings (tap the group name) > Topics > Enable. The group must be a supergroup — regular groups do not support forums.
2

Make the bot an administrator

Your bot needs admin permissions to manage forum topics. Go to Settings > Administrators > Add Administrator and select your bot. Grant at least Manage Topics permission.
3

No Comis configuration needed

Forum topic support is automatic. When your bot receives a message from a forum topic, Comis routes replies to that topic. No changes to config.yaml are required.

How it works

When a user sends a message in a forum topic:
  1. Comis detects the topic and attaches thread metadata to the message
  2. The agent processes the message as usual
  3. All replies — including multi-part responses, media, and voice — go to the same topic
  4. Typing indicators appear in the correct topic
Each topic gets its own session by default, so conversations in different topics stay separate. See Sessions for details on per-topic session isolation and how to configure it.

General Topic

Every forum group has a General topic that exists by default. Comis handles the General Topic automatically — no special configuration is needed. Messages sent to the General Topic work the same as messages in any other topic.
Your agent can create, edit, close, and reopen forum topics using platform actions. This lets the agent organize conversations programmatically — for example, creating a new topic for each support ticket.

Complete walkthrough: from zero to first reply

Here is a top-to-bottom run for a brand-new bot called MyTeamBot:
1

Create the bot

Open Telegram, message @BotFather, send /newbot, type MyTeamBot as the display name, then my_team_comis_bot as the username. BotFather replies with a token like 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11.
2

Wire it into Comis

Add to ~/.comis/.env:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Add to ~/.comis/config.yaml under channels:
channels:
  telegram:
    enabled: true
    botToken: "${TELEGRAM_BOT_TOKEN}"
3

Restart the daemon and verify

Restart Comis:
comis daemon stop && comis daemon start
Tail the logs:
comis daemon logs
You should see a line like {"level":30,"module":"channel-telegram","msg":"Telegram adapter connected"}.
4

Send the first message

In Telegram, search for @my_team_comis_bot, tap Start, and send Hello!. The bot shows a typing indicator, then replies with whatever your agent’s persona dictates — streamed live with edits every 300 ms until the response is complete.

Troubleshooting

The fastest diagnostic for “bot didn’t reply in a group” is to tail the daemon log while you send the test message:
pm2 logs comis --lines 0 | grep -E 'Inbound message|Group message did not activate|Group message ignored|autoreply:activated|Execution complete|Delivery complete'
Three possible outcomes tell you which layer is failing:
  1. No Inbound message log at all → Telegram never forwarded the message to the bot. This is a Telegram-side filter (privacy mode, bot not in group, mention not parsed as an entity). See the first accordion below.
  2. Inbound message followed by Group message did not activate agent → Comis received the message but the activation policy suppressed it. The log line includes isBotMentioned, replyToBot, and activationMode so you can see exactly why. See the second accordion.
  3. Inbound messageautoreply:activatedExecution completeDelivery complete → Working as designed. If the user still doesn’t see a reply, see the delivery accordion.
What happened: Telegram never sent the message to the bot. Most common causes:
  • Privacy mode is on AND the message wasn’t a recognized mention, reply, or /cmd@<botname>. With privacy on, Telegram filters every other message before it reaches the bot. Typing @<your_bot_username> as plain text is not enough - your Telegram client must parse it as a mention entity at send time (look for the in-app suggestion popup when you type the @).
  • The bot isn’t actually in the group. Check the member list. Re-add it via the group’s Add Members flow.
  • The bot was added to the group while privacy mode was on, then privacy was disabled. The flag is cached at join time - kick and re-add the bot. See Disable BotFather privacy mode.
Verify privacy state directly:
TOKEN=$(grep '^TELEGRAM_BOT_TOKEN' ~/.comis/.env | cut -d= -f2- | tr -d '"')
curl -s "https://api.telegram.org/bot${TOKEN}/getMe" | python3 -m json.tool
"can_read_all_group_messages": false means privacy is on (the BotFather default).Quick test that bypasses privacy mode entirely: send /start@<your_bot_username> in the group. /cmd@<botname> always reaches the bot regardless of privacy. If that fires the agent, your code path is fine and the issue was Telegram-side filtering on the earlier test.
What happened: Comis received the message, but the auto-reply gate suppressed it. The diagnostic log spells out why:
{"msg":"Group message did not activate agent",
 "isBotMentioned": false, "replyToBot": false,
 "reason":"group-not-mentioned", "activationMode":"mention-gated", ...}
Common causes:
  • activationMode: "mention-gated" and the message didn’t @-mention the bot. Either type @<your_bot_username> properly (tap the suggestion) or switch to groupActivation: "always" (privacy must be off - see the Groups section).
  • The message was an edit. Telegram doesn’t always re-emit mention entities for edits; send a fresh message instead.
  • Your activation policy expects a custom regex that didn’t match. Inspect the log’s reason field.
To make every group message activate the agent, set:
autoReplyEngine:
  groupActivation: always
and disable BotFather privacy mode.
What happened: A user other than yourself tried to talk to the bot, but their Telegram user ID isn’t in channels.telegram.allowFrom. You’ll see this log line:
{"msg":"Sender blocked by allowFrom filter",
 "senderId":"<their-id>", "errorKind":"auth", ...}
How to fix it: add their user ID to allowFrom, or remove allowFrom (or set it to []) to allow all senders. allowFrom only matches sender IDs - putting a group’s chat ID there does nothing.
What happened: The token is expired, revoked, or was copied incorrectly.How to fix it: Open Telegram, send /token to @BotFather, and select your bot to regenerate the token. Update the token in your ~/.comis/.env file and restart the daemon.
What happened: The privacy flag is per-bot in BotFather, but Telegram caches it on the bot’s group membership at the time of joining. Disabling privacy in BotFather does not retroactively apply to groups the bot is already in.How to fix it: kick the bot from each affected group, then re-add it. See Disable BotFather privacy mode for the full procedure plus the API call to verify the flag flipped.
What happened: Telegram uses long-polling for bot updates, which can occasionally have brief delays.How to fix it: This is normal Telegram behavior, not a Comis issue. If delays exceed several seconds consistently, check your server’s network connection and firewall rules for outbound HTTPS traffic.

Delivery Infrastructure

How streaming, typing indicators, and retry logic work under the hood.

All Channels

Compare all 9 supported platforms side by side.

Agent Configuration

Set up your agent’s personality, tools, and behavior.

Secret Management

Learn how to manage API keys and tokens securely.