Three-Service Model
q15 is not a monolith. It is three services, each with a clear ownership boundary, that run together as one stack.
The three services
Section titled “The three services”| Service | Owns | Listens |
|---|---|---|
q15-agent |
Prompt assembly, tool wiring, Telegram I/O, memory, file operations | Telegram (long-poll) |
q15-exec |
Command execution, session lifecycle, Nix package management | :50051 (gRPC) |
q15-proxy |
Credential injection, request mutation, TLS interception | :50052 (proxy), :18080 (PAC) |
q15-agent connects to q15-exec at q15-exec:50051. q15-exec connects to q15-proxy at q15-proxy:50052. The agent never talks to the proxy directly — the exec service routes outbound traffic through it.
A fourth service, q15-qdrant, stores embedding vectors when the embeddings tool is configured.
Deployment model
Section titled “Deployment model”One stack = one q15-agent + one q15-exec + one q15-proxy, running together in Compose or Kubernetes. Optionally a q15-qdrant sidecar for embeddings.
In Kubernetes, the supported topology is one namespace per q15 stack. Each stack contains its own ConfigMaps, Secrets, and persistent volumes. The namespace is the isolation boundary.
Storage contract
Section titled “Storage contract”Every stack has persistent volumes for:
| Path | Purpose |
|---|---|
/workspace |
Durable project tree and working files |
/memory |
Agent identity, semantic knowledge, working state, history |
/skills |
Installed skill artifacts |
/nix |
Nix store and fetched packages (keeps builds warm across sessions) |
/var/lib/q15/proxy |
Proxy-owned durable state |
/workspace may start empty on first deploy. That is a valid initial state. It is expected to persist long-term and survive restarts and upgrades.
How a turn flows
Section titled “How a turn flows”- User sends a Telegram message — The message arrives at
q15-agentvia long-polling. - Prompt assembly — The agent assembles context from core memory files, working memory, and conversation history.
- Model selection — Capabilities are inferred from the request. Models that cannot satisfy the requirements are filtered out. The remaining models are tried in configured preference order.
- Tool execution — Tool calls from the model are executed by the agent. Shell commands go through
q15-exec, which routes egress throughq15-proxy. - Persistence — The completed turn is written to
/memory/history/as a JSON file. Working memory may be updated. - Response — The agent sends the final response back to Telegram.
Auth bootstrap
Section titled “Auth bootstrap”Interactive auth is handled separately by q15-auth, an operator tool that runs on your machine, not inside the runtime containers. It produces auth.json, which gets mounted into the agent container.