A small, opinionated, slightly paranoid bridge between Telegram and your pi agent.
License: MIT
This repo is a single-owner remote admin bridge for talking to pi through Telegram.
That is the whole trick:
- pi is the agent
- this repo is the Telegram-shaped door
- a few locks were added so the door isn't completely feral
No giant platform. No orchestration theme park. No "AI operating system for synergy-driven workflows." Just a Telegram bot awkwardly wired into your pi so you can talk to it without SSHing from your phone while waiting in line for coffee.
- not a SaaS
- not a multi-user chat platform
- not an enterprise product
- not guaranteed to be a good idea
This project was vibe coded.
Which means:
- it works for me
- it may work for you
- it may also become a tiny goblin at an inconvenient time
There is no warranty and no promise of fitness for any purpose. Please review the code, restrict the workspace, and do not point this at anything you cannot afford to have deleted by a hallucinating LLM.
This bridge depends on pi and uses the pi SDK.
- pi repo: https://github.com/earendil-works/pi
- npm package: https://www.npmjs.com/package/@earendil-works/pi-coding-agent
- requires pi >= 1.0 (the package moved from
@mariozechner/pi-coding-agent)
You need pi installed, configured, and authenticated separately. This bridge does not replace pi. It just gives pi a Telegram handle.
Examples:
pi /login- credentials stored in
~/.pi/agent
If pi is broken locally, this bridge will not magically become wise through suffering. Fix pi first.
- Telegram bot connection: chat with pi on the go
- Persistent memory: session history per Telegram chat
- Aggressively locked by default: denies everyone unless they know the secret handshake
- Owner-only: mapped strictly to your exact numeric Telegram user ID
- Private-chat-only: ignores groups to avoid awkward robotic mass-replies
- TOTP / Shared Secret unlocking: like a dead-man's switch for your agent
- Timeout auto-locking: forgets access after a configurable TTL
- Audit logging: for when you inevitably ask "who did that?"
- Optional owner alerts: get DMs when unauthorized people try to poke your bot
- TUI manager: because typing out
systemctlcommands constantly gets old fast
Managing this bridge is surprisingly civil. We have a built-in terminal UI to set up your environment, test the config, and babysit the background daemon.
This version is designed for one owner only and remote admin-style access.
It is:
- locked by default
- strictly owner-only by Telegram user ID
- private-chat-only by default
- unlockable with TOTP (strongly recommended) or a shared secret
- auto-locking after a configurable timeout
- able to snitch on unauthorized attempts directly to your chat
- keeping receipts in an audit log
In other words: simple, but trying very hard not to be reckless.
bin/— executables (telepi,telepi-manage,telepi-tui)src/index.mjs— main bridge processsrc/manage.mjs— CLI managersrc/manager-lib.mjs— shared runtime and config helperssrc/tui.mjs— terminal UI manager.env.example— configuration templatelogs/audit.log— JSON-lines audit logdata/sessions/<chat-id>/...— persistent pi session history
npm install -g @lpgn/telepi
mkdir -p ~/telepi
cd ~/telepi
cp "$(npm root -g)/@lpgn/telepi/.env.example" .envTroubleshooting Global Installs:
EACCESpermissions error: Do not usesudo. Instead, configurenpmto use a user-owned directory (tools likenvmdo this automatically):
- Run:
mkdir -p ~/.npm-global- Run:
npm config set prefix '~/.npm-global'- Re-run the
npm install -gcommand above, then follow Step 2 to adjust your$PATH.command not found: telepiafter installing: If npm successfully installed the package into a custom directory (like~/.npm-global), but your terminal can't find the command, your$PATHis missing the npm bin folder.
- For bash/zsh: Run
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrcand restart your terminal.- For fish: Run
fish_add_path $HOME/.npm-global/binand restart your terminal.
Then edit .env.
By default, the global telepi installation uses your current working directory for .env, data/, logs/, run/, and generated systemd/ files.
If you want to keep those files somewhere specific regardless of where you are when you run it, set TELEPI_HOME=/path/to/telepi-home in your environment before running it.
git clone https://github.com/lpgn/telepi.git telepi
cd telepi
npm install
cp .env.example .envThen edit .env.
Minimum useful config:
TELEGRAM_BOT_TOKEN=your_bot_token
OWNER_TELEGRAM_USER_ID=your_numeric_telegram_user_id
UNLOCK_METHOD=totp
UNLOCK_TOTP_SECRET=your_base32_secretSee:
UNLOCK_METHOD=totp
UNLOCK_TOTP_SECRET=JBSWY3DPEHPK3PXPUse your own base32 secret and add it to an authenticator app (or just generate one using the built-in TUI's setup menu). Do not use the example secret above in production unless you enjoy improvisational security.
UNLOCK_METHOD=secret
UNLOCK_SHARED_SECRET=replace_with_a_long_random_secretOWNER_TELEGRAM_USER_ID— only this numeric Telegram user ID is allowedOWNER_CHAT_ID— optional extra lock tying it to one specific chatALLOW_PRIVATE_CHATS_ONLY— reject groups, supergroups, and channels (default: true)UNLOCK_TTL_MINUTES— auto-lock timeoutPI_WORKSPACE_DIR— where pi will operatePI_AGENT_DIR— where pi config/auth livesPI_MODEL_PROVIDER/PI_MODEL_NAME— optional fixed model overridePI_THINKING_LEVEL— optional thinking level overrideUNLOCK_STATE_FILE— optional persisted unlock state fileAUDIT_LOG_FILE— audit log location
telepiOr run it locally from the repo with:
npm starttelepi-tuiOr from the repo:
npm run tuiThe TUI is organized into three pleasantly functional sections:
- Setup — wizard, settings, unlock secret generation (TOTP QR codes!), systemd file generation, and config tests
- Bridge — check status, start, stop, restart
- Logs — view and clear bridge/audit logs like a true sysadmin
Useful keys:
Enter— open selected section or run selected actionEsc— go back (or escape your mistakes)1— jump to Setup2— jump to Bridge3— jump to Logsr— refreshPgUp/PgDn— scroll your logsq— quit
telepi-manage status
telepi-manage start
telepi-manage stop
telepi-manage restart
telepi-manage logs bridge
telepi-manage logs auditCommands you must type to the bot:
/status— show whether the bot is locked or feeling talkative/unlock <code>— unlock agent access temporarily (using your TOTP code or shared secret)/lock— lock immediately (for when the paranoia kicks in)/clear— clear the current pi session history (only when unlocked)
Normal text prompts are forwarded to pi only while unlocked.
- The bot starts locked. It is naturally suspicious.
- While locked, free-text prompts are politely (or silently) refused.
/unlock <code>unlocks it forUNLOCK_TTL_MINUTES.- After the timeout, it auto-locks again.
So yes, it is basically a remote control for your agent with an anxious man's dead-man switch.
If ALERT_OWNER_ON_DENIED=true, denied attempts generate a Telegram alert to the owner chat. Be prepared to find out how many bots are scraping Telegram usernames.
Audit events are appended as JSON lines to AUDIT_LOG_FILE.
Typical events include:
DENIED_USERDENIED_CHAT_TYPEUNLOCK_SUCCESSUNLOCK_FAILUREPROMPT_STARTPROMPT_ENDPROMPT_ERROR
Please do not treat "it has a lock" as equivalent to "it is impenetrable."
Recommended precautions:
- Enable Telegram 2FA on your account so someone can't steal your bot via SIM swapping
- Keep the bot token securely wrapped
- Restrict permissions on
.env,logs/,data/, and~/.pi/agent - Narrow
PI_WORKSPACE_DIRas much as possible so pi doesn't accidentally eat your system files - Set
OWNER_CHAT_IDif you want to pin access strictly to one chat instance - Rotate secrets if they ever appear in chat history, shell history, screenshots, or anywhere that feels bad
The TUI can actually generate this for you automatically! But if you're stubborn and like doing it by hand, the repo includes a generic service template at:
systemd/telepi.service.example
If you use the TUI generator or copy it yourself, your own machine-specific local service file will live at:
systemd/telepi.service
That local file is gitignored on purpose. No leaking paths.
If you want to install it system-wide, copy the generated or template file to:
/etc/systemd/system/telepi.service
Example of what the TUI generates:
[Unit]
Description=telepi
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/opt/telepi
EnvironmentFile=/opt/telepi/.env
ExecStart=/usr/bin/env telepi
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectKernelModules=true
LockPersonality=true
RestrictSUIDSGID=true
UMask=0077
[Install]
WantedBy=multi-user.targetThen make it official:
sudo systemctl daemon-reload
sudo systemctl enable --now telepi
sudo systemctl status telepiThis project is small on purpose. That is a feature.
If you wanted a massive AI enterprise workflow orchestrator platform, this is emphatically not that. If you wanted a compact Telegram-to-pi bridge with a few sensible security rails and a genuinely delightful manager TUI, that is exactly what this is.
Use it, fork it, improve it, or laugh at it. But please do so responsibly.
