Skip to main content
OpenSRE’s Telegram integration delivers investigation findings to any chat your bot has been added to — useful for mobile-first on-call rotations and personal alerting. Start the interactive shell with opensre (no subcommand). Slash commands below are run from that REPL.

Prerequisites

  • A Telegram account.
  • The Telegram mobile or desktop app, signed in.
  • The chat (group, channel, or direct message) where you want to receive findings.

Step 1: Create a bot with BotFather

BotFather is Telegram’s official bot for creating other bots.
  1. Open Telegram and search for @BotFather. Open the chat and tap Start.
  2. Send /newbot.
  3. When prompted, send a display name for your bot (e.g. OpenSRE Alerts).
  4. Send a username that ends in bot (e.g. opensre_alerts_bot). It must be globally unique.
  5. BotFather replies with an HTTP API token of the form <numeric-id>:<token-secret>. Copy it — it is your bot token. Treat it like a password. Anyone holding it can send messages as your bot.
You can change the bot name, picture, and description later by sending /mybots to BotFather and selecting your bot.

Step 2: Add the bot to a chat

The bot can deliver to three kinds of destinations. Pick the one that fits your team:
  1. Open the group where you want findings to land.
  2. Tap the group name → Add members → search for your bot username → Add.
  3. By default, bots in groups only see messages addressed to them, which is fine for delivery-only.

Step 3: Find your chat_id

The chat ID identifies where the bot should post. It is required — without it the bot has nowhere to send anything.
Posting to a public channel? Skip this step — setup accepts the channel’s @name (for example @acme_alerts) directly. Private groups and DMs have no @name, so they need the steps below.
  1. Send any message in the destination chat — for a channel, post anything; for a DM, send /start to your bot.
  2. In a browser, open:
    (replace <YOUR_BOT_TOKEN> with the token from Step 1)
  3. In the JSON response, look for a chat.id field. The value depends on the chat type: Copy the entire value, including the leading minus sign for groups and channels.
If getUpdates returns an empty array, post a fresh message in the chat and reload — Telegram only buffers recent updates.

Step 4: Configure the integration

Interactive shell:
CLI:
Choose Telegram from the integration list. The wizard prompts for:
  • Bot token (required) — stored in the system keyring (not plain .env)
  • Default chat ID or @channelname (required) — written to .env as TELEGRAM_DEFAULT_CHAT_ID
Credentials are also saved to ~/.opensre/integrations.json via upsert_integration("telegram", ...). Both answers are checked before anything is saved, so a wrong token or a chat the bot was never added to fails here rather than silently at the first alert.
Setup confirms the bot can see the chat, not that it may post there. For a channel the bot still needs the Post Messages permission from Step 2.
Non-interactive setup: Interactive shell:
CLI:

Option B: Environment variables

Set in .env (bot token can also live in the keyring after wizard setup):
OpenSRE picks these up at startup and registers Telegram as an active integration.
Credential resolution. Every Telegram delivery surface — investigations, background RCA completion notifications, the scheduler, /watchdog, /hermes watch, and /watch — resolves the bot token the same way: integration store first, then resolve_env_credential("TELEGRAM_BOT_TOKEN") (process env, then OS keyring). Chat id is non-secret: --chat-id → store default_chat_idTELEGRAM_DEFAULT_CHAT_ID env (plain os.getenv, never keyring). Either setup option above works for all of them.

Step 5: Verify

Interactive shell:
Or:
CLI:
This calls Telegram’s getMe endpoint. On success it reports the bot @username. On failure it reports the Telegram API error message verbatim.
Verify only checks that your bot token is valid. It does not start a listening process and does not test two-way communication. If you DM your bot at this point, it will appear online but not reply. To receive and respond to messages from Telegram, complete Step 6 below.
You can also trigger a real delivery test against a bundled fixture: Interactive shell:
CLI:
Findings should appear in the configured chat. Long reports are truncated to Telegram’s 4,096-character message limit.

