Skip to content

Quick Start

Get Legio running in under 5 minutes.

Prerequisites

RequirementVersionWhy
Python3.11+Type union syntax X | None, asyncio.TaskGroup
Telegram Bot TokenCreate via @BotFather
Anthropic API KeyFor Claude Agent SDK
Your Telegram IDFor 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 timeout

2. 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 actions

3. Configuration Reference

SettingSourceDefaultDescription
caesar.telegram_idlegio.tomlrequiredCaesar's Telegram user ID
modellegio.toml"sonnet"Claude model name passed to SDK
castra_dirlegio.toml"castra"Workspace root directory
max_centurioneslegio.toml10Concurrent centurio limit
history_windowlegio.toml50Nuntii visible per dispatch
session_idle_timeout_minuteslegio.toml30Minutes before idle session reap
TELEGRAM_BOT_TOKEN.envTelegram Bot API token
ANTHROPIC_API_KEY.envAnthropic API key
LEGIO_TOTP_SECRET.envBase32 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 legio

On 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() runs

First 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:

  1. Validate the name against ^[a-z][a-z0-9_-]*$
  2. Check centurio count against max_centuriones
  3. Render prompt.md from blueprints/centurio/prompt.md.template
  4. Render tools.json from blueprints/centurio/tools.json.template
  5. Create castra/centuriones/vorenus/commentarii/
  6. Re-scan the registry

Now address the centurio directly:

@vorenus What are the latest advances in quantum computing?

Telegram Commands

CommandDescriptionGate
/statusShow centurio statuses (✅ idle, ⏳ working, ❌ error)
/listList centuriones with descriptions
/create <name> <desc>Create a new centurio
/remove <name>Remove a centurioTOTP
/reset <name>Reset a centurio's SDK session
/edict <name> <text>Publish a standing order
/edictaList all standing orders
/revoke <name>Revoke a standing orderTOTP
/actaList shared knowledge entries
/history [n]Show last N nuntii (default 10, max 100)
/helpShow available commands

TOTP Setup (Optional)

To enable OTP-gated destructive actions:

  1. Generate a Base32 secret (e.g., via pyotp.random_base32())
  2. Add it to .env: LEGIO_TOTP_SECRET=JBSWY3DPEHPK3PXP
  3. 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

Built with Roman discipline.