Files
Playa/docs/telegram-bot.md

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

  1. Create a bot with @BotFather (/newbot) and copy the token.
  2. Find your numeric Telegram user id, for example by messaging @userinfobot.
  3. Install Claude Code on the machine that runs the bot and log in (claude, then /login). Check with claude --version; see claude-code-provider.md.
  4. 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 getUpdates waits 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 logs Telegram 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.