Chat with the pi coding agent from Telegram — rich text, streaming previews, file attachments, and native inline-keyboard dialogs.
Pigram is a session-local Telegram bridge for pi. It runs inside your pi session: no daemon, no background service, no extra process to babysit. Start pi, run one command, message your bot. When the pi session ends, the bridge stops with it.
- One-step setup. Install the extension, run
/pigram-setup, paste a bot token. That's it. - Session-local by design. The bridge lives and dies with your pi session. No installer, no
systemdunit, no orphaned daemon polling Telegram while you sleep. - Rich output. pi's markdown is converted to Telegram HTML — code blocks, bold, links, lists, all rendered natively.
- Streaming previews. Watch pi's reply build in real time via message edits, instead of waiting for the whole turn.
- File attachments. pi can send you generated files directly through the
telegram_attachtool. - Native dialogs. Inline-keyboard selects, confirms, and text inputs — pi can ask you a question mid-task and you tap an answer.
- Single-user pairing. The first account to send
/startis paired; everyone else is ignored. No allowlist to maintain.
- Node.js 22.19+ (pi's runtime floor)
- pi (
@earendil-works/pi-coding-agent)^0.80 - A Telegram bot token from @BotFather
pi install npm:@jetmiky/pigramThis adds Pigram to your pi settings so it loads on every session. To load it for a single session instead:
pi -e ./node_modules/@jetmiky/pigram/dist/index.js-
Create a bot with @BotFather: send
/newbot, pick a name and a…botusername. BotFather replies with a token like123456789:AAE…. -
In your pi session, run:
/pigram-setupPaste the token when prompted. Pigram validates it against Telegram, stores it, prints a BotFather
/setcommandsblock, and starts the bridge. -
Open your bot in Telegram and send
/startto pair your account.
Done. Send any message and it's forwarded to pi.
Scope: by default the config is stored per-project (
.pi/pigram.json, automatically git-ignored). Use/pigram-setup globalto store it in your home directory and reuse it across projects.
Send these to your bot in Telegram:
| Command | Description |
|---|---|
/new [name] |
Start a fresh pi session, optionally named |
/status |
Show session, directory, model, usage, cost, and context |
/model [provider/]id [thinking] |
Switch model, optionally with provider and thinking level |
/thinking <level> |
Change thinking level (off, minimal, low, medium, high, xhigh) |
/compact |
Compact the conversation context |
/resend |
Resend the latest assistant reply |
/stop |
Abort the active turn (or send: stop, wait, cancel, abort) |
/help |
Show help |
/git <status|log|nb> |
Run safe git shortcuts in the current directory |
Run /help once and copy the generated block into BotFather's /setcommands so the commands show up in Telegram's command menu.
For quick access, the stop command can also be triggered without a slash by sending one of these words exactly (case-insensitive):
stopwaitcancelabort
These are exact-match only — "stop the music" or "wait for me" are forwarded to pi as normal messages. When pi is idle, the bot replies with "Nothing to stop, Pi is idle."
These run inside pi (not Telegram) to control the bridge:
| Command | Description |
|---|---|
/pigram-setup [local|global] |
Configure and connect (one-step setup) |
/pigram-connect [local|global] |
Start the bridge using an existing config |
/pigram-disconnect |
Stop the bridge for this session |
/pigram-status |
Show config path, scope, paired user, and polling state |
Pigram is built as a set of small, single-responsibility modules wired together by a thin composition root. There is no business logic in the entrypoint — it only constructs and connects the pieces.
Telegram ⇄ Transport (Bot API) ⇄ Poller ⇄ Bridge ⇄ pi session
│
Dialog · Pairing · Commands · Prompt mapping
Configuration and runtime state are kept strictly separate:
- Config (
.pi/pigram.json) — user-edited: bot token + UX preferences. - State (
.pi/tmp/pigram/state.json) — machine-managed: update cursor, paired user, bot identity. Never hand-edited, always git-ignored.
See CONTEXT.md for the domain glossary and docs/adr/ for the architecture decisions (why session-local, the config shape, the package scope).
If you used the original pi-telegram, Pigram reads your old telegram.json automatically and migrates it (non-destructively — the old file is left untouched) into the new Config/State split on first connect. Just run /pigram-setup or /pigram-connect.
bun install
bun test # run the test suite
bun run typecheck # tsc --noEmit
bun run build # bundle ESM to dist/ (peer deps stay external)Built with TypeScript, tested with bun test, output as ESM for Node 22+. Peer dependencies (pi packages, typebox, marked) are kept external so the published bundle stays tiny and shares the host's pi runtime.
Pigram stands on the shoulders of two projects:
- pi-telegram by Mario Zechner (@badlogic) — the original Telegram bridge for pi. Pigram is a clean-architecture rewrite of that idea, and its proven markdown renderer and storage approach are carried forward here.
- TelePi — UX inspiration for several of the interaction patterns.
Thank you to both. Pigram exists because pi-telegram showed the way.
MIT — see the file for the full attribution notices.