Documentation

Customer setup, operator playbook, and a small reference section. Read top to bottom on first setup; jump via the side nav for day-2 ops.

Sign up

Email hello@xanadu.run with your team name and we'll mint a tenant_id on the spot (10 seconds, no credit card needed for the public beta). You'll get back a ready-to-paste .mcp.json snippet.

Wire your orchestrator's .mcp.json

{
  "mcpServers": {
    "xanadu": {
      "type": "http",
      "url": "https://xanadu.run/mcp",
      "headers": {
        "X-Xanadu-Tenant-Id": "your_tenant_id"
      }
    }
  }
}

Restart Claude Code / Cline / your orchestrator. You'll see three MCP tools available:

mcp__xanadu__dispatch_agent
mcp__xanadu__list_agents
mcp__xanadu__ledger_summary

From inside your session, just ask in plain language:

"use the code-reviewer agent via xanadu to review the recent diff"

BYOT — bring your own provider keys

Add X-Anthropic-Key and/or X-OpenRouter-Key to your .mcp.json headers. Every dispatch then bills against your provider quota; we only collect the per-token routing fee. Keys are held in a per-request context for the lifetime of the HTTP request and never persisted.

"headers": {
  "X-Xanadu-Tenant-Id": "your_tenant_id",
  "X-Anthropic-Key":    "sk-ant-...",
  "X-OpenRouter-Key":   "sk-or-v1-..."
}

The header override is gated by the agent's secrets: allowlist — a key for a provider the dispatched agent isn't configured for is silently dropped. That stops a hostile client from tricking a Claude-only agent into making OpenRouter calls.

Available agents

namerolemodel
code-reviewerfocused review, verdict lineanthropic/claude-sonnet-4.6
refactorerbehavior-preserving refactoranthropic/claude-sonnet-4.6
test-writertests matching project conventionsanthropic/claude-sonnet-4.6
kimi-reviewersame review duty via OpenRouter → Kimi K2.6openrouter/moonshotai/kimi-k2.6

Operator: prerequisites

You're running Xanadu in hosted mode on Fly (or any container host) and taking customers. Required env / secrets:

After secrets land, flyctl ssh console -C "xanadu doctor" should report OK on every check.

Onboard a customer

Two commands from inside the running container:

flyctl ssh console -a xanadu-mcp
xanadu tenants add cust_42 \
    --name "Customer Name" \
    --contact "alice@customer.example" \
    --markup 0.10 \
    --monthly-cap 500.00 \
    --tenants /data/tenants.json
xanadu tenants config cust_42 \
    --tenants /data/tenants.json \
    --format text

The second command prints the customer-facing setup blurb plus the exact .mcp.json blob — copy, email, done. TenantRegistry.reload_if_changed() stat()s the file on every dispatch, so the next inbound call serves the new tenant — no restart.

Or via HTTP (signup form / Stripe webhook / CF Worker)

curl -X POST https://xanadu.run/admin/tenants \
    -H "Authorization: Bearer $XANADU_ADMIN_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"name":"Customer Name","markup_rate":0.10,"monthly_budget_usd":500.0}'

# Response includes the pasteable .mcp.json blob
# {"tenant_id":"cust_abc123","mcp_json":{...}}

Per-tenant visibility

xanadu tenants info cust_42 --tenants /data/tenants.json
# title verdict: "clean" / "93% used" / "OVER CAP"
# body: config + MTD + remaining + failures-this-month + last 5 dispatches

xanadu ledger by-tenant --current-month --tenants /data/tenants.json
# Sorted by billed spend so loudest customers float to the top

Caps that actually enforce

Per-agent and per-tenant monthly_budget_usd are enforced at dispatch time. Two checks fire:

  1. Pre-sizing short-circuit: if MTD already meets/exceeds the cap, refuse before paying for sizing or spawning the backend.
  2. Post-estimate gate: if MTD + est_max_usd would exceed, refuse. Held under ledger.exclusive_lock() so concurrent dispatches can't both pass when only one fits.

Refusals write a structured budget_exceeded ledger row with the cap, MTD, and tenant_id; the customer sees a clear BudgetExceededError at the MCP layer.

Invoicing flow

# 1. Pre-flight: catches markup drift, MTD over cap, orphan tenants.
xanadu billing audit --current-month --tenants /data/tenants.json

# 2. Dry-run the Stripe push — see what would POST.
xanadu billing push --current-month --map /etc/xanadu/si_map.json --tenants /data/tenants.json

# 3. Commit when audit is clean.
xanadu billing push --current-month --commit --map /etc/xanadu/si_map.json

si_map.json is {tenant_id: subscription_item_id}. push refuses to send if any tenant in the window lacks a Stripe SI mapping — silent skips were the worst billing failure mode.

Deprovision a tenant

xanadu tenants remove cust_42 --yes --tenants /data/tenants.json

Hot-reload removes them from the live registry immediately. Existing ledger rows are kept (append-only) and show up under (unknown) in subsequent by-tenant rollups so the final invoice can still be audited.

Doctor — start every triage here

flyctl ssh console -a xanadu-mcp -C "xanadu doctor"

Walks the deploy and flags every misconfiguration that has caused production pain. Hosted-mode-relevant checks:

MCP tools

tooldoes
dispatch_agentRun an agent with a task; returns text + cost + dispatch_id.
list_agentsCatalog of available agents (name, description, default_model, budget).
ledger_summaryAggregate ledger across all dispatches; totals by agent / model / status / tenant.

HTTP headers

headerrole
X-Xanadu-Tenant-IdRequired in XANADU_REQUIRE_TENANT mode. Bound to a request-scoped ContextVar; dispatch_agent picks it up automatically.
X-Anthropic-KeyOptional BYOT. Customer's Anthropic key forwarded into the backend subprocess for this request only.
X-OpenRouter-KeyOptional BYOT. Same, for OpenRouter.
Authorization: Bearer …Only used by POST /admin/tenants; auth is timing-safe via secrets.compare_digest.

Built-in model pricing

Used to budget-gate before dispatch. When the backend reports a provider-billed cost, we bill on the provider's number instead and keep this only for estimation.

model$/M in$/M out
anthropic/claude-opus-4.75.0025.00
anthropic/claude-sonnet-4.63.0015.00
anthropic/claude-haiku-4.51.005.00
openrouter/moonshotai/kimi-k2.60.6843.42
openrouter/deepseek/deepseek-v4-pro0.4350.87
openrouter/qwen/qwen3-coder-next0.110.80