3.8 KiB
Telegram bot
hosts/Volcanic.AgenticCore.Telegram lets you chat with the agent from Telegram. It uses long polling (no public
URL, no webhook), gives every private chat its own agent session and workspace, and runs the model through the
Claude Code provider (claude-code/claude-opus-5-5) on your Claude subscription.
Setup
- Create a bot with @BotFather (
/newbot) and copy the token. - Find your numeric Telegram user id, for example by messaging @userinfobot.
- Install Claude Code on the machine that runs the bot and log in (
claude, then/login). Check withclaude --version; see claude-code-provider.md. - Run:
TELEGRAM_BOT_TOKEN=123456:ABC... \
TELEGRAM_ALLOWED_USER_IDS=111111111 \
dotnet run --project hosts/Volcanic.AgenticCore.Telegram
Open the bot in Telegram and say hello.
Configuration
Environment variables, or the Telegram section of appsettings.json (Telegram__Name in the environment):
| Setting | Default | Notes |
|---|---|---|
TELEGRAM_BOT_TOKEN / Telegram:BotToken |
— | Required |
TELEGRAM_ALLOWED_USER_IDS / Telegram:AllowedUserIds |
— | Required, comma separated. The bot refuses to start without it |
Telegram:WorkspaceRoot |
~/.volcanic/telegram-workspaces |
Chat <id> works in <root>/<id> |
Telegram:Model |
claude-code/claude-opus-5-5 |
Any provider/model the Claude Code provider serves |
Telegram:EditInterval |
00:00:01.5 |
Minimum time between edits of a streaming reply |
Telegram:ReconnectInitialDelay / ReconnectMaxDelay |
1 s / 60 s |
Backoff after lost connection |
Sessions are stored as usual under ~/.volcanic/agent/sessions/telegram-<chatId>/; after a restart each chat resumes
its most recent conversation.
Using it
Write normally. The reply streams into one message (split into several past Telegram's 4096 character limit);
each tool call shows as a line, ▶ bash: ls -la becoming ✓ bash or ✗ bash with an excerpt of the error.
A message sent while the agent works steers the current run. Photos (with or without a caption) are passed to the model.
| Command | |
|---|---|
/new |
Start a new conversation |
/stop |
Stop the current run |
/status |
Model, thinking level, session, context usage, workspace |
/sessions, /resume <id> |
List and resume earlier conversations (an id prefix is enough) |
/compact |
Summarise the conversation to free context |
/thinking [level] |
Show or set the thinking level (Claude Code --effort) |
/help |
Short help |
Any other /command is passed to the session, so extension commands such as /claude-code-doctor work.
When an extension asks something, the question appears with buttons (or as a reply prompt for free text).
Security
The agent has the built-in tools, including bash, and runs them as the bot's OS user. Only allow-listed user ids
are served (everyone else is ignored and logged), and only in private chats. Run the bot as a dedicated user or in a
container, and treat the workspace root as writable by anyone on the allow-list.
Connection loss
Polling uses Telegram.Bot's built-in loop with a hardened error handler:
- a failed
getUpdateswaits 1 s, 2 s, 4 s … up to 60 s (±20 % jitter) before the next attempt, instead of retrying in a tight loop; the first successful poll resets the delay and logsTelegram connection restored; - the update offset only moves past updates that were handed on, so reconnecting neither loses nor repeats messages;
- if the loop itself ever ends while the host runs, it is restarted from the last offset;
- a
401(revoked or wrong token) is the one error it does not retry: the host logs it and exits with code 1.
Replies that fail to send (Telegram unreachable mid-run) are logged; the render loop keeps going and later edits catch the message up.