12 KiB
oh-my-pi-telegram
A Telegram companion hub for live Oh My Pi (omp) sessions —
queue prompts, stream replies, send files and voice, and supervise your agent from your phone.
Install · Features · How it works · Limitations · Development · CI/CD
Note
Project status: fork of
@llblab/[email protected](SHAafe09c5), repackaged as@evandrodevbr/oh-my-pi-telegramand declared as anompextension. PerCHANGELOG.md, the fork passes the upstream gates (typecheck, 1229/1230 tests with one platform-only skip,npm auditwith 0 vulnerabilities, cleannpm pack --dry-run). The latest commit adds a design spec for an OMP 17 status-bar segment (docs/superpowers/specs/); 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.
# 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:
- Create a bot with @BotFather (
/newbot) and copy the token. - In
omp, run/telegram-setupand paste the token. - Run
/telegram-connectto activate polling for this instance. - 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 fromTELEGRAM_BOT_TOKEN,TELEGRAM_BOT_KEY,TELEGRAM_TOKENorTELEGRAM_KEY; the saved config lives in~/.pi/agent/telegram.json.
Why this fork and not upstream
llblab/[email protected] targets the Pi extension platform (@earendil-works/pi-*).
omp consumes the same platform republished as @oh-my-pi/pi-coding-agent. This fork:
- Renames the package to
@evandrodevbr/oh-my-pi-telegramso it is unambiguous in theompextension registry. - Keeps the upstream
peerDependencieson@earendil-works/pi-{ai,agent-core,coding-agent}>=0.80.6, the runtime surfaceompconsumes — no code changes or shims. - Declares the extension through an
ompblock inpackage.json(extensions, display name andcompatibleWith: >=16.5.2); the oldpiblock was replaced by it. - Re-runs every upstream gate (
typecheck→test→audit→pack:check) on thev0.22.0source.
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 <agent-dir>/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
flowchart LR
TG["Telegram<br/>private DM · Threaded Mode"] -->|"getUpdates"| POLL
subgraph OMP["omp instance (extension)"]
POLL["polling + updates<br/>pairing · routing"] --> Q["turns + queue<br/>control · priority · default"]
Q -->|"sendUserMessage"| AG["agent session<br/>(currently active)"]
AG -->|"lifecycle events"| OUT["previews · rich replies<br/>files · voice · buttons"]
end
OUT -->|"Bot API"| TG
POLL <-->|"local bus<br/>Unix socket / named pipe"| F["follower omp instances<br/>(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 · Public API · Delivery · Activity · Inbound · Outbound · Voice · Sections · Updates · Multi-Instance Bus · Locks · UI Style · Callback Namespaces · Command Templates — index in docs/README.md.
Limitations
- Telegram is a companion surface around a live runtime, not a second runtime: no hidden
ompprocesses, 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
Alltab are not routed as prompts once bound threads exist; use a bound thread tab. - Package metadata declares the extension only under
omp.extensions(thepiblock was removed in572967c); install this fork throughomp, and use upstream@llblab/pi-telegramfor plain Pi. - Open work is tracked in
BACKLOG.md(promoted-follower reload evidence, native Windows Threaded Mode follow-ups, evidence-backed Telegram client and Rich Markdown quirks).
Development
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. Completed delivery history: CHANGELOG.md.
CI/CD
.github/workflows/validate.yml— on every push and pull request: Node 24,npm ci,npm run validate..github/workflows/release.yml— on tagsv*.*.*: checks that the tag matchespackage.json's version, extracts that version's section fromCHANGELOG.mdinto the release notes, and creates the release withgh release create(a GitHub CLI call). The extraction expects a## <version>heading; the fork's entry currently sits under## Unreleasedas a###heading, so a tag would fail that check until the section is promoted.
Credits and notices
- MIT licensed (
LICENSE): copyright Evandro Fonseca Junior (evandrodevbr) and llblab. - Built on
llblab/pi-telegram, itself a fork ofbadlogic/pi-telegram; runs inside Oh My Pi and talks to the Telegram Bot API. - Unofficial project, not affiliated with Telegram or the Oh My Pi maintainers.