Step 6: Enable two-way chat (DM the agent from Telegram)

Skip this step if you only need outbound delivery (alerts, cron reports, investigation findings posted to a chat). Steps 1–5 are sufficient for that.
After verify succeeds, you have outbound delivery but the bot will not reply to your messages yet. Two extra steps are required:

6a — Allow your Telegram user

Find your numeric user id with @userinfobot, then: Interactive shell:
CLI:
Or set in .env:
Use the numeric user id (Telegram’s from.id), not a @username and not the bot handle. Inbound authorization only ever matches the numeric id, so a @handle produces an allow-list entry that can never match a real sender — you will see User <id> is not in the allowed users list for every message. The CLI now rejects non-numeric Telegram ids, but older entries may still be wrong; check with /messaging status -p telegram (or opensre messaging status -p telegram) and re-add with the numeric id.

6b — Start the gateway daemon

This runs the background daemon that listens for inbound Telegram DMs and routes them to the OpenSRE agent. Once it is running, DM your bot from Telegram — use /new for a fresh session or /help for built-in commands. Useful follow-up commands:
The gateway uses long polling — no public HTTPS URL or port forwarding is required for local use. See the Two-way chat gateway section below for deployment and remote-host setup.

Programmatic messaging: telegram_send_message tool

When the Telegram integration is configured, OpenSRE exposes a telegram_send_message tool. The tool can send user-requested action messages, incident notifications, or follow-up updates to the configured default chat, or to an explicit chat_id when one is supplied. Ask in plain language from the interactive shell (for example: “send a Telegram message to the team that DB CPU is back below 70%”).
The tool resolves the bot token from the same credential chain as the watchdog: integration store, then resolve_env_credential("TELEGRAM_BOT_TOKEN") (env then keyring). If chat_id is omitted, it sends through the configured default_chat_id, so a user can ask OpenSRE to send a message through the configured Telegram bot without knowing or exposing the bot token. Delivery is an external side effect. Its result includes a stable status, sent, error_type, chat_id, reply_to_message_id, and message_length shape so follow-up tool calls can tell configuration failures from Telegram delivery failures.

Two-way chat gateway (DM text)

OpenSRE can also run a Telegram messaging gateway so you can chat with the agent from your phone in a private DM. v1 supports text-only direct messages (no groups, voice, or attachments).

Allow your Telegram user

Find your numeric user id with @userinfobot, then: Interactive shell:
CLI:
or set TELEGRAM_ALLOWED_USERS=123456789 in .env.
Use the numeric user id (Telegram’s from.id), not a @username and not the bot handle. Inbound authorization only ever matches the numeric id, so a @handle produces an allow-list entry that can never match a real sender — you will see User <id> is not in the allowed users list for every message. The CLI now rejects non-numeric Telegram ids, but older entries may still be wrong; check with /messaging status -p telegram (or opensre messaging status -p telegram) and re-add with the numeric id.

DM pairing (optional)

Same policy as other messaging platforms. Generate a code: Interactive shell:
CLI:
Then open Telegram, DM your bot, and send:
Check pairing status: Interactive shell:
CLI:
Revoke access for a user: Interactive shell:
CLI:

Long polling (local and production)

No public HTTPS URL required. The gateway is OpenSRE’s background agent daemon — one process that runs the Telegram chat worker, the web health app, and the cron task scheduler. It runs in the background by default:
Starting prints the log location; logs are stored in ~/.opensre/gateway/gateway.log. If Telegram is not configured the daemon still runs the other components and opensre gateway status shows telegram: not configured. The same controls are available inside the interactive shell via /gateway:
Send a DM to your bot. Use /new to start a fresh session; /help for built-in commands. The gateway uses the same headless agent harness as the interactive shell, with Telegram-specific wiring:
  • Prompt grounding — CLI reference, AGENTS.md, integration list, and investigation flow context
  • Read-only evidence tools — live integration queries (GitHub, logs, metrics, etc.) via the gather pass when integrations are configured
  • Action toolsshell_run and investigation_start
