206 lines
12 KiB
Markdown
206 lines
12 KiB
Markdown
<div align="center">
|
|
|
|
# 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.**
|
|
|
|

|
|

|
|

|
|
|
|
[Install](#installation) · [Features](#what-it-does) · [How it works](#how-it-works) · [Limitations](#limitations) · [Development](#development) · [CI/CD](#cicd)
|
|
|
|
<img src="screenshot.png" width="520" alt="pi-telegram running in Telegram">
|
|
|
|
</div>
|
|
|
|
> [!NOTE]
|
|
> **Project status:** fork of [`@llblab/[email protected]`](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/[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:
|
|
|
|
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 `<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 |
|
|
|
|
<details>
|
|
<summary>Commands</summary>
|
|
|
|
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.
|
|
|
|
</details>
|
|
|
|
<details>
|
|
<summary>Environment variables</summary>
|
|
|
|
| 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 }`.
|
|
|
|
</details>
|
|
|
|
## How it works
|
|
|
|
```mermaid
|
|
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.
|
|
|
|
<details>
|
|
<summary>Layout and public entrypoints</summary>
|
|
|
|
| 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).
|
|
|
|
</details>
|
|
|
|
## 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 `## <version>` 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.
|