Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pi-telegram-bridge

Run your Oh My Pi (OMP) / Pi coding agent over Telegram — streaming replies, voice notes, scheduled prompts, and one-tap approvals.

License Runtime Language

pi-telegram-bridge is a standalone Bun/TypeScript service that connects a Telegram bot to your Oh My Pi coding agent session. Message it like you'd message a person — it streams edited replies back, keeps one session per chat (or per forum topic), and can talk to you, listen to voice notes, run on a schedule, and gate risky actions behind an Approve/Cancel tap.

Table of contents

Features

  • Streaming edited replies — the bot's message is edited in place as the agent's answer streams in, instead of a wall of new messages.
  • Tool-progress bubble — a single ephemeral message shows what the agent is doing (off / new / all / verbose, cycled with /verbose), then disappears once text starts.
  • Forum topic routing — in a Telegram forum group, each topic gets its own agent session; messages are routed by chatId:threadId.
  • Voice-note input — send a voice note and it's transcribed locally (faster-whisper) and fed to the agent as text.
  • Voice replies (TTS) — optionally, replies are also spoken back as a voice message via a command you plug in (/voice on|off).
  • Image & document intake — photos are attached as vision input and saved to disk for file tools; documents are downloaded so the agent can read them.
  • Inline slash commands — a curated command menu plus the full OMP command surface (builtins, file/skill/extension commands), with an inline-keyboard /model picker (provider → model).
  • Cron-like scheduler — fire prompts into any chat/topic at fixed times, with day-of-week or one-time dates, timezone-aware, restart-safe.
  • One-tap approval gates — the agent can request explicit confirmation for an action; you get Approve ✓ / Cancel ✗ buttons.
  • Pause / resume + message queueing/pause holds new messages (current turn still finishes); /resume drains them in order; /queue inspects what's held.
  • Allowlist auth — only numeric Telegram user IDs you list can talk to the bot.
  • HTML formatting with plain-text fallback — rich formatting when Telegram accepts it, degrading gracefully otherwise.
  • Built-in resilience — Telegram flood-wait handling, network retry with backoff on the poll loop, and bot-token redaction in every log line.
  • Reboot announce — the bot pings its owners after a restart so a crash or redeploy is visible, not silent.

Requirements

  • Bun (runtime + package manager).
  • An installed Oh My Pi (OMP) / Pi Agent SDK (@oh-my-pi/pi-coding-agent) — this bridge assumes you already have OMP set up and usable.
  • Optional, for voice notes: ffmpeg on PATH, plus a Python virtualenv with faster-whisper installed (see Voice notes).
  • Optional, for voice replies: any command-line TTS tool you point OMP_TG_TTS_CMD at (see Voice replies / TTS); ffmpeg is also used here to transcode to Opus/OGG for Telegram.

Install

git clone https://github.com/<you>/pi-telegram-bridge.git
cd pi-telegram-bridge
bun install

# State directory — holds your .env, identity, sessions, schedule, etc.
mkdir -p ~/.omp-telegram
cp .env.example ~/.omp-telegram/.env
  1. Create a bot — message @BotFather on Telegram, run /newbot, and copy the token into TELEGRAM_BOT_TOKEN in ~/.omp-telegram/.env.

  2. Find your numeric user ID — start the bridge once with TELEGRAM_ALLOWED_USER_IDS empty and message the bot; it replies with your user ID (see Security). Alternatively, message any "get my ID" bot (e.g. @userinfobot).

  3. Set the allowlist — put that ID (comma-separated for multiple people) into TELEGRAM_ALLOWED_USER_IDS in .env, then restart the bridge.

  4. Give it an identity (optional but recommended) — copy examples/identity.example.md to ~/.omp-telegram/SOUL.md and edit it. This is injected into the agent's system prompt on every session, so it's the place to set tone, persona, and Telegram-specific habits.

    cp examples/identity.example.md ~/.omp-telegram/SOUL.md

Running

Directly with Bun (loads .env from the current working directory automatically):

cd pi-telegram-bridge
bun run src/bridge.ts

Or as a systemd --user service (recommended for anything long-running):

cp systemd/pi-telegram-bridge.service.example ~/.config/systemd/user/pi-telegram-bridge.service
# edit the ExecStart path to your actual clone location, then:
systemctl --user daemon-reload
systemctl --user enable --now pi-telegram-bridge
journalctl --user -u pi-telegram-bridge -f

The systemd unit loads config via EnvironmentFile=%h/.omp-telegram/.env, so keep your real .env there rather than in the repo.

Configuration

All configuration is environment variables, read once at startup. Set them in ~/.omp-telegram/.env (auto-loaded by Bun when you run from the repo directory) or in the systemd unit's EnvironmentFile.

