Pipe

Telegram Bot

Pipe v0.50.5

A Telegram bot for managing a VPS through an AI agent.

Overview

The Telegram bot is a client of the agent. It connects to the backend over a Unix socket and passes messages from Telegram to the agent. Answers are formatted as HTML and sent back to the user.

It handles confirmations with inline buttons (YES / NO; the decision is added to the same message), sends diagrams as photos, shows progress in a single message that keeps updating – every agent command and a few lines of its output (when the work is done it collapses to "Steps taken: N", tap to expand the list) and, most importantly, writes by itself when something happens: watcher alerts and watcher alerts, suggestions, findings of its own investigations and routine reports arrive without asking, each with action buttons (Investigate, Free up space, Patch, Fix it).

Under the message box there is a fixed keyboard: Server status, What's new, Projects, Help – the most common things without knowing any command. The / menu shows only the everyday commands; the full list is in /help.

Alerts

The bot keeps a permanent connection to the backend ({"command": "subscribe"}, renewed after a restart) and forwards events to every user in TELEGRAM_ALLOWED_USER_IDS:

Everything Pipe wrote by itself also lands in the inbox: /news (the What's new button) shows the latest messages with their buttons. When the bot should notify you is set with buttons in /notifications: the level (everything / important / critical only), quiet hours (at night only critical things, the rest in the morning with the report), the daily limit of suggestions. A message held back by these settings waits in the inbox.

TELEGRAM_ALERTS=0 in clients/telegram/.env turns forwarding off. Thresholds: Watching.

When notifications don't arrive

The bot gets alerts, reports and reminders through a permanent connection to the backend (an event subscription). When it is missing, /reminders and /alerts show a warning with the reason, and a reminder is marked waiting for pickup and arrives once the bot connects. The most common causes:

Logs: docker compose logs telegram | grep -i "kanal\|subskrypcja"; when it works: Subskrypcja alertow aktywna. TELEGRAM_ALERTS=0 only silences watcher alerts and reports; reminders and approval requests always arrive.

Voice messages

Record a voice message and the bot replies I heard: ... and passes the text to the agent. With the gemini provider the model itself transcribes the recording, with openai or groq their Whisper does; it works right away. For other providers set STT_BASE_URL, STT_API_KEY, STT_MODEL in backend/.env (for example a free Groq key or a local faster-whisper).

Photos and files

Send a screenshot, a log or a config file; the caption is the question ("why won't nginx accept this?"). Several photos sent at once (an album) reach the agent as one message. The limit is 10 MB per file. The model looks at images and reads text (after secrets are hidden); other files are saved on the server and the agent gets the path. A viewer can send images and text but not files to be saved. Details: Attachments.

Roles

Diagrams

/map or "show the architecture": the diagram arrives as a photo. A diagram larger than Telegram's photo limit (10 MB, sides adding up to 10000 px) arrives as a file in full resolution.

Formatting answers

The bot uses Telegram's HTML mode (not MarkdownV2). The reason: MarkdownV2 needs 18 special characters escaped, which breaks easily with dynamic content (for example container names with underscores). HTML needs only 3 characters escaped (<, >, &), which is much simpler.

Supported HTML tags:

The bot converts leftover Markdown (if the LLM produces it) into the matching HTML tags.

Text in backticks, including commands in confirmations, is shown verbatim, without Markdown conversion. So before tapping YES you see exactly the command that will run (including *, _, \\, <, & and backticks). The characters <, > and & outside tags are escaped automatically, so Telegram doesn't reject the message. Formatting code: clients/telegram/tg_format.py.

Reports and summaries

Requirements

Configuration

1. Create a bot with @BotFather

/newbot

Copy the bot token.

2. Find your user ID

Send /start to @userinfobot (https://t.me/userinfobot); it returns your numeric ID.

3. Fill in .env

cp .env.example .env

Edit .env:

TELEGRAM_BOT_TOKEN=1234567890:ABCxyz...
TELEGRAM_ALLOWED_USER_IDS=123456789
AGENT_SOCKET=/tmp/vps-agent.sock

# Must be identical to AGENT_TOKEN in backend/.env.
# Leave empty if the backend doesn't require a token.
AGENT_TOKEN=

# Bot language: en (default) or pl, the same as PIPE_LANG in backend/.env.
# PIPE_LANG=pl

You can add several IDs separated by commas: 123456789,987654321

Running

The bot starts automatically together with the backend with docker-compose up -d.

Starting it by hand:

pip install -r requirements.txt
python bot.py

What you can ask

The full list is below (the Commands section). You can also just write, for example:

Security

The bot stays silent for users outside the whitelist: it doesn't answer any message. That way it doesn't reveal its existence to unauthorized people.

Commands

In English (the default) the / menu shows English names (/report, /changes, /undo...). Polish and English names work in both languages.

CommandWhat it does
/statusServer status at once, without AI: a plain-words headline (All good or what needs attention), CPU, memory and disk bars, the number of new messages and projects
/newsThe inbox: what Pipe wrote by itself (alerts, findings, suggestions, reports), with action buttons (/nowosci)
/projectsWorkshop projects: state, address, Logs and Stop/Start buttons (/projekty)
/webPipe in the browser on your phone and computer: /web on exposes it at an HTTPS address, access requests arrive here with Let in / View only / Reject buttons (administrators only); /web off, /web revoke <no>
/cleanupFrees space without AI: untagged Docker images, old build cache, downloaded apt packages and npm/pip caches; says how much it freed. Admins only (/sprzataj)
/notificationsWhen Pipe should notify you: level, quiet hours, suggestion limit – with buttons (/powiadomienia)
/update [check]Update Pipe itself (confirmed with buttons); check only shows the versions
/reportThe morning report on demand: health, alerts, changes since yesterday, certificates, backups, updates, LLM cost + chart
/changes [24h|3d]What changed on the server: packages, container images, ports, cron, accounts, SSH keys, configs
/chart [load|ram|disk] [24h|7d]Chart from the watcher's history as a photo
/healthTLS certificates, site responses, DNS and backup freshness (not in the menu or /help – /status shows problems)
/auditHost security score 0-100 with ready fixes (write "fix 1")
/incidentsIncident memory: what happened, what was found, what helped
/approvalsOperations of external agents (MCP) waiting for approval; Approve/Reject buttons for admins, with the safety-fuse plan
/mcp [add <add-on>|<name> <npx ...|uvx ...|URL> | remove <name> | reload]Connected MCP servers with their state and ready add-ons (Google, Outlook, Microsoft 365, GitHub) with an Add button (administrators). Do not type keys in the chat – the /mcp window in pipe web or the CLI
/journalApproved changes with backups (what, when, whether it can be undone)
/undo [id]Undoes the last (or the given) change: a preview of the diff and inverse commands, then an Undo button. Works without the LLM
/vulnsKnown vulnerabilities in packages, container images, on remote servers and in applications, each with a short explanation. Viewers can use it too
/patch [images|server|apps|servers|<target>]Patches right away, without buttons or questions (admin): this server's packages, application dependencies (bumped in the dependency files, the compose project rebuilt), container images and remote servers, then cleans up old images and caches. One message shows the steps live, at the end a short result: what was patched, what stayed unchanged and why, how much space was freed. The Patch button on a vulnerability alert patches what the alert is about. Works without the LLM
/costLLM token usage today and over the last days (with cost when prices are in .env)
/view [simple|technical|description]Pipe's view (/widok): without an argument Simple / Technical buttons. Simple changes the / menu, /help and the keyboard (status, news, skills, help), and the agent writes in plain words; shared with the CLI and pipe web. On the first /start the bot asks what you want to do – a button or a few words. Admin only
/language [pl|en]Pipe's language: switches agent instructions, reports, bot messages and the / menu without a restart, shared with the CLI and pipe web; admin only
/providers [id [model]]LLM providers: buttons for providers that have a key (the active one too, to change its model), then the provider's models as paged buttons; the current one is marked, "Keep ..." keeps it. /providers groq llama picks a model by name fragment, /providers model changes the model of the current provider. The bot never takes API keys (they would stay in the chat history); add them in pipe web or the CLI. Admin only
/yolo [on|off]YOLO mode: changes in this conversation run without YES/NO buttons (the safety fuse, the journal and /undo still work; forbidden operations are refused). Off by default, admin only, forgotten when the backend restarts
/map [title]Infrastructure diagram as a photo (no LLM, so fast and free)
/serverShows SERVER.md. When there is none, the agent explores the server and creates it
/server updateThe agent explores the server again and updates SERVER.md and DIRECTORY
/directoryMap of repositories and directories (DIRECTORY)
/skillsList of saved skills with their commands
/download skill|plugin <owner/repo|URL> [filter]Skills and plugins from a git repository: a preview with Install / Cancel buttons (/pobierz); admin only
/alertsActive watcher alerts and recent events (not in the menu or /help – messages are in /news)
/routinesTasks run on a schedule
/reminders [cancel <id>]One-off reminders; they arrive on time to the person who set them
/targetsRemote servers, containers and clusters
/newNew conversation from a clean slate (the bot has one conversation per user); the server notes, directories, skills, style and alerts stay
/vibeWhat the agent knows about your conversation style; /vibe reset clears it
/<skill>Runs a skill, for example /renew_certificate. You can add hints: /renew_certificate only for example.com
/historyLatest audit-log entries, no LLM (not in the menu or /help – /journal shows changes)
/helpCommand list

The bot sets the suggestion menu shown after typing / at startup and refreshes it after every message, so a new skill shows up in the menu right away. The menu is set separately for the chat of each user in TELEGRAM_ALLOWED_USER_IDS, not globally, so people outside the list don't see skill names or descriptions. If you don't see the menu, write anything to the bot (Telegram only allows setting the menu after the chat has started).

For an unknown command the bot replies with a hint instead of staying silent.

Edit this page on GitHub