# oh-my-pi-telegram **A Telegram companion hub for live [Oh My Pi](https://github.com/can1357/oh-my-pi) (`omp`) sessions — queue prompts, stream replies, send files and voice, and supervise your agent from your phone.** ![Version](https://img.shields.io/badge/version-0.22.0--evandro.1-informational) ![Node](https://img.shields.io/badge/node-%3E%3D22.19.0-informational) ![License](https://img.shields.io/badge/license-MIT-informational) [Install](#installation) · [Features](#what-it-does) · [How it works](#how-it-works) · [Limitations](#limitations) · [Development](#development) · [CI/CD](#cicd) pi-telegram running in Telegram
> [!NOTE] > **Project status:** fork of [`@llblab/pi-telegram@0.22.0`](https://github.com/llblab/pi-telegram/tree/v0.22.0) > (SHA `afe09c5`), repackaged as `@evandrodevbr/oh-my-pi-telegram` and declared as an > `omp` extension. Per [`CHANGELOG.md`](CHANGELOG.md), the fork passes the upstream > gates (typecheck, 1229/1230 tests with one platform-only skip, `npm audit` with 0 > vulnerabilities, clean `npm pack --dry-run`). The latest commit adds a design spec > for an OMP 17 status-bar segment ([`docs/superpowers/specs/`](docs/superpowers/specs/2026-07-15-telegram-omp-status-design.md)); > that spec needs a new OMP core API and is **not implemented in this repository yet**. > [!IMPORTANT] > **This is a runtime adapter, not a remote terminal.** Telegram prompts are normal > model turns in the instance's *currently active* session and inherit its > post-compaction context, so token cost is not proportional only to the new mobile > message. Telegram can compact the current session, but cannot create, resume, fork, > browse or switch sessions, and arbitrary slash commands are never forwarded to the TUI. ## Installation Requires `omp` ≥ 16.5.2 (`@oh-my-pi/pi-coding-agent`) and Node.js ≥ 22.19.0. ```bash # From git (this repository) omp plugin install https://git.evandro.dev.br/evandro/oh-my-pi-telegram.git # From npm (once the package is published) omp plugin install npm:@evandrodevbr/oh-my-pi-telegram # From a local checkout (development) omp plugin link /path/to/oh-my-pi-telegram ``` Restart (or reload) `omp` so the extension loads, then: 1. Create a bot with [@BotFather](https://t.me/BotFather) (`/newbot`) and copy the token. 2. In `omp`, run `/telegram-setup` and paste the token. 3. Run `/telegram-connect` to activate polling for this instance. 4. In the bot DM, send `/start`. > [!WARNING] > **The first Telegram user to message the bot becomes the allowed owner**; everyone > else is ignored. Pair right after `/telegram-connect`, and never put the bot token in > chat, source, committed config or logs. Setup can prefill the token from > `TELEGRAM_BOT_TOKEN`, `TELEGRAM_BOT_KEY`, `TELEGRAM_TOKEN` or `TELEGRAM_KEY`; the saved > config lives in `~/.pi/agent/telegram.json`. ## Why this fork and not upstream `llblab/pi-telegram@0.22.0` targets the Pi extension platform (`@earendil-works/pi-*`). `omp` consumes the same platform republished as `@oh-my-pi/pi-coding-agent`. This fork: 1. Renames the package to `@evandrodevbr/oh-my-pi-telegram` so it is unambiguous in the `omp` extension registry. 2. Keeps the upstream `peerDependencies` on `@earendil-works/pi-{ai,agent-core,coding-agent}` `>=0.80.6`, the runtime surface `omp` consumes — no code changes or shims. 3. Declares the extension through an `omp` block in `package.json` (`extensions`, display name and `compatibleWith: >=16.5.2`); the old `pi` block was replaced by it. 4. Re-runs every upstream gate (`typecheck` → `test` → `audit` → `pack:check`) on the `v0.22.0` source. Lineage: `badlogic/pi-telegram` → `llblab/pi-telegram` (0.22.0) → **this fork**. ## What it does | Surface | What you can do | |---|---| | **Prompt intake** | Send text, replies, edits, images, files, albums and voice notes into the session | | **Queue control** | Messages sent while the agent is busy become queued turns; inspect, delete, promote, continue, abort, stop or force the next one | | **Operator menu** | `/start` opens status, prompt templates, model, thinking level, settings, queue and extension sections | | **Prompt templates** | Run Pi prompt templates as Telegram-safe commands such as `/fix_tests` | | **Model and thinking** | Switch model or reasoning level through safe continuation flows; confirm `/compact` | | **Rich replies** | Native Rich Markdown (default) or legacy Markdown-to-HTML for final answers; optional live draft previews; native `…typing` status while the agent works | | **Files** | Inbound files land in `/tmp/telegram` (50 MiB default limit); `telegram_attach` returns artifacts as real files | | **Voice** | Inbound voice through command-template, programmatic or STT handlers; outbound via `telegram_voice` and TTS providers | | **Buttons** | Hidden `telegram_button` comments become inline buttons whose callbacks re-enter the session | | **Threaded Mode** | One leader plus visible follower `omp` instances, each with its own Telegram thread, through one bot | | **Named profiles** | Run independent bots from one agent directory with isolated polling, diagnostics and bus transport | | **Extension platform** | Companion extensions add commands, menu sections, status rows, update/callback handlers, inbound/outbound handlers and voice providers | | **Diagnostics** | `/telegram-status` shows connection, mode, queue, transport and recent redacted events |
Commands In the bot DM: | Command | Purpose | |---|---| | `/start` | Pair when needed and open the operator menu | | `/compact` | Confirm and run session compaction when safe | | `/next` | Dispatch the next queued turn, aborting first if needed | | `/continue` | Enqueue a priority continuation prompt | | `/abort` | Abort the active run, keeping the queue | | `/stop` | Abort the active run and clear waiting Telegram turns | `/help`, `/status`, `/model`, `/thinking`, `/queue` and `/settings` are hidden shortcuts into the same menus. Inside `omp`: | Command | Purpose | |---|---| | `/telegram-setup [profile]` | Save or update the default (or a named-profile) bot token | | `/telegram-connect [profile]` | Activate a profile and acquire its transport ownership | | `/telegram-disconnect` | Stop polling and release ownership | | `/telegram-status` | Inspect connection, mode, queue, transport and diagnostics | Profile names use lowercase ASCII letters and digits (max 32 characters); `default`, `main` and `active` are reserved.
Environment variables | Area | Variables | |---|---| | Bot token bootstrap | `TELEGRAM_BOT_TOKEN`, `TELEGRAM_BOT_KEY`, `TELEGRAM_TOKEN`, `TELEGRAM_KEY` | | HTTP proxy | `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, plus `NODE_USE_ENV_PROXY=1` or Node `--use-env-proxy` | | Network family | `PI_TELEGRAM_NETWORK_FAMILY` = `auto`, `ipv4`, `ipv6` or `ipv4-fallback` | | Agent data root | `PI_CODING_AGENT_DIR` | | Inbound file limit | `PI_TELEGRAM_INBOUND_FILE_MAX_BYTES`, `TELEGRAM_MAX_FILE_SIZE_BYTES` | | Outbound attachment limit | `PI_TELEGRAM_OUTBOUND_ATTACHMENT_MAX_BYTES`, `TELEGRAM_MAX_ATTACHMENT_SIZE_BYTES` | Defaults: config in `~/.pi/agent`, inbound temp files in `~/.pi/agent/tmp/telegram`, and `assistant: { rendering: "rich", draftPreviews: false }`.
## How it works ```mermaid flowchart LR TG["Telegram
private DM · Threaded Mode"] -->|"getUpdates"| POLL subgraph OMP["omp instance (extension)"] POLL["polling + updates
pairing · routing"] --> Q["turns + queue
control · priority · default"] Q -->|"sendUserMessage"| AG["agent session
(currently active)"] AG -->|"lifecycle events"| OUT["previews · rich replies
files · voice · buttons"] end OUT -->|"Bot API"| TG POLL <-->|"local bus
Unix socket / named pipe"| F["follower omp instances
(Threaded Mode)"] ``` The core loop is: Telegram message → Telegram turn → queue or active dispatch → agent lifecycle → streaming preview / native active status → final Rich Markdown reply → optional files, voice, buttons or callback actions. Exactly one instance owns `getUpdates` per bot; in Threaded Mode followers are visible processes the operator started and ran `/telegram-connect` in — Telegram never launches hidden `omp` processes.
Layout and public entrypoints | Path | Role | |---|---| | `index.ts` | Composition root: wires live ports, session state, transport adapters and lifecycle hooks | | `lib/*.ts` | Flat domain modules (queue, polling, locks, bus, menus, rendering, delivery…) forming an acyclic import graph | | `api/*.ts` | Public companion-extension entrypoints: `inbound`, `outbound`, `delivery`, `activity`, `updates`, `commands`, `sections`, `status`, `voice`, `keyboard` | | `docs/` | Architecture and contract documentation | | `tests/*.test.ts` | Domain regressions run with `node --test` | State: `~/.pi/agent/telegram.json` (config), `~/.pi/agent/locks.json` (polling ownership) and profile-scoped redacted `logs*.jsonl` under `tmp/telegram` (never model context). Documentation: [Architecture](docs/architecture.md) · [Public API](docs/public-api.md) · [Delivery](docs/delivery.md) · [Activity](docs/activity.md) · [Inbound](docs/inbound.md) · [Outbound](docs/outbound.md) · [Voice](docs/voice.md) · [Sections](docs/sections.md) · [Updates](docs/updates.md) · [Multi-Instance Bus](docs/multi-instance-bus.md) · [Locks](docs/locks.md) · [UI Style](docs/ui-style.md) · [Callback Namespaces](docs/callback-namespaces.md) · [Command Templates](docs/command-templates.md) — index in [`docs/README.md`](docs/README.md).
## Limitations - Telegram is a companion surface around a live runtime, not a second runtime: no hidden `omp` processes, no PTY or fake terminal, no raw TTY input, no session replacement without an official extension API, and non-owner users cannot control the bridge. - In Threaded Mode, threadless messages sent from the `All` tab are not routed as prompts once bound threads exist; use a bound thread tab. - Package metadata declares the extension only under `omp.extensions` (the `pi` block was removed in `572967c`); install this fork through `omp`, and use upstream `@llblab/pi-telegram` for plain Pi. - Open work is tracked in [`BACKLOG.md`](BACKLOG.md) (promoted-follower reload evidence, native Windows Threaded Mode follow-ups, evidence-backed Telegram client and Rich Markdown quirks). ## Development ```bash npm ci npm run typecheck # tsc --noEmit npm test # node --experimental-strip-types --test tests/*.test.ts npm run audit # npm audit npm run pack:check # npm pack --dry-run npm run validate # all of the above ``` Engineering conventions: [`AGENTS.md`](AGENTS.md). Completed delivery history: [`CHANGELOG.md`](CHANGELOG.md). ## CI/CD - [`.github/workflows/validate.yml`](.github/workflows/validate.yml) — on every push and pull request: Node 24, `npm ci`, `npm run validate`. - [`.github/workflows/release.yml`](.github/workflows/release.yml) — on tags `v*.*.*`: checks that the tag matches `package.json`'s version, extracts that version's section from `CHANGELOG.md` into the release notes, and creates the release with `gh release create` (a GitHub CLI call). The extraction expects a `## ` heading; the fork's entry currently sits under `## Unreleased` as a `###` heading, so a tag would fail that check until the section is promoted. ## Credits and notices - MIT licensed ([`LICENSE`](LICENSE)): copyright Evandro Fonseca Junior (evandrodevbr) and llblab. - Built on [`llblab/pi-telegram`](https://github.com/llblab/pi-telegram), itself a fork of [`badlogic/pi-telegram`](https://github.com/badlogic/pi-telegram); runs inside [Oh My Pi](https://github.com/can1357/oh-my-pi) and talks to the Telegram Bot API. - Unofficial project, not affiliated with Telegram or the Oh My Pi maintainers.