A Telegram interface to an always-on personal AI assistant, running on exe.dev, powered by flue.
I've been using exe.dev for remote development over SSH in VS Code and Zed and wanted to build a Telegram agent specifically for their platform.
exe.dev is a new cloud from the co-founder of Tailscale. Instead of getting a single VM, you get a pool of compute, memory, and disk that you can use to create many cloud-hypervisor VMs. Every VM has access to a LLM gateway with a monthly allocation of credits. They also include useful features like a reverse proxy for web apps, authentication for users, bearer tokens for services, and sending/receiving email.
flue is a framework for building agents from the Astro team at Cloudflare. It uses pi-ai and pi-agent-core under the hood. It can be deployed to Cloudflare workers, run as a Hono server, or be embedded as a runtime. It provides automatic compaction, SQLite session persistence, and a durable job queue with lease-based ownership, so a crashed turn can be retried when the service is back online. The official Telegram channel only supports webhooks, so grammy is used for long-polling instead of exposing a port.
- Inbound: a text message is allow-listed against
TELEGRAM_ALLOWED_USER, then queued per-session. At most one turn runs at a time per chat; anything that arrives mid-turn is buffered and joined into a single follow-up turn once the current one settles, rather than piling up concurrent dispatches or dropping messages. - Outbound: a "Thinking…" placeholder is sent immediately and edited in place roughly once a second as the model streams, then finalized and converted to Telegram MarkdownV2 (with plain-text fallback), and split across Telegram's 4096-character limit on sentence/newline boundaries.
- Storage: sessions and in-flight turns live in
flue's SQLite database, not in memory. Restart the process mid-response and it picks the turn back up instead of losing it. - Models: the model catalog is fetched once from the exe.dev gateway at startup. Each chat can switch models with
/model <name>.
Note
You can clone the repo anywhere, but the database file lives in $XDG_DATA_HOME/exe-agent or ~/.local/share/exe-agent.
git clone https://github.com/adamelliotfields/exe-agent.git ~/.exe-agent
cd ~/.exe-agent
npm i
Development:
npm run devPreview:
npm run build
npm startProduction:
Note
Update exe-agent.service if you didn't clone into ~/.exe-agent or if you aren't using the default exedev user.
npm run build
sudo cp ~/.exe-agent/systemd/exe-agent.service /etc/systemd/system/exe-agent.service
sudo systemctl daemon-reload
sudo systemctl enable --now exe-agent.service
journalctl -u exe-agent -f # tail logsNote
You don't need an API token for the exe.dev LLM gateway.
Required:
TELEGRAM_BOT_TOKENTELEGRAM_ALLOWED_USER
Optional:
EXE_AGENT_ALLOWED_MODELS: comma-separated model names to expose (defaults toGET /v1/models)EXE_AGENT_DEFAULT_MODEL: default model (defaults toallowedModels[0])EXE_AGENT_CONTEXT_WINDOW: context window size in tokens (defaults to256000)EXE_AGENT_MAX_TOKENS: max tokens per response (defaults to64000)EXE_AGENT_HOME: working directory for the agent (defaults to$HOME)LOG_LEVEL:INFO,ERROR, orFATALto disable (defaults toINFO)
Example .env:
Note
The .env file is only loaded automatically in development. You must otherwise use Node's --env-file or systemd's EnvironmentFile.
TELEGRAM_BOT_TOKEN=<your-bot-token>
TELEGRAM_ALLOWED_USER=<your-user-id>
EXE_AGENT_ALLOWED_MODELS=deepseek-v4-flash,glm-5p2,kimi-k3,minimax-m3
EXE_AGENT_DEFAULT_MODEL=minimax-m3
EXE_AGENT_CONTEXT_WINDOW=128000
EXE_AGENT_MAX_TOKENS=32000
EXE_AGENT_HOME=/home/exedev
LOG_LEVEL=infoflue will automatically load $EXE_AGENT_HOME/AGENTS.md and $EXE_AGENT_HOME/.agents/skills/**/SKILL.md.
The system prompt is a concatenation of:
- Assistant instructions
- Additional
AGENTS.mdinstructions - Available
SKILL.mddescriptions from frontmatter
Note that there is no SOUL.md. Put everything in AGENTS.md: your personal bio, communication preferences, environment information, what you're working on, what your interests are, and so on.
write: Creates or overwrites a file. Automatically creates parent directories if they don't exist.read: Reads a file from disk. Output is truncated to 2000 lines or 50kb. Can useoffsetandlimitparameters to read specific sections.edit: Edits a file by finding exact text and replacing it.grep: Searches files for a regex pattern.glob: Finds files by filename pattern.bash: Runs any Bash command in the working directory ($EXE_AGENT_HOME). Returns stdout and stderr.task: Spawns a detached child agent to work on a task independently. Returns only the final answer.
Send /newbot to @BotFather. Your bot's username must end in bot.
Tip #1: Use dockernamegenerator.com to generate random names like jolly_feynman_bot or refresh repo.new for names like ubiquitous_waffle_bot.
Tip #2: Create a second bot for development. Telegram only allows one active connection per bot token.
Send /start to @UserInfoBot.
/start: greeting/stop: stop the in-flight turn, but don't start a fresh session/new: abort the in-flight turn, clear any per-session model override, start a fresh session/models: list available models, marking the active and default ones/model <name>: switch model for this session
See AGENTS.md for architecture and conventions.