How it works Features Docs Compare Blog GitHub
Self-host it Sign up
Documentation

Get polyrouter running.

Self-host in a few minutes, mint an agent key, and point any OpenAI- or Anthropic-compatible SDK at your instance. Requires Docker with Compose v2.

Quickstart

One command checks Docker, fetches a source archive at a single ref, generates secrets into a mode-600 .env, and boots the stack. The first build takes a few minutes; set POLYROUTER_IMAGE=ghcr.io/izzoa/polyrouter:<version> and the installer pulls that published image instead, skipping the build. The ref defaults to main — pipe through POLYROUTER_REF=<commit-sha> to pin it, which the installer recommends for a reproducible install.

$ curl -fsSL https://polyrouter.app/install.sh | sh
# or from a checkout — uses your working tree, downloads nothing
git clone https://github.com/izzoa/polyrouter.git
cd polyrouter && ./install.sh
Note The app publishes on loopback only by default, and the first account to sign up becomes the admin — that happens at sign-up, before the setup guide runs, not as a step inside it. Registration then closes to invite-only: teammates join through single-use links that expire in 72 hours, issued under Users. Sign up at http://localhost:3001 before exposing anything.
localhost:3001
Setup guide
three steps to your first routed request
Agent 2 Provider 3 Routing
Connect a provider
Bring what you already pay for. polyrouter never marks up tokens — you pay providers directly. We'll sync its models and assign the first to your default tier.
Name
Anthropic
API keyOpenAI, Anthropic, DeepSeek, Groq… pay per token
SubscriptionReuse ChatGPT Plus / Claude Max quota (check ToS)
Custom endpointAny OpenAI/Anthropic-compatible base URL
LocalOllama, LM Studio, llama.cpp — free, on this box
Protocol
Anthropic-compatible
Base URL
https://api.anthropic.com
Credential
sk-ant-••••••••••••••••
Connect provider & sync models
Synced — claude-sonnet-5 assigned to the default tier.
Next: verify
The dashboard's setup guide: three steps to a first routed request — connect a provider, mint an agent key, then send a request.

Connect an agent

Create a key in the dashboard (Agents → New agent — shown once), then point your client at your instance. Any tool that lets you set a base URL and API key works with no other changes.

OpenAI SDKhttps://<your-instance>/v1
Anthropic SDKhttps://<your-instance>
API keyAuthorization: Bearer poly_… or x-api-key: poly_…
OPENAI-COMPATIBLE
curl https://you/v1/chat/completions \
  -H "Authorization: Bearer poly_…" \
  -H "Content-Type: application/json" \
  -d '{"model":"auto",
       "messages":[{"role":"user",
                    "content":"hi"}]}'
ANTHROPIC-COMPATIBLE
curl https://you/v1/messages \
  -H "x-api-key: poly_…" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-sonnet-5",
       "max_tokens":256,
       "messages":[{"role":"user",
                    "content":"hi"}]}'
Tip Pin a routing tier instead of a model by sending x-polyrouter-tier: fast with "model":"auto" — create the fast tier under Routing first. A fresh instance has only default, and a header value matching no tier is advisory: the request quietly falls through to default routing rather than erroring. You can also invent your own value — add a header rule under Routing → Rules that maps x-polyrouter-tier: shopping to any tier or model; the remap is checked before the direct tier lookup, so it wins even when a tier of the same name exists.

Harnesses: OpenClaw, Hermes & coding agents

Any coding harness or agent works — it's just a base URL and a poly_ key. polyrouter is built for them: the L1 structural router excludes the harness system preamble from its features, so a huge OpenClaw or Hermes system prompt can't skew model:"auto" toward the top tier.

Harness traffic also carries a workload class. Fenced code above the configured thresholds — 30% of the scanned window and at least 200 characters by default — reads as code; an image reads as vision, a declared JSON output format as structured. Point a Workload target at a tier or model under Routing → Auto and that class claims its auto requests before band targets, Layer 2 and the cascade — an explicit model or the tier header still wins, and unset classes change nothing. How routing decides →

OPENCLAW · ~/.openclaw/openclaw.json
// ~/.openclaw/openclaw.json  (JSON5)
{
  models: {
    providers: {
      polyrouter: {
        baseUrl: "https://<your-instance>/v1",
        apiKey: "poly_…",
        api: "openai-completions",
        models: [{ id: "auto" }],
      },
    },
  },
  agents: { defaults: { model: { primary: "polyrouter/auto" } } },
}
HERMES · ~/.hermes/config.yaml
# ~/.hermes/config.yaml
model:
  default: auto
  provider: custom
  base_url: "https://<your-instance>/v1"
  api_key: "poly_…"
Prefer secrets out of the YAML? Set api_key: ${POLYROUTER_KEY} and put POLYROUTER_KEY=poly_… in ~/.hermes/.env.
OTHER HARNESSES · OpenAI-compatible
# any tool that lets you set an OpenAI base URL and key
export OPENAI_BASE_URL="https://<your-instance>/v1"
export OPENAI_API_KEY="poly_…"   # then run with model: auto
These are the OpenAI SDK's own variables — polyrouter just needs a base URL and a key, so anything that reads them works unchanged.
Tip When you mint the key, pick OpenClaw or Hermes as the platform to get its native config block; choose cURL / other for anything not listed — the connection is identical.
Why harnesses route correctly here
Harnesses send large, repetitive system preambles. Rule-based routers read those and push everything into the top tier — the failure that led other gateways to drop automatic routing.
polyrouter fingerprints and subtracts the preamble in L1, so auto reflects the actual task, not the boilerplate. See the comparison →

Explore the docs

Six focused guides for going deeper — how routing decides, how providers connect, the wire API, the security posture, every config knob, and day-two operations.

View on GitHub Explore features →