Telegram
Moltis can connect to Telegram as a bot, letting you chat with your agent from any Telegram conversation. The integration uses Telegram’s Bot API with long polling — no public URL or webhook endpoint is required.
How It Works
┌──────────────────────────────────────────────────────┐
│ Telegram Bot API │
│ (api.telegram.org/bot...) │
└──────────────────┬───────────────────────────────────┘
│ long polling (getUpdates)
▼
┌──────────────────────────────────────────────────────┐
│ moltis-telegram crate │
│ ┌────────────┐ ┌────────────┐ ┌────────────────┐ │
│ │ Handler │ │ Outbound │ │ Plugin │ │
│ │ (inbound) │ │ (replies) │ │ (lifecycle) │ │
│ └────────────┘ └────────────┘ └────────────────┘ │
└──────────────────┬───────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ Moltis Gateway │
│ (chat dispatch, tools, memory) │
└──────────────────────────────────────────────────────┘
The bot connects outward to Telegram’s servers via polling. No port forwarding, public domain, or TLS certificate is needed. This makes it easy to run on a home machine or behind a NAT.
Prerequisites
Before configuring Moltis, create a Telegram bot:
- Open Telegram and message @BotFather
- Send
/newbotand follow the prompts to choose a name and username - Copy the bot token (e.g.
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
Configuration
Add a [channels.telegram.<account-id>] section to your moltis.toml:
[channels.telegram.my-bot]
token = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
Make sure "telegram" is included in channels.offered so the Web UI shows
the Telegram option:
[channels]
offered = ["telegram"]
Configuration Fields
| Field | Required | Default | Description |
|---|---|---|---|
token | yes | — | Bot token from @BotFather |
dm_policy | no | "allowlist" | Who can DM the bot: "open", "allowlist", or "disabled" |
group_policy | no | "open" | Who can talk to the bot in groups: "open", "allowlist", or "disabled" |
mention_mode | no | "mention" | When the bot responds in groups: "always", "mention" (only when @mentioned), or "none" |
allowlist | no | [] | User IDs or usernames allowed to DM the bot (when dm_policy = "allowlist") |
group_allowlist | no | [] | Group/chat IDs allowed to interact with the bot |
untrusted_audience | no | "public" | Tool audience ceiling for turns outside an operator direct chat: "public" or "trusted" |
untrusted_tools | no | "deny_all" | Tool name policy for those turns: "deny_all", or "policy" to let configured policy layers decide |
model | no | — | Override the default model for this channel |
model_provider | no | — | Provider for the overridden model |
agent_id | no | — | Default agent ID for this bot’s sessions |
reply_to_message | no | false | Send bot responses as Telegram replies to the user’s message |
otp_self_approval | no | true | Enable OTP self-approval for non-allowlisted DM users |
otp_cooldown_secs | no | 300 | Cooldown in seconds after 3 failed OTP attempts |
stream_mode | no | "edit_in_place" | Streaming mode: "edit_in_place" or "off" |
edit_throttle_ms | no | 2000 | Minimum milliseconds between streaming edit updates |
stream_notify_on_complete | no | false | Send the final answer as a notifying message instead of silently reusing the progress message |
stream_min_initial_chars | no | 30 | Minimum characters before sending the first temporary progress message |
stream_progress_max_chars | no | 3500 | Maximum recent progress characters kept visible in the temporary streamed message |
Full Example
[channels]
offered = ["telegram"]
[channels.telegram.my-bot]
token = "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
dm_policy = "allowlist"
group_policy = "open"
mention_mode = "mention"
allowlist = ["123456789", "alice_username"]
group_allowlist = ["-1001234567890"]
reply_to_message = true
model = "claude-sonnet-4-20250514"
model_provider = "anthropic"
agent_id = "research"
otp_self_approval = true
stream_mode = "edit_in_place"
edit_throttle_ms = 2000
Tools in Shared Chats
By default, Telegram group chats, guest DMs (messages from non-operators), and unknown chat kinds receive no tools. As with Slack, MCP tools require both account settings below:
[channels.telegram.my-bot]
untrusted_audience = "trusted"
untrusted_tools = "policy"
untrusted_audience = "trusted" makes MCP, WASM, and other trusted-audience
tools eligible. untrusted_tools = "policy" removes the blanket name denial
and lets the tool policy layers decide which tools are
available. Neither setting alone enables MCP tools, and a policy allow list
alone cannot bypass the default ceiling.
For TOML-managed accounts, restrict tools for each enabled chat type with
tools.groups.<chat_type> policies, including private for guest DMs. For
UI-managed accounts, database-backed tools.groups policies are not currently
part of runtime policy resolution: configure a restrictive global or provider
policy before lifting the ceiling. Denials in any policy layer still win.
These settings do not grant /sh, privileged commands, or owner-private prompt
context in shared chats. Those remain restricted to operators in proven direct
chats.
Per-User and Per-Channel Model and Agent Overrides
You can override the model or agent for specific users or group chats:
[channels.telegram.my-bot]
token = "..."
model = "claude-sonnet-4-20250514"
model_provider = "anthropic"
[channels.telegram.my-bot.channel_overrides."-1001234567890"]
model = "gpt-4o"
model_provider = "openai"
agent_id = "triage"
[channels.telegram.my-bot.user_overrides."123456789"]
model = "claude-opus-4-20250514"
model_provider = "anthropic"
agent_id = "research"
User overrides take priority over channel overrides, which take priority over the account default, for both model selection and agent selection.
Access Control
Telegram uses the same gating system as Discord and other channels.
DM Policy
Controls who can send direct messages to the bot.
| Value | Behavior |
|---|---|
"allowlist" | Only users listed in allowlist can DM (default) |
"open" | Anyone who can find the bot can DM it |
"disabled" | DMs are silently ignored |
Group Policy
Controls who can interact with the bot in group chats.
| Value | Behavior |
|---|---|
"open" | Bot responds in any group (default) |
"allowlist" | Only groups listed in group_allowlist are allowed |
"disabled" | Group messages are silently ignored |
Mention Mode
Controls when the bot responds in groups (does not apply to DMs).
| Value | Behavior |
|---|---|
"mention" | Bot only responds when @mentioned (default) |
"always" | Bot responds to every message in allowed groups |
"none" | Bot never responds in groups (useful for DM-only bots) |
Allowlist Matching
Allowlist entries support:
- Exact match (case-insensitive):
"alice","123456789" - Glob wildcards:
"admin_*","*_bot","user_*_vip"
Both the user’s numeric Telegram ID and their username are checked
against the allowlist. For example, if a user has ID 123456789 and username
alice, either "123456789" or "alice" in the allowlist grants access.
OTP Self-Approval
When dm_policy = "allowlist" and otp_self_approval = true (the default),
unknown users who DM the bot receive a verification challenge:
- User sends a DM to the bot
- Bot responds with a challenge prompt (the 6-digit code is not shown to the user)
- The code appears in the Moltis web UI under Channels > Senders
- The bot owner shares the code with the user out-of-band
- User replies with the 6-digit code
- On success, the user is automatically added to the allowlist
After 3 failed attempts, the user is locked out for otp_cooldown_secs seconds
(default: 300). Codes expire after 5 minutes.
Set otp_self_approval = false if you want to manually approve every user from
the web UI.
Streaming
By default (stream_mode = "edit_in_place"), Telegram shows temporary progress
while a turn is running. The bot sends a silent progress message after
stream_min_initial_chars characters (default: 30), edits that progress message
at most once every edit_throttle_ms milliseconds (default: 2000), and keeps only
the latest stream_progress_max_chars progress characters visible.
When the final answer is ready, the progress message is cleaned up or reused and
the final answer is delivered separately from intermediate progress. With
stream_notify_on_complete = false (default), Moltis may silently reuse the
existing progress message for the final answer. With stream_notify_on_complete = true, Moltis deletes the progress message where possible and sends the final
answer as a new notifying message.
Session Commands
Telegram supports the standard channel session commands:
| Command | Description |
|---|---|
/new | Start a fresh session for the current chat |
/sessions | List or switch among sessions already bound to the current chat |
/attach | List existing non-cron sessions and rebind one to the current chat |
/agent | List or switch chat agents |
/mode | List or switch temporary session modes |
/model | List or switch models |
/approvals | List pending exec approvals for the current session |
/approve N | Approve the numbered exec request from /approvals |
/deny N | Deny the numbered exec request from /approvals |
/sessions is intentionally scoped to the current chat. If you want to bring a
different existing session into the chat, use /attach instead. Reattaching a
session moves that session’s channel binding to the current chat, it is not a
copy.
Set stream_mode = "off" to disable streaming and send the full response as a
single message.
When stream_notify_on_complete = true, the bot sends a short non-silent
message after streaming finishes. This can trigger a Telegram push notification
on the user’s device (since silent edits don’t always trigger notifications).
Finding Your Telegram User ID
To find your numeric Telegram user ID (for the allowlist):
- Message @userinfobot on Telegram
- It replies with your user ID, first name, and username
- Use the numeric ID as a string in your config:
allowlist = ["123456789"]
Alternatively, use your Telegram username (without the @): allowlist = ["your_username"].
Web UI Setup
You can also configure Telegram through the web interface:
- Open Settings > Channels
- Click Connect Telegram
- Enter an account ID (any alias) and your bot token
- Adjust DM policy, mention mode, and allowlist as needed
- Click Connect
The same form is available during onboarding when Telegram is in channels.offered.
In Settings > Channels, use the account’s Advanced Config JSON editor for settings without dedicated form fields. To opt into trusted-audience tools and policy-based access, set:
{
"untrusted_audience": "trusted",
"untrusted_tools": "policy"
}
Read Tools in Shared Chats and configure restrictive
access and tool policies first. Channel settings added or edited in the web UI
are stored in data_dir()/moltis.db, not written back to moltis.toml. Use the
TOML examples only for manually managed accounts.
Troubleshooting
Bot doesn’t respond
- Verify the bot token is correct (ask @BotFather for
/tokenif unsure) - Check
dm_policy— if set to"allowlist", make sure your user ID or username is listed inallowlist - An empty
allowlistwithdm_policy = "allowlist"blocks all DMs - Check
group_policy— if"disabled", group messages are ignored - Look at logs:
RUST_LOG=moltis_telegram=debug moltis
”allowed_users” doesn’t work
The field name is allowlist, not allowed_users. If you’re migrating from
OpenClaw, note that the field was renamed. Values must also be strings
(e.g. ["123456789"]), not integers.
Bot responds to everyone
- Check that
dm_policy = "allowlist"is set (it’s the default) - Verify you have entries in
allowlist— an empty allowlist withdm_policy = "allowlist"blocks everyone, butdm_policy = "open"allows everyone
Bot doesn’t respond in groups
- Check
mention_mode— if set to"mention", you must @mention the bot - Check
group_policy— if"disabled", group messages are ignored - Check
group_allowlist— if non-empty, the group must be listed