{"id":50232464,"url":"https://github.com/benedict2310/TelePi","last_synced_at":"2026-08-09T02:30:21.217Z","repository":{"id":346036849,"uuid":"1186680501","full_name":"benedict2310/TelePi","owner":"benedict2310","description":"Telegram bridge for the Pi coding agent — continue sessions from your phone with voice, images, and handback","archived":false,"fork":false,"pushed_at":"2026-07-26T20:03:16.000Z","size":433,"stargazers_count":123,"open_issues_count":8,"forks_count":25,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-26T22:05:10.334Z","etag":null,"topics":["ai-agents","coding-agent","developer-tools","pi","remote-control","telegram-bot","voice-transcription"],"latest_commit_sha":null,"homepage":"https://futurelab.studio/blog/telepi-telegram-remote-control-for-pi/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/benedict2310.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-19T22:04:51.000Z","updated_at":"2026-07-26T20:03:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/benedict2310/TelePi","commit_stats":null,"previous_names":["benedict2310/telepi"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/benedict2310/TelePi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benedict2310%2FTelePi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benedict2310%2FTelePi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benedict2310%2FTelePi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benedict2310%2FTelePi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/benedict2310","download_url":"https://codeload.github.com/benedict2310/TelePi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/benedict2310%2FTelePi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":36432326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-08-06T04:43:03.162Z","status":"online","status_checked_at":"2026-08-09T02:00:06.528Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","coding-agent","developer-tools","pi","remote-control","telegram-bot","voice-transcription"],"created_at":"2026-05-26T19:00:32.247Z","updated_at":"2026-08-09T02:30:21.121Z","avatar_url":"https://github.com/benedict2310.png","language":"TypeScript","funding_links":[],"categories":["Extensions"],"sub_categories":[],"readme":"# TelePi\n\n**Run your Pi coding agent from Telegram: voice prompts, screenshots, session handoff, and terminal handback.**\n\nTelePi is a Telegram bridge for the [Pi coding agent](https://github.com/badlogic/pi-mono). It runs locally on your machine, opens real Pi sessions in your repositories, lets you continue from your phone, and hands the exact same session back to the terminal when you return.\n\n**Who this is for:** developers already using Pi who want a safe mobile control surface for coding-agent work: reply from the train, send a screenshot, dictate a prompt, watch progress, then resume in the CLI without losing context.\n\nEarly open-source release: **80+ stars, 13 forks, and hundreds of npm downloads**. Current npm release: `@futurelab-studio/telepi` **v0.4.2**, with macOS `launchd`, Linux `systemd --user`, image prompts, prompt inbox, local/cloud voice transcription, and Pi command bridging. Read the [Futurelab TelePi deep dive](https://futurelab.studio/blog/telepi-telegram-remote-control-for-pi/) for the longer story.\n\n\u003e **Demo placeholder:** GIF coming soon. The core loop is: Pi CLI `/handoff` → Telegram text/voice/image prompt → `/handback` → resume the same Pi session in your terminal.\n\n## Try it in 5 minutes\n\nYou need:\n\n- **Node.js 22.19+**\n- A Telegram bot token from [@BotFather](https://t.me/BotFather)\n- Your numeric Telegram user ID for the allowlist\n- Pi installed and authenticated locally (`~/.pi/agent/auth.json` exists after a working Pi login)\n\nInstall the npm package and run the guided setup:\n\n```bash\nnpm install -g @futurelab-studio/telepi\ntelepi setup\ntelepi status\n```\n\n`telepi setup` asks for your bot token, allowed Telegram user IDs, and default workspace. It installs the local service for your platform and the Pi `/handoff` extension.\n\n**Success checkpoint:** open Telegram and send `/start` to your bot. You should see your workspace/session status and voice backend status. If not, jump to [Troubleshooting activation blockers](#troubleshooting-activation-blockers).\n\n## Your first TelePi session\n\n1. Start or open a Pi session in a repository.\n2. Run `/handoff` from Pi.\n3. Open Telegram and find your bot.\n4. Send a text prompt, voice message, or screenshot/photo.\n5. Use `/handback` to resume the same session in your terminal.\n\n## Security model\n\nTelePi gives Telegram access to a coding agent, so it is designed to stay private by default:\n\n- **Telegram user allowlist:** only IDs in `TELEGRAM_ALLOWED_USER_IDS` can interact with the bot.\n- **Workspace-scoped execution:** Pi tools are created for the active workspace and re-scoped when you switch sessions.\n- **Local user service:** installed mode runs under your own macOS/Linux user account, not as a public server.\n- **No public bot access when configured correctly:** anyone else who discovers the bot is rejected unless their Telegram user ID is allowlisted.\n- **Docker support:** run TelePi in a non-root container with explicit read/write mounts if you want stronger filesystem isolation.\n\n## Features\n\n- **Bi-directional hand-off**: Move sessions CLI → Telegram (`/handoff`) and back (`/handback`)\n- **Per-chat/topic sessions**: Every Telegram chat or forum topic gets its own Pi session, picker state, and retry history\n- **Voice and image messages**: Send voice/audio for transcription, or photos/image documents as Pi image inputs\n- **Local or cloud transcription**: [Parakeet CoreML](https://github.com/sebastian-software/parakeet-coreml) on Apple Silicon, [Sherpa-ONNX Parakeet](https://k2-fsa.github.io/sherpa/onnx/) for Intel Macs (and as a CPU fallback), or OpenAI Whisper in the cloud\n- **Session tree navigation**: Browse, branch, and label your Pi session history with `/tree`, `/branch`, `/label`\n- **Cross-workspace sessions**: Browse and switch between sessions from any project\n- **Model switching**: Change AI models on the fly via `/model`\n- **Workspace-aware `/new`**: Create sessions in any known project workspace\n- **Pi slash-command bridge**: Run discovered Pi prompt templates, skills, and extension commands from Telegram, browse them with the paginated `/commands` picker, and surface Telegram-compatible ones in the native slash-command menu\n- **External prompt inbox**: Let cron jobs, mail filters, webhooks, or log watchers drop `.txt` prompts into a watched directory\n- **Helpful recovery commands**: `/help` for quick usage guidance and `/retry` to resend the last prompt in the current chat/topic\n- **Extension dialog support**: Pi extension commands can ask for Telegram-native selects, confirms, and text input mid-command\n- **Native Telegram UX**: Topic-safe inline keyboards, typing indicators, HTML-formatted responses, friendly user-facing errors, auto-retry on rate limits\n- **Security**: Telegram user allowlist, workspace-scoped tools, Docker support\n\n## Full setup details\n\nThe npm global install is the main path for TelePi on macOS (`launchd`) and Linux (`systemd --user`).\n\n1. Install TelePi globally:\n   ```bash\n   npm install -g @futurelab-studio/telepi\n   ```\n2. Run the installer using either flow:\n   ```bash\n   telepi setup\n   ```\n   When run in a terminal, `telepi setup` prompts for the three setup values TelePi currently cares about:\n   - `TELEGRAM_BOT_TOKEN`\n   - `TELEGRAM_ALLOWED_USER_IDS`\n   - `TELEPI_WORKSPACE`\n\n   On a fresh config copied from `.env.example`, the example values are treated as placeholders, not saved defaults — pressing Enter still requires you to enter your real bot token, allowed user ID list, and workspace.\n\n   Or use the fast positional form:\n   ```bash\n   telepi setup \u003cbot_token\u003e \u003cuserids\u003e \u003cworkspace\u003e\n   ```\n   where `\u003cuserids\u003e` uses the same comma-separated format as the config file, for example `123456789,987654321`.\n\n   `telepi setup` will:\n   - create or update `~/.config/telepi/config.env`\n   - preserve any existing optional config values already present in that file\n   - on macOS, install/update `~/Library/LaunchAgents/com.telepi.plist`\n   - on Linux, install/update `~/.config/systemd/user/telepi.service` and run `systemctl --user daemon-reload \u0026\u0026 systemctl --user enable --now telepi.service`\n   - install the Pi `/handoff` extension at `~/.pi/agent/extensions/telepi-handoff.ts`\n\n   If you run setup non-interactively, you must either pass all three positional values or already have them configured; TelePi fails clearly instead of writing placeholder values.\n3. Verify the installed config at `~/.config/telepi/config.env` with your real values:\n   ```dotenv\n   TELEGRAM_BOT_TOKEN=123456789:AAFf_real_token_from_botfather\n   TELEGRAM_ALLOWED_USER_IDS=111111111,222222222\n   TELEPI_WORKSPACE=/Users/you/your-main-project\n   ```\n   Notes:\n   - `TELEPI_WORKSPACE` is strongly recommended in installed mode so fresh Telegram sessions start in the right project\n   - `PI_SESSION_PATH` is usually injected automatically by `/handoff`\n   - `OPENAI_API_KEY`, `SHERPA_ONNX_MODEL_DIR`, `PI_MODEL`, and `TOOL_VERBOSITY` are optional\n4. Verify the install:\n   ```bash\n   telepi status\n   ```\n5. Open Telegram and send `/start` to your bot.\n\nRerunning `telepi setup` after upgrades is safe; it refreshes the service unit and extension while preserving your config. After setup, `/handoff` automatically reuses the installed `launchd` service on macOS or `systemd --user` service on Linux by default.\n\n## Troubleshooting activation blockers\n\n### How do I get a Telegram bot token?\n\nOpen [@BotFather](https://t.me/BotFather), send `/newbot`, choose a name and username, then copy the token into `telepi setup` as `TELEGRAM_BOT_TOKEN`.\n\n### How do I find my Telegram user ID?\n\nMessage a helper bot such as [@userinfobot](https://t.me/userinfobot) and copy the numeric ID into `TELEGRAM_ALLOWED_USER_IDS`. Use comma-separated IDs for multiple people, for example `123456789,987654321`.\n\n### Bot does not respond\n\nRun `telepi status` first. Then check that the token is correct, your numeric user ID is allowlisted, you messaged the right bot, and you do not have a second TelePi process polling the same token. On macOS, logs are in `~/Library/Logs/TelePi/`; on Linux, use `journalctl --user -u telepi.service -f`.\n\n### Pi auth missing\n\nStart Pi locally once and complete authentication before using TelePi. TelePi expects Pi credentials under `~/.pi/agent/auth.json` and sessions under `~/.pi/agent/sessions/`.\n\n### Service not running\n\nRun `telepi status`. On macOS, restart the LaunchAgent with `launchctl kickstart -k gui/$UID/com.telepi`. On Linux, run `systemctl --user status telepi.service` and `systemctl --user restart telepi.service`; on headless systems you may also need `loginctl enable-linger \"$USER\"`.\n\n### Voice transcription not working\n\nSend `/start` and check the voice backend status. Local transcription needs `ffmpeg` plus either `parakeet-coreml` on Apple Silicon or `sherpa-onnx-node` with `SHERPA_ONNX_MODEL_DIR` for Intel/CPU fallback. Cloud transcription needs `OPENAI_API_KEY` in `~/.config/telepi/config.env`. See [Voice and Image Messages](#voice-and-image-messages) for setup details.\n\n## Development from Source\n\nUse a source checkout when you want to hack on TelePi or run the latest unreleased code.\n\n1. Install dependencies:\n   ```bash\n   npm install\n   ```\n2. Copy the example environment file and fill it in:\n   ```bash\n   cp .env.example .env\n   ```\n   Replace the example values from `.env.example` with your real settings. At minimum set:\n   - `TELEGRAM_BOT_TOKEN`\n   - `TELEGRAM_ALLOWED_USER_IDS`\n   - `TELEPI_WORKSPACE` if you want fresh Telegram sessions rooted somewhere other than the repo directory\n3. Start the bot in development mode:\n   ```bash\n   npm run dev\n   ```\n4. To test the installed-mode flow from a checkout, build first and use the built CLI entrypoint:\n   ```bash\n   npm run build\n   node dist/cli.js setup\n   # or: node dist/cli.js setup \u003cbot_token\u003e \u003cuserids\u003e \u003cworkspace\u003e\n   node dist/cli.js status\n   ```\n\nIf you are working from a built checkout or GitHub Release artifact instead of a global npm install, install runtime dependencies first — the `dist/` files are not self-contained:\n\n```bash\nnpm install --omit=dev\n# or: npm ci --omit=dev\nnode dist/cli.js setup\nnode dist/cli.js start\n```\n\n\n## Telegram Commands\n\n| Command | Description |\n|---------|-------------|\n| `/start` | Welcome message, session info, and voice backend status |\n| `/help` | Quick command reference and usage tips |\n| `/commands` | Open a paginated picker for TelePi commands plus discovered Pi prompt templates, skills, and extension commands |\n| `/new` | Create a fresh session (shows workspace picker if multiple known) |\n| `/retry` | Re-send the last prompt in the current chat/topic |\n| `/handback` | Hand session back to Pi CLI (copies resume command to clipboard) |\n| `/abort` | Cancel the current Pi operation |\n| `/session` | Show current session details (ID, file, workspace, model) |\n| `/sessions` | List all sessions across all workspaces with tap-to-switch buttons |\n| `/sessions \u003cpath\\|id\u003e` | Switch directly to a specific session file or session ID/prefix |\n| `/model` | Pick a different AI model from an inline keyboard |\n| `/tree` | View the session entry tree; navigate with inline buttons |\n| `/branch \u003cid\u003e` | Navigate to a specific entry ID (with confirmation) |\n| `/label [args]` | Add or clear labels on entries for easy reference |\n\nSessions, inline keyboards, and `/retry` state are isolated per Telegram chat/topic, so forum topics can be used independently without colliding with each other.\n\n`/commands` now opens a mobile-friendly inline picker with pagination plus `All`, `TelePi`, and `Pi` filters. Tapping a TelePi entry runs the built-in command immediately, and tapping a Pi entry forwards the slash command into the active Pi session. Telegram-compatible discovered Pi commands (for example `/review` or `/compact`) are also synced into Telegram's native slash-command interface for the current chat. Commands that Telegram cannot represent, such as `/skill:browser-tools`, stay available through the picker and by manual typing.\n\nAny non-TelePi slash command that matches the active Pi session's discovered commands is forwarded into Pi unchanged. That means Telegram can now trigger file-based prompt templates (for example `/review`), skills (`/skill:browser-tools`), and compatible extension commands. Interactive extension commands can also open Telegram-native select/confirm/input dialogs while the command is running.\n\n## External Prompt Inbox\n\nFor cron jobs, mail filters, webhooks, or log watchers, keep the external trigger outside TelePi and write a `.txt` file into a prompt inbox instead:\n\n```env\nTELEPI_PROMPT_INBOX_DIR=/absolute/path/to/prompt-inbox\nTELEPI_PROMPT_INBOX_INTERVAL_MS=60000  # optional; default 60s, minimum 1s\n```\n\nWhen enabled, TelePi polls the directory, processes one `.txt` file at a time, sends its trimmed contents to the root chat for the first `TELEGRAM_ALLOWED_USER_IDS` entry, and deletes the file after accepting it. If that chat is already busy, files stay queued for the next poll. Empty `.txt` files are deleted to avoid loops; subdirectories and non-`.txt` files are ignored.\n\n## Voice and Image Messages\n\nSend any Telegram **voice message** or **audio file** and TelePi will transcribe it and feed the transcript straight into Pi as a text prompt.\n\n```\n[you send a voice message]\n🎤 \"How does the session hand-off work?\" (via parakeet)\n\n[Pi responds normally]\n```\n\nTelePi supports three transcription backends and picks the best one automatically:\n\n| Backend | How to enable | Cost | Privacy |\n|---------|---------------|------|---------|\n| **Parakeet CoreML** (local) | `npm install parakeet-coreml` + `brew install ffmpeg` | Free | On-device |\n| **Sherpa-ONNX Parakeet** (local, Intel Mac path) | `npm install sherpa-onnx-node` + download model + set `SHERPA_ONNX_MODEL_DIR` | Free | On-device |\n| **OpenAI Whisper** (cloud) | `OPENAI_API_KEY=sk-...` in your TelePi config file | ~$0.006/min | Cloud |\n\nTelePi tries backends in this order:\n\n1. **Parakeet CoreML** — best local path on Apple Silicon\n2. **Sherpa-ONNX Parakeet** — the local/offline path for Intel Macs, where `parakeet-coreml` does not run (and a CPU fallback on Apple Silicon)\n3. **OpenAI Whisper** — cloud fallback\n\nThe `/start` command shows which backends are currently active.\n\nSend a Telegram **photo** or **image document** to pass it to Pi as image input. Captions become the prompt; without a caption TelePi asks Pi to analyze the image.\n\n### Installing Parakeet CoreML (local transcription on Apple Silicon)\n\nParakeet CoreML is an optional dependency (~1.5 GB download, macOS only with Apple Silicon):\n\n```bash\nnpm install parakeet-coreml\nbrew install ffmpeg   # required for audio decoding\n```\n\nOn first use the CoreML model is downloaded automatically. Subsequent calls use the cached model.\n\n### Installing Sherpa-ONNX Parakeet (local transcription for Intel Macs)\n\nThis is the recommended local transcription path on Intel Macs, since `parakeet-coreml` is Apple-Silicon-only. It can also be used on Apple Silicon, but TelePi will still prefer Parakeet CoreML there when available.\n\nInstall the optional Node binding:\n\n```bash\nnpm install sherpa-onnx-node\nbrew install ffmpeg   # required for audio decoding\n```\n\nDownload and extract the Parakeet model layout TelePi expects (`encoder.int8.onnx`, `decoder.int8.onnx`, `joiner.int8.onnx`, `tokens.txt`). The v3 multilingual model below is the intended Intel Mac setup:\n\n```bash\ncurl -LO https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2\ntar xvf sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8.tar.bz2\n```\n\nPoint TelePi at the extracted directory:\n\n```bash\nexport SHERPA_ONNX_MODEL_DIR=\"$(pwd)/sherpa-onnx-nemo-parakeet-tdt-0.6b-v3-int8\"\n```\n\nIf `SHERPA_ONNX_MODEL_DIR` is set, TelePi treats missing model files or a missing `sherpa-onnx-node` package as configuration errors and will not silently fall through to OpenAI.\n\nIf the native module cannot find its shared libraries on macOS, start TelePi with:\n\n```bash\nexport DYLD_LIBRARY_PATH=\"$(pwd)/node_modules/sherpa-onnx-darwin-$(uname -m | sed 's/x86_64/x64/;s/arm64/arm64/'):${DYLD_LIBRARY_PATH}\"\n```\n\nFor the exact family of Sherpa Parakeet models TelePi currently supports, plus platform notes, see:\n\n- https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-transducer/nemo-transducer-models.html\n\n### Using OpenAI Whisper (cloud transcription)\n\nAdd your key to your TelePi config file (`~/.config/telepi/config.env` in installed mode, or `.env` in a source checkout):\n\n```\nOPENAI_API_KEY=sk-...\n```\n\nNo additional packages are required. Supports the same audio formats Telegram delivers (Ogg Opus, MP3, M4A, WAV, etc.).\n\n## Session Tree Navigation\n\nEvery prompt and response in Pi is stored as a tree of entries. TelePi exposes this tree so you can review history and jump back to any point to create a new branch.\n\n### `/tree`\n\nShows the session entry tree as a preformatted diagram with inline navigation buttons.\n\n```\n/tree        — default view (last 10 entries, branch points highlighted)\n/tree all    — full tree with navigation buttons on every entry\n/tree user   — user messages only\n```\n\nInline buttons let you switch between filter modes without retyping the command.\n\n### `/branch \u003cid\u003e`\n\nNavigate to any entry by its short 4-character ID (shown in `/tree`). TelePi asks for confirmation and offers two options:\n\n- **Navigate here** — moves the session leaf to the selected entry; your next message creates a new branch from that point\n- **Navigate + Summarize** — same, but first generates a concise summary of the branch you are leaving\n\n### `/label [args]`\n\nAttach human-readable labels to entries so you can find them easily in `/tree`.\n\n```\n/label fix-auth          — label the current leaf \"fix-auth\"\n/label \u003cid\u003e fix-auth     — label a specific entry\n/label clear \u003cid\u003e        — remove a label\n/label                   — list all labels in the session\n```\n\nLabeled entries are highlighted in `/tree` output and shown in `/branch` confirmations.\n\n## Session Hand-off\n\nTelePi supports seamless bi-directional session hand-off between Pi CLI and Telegram. Both directions preserve the **full conversation context** — the JSONL session file is the single source of truth, and whichever side opens it gets the complete history, including any messages added by the other side.\n\n### CLI → Telegram (`/handoff`)\n\nYou're working in Pi CLI on your laptop and want to continue from your phone:\n\n1. **In Pi CLI**, type `/handoff`\n2. The extension hands off your current session to TelePi — in direct mode it starts TelePi immediately, and in `launchd` mode it restarts the installed LaunchAgent with the handed-off session. The default `auto` behavior picks `launchd` after `telepi setup`, otherwise direct mode — then shuts down Pi CLI\n3. **Open Telegram** — TelePi is already running with your full conversation context. Just keep typing (or speak).\n\n**Extension installation**\n\n- If you used `telepi setup`, the extension is already installed at `~/.pi/agent/extensions/telepi-handoff.ts`\n- If you are developing from a source checkout without `telepi setup`, symlink it manually:\n\n```bash\ncd /path/to/TelePi\nln -s \"$(pwd)/extensions/telepi-handoff.ts\" ~/.pi/agent/extensions/telepi-handoff.ts\n```\n\nPi auto-discovers it after symlinking (or run `/reload` in Pi).\n\nThe extension supports three hand-off mode settings, controlled via shell environment variables:\n\n- `TELEPI_HANDOFF_MODE=auto` *(default)* — if `telepi setup` assets are present, reuse `launchd` on macOS or `systemd --user` on Linux; otherwise use direct mode\n- `TELEPI_HANDOFF_MODE=direct` — always start a fresh direct TelePi process; best for source-checkout development or when the installed service is unloaded\n- `TELEPI_HANDOFF_MODE=launchd` — force macOS `launchd` hand-off by setting `PI_SESSION_PATH` in the `launchd` user environment and restarting the configured LaunchAgent\n- `TELEPI_HANDOFF_MODE=systemd` — force Linux `systemd --user` hand-off by setting `PI_SESSION_PATH` in the user service manager and restarting `telepi.service`\n- `TELEPI_LAUNCHD_LABEL` *(optional, default: `com.telepi`)* — LaunchAgent label/plist name to restart in `launchd` mode or auto-detect\n\n#### Direct mode\n\nDirect mode starts a separate TelePi process. That is the natural default for source-checkout development, where you typically export:\n\n```bash\nexport TELEPI_DIR=\"/path/to/TelePi\"\n```\n\nIf a global `telepi` command is available and `~/.config/telepi/config.env` exists, direct mode can also launch the installed CLI explicitly. If the installed config is missing, `/handoff` now falls back to `TELEPI_DIR` when that source checkout path is available.\n\n#### launchd mode (default after `telepi setup` on macOS)\n\nIf you installed TelePi with `telepi setup`, no extra shell exports are required: `/handoff` auto-detects the installed config + LaunchAgent plist and reuses the resident `launchd`-managed bot instead of starting a second direct polling process.\n\nIf you are testing the installed flow from a source checkout, run the installer from the built checkout first:\n\n```bash\nnpm run build\nnode dist/cli.js setup\n```\n\nYou can still force launchd mode explicitly (or point at a non-default label) with:\n\n```bash\nexport TELEPI_HANDOFF_MODE=launchd\nexport TELEPI_LAUNCHD_LABEL=com.telepi\n```\n\nIn `launchd` mode, `/handoff` only does two things: set `PI_SESSION_PATH` in `launchd`, then restart the configured LaunchAgent. That keeps TelePi to a single bot process and avoids Telegram token conflicts.\n\n\u003e **Note:** `launchctl setenv` does not persist across reboots. After a machine restart, `PI_SESSION_PATH` will be cleared and TelePi will start a fresh session until the next `/handoff`.\n\n\u003e **Note:** `telepi setup` installs the plist with `KeepAlive`, so launchd will restart TelePi if it exits. To fully stop TelePi, unload the agent: `launchctl bootout gui/$UID/com.telepi`.\n\n#### systemd mode (default after `telepi setup` on Linux)\n\nOn Linux, `telepi setup` installs a user service at `~/.config/systemd/user/telepi.service`, reloads the user daemon, enables the service, and starts/restarts it. `/handoff` auto-detects that service and runs:\n\n```bash\nsystemctl --user set-environment PI_SESSION_PATH=/path/to/session.jsonl\nsystemctl --user restart telepi.service\n```\n\nIf `systemctl --user` is unavailable, make sure your distro has user systemd sessions enabled. On headless servers you may need lingering:\n\n```bash\nloginctl enable-linger \"$USER\"\n```\n\nUseful commands:\n\n```bash\nsystemctl --user status telepi.service\njournalctl --user -u telepi.service -f\nsystemctl --user stop telepi.service\n```\n\n### Telegram → CLI (`/handback`)\n\nYou're on your phone and want to get back to your terminal:\n\n1. **In Telegram**, type `/handback`\n2. TelePi disposes the session and sends you the exact command to resume, e.g.:\n   ```\n   cd '/Users/you/myproject' \u0026\u0026 pi --session '/Users/you/.pi/agent/sessions/.../session.jsonl'\n   ```\n3. On macOS and Linux desktops with `wl-copy`, `xclip`, or `xsel`, the command is **copied to your clipboard** automatically\n4. **In your terminal**, paste and run — Pi CLI opens with the full conversation, including everything from Telegram\n5. TelePi stays alive — send any message in Telegram to start a fresh session\n\nYou can also resume with the shorthand:\n\n```bash\n# Continue the most recent session in the project\ncd /path/to/project \u0026\u0026 pi -c\n```\n\n### Manual hand-off\n\nWithout the extension, you can hand off manually:\n\n1. Note the session file path from Pi CLI (shown on startup)\n2. Start TelePi with that session explicitly:\n\n```bash\nTELEPI_CONFIG=\"$HOME/.config/telepi/config.env\" PI_SESSION_PATH=\"/path/to/session.jsonl\" telepi start\n```\n\nFrom a source checkout, use the development entrypoint instead:\n\n```bash\ncd /path/to/TelePi\nPI_SESSION_PATH=\"/path/to/session.jsonl\" npm run dev\n```\n\n### How it works\n\nBoth Pi CLI and TelePi use the same `SessionManager` from the Pi SDK to read/write session JSONL files stored under `~/.pi/agent/sessions/`. When either side opens a session file:\n\n1. `SessionManager.open(path)` loads all entries from the JSONL file\n2. `buildSessionContext()` walks the entry tree from the current leaf to the root\n3. The full message history (including compaction summaries and branch context) is sent to the LLM\n\nThis means hand-off is lossless — no context is dropped regardless of how many times you switch between CLI and Telegram.\n\n## Cross-Workspace Sessions\n\nTelePi discovers sessions from **all** project workspaces stored under `~/.pi/agent/sessions/`. This means:\n\n- **`/sessions`** shows sessions from every project (OpenClawd, homepage, TelePi, etc.), grouped by workspace\n- **`/new`** shows a workspace picker when multiple workspaces are known, so you can start a new session in any project\n- **Switching sessions** automatically updates the workspace — coding tools are re-scoped to the correct project directory\n\nSessions are stored under `~/.pi/agent/sessions/--\u003cencoded-workspace-path\u003e--/`.\n\nFor a fuller module walkthrough after the bot/install refactors, see [`docs/architecture.md`](docs/architecture.md).\n\n## File Layout\n\nInstalled mode (`telepi setup`) creates or manages these user-level files:\n\n```text\n~/.config/telepi/\n└── config.env                     ← generated from .env.example and updated by telepi setup\n\n~/Library/LaunchAgents/            (macOS)\n└── com.telepi.plist              ← launchd service generated by telepi setup\n\n~/.config/systemd/user/            (Linux)\n└── telepi.service                 ← systemd user service generated by telepi setup\n\n~/Library/Logs/TelePi/             (macOS)\n├── telepi.out.log\n└── telepi.err.log\n\n~/.local/state/telepi/logs/        (Linux)\n├── telepi.out.log\n└── telepi.err.log\n\n~/.pi/agent/extensions/\n└── telepi-handoff.ts             ← installed Pi CLI extension\n```\n\nSource checkout layout:\n\n```text\nTelePi/\n├── dist/\n│   ├── cli.js                    ← built CLI entrypoint (`node dist/cli.js ...`)\n│   └── index.js                  ← built bot entrypoint\n├── docs/\n│   ├── architecture.md           ← module layout and runtime overview\n│   └── npm-trusted-publishing.md ← npm release automation playbook\n├── extensions/\n│   └── telepi-handoff.ts         ← Pi CLI extension source\n├── launchd/\n│   └── com.telepi.plist          ← launchd template used by telepi setup\n├── systemd/\n│   └── telepi.service            ← systemd user-service template used by telepi setup\n├── scripts/\n│   └── package-release.mjs       ← builds release tarballs + sha256 checksums\n├── src/\n│   ├── cli.ts                    ← CLI commands (`start`, `setup`, `status`)\n│   ├── index.ts                  ← entry point\n│   ├── bot.ts                    ← Grammy wiring, callbacks, and shared picker state\n│   ├── bot/\n│   │   ├── commands/             ← grouped bot command handlers (`basic`, `sessions`, `model`, `tree`)\n│   │   ├── chat-state.ts         ← per-chat/topic transient state and `/retry` memory\n│   │   ├── extension-dialogs.ts  ← Telegram-backed extension select/confirm/input dialogs\n│   │   ├── keyboard.ts           ← inline keyboard pagination helpers\n│   │   ├── message-rendering.ts  ← Telegram HTML/plain rendering and chunking helpers\n│   │   ├── prompt-handler.ts     ← prompt execution, streaming, and tool updates\n│   │   ├── slash-command.ts      ← slash-command normalization and command catalog helpers\n│   │   └── telegram-transport.ts ← safe reply/edit/send helpers and Telegram file downloads\n│   ├── config.ts                 ← environment config\n│   ├── errors.ts                 ← user-facing error helpers\n│   ├── format.ts                 ← markdown → Telegram HTML\n│   ├── install.ts                ← public installed-mode setup/status facade used by the CLI\n│   ├── install/\n│   │   ├── config.ts             ← config-file setup/update helpers\n│   │   ├── extension.ts          ← extension install/status helpers\n│   │   ├── launchd.ts            ← LaunchAgent plist and launchctl helpers\n│   │   ├── platform.ts           ← platform detection and install context resolution\n│   │   ├── service-manager.ts    ← shared launchd/systemd service manager interface\n│   │   ├── systemd.ts            ← systemd unit and systemctl helpers\n│   │   └── shared.ts             ← shared install types/constants\n│   ├── model-scope.ts            ← model filtering and grouping\n│   ├── pi-session.ts             ← Pi SDK session wrapper\n│   ├── telegram-ui-context.ts    ← Pi extension UI adapter backed by Telegram dialogs\n│   ├── tree.ts                   ← session tree rendering \u0026 navigation\n│   └── voice.ts                  ← audio transcription (Parakeet CoreML / Sherpa-ONNX / OpenAI)\n├── test/\n│   ├── bot.test.ts               ← high-level bot integration tests\n│   ├── bot/\n│   │   ├── chat-state.test.ts\n│   │   ├── extension-dialogs.test.ts\n│   │   ├── keyboard.test.ts\n│   │   ├── message-rendering.test.ts\n│   │   ├── slash-command.test.ts\n│   │   └── telegram-transport.test.ts\n│   ├── config.test.ts            ← config/env loading tests\n│   ├── errors.test.ts            ← error helper unit tests\n│   ├── format.test.ts            ← formatter unit tests\n│   ├── install.test.ts           ← install/setup integration tests\n│   ├── pi-session.test.ts        ← session service integration tests\n│   ├── telegram-ui-context.test.ts ← extension UI adapter unit tests\n│   ├── tree.test.ts              ← tree rendering unit tests\n│   ├── voice.decode.test.ts      ← ffmpeg audio decode tests\n│   └── voice.test.ts             ← voice transcription unit tests\n├── vitest.config.ts\n├── .env.example\n├── Dockerfile\n└── docker-compose.yml\n```\n\n## Docker\n\nFor production use with Docker:\n\n```bash\ndocker compose up --build\n```\n\nThe compose file:\n- Mounts `~/.pi/agent` read-only (for auth and settings)\n- Mounts `~/.pi/agent/sessions` read-write (for session persistence)\n- Mounts your workspace directory read-write\n- Runs as non-root, drops capabilities, enables `no-new-privileges`\n\n## Security Notes\n\n- Only Telegram user IDs in `TELEGRAM_ALLOWED_USER_IDS` can interact with the bot\n- Pi tools are scoped to the workspace via `createCodingTools(workspace)` and re-scoped on session switch\n- The `/handoff` extension only shuts down Pi CLI if TelePi launches or restarts successfully\n- URL sanitization blocks `javascript:` and other unsafe protocols in formatted output\n- Shell commands in `/handback` use `spawnSync` (no shell interpretation) for clipboard copy\n- Voice files are downloaded to a temporary directory and deleted immediately after transcription\n\n## Architecture\n\n```text\nTelegram\n  ↓\nGrammy bot (`src/bot.ts`)\n  ├── transport helpers         → `src/bot/telegram-transport.ts`\n  ├── rendering helpers         → `src/bot/message-rendering.ts`\n  ├── prompt lifecycle          → `src/bot/prompt-handler.ts`\n  ├── chat-local busy/retry     → `src/bot/chat-state.ts`\n  ├── extension dialogs         → `src/bot/extension-dialogs.ts`\n  ├── grouped command handlers  → `src/bot/commands/*`\n  └── voice route               → `src/voice.ts`\n                                     └── ffmpeg decode + local/cloud transcription backends\n        ↓\nPiSessionRegistry / PiSessionService (`src/pi-session.ts`)\n  ├── AgentSession / SessionManager → `~/.pi/agent/sessions/`\n  ├── workspace + saved-session switching\n  ├── model scope / registry integration\n  ├── tree navigation + labels\n  └── handback/session lifecycle\n        ↓\nPi SDK + workspace-scoped coding tools\n```\n\nThe detailed module map, testing layout, and remaining large hotspots are documented in [`docs/architecture.md`](docs/architecture.md).\n\n## Development\n\n```bash\nnpm install\nnpm run dev            # Run with tsx (auto-loads .env)\nnpm run build          # TypeScript compilation\nnpm run build:clean    # Clean dist/ and rebuild\nnpm test               # Run tests\nnpm run test:coverage  # Run tests with coverage report\nnpm run package:release  # Create artifacts/telepi-vX.Y.Z.tar.gz + checksum\nnpm run ci:release     # Test + clean build + package release artifact\n```\n\n## Release Automation\n\nGitHub Actions publishes npm and creates the GitHub Release automatically on tag pushes matching `v*.*.*`.\n\nMaintainer flow:\n\n```bash\nnpm version patch   # or minor / major\ngit push origin main --follow-tags\n```\n\nThe release workflow then:\n- verifies the pushed tag matches `package.json`\n- installs dependencies and runs release CI via `npx --yes npm@11.10.0`\n- publishes `@futurelab-studio/telepi` to npm\n- creates a GitHub Release with the packaged tarball and checksum\n\nNotes:\n- prerelease tags like `v0.2.0-beta.1` are published to npm with the `next` dist-tag and marked as GitHub prereleases\n- npm publishing uses Trusted Publishing from GitHub Actions; no `NPM_TOKEN` secret is required\n- the trusted publisher must be configured on npm for repo `benedict2310/TelePi` and workflow `.github/workflows/release.yml`\n- npm Trusted Publishing currently requires npm CLI `11.5.1+` and Node `22.14.0+`; TelePi keeps the runner's bundled npm unchanged and uses `npx --yes npm@11.10.0` for release steps because older npm versions can fail with misleading `E404 Not Found` publish errors even when OIDC is configured correctly\n- the workflow has been verified end-to-end with release `v0.2.2`\n- reusable setup details for this pattern live in `docs/npm-trusted-publishing.md`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenedict2310%2FTelePi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbenedict2310%2FTelePi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbenedict2310%2FTelePi/lists"}