---
slug: "kdejaeger-pi-telegram-plus"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/kdejaeger/pi-telegram-plus@master/README.md"
repo: "https://github.com/kdejaeger/pi-telegram-plus"
source_file: "README.md"
branch: "master"
---
# pi-telegram-plus

<p>
  <img src="https://img.shields.io/badge/node-%3E%3D22.19.0-339933?style=flat-square&logo=node.js" alt="node" />
</p>

**Full Telegram control of [pi coding agent](https://github.com/earendil-works/pi-coding-agent) — commands, interactive UI, model/session management, file transfer, and real-time streaming output, all from Telegram.**

`pi-telegram-plus` is a pi extension that turns Telegram into a full-featured remote control surface for the pi coding agent. It's not just a notification bot — it mirrors the core pi TUI experience into Telegram, with interactive menus, inline keyboards, file attachments, and live agent output rendering.

> **Forked from [jalyfeng/pi-telegram-plus](https://github.com/jalyfeng/pi-telegram-plus)** — extended with Rich Message API, improved error handling, guardrails/ask-user-question custom UI support, and more.

---

## Features

### 🤖 Bot Connectivity
- **Long polling** — receives messages and callback queries in real time
- **Multi-instance safe** — file-based polling lock prevents multiple pi instances from racing on the same bot token
- **Automatic reconnection** — exponential backoff on transient failures
- **Bot command menu sync** — automatically syncs available commands to Telegram's BotMenu (up to 100 commands)

### 🎮 Full Session Control
All pi session lifecycle commands available via Telegram:

| Command | Description |
|---------|-------------|
| `/new` | Start a new session |
| `/fork` | Fork from a previous user message |
| `/clone` | Clone at a previous user message |
| `/tree` | Navigate session tree |
| `/resume` | Resume a previous session |
| `/compact` | Compact session context |
| `/name` | Set or show session name |
| `/session` | Show session statistics |

### 🧠 Model & Authentication Management
- `/model` — View available models / switch current model via interactive selection
- `/scoped-models` — Toggle scoped model sets
- `/thinking` — Adjust thinking level (off/minimal/low/medium/high/xhigh)
- `/login` — OAuth or API key authentication with full interactive flow
- `/logout` — Remove stored credentials

### 📨 Message Modes
Two modes for handling incoming messages while the agent is running:

- **`steer`** (default) — New messages inject into the current turn via `streamingBehavior: "steer"`. The agent stays streaming while receiving new input.
- **`queue`** — Messages wait in a per-chat queue for the current turn to finish.

### 🖥️ Interactive Telegram UI
Full interactive UI components built on inline keyboards:

- **Notify** — status/error messages
- **Confirm** — Yes / No / Cancel buttons
- **Input** — text input with Cancel button; replies are captured as input
- **InputSecret** — same as Input, but the prompt message is auto-deleted after reply to protect sensitive data
- **Select** — paginated option list with Prev/Next navigation
- **Editor** — multi-line text input prompt
- **Custom** — routes external extension UIs (e.g. `ask_user_question`, guardrails prompts) through Telegram

### 🎨 Message Rendering
- **Rich Message API** — native Telegram markdown rendering via `sendRichText`/`editRichText`, no extra dependencies
- **Tool execution rendering** — Configurable level (`hidden` / `brief` / `full`) for tool call visibility
- **Thinking rendering** — Configurable level (`hidden` / `brief` / `full`) for agent thinking blocks
- **Output splitting** — Safe UTF-8-aware splitting at Telegram's 4096-byte limit
- **Image output** — Automatically sends agent-generated images as Telegram photos

### 📎 File Attachments

**Upload (agent → Telegram):**
- Custom `tg_attach` tool available to the agent
- Sends files/documents/photos to the active Telegram chat
- Size limit enforcement (default 50 MB)
- Sensitive path blocking (e.g., `/etc`, `~/.ssh`)
- Automatic photo detection (jpg/png/webp → send as photo, fallback to document)

**Download (Telegram → user → agent):**
- Automatically saves incoming photos, documents, videos, audio, voice, stickers to the working directory
- Reports saved paths back to the user
- Handles name sanitization and deduplication

### ⚙️ Telegram-Specific Commands

| Command | Description |
|---------|-------------|
| `/tg-setup` | Configure Telegram bot token (first-time setup) |
| `/tg-connect` | Enable / start Telegram connection |
| `/tg-disconnect` | Disable / stop connection (keeps token) |
| `/tg-config` | Configure rendering levels and message mode |
| `/tg-bind-cwd` | Bind a workspace directory to a separate bot token |
| `/tg-unbind-cwd` | Remove workspace bot binding |
| `/tg-list` | List all Telegram bot bindings |

### 🔧 Utility Commands

| Command | Description |
|---------|-------------|
| `/cwd` | Show current working directory |
| `/cd` | Switch pi working directory |
| `/stop` | Abort the current agent turn |
| `/status` | Show runtime snapshot (workspace, model, context, messages) |
| `/settings` | Open settings menu |
| `/copy` | Copy last assistant text |
| `/export` | Export session to HTML/JSONL |
| `/import` | Import a session JSONL file |
| `/share` | Export session for sharing (gist) |
| `/reload` | Reload extensions, skills, prompts |
| `/quit` | Shut down pi |
| `/changelog` | Show changelog link |
| `/hotkeys` | Show keyboard shortcuts reference |

---

## Installation

### Prerequisites

- Node.js >= 22.19.0
- [pi coding agent](https://github.com/earendil-works/pi-coding-agent) installed globally
- A Telegram bot token from [@BotFather](https://t.me/BotFather)

### Install via npm

```bash
pi install npm:@kdejaeger/pi-telegram-plus
```

> **Forked from [jalyfeng/pi-telegram-plus](https://github.com/jalyfeng/pi-telegram-plus)** — this fork is published on npm as `@kdejaeger/pi-telegram-plus`.

### Or install from source

```bash
git clone https://github.com/kdejaeger/pi-telegram-plus.git
cd pi-telegram-plus
npm install
pi packages add .
```

### Configure your Telegram bot

Start pi, then run:

```
/tg-setup
```

Paste your bot token when prompted. The bot will connect automatically.

> **Note:** On first message from any user, pi-telegram-plus automatically authorizes that user ID. Only that user can control the bot afterward.

---

## Configuration

### Per-Workspace Bot Tokens

You can bind different bot tokens to different directories:

```
/tg-bind-cwd /path/to/project
```

This creates a workspace-specific binding in `~/.pi/agent/tg.json`. Workspace bindings take priority over the global configuration.

### Rendering & Mode Settings

Via interactive menu:

```
/tg-config
```

Or directly:

```
/tg-config tool brief       # Tool rendering: hidden | brief | full
/tg-config thinking full    # Thinking rendering: hidden | brief | full
/tg-config mode steer       # Message mode: queue | steer
/tg-config retry 3          # API retry count: 0-10
/tg-config status full      # TUI footer: hidden | minimal | brief | full
```

| `status` level   | Footer shows |
|------------------|---|
| `hidden`         | No telegram+ status line |
| `minimal`        | `tg+` with state icon, no username |
| `brief`          | `telegram+` with state icon, no username |
| `full` (default) | `telegram+` with state icon and @username |

### Logging

`pi-telegram-plus` writes diagnostic logs to a file-based JSON Lines logger:

- **Location:** `~/.pi/agent/logs/pi-telegram-plus-YYYY-MM-DD.log` (one file per UTC day)
- **Format:** One JSON object per line — `{ "ts": "…", "level": "…", "msg": "…", "scope": "…", … }`
- **Levels:** `debug`, `info`, `warn`, `error` — configurable via `PI_TELEGRAM_PLUS_LOG_LEVEL` env var
- **Rotation:** Files rotate at 10 MiB per day, keeping up to 5 rotated copies

View recent logs:

```bash
tail -f ~/.pi/agent/logs/pi-telegram-plus-$(date +%F).log | jq .
```

---

## How It Works

```
┌─────────────────┐     Long Polling      ┌──────────────────────┐
│   Telegram Bot   │ ◄──────────────────► │  pi-telegram-plus    │
│  (api.telegram)  │     Callback Queries  │  (pi extension)      │
└─────────────────┘                       │                      │
        ▲                                 │  ┌────────────────┐  │
        │ Messages / Files                │  │  Controller     │  │
        │                                 │  │  ├─ handleMsg   │  │
  ┌─────────┐                            │  │  ├─ handleCB    │  │
  │  User    │                            │  │  └─ runPrompt   │  │
  │ (Telegram)│                           │  │                  │  │
  └─────────┘                            │  │  ┌─────────────┐ │  │
        ▲                                │  │  │ TelegramUI  │ │  │
        │ Streaming Output               │  │  │ (interactive)│ │  │
        │ Live Tool/Thinking Events      │  │  └─────────────┘ │  │
        │ File Attachments (tg_attach)   │  │                  │  │
        └───────────────────────────────────┤  ┌─────────────┐ │  │
                                          │  │  Renderer   │ │  │
                                          │  │  (Rich Msg  │ │  │
                                          │  │   API /     │ │  │
                                          │  │   Markdown) │ │  │
                                          │  └─────────────┘ │  │
                                          │         │         │  │
                                          │         ▼         │  │
                                          │  ┌─────────────┐  │  │
                                          │  │ pi Agent    │  │  │
                                          │  │ (session,   │  │  │
                                          │  │ models,      │  │  │
                                          │  │ tools, ...) │  │  │
                                          │  └─────────────┘  │  │
                                          └──────────────────────┘
```

### Architecture Overview

- **`index.ts`** — Extension entry point. Wires all modules together and handles `session_start`/`session_shutdown` lifecycle events.
  - Registers the `tg_attach` tool (schema via `typebox`)
  - Imports and initializes all modules
- **`lib/telegram-api.ts`** — Raw Telegram Bot API client with retry logic, file upload/download, and Rich Message API (sendRichText/editRichText).
- **`lib/polling.ts`** — Long polling loop with multi-instance file lock. Re-reads config while holding the lock to prevent offset regressions.
- **`lib/controller.ts`** — Message routing: slash commands, text prompts, media attachments, callback queries. Routes custom extension UIs (guardrails, ask_user_question) to the Telegram UI runtime.
- **`lib/telegram-ui.ts`** — Interactive UI layer: notify, confirm, input, inputSecret, select (pagination), editor, and generic `custom()` handler for external extension UIs.
- **`lib/renderer.ts`** — Hooks into agent lifecycle events (`agent_start`, `tool_execution_*`, `message_end`) and streams rendered output to Telegram via the Rich Message API.
- **`lib/html.ts`** — HTML escaping utilities (for safe Telegram HTML mode fallback).
- **`lib/text-split.ts`** — UTF-8-safe text splitter for Telegram's 4096-byte message limit.
- **`lib/config.ts`** — Configuration persistence with file locking for concurrent-safe writes. Supports global + workspace scopes.
- **`lib/attachments.ts`** — `tg_attach` tool registration (TypeBox schema) and outbound attachment delivery.
- **`lib/logger.ts`** — File-based JSON Lines logger with rotation, used for debugging Telegram issues.
- **`lib/session-capture.ts`** — Monkeys patches `AgentSession.bindExtensions` to intercept session lifecycle and capture the active session reference.
- **`lib/status.ts`** — TUI status line integration showing connection state.
- **`lib/heartbeat.ts`** — Periodic typing indicator while processing.
- **`lib/menu-commands.ts`** — Builds and syncs the Telegram BotMenu command list.
- **`lib/callback-protocol.ts`** — Encodes/decodes inline button callback data.
- **`lib/command-parser.ts`** — Slash command parser & bot-username normalizer.
- **`lib/types.ts`** — All TypeScript interfaces & types.
- **`lib/commands/`** — Command handler modules: model, session, auth (login/logout), lifecycle, settings, tg-config, telegram-commands, info.

---

## Project Structure

```
pi-telegram-plus/
├── index.ts                     # Extension entry point
├── package.json
├── tsconfig.json
├── vitest.config.ts
└── lib/
    ├── types.ts                  # All TypeScript interfaces & types
    ├── telegram-api.ts          # Telegram Bot HTTP API client
    ├── polling.ts                # Long polling with multi-instance lock
    ├── controller.ts                # Message router & prompt executor
    ├── telegram-ui.ts            # Interactive UI (notify, confirm, input, select, editor, custom)
    ├── renderer.ts               # Agent event → Telegram output renderer
    ├── html.ts                   # HTML escaping utilities
    ├── text-split.ts              # UTF-8-safe text splitter for 4096 byte limit
    ├── command-parser.ts         # Slash command parser & bot-username normalizer
    ├── config.ts                 # Configuration store (global + workspace scopes)
    ├── attachments.ts            # Outbound file attachment tool (tg_attach)
    ├── heartbeat.ts              # Typing indicator pulse
    ├── status.ts                 # TUI status line formatter
    ├── logger.ts                 # File-based JSON Lines logger with rotation
    ├── session-capture.ts        # Agent session capture & handler patching
    ├── menu-commands.ts          # Telegram BotMenu sync
    ├── callback-protocol.ts      # UI callback encoding/decoding
    ├── commands/
    │   ├── register.ts           # Command registry aggregator
    │   ├── model.ts              # /model, /scoped-models, /thinking
    │   ├── session.ts            # /new, /fork, /clone, /tree, /resume, /cd, /cwd, /name, /session
    │   ├── auth.ts               # /login (OAuth + API key), /logout
    │   ├── info.ts               # /status, /copy, /export, /import, /share, /changelog, /hotkeys
    │   ├── lifecycle.ts          # /compact, /reload, /stop, /quit
    │   ├── settings.ts           # /settings menu
    │   ├── tg-config.ts          # /tg-config
    │   └── telegram-commands.ts  # /tg-setup, /tg-connect, /tg-disconnect, /tg-bind-cwd, /tg-list
    └── __tests__/
        ├── attachments.test.ts
        ├── callback-protocol.test.ts
        ├── config.test.ts
        ├── controller.test.ts
        ├── html.test.ts
        ├── info-status.test.ts
        ├── status.test.ts
        ├── telegram-ui.test.ts
        └── text-split.test.ts
```

---

## Development

```bash
# Type checking
npm run typecheck

# Run tests
npm test

# Watch mode
npm run test:watch
```

---

## Security

- **No secrets in source code** — All bot tokens and API keys are read from `~/.pi/agent/tg.json` and `~/.pi/agent/auth.json` at runtime.
- **File permissions** — Configuration files are created with `chmod 600` (owner-only access).
- **Sensitive input protection** — API key inputs use `inputSecret` which automatically deletes the user's message after reading.
- **Attachment path safety** — Outbound `tg_attach` blocks sensitive paths (`/etc`, `~/.ssh`, etc.).
- **Polling lock** — File-based lock prevents multiple pi instances from polling the same bot token simultaneously.
- **First-user authorization** — The first Telegram user to message the bot is automatically authorized; subsequent users are rejected.

---

## Changelog

See [CHANGELOG.md](https://github.com/kdejaeger/pi-telegram-plus/blob/HEAD/CHANGELOG.md).