Personal AI agent assistant. A lightweight, self-hosted alternative to OpenClaw focused on Telegram and Claude Code. Define named agents with distinct roles and models, message them from Telegram, and monitor everything from Mission Control.
Telegram ──> Go Gateway ──> Router ──> Embedded NATS ──> Agent Containers (Docker)
| |
SQLite DB Claude Code SDK
|
Mission Control (React SPA)
A single Go binary that orchestrates the full loop: receives messages from Telegram, routes them to the right agent, spins up isolated Docker containers running Claude Code, streams responses back, and serves a real-time Mission Control web UI.
- Mission Control — Real-time dashboard with WebSocket updates
- Telegram I/O — Chat with your agents from your phone
- Telegram commands —
/start,/stop,/reset,/nix,/agents,/commands - Named agents — Multiple agents with distinct roles, models, and configurations
- Smart routing —
@agent_nameprefix or AI-powered routing via the default agent - Per-agent isolation — Each agent runs in its own Docker container with its own filesystem
- Persistent memory — Per-agent SQLite memory database with MCP tools for storing and recalling facts across sessions
- Agent identity — Each agent has an
AGENT.mdfor personality and expertise, editable from Mission Control or by agents themselves - User profile — Agents know who you are via
USER.md, editable from Mission Control or by agents themselves - Scheduled tasks — Cron, interval, or one-shot jobs that run agents and deliver results via Telegram
- Secure vault — AES-256-GCM encrypted secrets injected as env vars or files at container start, never exposed to the LLM
- Web & browser access — Agents can search the web and automate browsers via playwright-cli
- Hot config reload — Edit
praktor.yamland changes apply automatically, no restart needed - Nix package manager — Agents can install packages on demand (Python, ffmpeg, LaTeX, etc.) via MCP tools or the
/nixTelegram command - Agent extensions — Per-agent MCP servers, plugins, and skills, managed via Mission Control
- Agent swarms — Graph-based multi-agent orchestration with fan-out, pipeline, and collaborative patterns
- Backup & restore — Back up and restore all Docker volumes as zstd-compressed tarballs via CLI
- Docker and Docker Compose
- A Telegram bot token (create one with @BotFather)
- A Claude authentication method: Anthropic API key or Claude Code OAuth token (
claude setup-token)
Note on OAuth tokens: Using Claude Code OAuth tokens with third-party applications must comply with Anthropic's authentication and credential use policy. Review the policy before using this method. OAuth token support is deprecated and will be removed in a future version.
git clone https://github.com/mtzanidakis/praktor.git
cd praktor
cp config/praktor.example.yaml config/praktor.yaml
cp .env.example .env && chmod 0600 .envEdit .env and fill in your credentials (see comments in the file for details). Set DOCKER_GID to the group ID of the docker group on your host so the non-root container user can access the Docker socket:
grep docker /etc/group # look for the docker group GIDEdit config/praktor.yaml to define your agents:
telegram:
allow_from: [] # Telegram user IDs (empty = allow all)
main_chat_id: 0 # Chat ID for scheduled task / swarm results
defaults:
model: "claude-sonnet-4-6"
max_running: 5
idle_timeout: 10m
agents:
general:
description: "General-purpose assistant for everyday tasks"
nix_enabled: true
coder:
description: "Software engineering specialist"
model: "claude-opus-4-6"
nix_enabled: true
env:
GITHUB_TOKEN: "secret:github-token" # Resolved from vault
researcher:
description: "Web research and analysis"
allowed_tools: [WebSearch, WebFetch, Read, Write]
router:
default_agent: generaldocker compose build agent # Build the agent image locally
docker compose up -d # Start the stack (pulls gateway from GHCR)
docker compose logs -f # Watch logsThe agent image must be built locally because it bundles proprietary third-party software that cannot be redistributed. See Third-Party Notice for details.
Mission Control is available at http://localhost:8080.
Open Telegram and send a message to your bot. Praktor routes it to the right agent, spins up a container, and responds. Use @agent_name to target a specific agent:
Hello! → routed to default agent
@coder fix the login bug → routed to coder
@researcher find papers on RAG → routed to researcher
For a secure setup without exposed ports, see Production Deployment with Tailscale.
Pull the latest code, images, and rebuild the agent:
./scripts/upgrade.shThen restart the stack:
docker compose up -dThe gateway watches praktor.yaml for changes and applies them automatically within seconds. No restart required.
| Reloads live | Requires restart |
|---|---|
| Agent definitions, default model/image/max_running/idle_timeout, default router agent, scheduler poll interval, main_chat_id | Telegram token, web port, NATS config, vault passphrase |
When an agent's config changes, its running container is stopped and lazily restarted on the next message. You can also trigger a reload manually:
docker compose kill -s HUP praktorPraktor includes an encrypted vault for API keys, tokens, SSH keys, and service account files. Secrets are encrypted at rest with AES-256-GCM (Argon2id key derivation) and injected into containers at start time — never passed through the LLM.
praktor vault set github-token --value "ghp_xxx" --description "GitHub PAT"
praktor vault set ssh-key --file ~/.ssh/id_rsa --description "Deploy key"
praktor vault list
praktor vault get github-token
praktor vault assign github-token --agent coder
praktor vault global github-token --enable
praktor vault delete github-tokenSecrets can also be managed from the Secrets page in Mission Control.
Reference secrets with secret:name syntax in env values or files:
agents:
coder:
env:
GITHUB_TOKEN: "secret:github-token" # Injected as env var
files:
- secret: gcp-service-account # Injected as file
target: /etc/gcp/sa.json
mode: "0600"All agent containers come with playwright-cli pre-installed and configured to use system Chromium. Agents can navigate websites, fill forms, take screenshots, and extract data — no setup needed.
The browser session persists across messages within the same agent session and shuts down with the container on idle timeout.
@general take a screenshot of https://example.com
@general go to https://example.com/form, fill in the email field, and submit
The playwright-cli skill is automatically loaded into every agent's system prompt, teaching it the full command set (open, goto, click, fill, screenshot, snapshot, tabs, etc.).
Extend agents with MCP servers, plugins, and skills — all managed per-agent from Mission Control. Extensions are applied automatically when containers start.
Extensions require
nix_enabled: trueon the agent. Dependencies are auto-installed via nix.
Connect agents to external tools via the Model Context Protocol. Supports stdio (local commands) and HTTP transports.
In Mission Control, go to the agent's Extensions tab, add an MCP server, and configure the JSON:
HTTP server (e.g., Context7):
{
"type": "http",
"url": "https://mcp.context7.com/mcp",
"headers": { "CONTEXT7_API_KEY": "secret:context7-api-key" }
}Stdio server:
{
"type": "stdio",
"command": "some-tool",
"args": ["--flag"],
"env": { "API_KEY": "secret:some-api-key" }
}Secret references (secret:name) in env and headers values are resolved from the vault at container start. Stdio commands that aren't already in $PATH are auto-installed via nix.
MCP servers are injected at runtime via the SDK
query()call. They won't appear inclaude mcp list— but agents can use their tools during conversations.
Claude Code marketplace plugins, installed via claude plugin install on first container start. Persisted on the agent's home volume so installation is one-time.
Plugin names use the plugin-name@marketplace format. Plugins can be temporarily disabled without uninstalling.
Marketplaces: Plugins come from marketplaces. The claude-plugins-official marketplace is always available, but third-party marketplaces must be registered first. Add marketplace sources (owner/repo, git URLs, or URLs to marketplace.json) in the Marketplaces tab — they are registered via claude plugin marketplace add before plugin installation.
Custom instructions written to ~/.claude/skills/{name}/SKILL.md on container start. Claude Code discovers them automatically.
Each skill has a description and a content body (the SKILL.md text). Skills can also include additional files (base64-encoded) written alongside the SKILL.md in the skill directory — useful for scripts or configs the skill references. Removed skills have their directories cleaned up on the next container start.
Saving extensions in Mission Control stops the running agent container. On the next message:
- The gateway loads extensions from the DB, resolves any
secret:references from the vault - The resolved extensions are passed to the container as the
AGENT_EXTENSIONSenv var - The agent-runner auto-installs missing nix dependencies for stdio MCP server commands
- MCP servers are merged into the SDK
query()call; skills are written to disk; plugins are installed/enabled
Swarms let multiple agents collaborate on a task. Define a graph of agents and connections, and Praktor orchestrates execution.
| Pattern | Connection | Behavior |
|---|---|---|
| Fan-out | None | Agents run in parallel, independently |
| Pipeline | A → B | B waits for A and receives A's output as context |
| Collaborative | A ↔ B | Agents share a real-time chat channel |
The lead agent always runs last and synthesizes all results.
The Swarms page provides a visual graph editor: add agents, draw connections, toggle between pipeline and collaborative edges, set the lead agent, write prompts, and launch. Running swarms show real-time status updates.
@swarm researcher,writer,reviewer: Write a blog post about AI agents
@swarm researcher>writer>reviewer: Write a blog post about AI agents
@swarm researcher<>writer,reviewer: Write a blog post about AI agents
Results are delivered to the originating chat when the swarm completes.
Agents with nix_enabled: true can install any package from nixpkgs on demand — no custom Docker images needed.
When an agent needs a missing tool (e.g. Python, ffmpeg), it will automatically search and install it via nix MCP tools. Installed packages persist across sessions.
| Tool | Description |
|---|---|
nix_search |
Search nixpkgs for packages |
nix_add |
Install a package |
nix_list_installed |
List installed packages |
nix_remove |
Remove a package |
nix_upgrade |
Upgrade all packages |
/nix search python3 # Search for packages
/nix add python3 # Install a package
/nix list # List installed packages
/nix remove python3 # Remove a package
/nix upgrade # Upgrade all packages
/nix list @coder # Target a specific agent
Back up all praktor state (SQLite, NATS, agent workspaces, home dirs, nix stores) into a single zstd-compressed tarball, and restore it later.
praktor backup -f /path/to/backup.tar.zstCreates a tarball of all praktor-* Docker volumes. Each volume becomes a top-level directory in the archive.
praktor restore -f /path/to/backup.tar.zst # Fails if volumes exist
praktor restore -f /path/to/backup.tar.zst -overwrite # Overwrites existing volumesRestores volumes from a backup archive. Without -overwrite, refuses to restore if any target volume already exists.
Both commands accept -image <name> to override the helper container image (default: alpine:3).
The included docker-compose.override.yml-prod configures hourly automated backups using Ofelia, a Docker job scheduler. It runs praktor backup inside the container and writes to a ./dumps bind mount. Adjust the schedule or add your own jobs via Ofelia labels.
For production, a docker-compose.override.yml-prod is included that adds a tsrp (Tailscale Reverse Proxy) sidecar and removes the public port mapping. Mission Control becomes accessible only over your Tailscale network.
ln -s docker-compose.override.yml-prod docker-compose.override.ymlAdd the following to your .env:
HOSTNAME=praktor # Tailscale machine name
TS_AUTHKEY=tskey-auth-... # Tailscale auth key (https://login.tailscale.com/admin/settings/keys)Then start as usual — the override is picked up automatically:
docker compose up -dMission Control will be available at https://praktor.<your-tailnet>.ts.net. The tsrp container stores its Tailscale state in ./state/.
After cloning the repo, you can use Claude Code to get help with any aspect of Praktor. The project includes a detailed CLAUDE.md that gives Claude full context about the architecture, configuration, and available APIs.
git clone https://github.com/mtzanidakis/praktor.git
cd praktor
claudeFor example, you can ask Claude Code things like:
- "How do I install an MCP server on a Praktor agent?"
- "How do I add a new agent to my configuration?"
- "How do I set up secrets for an agent?"
go mod download # Install Go dependencies
make dev # Run the gateway locally
make test # Run testsMission Control with hot reload:
cd ui && npm install && npm run dev # Vite dev server on :5173, proxies /api to :8080See LICENSE.
This project integrates with third-party tools that have their own licenses and terms of service. In particular, Claude Code and the Claude Agent SDK are proprietary software by Anthropic and subject to Anthropic's Commercial Terms of Service. They are not included in this repository — users must install them at build time and are responsible for complying with Anthropic's terms. Pre-built Docker images containing these components should not be redistributed without Anthropic's permission.