Variable Required Default Description
TELEGRAM_BOT_TOKEN yes Bot token from @BotFather.
TELEGRAM_ALLOWED_USER_IDS yes Comma-separated numeric Telegram user IDs allowed to use the bot. Empty = bootstrap mode (bot replies with your ID but does nothing else).
OMP_TG_WORKDIR no your home directory Working directory the agent session runs in (its file-tool root, cwd).
OMP_TG_MODEL no OMP's default model Model pattern to select for every session.
OMP_TG_AUTO_APPROVE no true Whether the agent auto-approves its own tool calls (false re-enables OMP's normal approval flow).
OMP_TG_PROGRESS no off Default tool-progress display mode: off, new, all, or verbose. Per-chat, cycled with /verbose.
OMP_TG_THINKING no OMP default Reasoning effort for every session: off, minimal, low, medium, high, xhigh, auto.
OMP_TG_TZ no UTC IANA timezone the scheduler evaluates job times in (e.g. America/New_York).
OMP_TG_STATE_DIR no ~/.omp-telegram Directory for .env, SOUL.md, sessions.json, schedule.json, and all other runtime state.
OMP_TG_BOOT_PING no on Whether the bot announces itself to every allowed user after a (re)start. Set off to disable.
OMP_TG_BOOT_MESSAGE no "Bridge is back online after a reboot." Text sent on boot announce.
OMP_TG_TTS_CMD no unset (TTS off) Path/command for text-to-speech. Invoked as <cmd> <output.wav> [voice] with the reply text on stdin; must write a WAV file.
OMP_TG_TTS_VOICE no unset Optional voice name, passed as OMP_TG_TTS_CMD's second argument.
OMP_TG_WHISPER_MODEL no small.en faster-whisper model name used to transcribe voice notes.

Slash commands

Telegram's command menu (populated via setMyCommands, capped at 30 entries) is a curated set of bridge + OMP commands, topped up with any of your own discovered commands (file/skill/extension) and then OMP builtins until the menu is full:

Command Description
/new Start a fresh session
/stop (/abort) Interrupt the current task now and drop the queue
/pause Hold new messages until /resume (the current turn still finishes)
/resume Resume and process held messages, in order
/queue [clear] Show held + queued messages, or clear both
/compact [instructions] Compact context (keeps the session)
/autocompact [on|off] Toggle automatic compaction
/model [name] Switch model — opens a two-step provider→model picker, or matches a name directly
/advisor [on|off|status] Toggle OMP's second-model reviewer
/think [level] Set reasoning effort: off, minimal, low, medium, high, xhigh, auto
/verbose Cycle tool-progress display: off → new → all → verbose
/voice [on|off] Toggle spoken (TTS) replies for this chat
/status Show session status (model, context, paused/queue state, advisor)
/usage Token usage & cost for this session
/context Context-window breakdown
/todo Show the agent's current task list
/orchestrate <goal> Run a goal in multi-agent orchestration mode (the bare word orchestrate in any message does the same)
/workflow <goal> Author a deterministic multi-subagent workflow for a goal
/commands List every slash command actually available in this session
/help Show usage help
/id Show your Telegram user ID and this chat's ID (works even when unauthorized)

Every other /command is forwarded exactly like an OMP CLI session would handle it: built-ins with no bridge override (e.g. /export, /mcp), file commands, skill commands, extension commands, and MCP-prompt commands all expand through OMP's own pipeline. An unrecognized /x is delivered to the model verbatim. A small number of TUI-only commands (/plan, /settings, /fork, /retry, …) don't exist over chat — /commands lists what's actually reachable.

Topics & forums

Add the bot to a Telegram forum-mode group and it treats each topic as an independent chat: every topic gets its own agent session, keyed by chatId:threadId, with its own history, model, and tool-progress mode. Messages sent in the "General" topic (no message_thread_id) use the chat-level session. This makes a forum a natural way to run several parallel conversations (or scheduled jobs — see below) against one bot.

Voice notes

Voice notes are transcribed locally — audio never leaves your machine. Set up the venv once inside your state directory:

cd ~/.omp-telegram
cp /path/to/pi-telegram-bridge/src/transcribe.py .
python3 -m venv .venv
.venv/bin/pip install -r /path/to/pi-telegram-bridge/examples/requirements.txt

The bridge shells out to ~/.omp-telegram/.venv/bin/python ~/.omp-telegram/transcribe.py <audio-file> (paths derived from OMP_TG_STATE_DIR) for every voice note or audio message it receives, using faster-whisper on CPU with int8 quantization. The model (default small.en, override with OMP_TG_WHISPER_MODEL) is downloaded on first use and cached under ~/.omp-telegram/models/, so the first transcription is slower than the rest. Requires ffmpeg to decode Telegram's Opus/OGG voice format.

Voice replies / TTS

Spoken replies are entirely optional and off by default. Set OMP_TG_TTS_CMD to any command that:

  • is invoked as <cmd> <output.wav-path> [voice-name],
  • receives the reply text on stdin,
  • and writes a valid WAV file to the given path (exit code 0 on success).

The bridge then transcodes that WAV to Opus/OGG with ffmpeg and sends it as a Telegram voice message. Enable it per chat with /voice on (persisted in state; /voice off to disable again).

A minimal wrapper around a local TTS engine might look like:

#!/usr/bin/env bash
# examples-style wrapper: args are <out.wav> [voice]; text comes in on stdin.
set -euo pipefail
out="$1"
voice="${2:-default}"
text="$(cat)"
your-tts-engine --voice "$voice" --text "$text" --output "$out"

Point OMP_TG_TTS_CMD at that script's path, and optionally set OMP_TG_TTS_VOICE to a voice name it understands.

Scheduler

The bridge can inject prompts into any chat (or forum topic) on a schedule — Telegram bots can't poll on their own, so this is how you get proactive/autonomous behavior (morning briefings, reminders, periodic checks). Jobs live in ~/.omp-telegram/schedule.json; see examples/schedule.example.json for a starting point. Each job:

{
  "id": "unique-job-id",          // required, stable identifier
  "enabled": true,                 // optional, default true
  "time": "07:30",                 // required, 24h "HH:MM" in OMP_TG_TZ
  "days": ["mon", "tue", "wed"],    // optional; array of weekday abbrevs, or "daily" (default)
  "date": "2026-12-25",             // optional; one-time job on this exact date, overrides "days"
  "chatId": 123456789,              // required, target chat
  "threadId": 42,                   // optional, forum topic id — omit for DM/non-topic chats
  "prompt": "Give me a quick morning summary.",
  "silent": false                   // optional; true runs with tool-progress off and posts nothing on an empty reply
}

A job fires at most once per matching day; fired state is persisted to schedule-state.json so a restart never double-fires. A job whose time has already passed on the day the bridge first starts is marked fired (not backfilled), so a fresh deploy doesn't spam old jobs.

Security

  • Single/small-owner model. This bridge isn't multi-tenant — it grants full agent access (file system, shell, whatever tools your OMP setup exposes) to every ID in TELEGRAM_ALLOWED_USER_IDS. Only add people you'd trust with a terminal on this machine.
  • Keep your bot token secret. Anyone with the token can run their own poller against your bot (see 409 Conflict) or message your users as the bot. Treat it like a password; it lives only in .env / the systemd EnvironmentFile, never in the repo.
  • Token redaction. The bridge strips the bot token from every error string before it can reach logs — but a stray echo/debug of your .env won't be caught by that, so still keep the file out of version control (see .gitignore).
  • OMP_TG_AUTO_APPROVE. Defaults to true, meaning the agent approves its own tool calls without asking. Set it to false to fall back to OMP's normal approval flow, or rely on the agent's own APPROVE: gates (one-tap Approve ✓ / Cancel ✗ buttons) for specific risky actions it flags itself.
  • Bootstrap mode. With TELEGRAM_ALLOWED_USER_IDS empty, the bot will tell anyone who messages it their numeric user ID and do nothing else — useful for onboarding, but set the allowlist and restart before leaving it running.

Troubleshooting

  • 409 Conflict in the logs / poll errors mentioning "Conflict" — another process (a second bridge instance, a webhook, or someone else's poller) is calling getUpdates with the same bot token. Telegram allows only one long-poll consumer per token at a time. Stop the other process, or create a separate bot via @BotFather for the second use.
  • Bot never replies / "Unauthorized." — your numeric Telegram user ID isn't in TELEGRAM_ALLOWED_USER_IDS. Message the bot with the allowlist empty (or check /id once you are authorized elsewhere) to find your ID, add it, and restart.
  • TELEGRAM_BOT_TOKEN is not set on startup.env isn't being loaded. Confirm it's in OMP_TG_STATE_DIR (systemd) or the repo's working directory (bun run), and that the unit's EnvironmentFile path is correct.
  • Voice notes fail to transcribe — confirm ~/.omp-telegram/transcribe.py and ~/.omp-telegram/.venv exist (see Voice notes) and that ffmpeg is installed.
  • Repeated network errors on startup — the poll loop retries with exponential backoff (capped at 30s) and logs each attempt; transient network issues resolve on their own once connectivity returns.

Roadmap

See ROADMAP.md for deferred ideas and how to contribute.

License

MIT © 2026 pi-telegram-bridge contributors

About

Run your Oh My Pi (OMP) / Pi Agent over Telegram — streaming replies, voice notes, scheduled prompts, topic routing, and one-tap approvals.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages