README
¶
Praktor
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.
Features
- 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. Multiple tasks execute in parallel (up to 3 concurrent) with independent sessions
- 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 agent-browser
- 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
Prerequisites
- 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.
Getting Started
1. Clone and Configure
git clone https://github.com/mtzanidakis/praktor.git
cd praktor
cp config/praktor.example.yaml config/praktor.yaml
cp .env.example .env && chmod 0600 .env
Edit .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 GID
Edit 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: general
2. Build and Run
docker compose build agent # Build the agent image locally
docker compose up -d # Start the stack (pulls gateway from GHCR)
docker compose logs -f # Watch logs
The 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.
3. Start Chatting
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.
Upgrading
Pull the latest code, images, and rebuild the agent:
./scripts/upgrade.sh
Then restart the stack:
docker compose up -d
Hot Config Reload
The 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 praktor
Vault (Encrypted Secrets)
Praktor 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.
CLI
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-token
Secrets can also be managed from the Secrets page in Mission Control.
Usage in Agent Config
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"
Browser Automation
All agent containers come with agent-browser pre-installed and configured to use system Chromium. The native Rust CLI is built from source during the Docker build for musl/Alpine compatibility. 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 open https://example.com and tell me what you see
@general go to https://example.com/form, fill in the email field, and submit
The agent-browser skill is automatically loaded into every agent's system prompt, teaching it the full command set (open, snapshot, click, fill, screenshot, sessions, etc.).
Agent Extensions
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.
MCP Servers
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.
Plugins
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.
Skills
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.
How It Works
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
Agent Swarms
Swarms let multiple agents collaborate on a task. Define a graph of agents and connections, and Praktor orchestrates execution.
Orchestration Patterns
| 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.
From Mission Control
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.
From Telegram
@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.
Nix Package Manager
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.
MCP Tools
| 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 |
Telegram Command
/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
Backup & Restore
Back up all praktor state (SQLite, NATS, agent workspaces, home dirs, nix stores) into a single zstd-compressed tarball, and restore it later.
Backup
praktor backup -f /path/to/backup.tar.zst
Creates a tarball of all praktor-* Docker volumes. Each volume becomes a top-level directory in the archive.
Restore
praktor restore -f /path/to/backup.tar.zst # Fails if volumes exist
praktor restore -f /path/to/backup.tar.zst -overwrite # Overwrites existing volumes
Restores 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).
Scheduled Backups
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.
Production Deployment with Tailscale
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.yml
Add 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 -d
Mission Control will be available at https://praktor.<your-tailnet>.ts.net. The tsrp container stores its Tailscale state in ./state/.
Getting Help
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
claude
For 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?"
Development
go mod download # Install Go dependencies
make dev # Run the gateway locally
make test # Run tests
Mission Control with hot reload:
cd ui && npm install && npm run dev # Vite dev server on :5173, proxies /api to :8080
License
See LICENSE.
Third-Party Notice
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.