Quick Start
Get Legio running in under 5 minutes.
Prerequisites
| Requirement | Version | Why |
|---|---|---|
| Python | 3.11+ | Type union syntax X | None, asyncio.TaskGroup |
| Telegram Bot Token | — | Create via @BotFather |
| Anthropic API Key | — | For Claude Agent SDK |
| Your Telegram ID | — | For Caesar authentication (use @userinfobot) |
Installation
bash
# Clone the repository
git clone https://github.com/xiaolai/legio.git
cd legio
# Install dependencies
pip install -e ".[dev]"Configuration
1. Create legio.toml
toml
[caesar]
telegram_id = 123456789 # Your Telegram user ID
[legio]
model = "sonnet" # Claude model name
castra_dir = "castra" # Workspace directory
max_centuriones = 10 # Max concurrent agents
history_window = 50 # Messages visible per dispatch
session_idle_timeout_minutes = 30 # Idle session timeout2. Create .env
bash
TELEGRAM_BOT_TOKEN=your-telegram-bot-token
ANTHROPIC_API_KEY=your-anthropic-api-key
LEGIO_TOTP_SECRET=your-base32-totp-secret # Optional: enables OTP for destructive actions3. Configuration Reference
| Setting | Source | Default | Description |
|---|---|---|---|
caesar.telegram_id | legio.toml | required | Caesar's Telegram user ID |
model | legio.toml | "sonnet" | Claude model name passed to SDK |
castra_dir | legio.toml | "castra" | Workspace root directory |
max_centuriones | legio.toml | 10 | Concurrent centurio limit |
history_window | legio.toml | 50 | Nuntii visible per dispatch |
session_idle_timeout_minutes | legio.toml | 30 | Minutes before idle session reap |
TELEGRAM_BOT_TOKEN | .env | — | Telegram Bot API token |
ANTHROPIC_API_KEY | .env | — | Anthropic API key |
LEGIO_TOTP_SECRET | .env | — | Base32 TOTP secret (optional) |
Secrets vs Settings
Non-secrets go in legio.toml (committed to git). Secrets go in .env (gitignored). Config is loaded once into a frozen LegioConfig dataclass and passed through constructors — no global state.
Running
bash
python -m legioOn first run, ensure_castra() creates the workspace:
castra/
legatus/
prompt.md # Copied from blueprints/legatus/prompt.md.template
centuriones/ # Empty — centuriones created on demand
edicta/ # Empty
acta/ # Empty
praetorium.db # Created when Praetorium.open() runsFirst Interaction
Open your Telegram bot and send a message:
Hello, Legatus! Create a research centurio named vorenus
specialized in technology analysis.The Legatus will use its create_centurio MCP tool to:
- Validate the name against
^[a-z][a-z0-9_-]*$ - Check centurio count against
max_centuriones - Render
prompt.mdfromblueprints/centurio/prompt.md.template - Render
tools.jsonfromblueprints/centurio/tools.json.template - Create
castra/centuriones/vorenus/commentarii/ - Re-scan the registry
Now address the centurio directly:
@vorenus What are the latest advances in quantum computing?Telegram Commands
| Command | Description | Gate |
|---|---|---|
/status | Show centurio statuses (✅ idle, ⏳ working, ❌ error) | — |
/list | List centuriones with descriptions | — |
/create <name> <desc> | Create a new centurio | — |
/remove <name> | Remove a centurio | TOTP |
/reset <name> | Reset a centurio's SDK session | — |
/edict <name> <text> | Publish a standing order | — |
/edicta | List all standing orders | — |
/revoke <name> | Revoke a standing order | TOTP |
/acta | List shared knowledge entries | — |
/history [n] | Show last N nuntii (default 10, max 100) | — |
/help | Show available commands | — |
TOTP Setup (Optional)
To enable OTP-gated destructive actions:
- Generate a Base32 secret (e.g., via
pyotp.random_base32()) - Add it to
.env:LEGIO_TOTP_SECRET=JBSWY3DPEHPK3PXP - Add the secret to your authenticator app (Google Authenticator, Authy, etc.)
When you use /remove or /revoke, the bot will prompt for a 6-digit OTP:
🔐 Removing centurio: vorenus
Enter your 6-digit OTP:You have 3 attempts within 120 seconds. OTP messages are automatically deleted from chat after verification.
Running Tests
bash
# Run full test suite (100% coverage required)
pytest
# Run only security tests
pytest -m security
# Run only integration tests
pytest -m integration
# Check file length limits (350 pure LOC)
python scripts/check_file_length.py