Investigation delivery, background RCA completion notifications, watchdog alerts, and cron still use the outbound-only paths documented above — they do not require the gateway process.

Deploying the gateway to a remote host

Running the gateway on a server with make deploy-gateway (EC2) is different from local use in one important way: the remote host cannot read your local machine’s keychain. Guided setup stores the bot token (and your LLM API key) in the system keyring, which is perfect locally but does not travel to the deployed instance. So make deploy-gateway validates that the required secrets are present as plaintext env vars in .env, and aborts if they are only in the keychain:
If make deploy-gateway reports MISSING: TELEGRAM_BOT_TOKEN — API key not set or MISSING: OPENAI_API_KEY — API key not set (or your provider’s key env) even though local setup succeeded, this is why — copy the values into .env (or .env.deploy.example) for the deploy. A “missing” here means “not in the deploy env”, not “not configured”.

Scheduled, background, and watchdog delivery

Background investigation completion (RCA)

When the interactive shell runs investigations in background mode, Telegram can deliver the RCA summary as soon as a job finishes. Configure Telegram first (Steps 4–5 — the gateway in Step 6 is not required), then in the shell:
Keep using the shell while the RCA runs. On completion the summary — root cause, top analysis, next steps, and a short stats block — is posted as plain text to your default chat, truncated to Telegram’s 4,096-character limit. Confirm delivery with /background show <task_id>: the notify row reads telegram:sent, telegram:failed: <error>, or telegram:missing telegram integration: … when the bot token or chat id is not configured. A notification problem never fails the investigation itself. See Background investigations for the full command set.

Cron (recurring reports)

Interactive shell:
CLI:
See Cron for task kinds and scheduler daemon setup.

Watchdog (process threshold alarms)

Configure Telegram first (Steps 4–5), then: Interactive shell:
Or:
CLI:

Hermes incident escalation

Interactive shell:
CLI:
See Hermes for log tailing and incident classification setup.

Troubleshooting

/integrations verify telegram, /verify telegram, and opensre integrations verify telegram only call Telegram’s getMe endpoint, so they surface token-validity errors but cannot detect chat-routing problems. Delivery-time errors only show up when an investigation actually posts.

Errors from verify

Missing bot_token TELEGRAM_BOT_TOKEN is empty. Re-check .env and restart any long-running OpenSRE process so it re-reads the file. Telegram API check failed: 401 Client Error: Unauthorized for url: … The bot token is invalid or has been revoked. Generate a new one in BotFather (/mybots → your bot → API Token → Revoke current token) and update .env. The for url: portion of the message shows the token as <redacted> — Telegram’s API endpoint embeds the token in the path, so the verifier scrubs it before surfacing the error.

Errors that only surface during delivery

These are Telegram API responses that come back when OpenSRE actually tries to post a finding. verify only calls getMe, so it cannot catch them. They appear in OpenSRE logs as [telegram] post message failed: <description> with the Telegram description copied verbatim. description: chat not found The bot is not in the chat, or TELEGRAM_DEFAULT_CHAT_ID is wrong. Re-add the bot and re-fetch chat_id from getUpdates. description: bot was kicked from the large group … (or similar) Re-add the bot. For channels, the bot must be an administrator with Post Messages permission. Findings never arrive, but verify passes getMe only confirms the token is valid; it does not test delivery. Send a fresh message in the destination chat and re-fetch chat_id from getUpdates — your chat_id may have changed (for example, if a group was upgraded and now uses a -100 prefix). Gateway: User <id> is not in the allowed users list Run /messaging status -p telegram and confirm the sender’s numeric user id is listed. Re-add with /messaging allow -p telegram -u <user_id> or complete /messaging pair -p telegram pairing.