The Telegram bridge lets you chat with the omp agent from any Telegram
client — phone, desktop, web. DMs to your bot create or resume an omp
session keyed by chat_id; the agent's replies stream back via Telegram's
editMessageText.
The bridge is a standalone Bun process in apps/bridges/telegram/,
supervised by the deck server. Crashing the bridge does not affect the
deck or any in-flight chat sessions.
- Telegram long-polling has its own lifecycle (rate limits, transient 5xx, occasional 429s). Isolating it from the deck server keeps a single Telegram hiccup from interrupting the chat UI.
- The bridge can be restarted independently when you change credentials.
Talk to @BotFather on Telegram. Send /newbot,
pick a name and username, copy the bot token he gives you. It looks like:
1234567890:ABCdefGHIJklmnopQRSTuvwxyz
Telegram usernames are not enough — the bridge allowlist needs the numeric
user ID. Message @userinfobot on Telegram. It
echoes your ID back, like 987654321.
If multiple people will DM the bot, collect each of their IDs.
Open the deck, navigate to Settings → Messaging → Telegram.
- Bot token — paste the token. Saved masked.
- Allowed users — comma-separated numeric IDs (e.g.
987654321,123456789).
Both must be set. The bridge refuses to start without them.
Click Start in the Telegram card. The status pill flips to RUNNING,
showing the pid and uptime. Expand Bridge logs to confirm
telegram bridge started lands within a second.
Open Telegram, search for the bot username, hit Start, send any message. Within a few seconds the bridge:
- Creates a new omp session at
OMP_DECK_DEFAULT_CWD(or the cwd of the chat-to-session mapping if you've messaged the bot before). - Forwards your text as a prompt.
- Streams the agent's reply back, edited in real-time via
editMessageTextto avoid spamming you with one message per token.
If the agent's reply exceeds Telegram's 4096-char message cap, the bridge chunks it across multiple messages.
Send a photo with an optional caption. The bridge downloads the largest
size, base64-encodes it, and forwards it as an omp ImageAttachment on the
prompt frame. The agent can read it like any other image.
Send /reset in the Telegram chat. The bridge disposes the current omp
session and drops the chat→session mapping. The next message starts a fresh
session.
The mapping lives at <dataDir>/telegram-bridge.db (SQLite). It survives
deck restarts so your conversation with the bot picks up across sessions.
To reset: rm <dataDir>/telegram-bridge.db while the bridge is stopped, then
restart it.
| What | How |
|---|---|
| Start | Settings → Messaging → Telegram → Start |
| Stop | Settings → Messaging → Telegram → Stop |
| Restart (after token change) | Restart button (or Stop then Start) |
| View logs | Toggle "Bridge logs" in the Telegram card |
| Crash detection | Status pill flips to CRASHED with the exit code; crash count increments. Click Start to retry. |
The deck supervises the child process — when the deck server shuts down
(Ctrl+C or /api/server/restart), the bridge child is killed via
safeShutdown. There's no orphaned process after a clean exit.
- Group chats. DM-only.
- Multi-user routing. Single owner, single bot. If two people in
TELEGRAM_ALLOWED_USERSDM the bot at the same time, they get separate sessions (keyed bychat_id) but shareOMP_DECK_DEFAULT_CWDand provider quotas. - Hosting outside the tailnet. The bridge always uses Telegram's outbound API (no inbound port needed), so it works behind NAT/Tailscale without exposing a port. But the deck it talks to is still loopback-only; the bridge is the only thing reaching out.
- Slack / Discord / Matrix. Same pattern but distinct catalog work — filed under deck-future. The bridge supervisor framework is reusable.
Bridge crashes immediately with "TELEGRAM_BOT_TOKEN is required".
The credentials saved in Settings aren't reaching the bridge process. The
deck's managed .env writes to <dataDir>/.env and the bridge reads from
the same file. Confirm via cat <dataDir>/.env (Linux/macOS) or
type %LOCALAPPDATA%\omp-deck\.env (Windows).
Bridge crashes with "TELEGRAM_ALLOWED_USERS must contain at least one numeric Telegram user id". You set a username instead of the numeric ID. Get the numeric ID via @userinfobot.
Bot doesn't respond to messages. Check logs (expand "Bridge logs" in the card). The most common cause is the user not being in the allowlist — the bridge replies with "This omp-deck bot is private." and refuses to process.
Replies are slow.
The bridge debounces editMessageText calls at TELEGRAM_EDIT_INTERVAL_MS
(default 700ms) to avoid Telegram rate limits. Tune in .env:
TELEGRAM_EDIT_INTERVAL_MS=300Lower bound is 250ms — Telegram will reject faster updates.