What it is
A self-hosted AI gateway running on my VPS as a rootless Docker stack: multiple named agents with group-scoped tool permissions, reached over end-to-end-encrypted Matrix and a private allowlisted Telegram bot, backed by a commercial LLM endpoint via a private API key. Cron jobs fire briefings, digests, and reviews on a schedule — turning "chat with an LLM" into a disciplined, scheduled operations assistant.
Why it exists
Two gaps I wanted to close:
- Ambient agents as operations assistants, not chatbots. Claude Code in a terminal is great for on-demand work. But the most useful moments are scheduled: a 08:00 briefing summarising overnight alerts, a Friday RSS digest so I don't start the weekend reading 200 headlines, a Monday task review pulling from my self-hosted Plane. Those need a long-running service, not an interactive REPL.
- Messaging-native agent access without exposing raw model endpoints. I didn't want to expose LLM APIs directly to the public internet, but I also wanted to ping agents from my phone without opening a laptop. Matrix + Telegram are both message-bus endpoints I already trust; wrapping agents behind them means no raw LLM endpoint is ever directly reachable.
OpenClaw bridges those: long-running multi-agent service + messaging-only ingress + scheduled workloads + auditable tool permissions per agent.
Architecture
Rootless Docker on the VPS hosts the gateway. Each agent is a named configuration with its own tool allowlist and scope. Ingress comes only through the two messaging bridges (Matrix for secure interactive use, Telegram for mobile). Outbound calls hit a commercial LLM over a private API key held in git-crypt secrets — nothing about the model vendor is baked into the gateway logic, so the backend is swappable.
What I built
- Rootless Docker deployment — the whole stack runs unprivileged on the VPS (shares the security posture of every other Docker stack there). Declared in the NixOS flake like all other homelab services; rebuild-from-scratch takes one
aku sync. - Named agents with group-scoped tool permissions — each agent has an explicit tool allowlist. Different agents have different capabilities; the scope lives in declarative config, not model prompts, so it survives jailbreaks.
- E2E-encrypted Matrix bridge — Element Web + Synapse homeserver (part of
my-homelab) carries interactive conversations. Encryption via olm; no plaintext logs on the server; each agent has its own room-level ACL. - Private allowlisted Telegram bot — mobile-friendly ingress; the bot rejects any user not on the allowlist before routing to an agent. Zero direct LLM endpoint exposure.
- Commercial LLM backend via private API key — the LLM provider is configurable per-agent; API keys live in git-crypt secrets and are injected into the container via
env_file. Vendor-neutral — switching providers is a secret-update, not a code change. - Cron-driven scheduled jobs — three active schedules: weekday 08:00 morning briefing (alerts + calendar), Friday 19:00 weekly RSS digest (Miniflux-AI pre-summarised feeds), Monday 09:00 weekly task review (Plane tickets + commitments). Jobs are idempotent and survive VPS restarts.
- Audit trail — every agent call logs the inputs, the tool invocation, and the LLM request ID. Useful for cost tracking and for catching a drifting agent before it becomes a production issue.
Results
- Ambient, scheduled AI that talks back through channels I already use (Matrix + Telegram) — no new interface to build or learn.
- No direct LLM endpoint ever reachable from the public internet — messaging bridges are the only ingress.
- Declarative end-to-end — the gateway, its agents, its messaging bridges, and its cron jobs are all part of the NixOS flake. Rebuilds from source in minutes.
- Backend-agnostic — swap the LLM provider behind a config change.
Stack
NixOS, Docker (rootless), Docker Compose, Matrix Synapse + Element, Telegram Bot API, cron, Python (agent glue), systemd, git-crypt.
Status
- Repo: private.
- Running: VPS daily since 2025; three scheduled jobs active; agents reachable from Matrix and Telegram.
- Note: implementation details (agent names, bot handle, specific LLM backend/model) are intentionally redacted from public-facing documentation for security — happy to share more in interviews.
- Related:
my-homelab(where it runs),claude-code-mcp-operator(the interactive-agent side).
