A zero-dependency Node.js proxy that sits between OpenClaw and the Anthropic API, automatically routing each request to the cheapest Claude model capable of handling it. Inspired by ClawRouter's weighted scoring approach.
Everything runs locally on your OpenClaw server. No data is sent to ibl.ai or any third party — the router is a localhost proxy that forwards directly to your chosen LLM provider (Anthropic, OpenRouter, etc.) using your own API key.
Install from your terminal:
git clone https://github.com/iblai/iblai-openclaw-router.git router
cd router && bash scripts/install.shOr just ask your OpenClaw agent:
Install iblai-router from https://github.com/iblai/iblai-openclaw-router
Your agent will clone the repo, run the install script, and register the model provider — all in one go.
That's it — iblai-router/auto is now available as a model. Typical savings: ~80% vs always using the most expensive model. Uninstall anytime by telling your agent "uninstall iblai-router" or running bash scripts/uninstall.sh.
| Without router | With router | Saved | |
|---|---|---|---|
| Cron jobs (ops alerts, inbox checks) | $121.63 | $24.33 | $97.31 (80%) |
| Subagent tasks (issue triage, comms) | $58.20 | $11.64 | $46.56 (80%) |
| Deep reasoning (strategy, analysis) | $25.00 | $25.00 | $0.00 |
| Total | $204.83 | $60.97 | $143.87 (70%) |
The router scores only user messages, not the system prompt — this is critical. OpenClaw sends a large, keyword-rich system prompt with every request, and scoring it inflates every request to the most expensive tier. With system prompt excluded, routine tasks correctly score low and route to cheaper models. Deep reasoning tasks still route to Opus based on their actual content.
Check your savings anytime — just ask your agent:
What are my iblai-router cost savings?
Or from the command line:
curl -s http://127.0.0.1:8402/stats | python3 -m json.toolOpenClaw → localhost:8402 → api.anthropic.com
│
▼
14-dimension weighted scorer (<1ms)
Extracts text from system prompt + last 3 messages
Scores across: token count, code presence, reasoning markers,
technical terms, creative markers, simple indicators, multi-step
patterns, question complexity, imperative verbs, constraints,
output format, domain specificity, agentic tasks, relay indicators
│
▼
Maps weighted score to tier via sigmoid confidence
│
├── score < 0.0 → LIGHT (Haiku) $1/$5 per 1M tokens
├── 0.0 – 0.35 → MEDIUM (Sonnet) $3/$15 per 1M tokens
└── score > 0.35 → HEAVY (Opus) $15/$75 per 1M tokens
│
▼
Overrides:
• 2+ reasoning keywords in user message → HEAVY (0.95 confidence)
• >50K estimated tokens → HEAVY (large context)
• Low confidence (ambiguous) → defaults to MEDIUM
│
▼
Replaces model field in request body → proxies to Anthropic
The proxy speaks native Anthropic Messages API format — it receives the exact same request OpenClaw would send to Anthropic, scores it, swaps the model, and forwards it. Streaming works transparently.
In your OpenClaw chat or TUI, just say:
Install iblai-router from https://github.com/iblai/iblai-openclaw-router
Your agent will clone the repo, run the install script, and register iblai-router/auto as a model provider automatically.
cd ~/.openclaw/workspace
git clone https://github.com/iblai/iblai-openclaw-router.git router
bash router/scripts/install.shThen register the model in your OpenClaw session:
/config set models.providers.iblai-router.baseUrl http://127.0.0.1:8402
/config set models.providers.iblai-router.api anthropic-messages
/config set models.providers.iblai-router.apiKey passthrough
/config set models.providers.iblai-router.models [{"id":"auto","name":"iblai-router (auto)","reasoning":true,"input":["text","image"],"contextWindow":200000,"maxTokens":8192}]
Done. Use iblai-router/auto as your model anywhere.
To uninstall: bash router/scripts/uninstall.sh
Step-by-step if you prefer full control:
# 1. Clone into your workspace
cd ~/.openclaw/workspace
git clone https://github.com/iblai/iblai-openclaw-router.git router
# 2. Create the systemd service
sudo tee /etc/systemd/system/iblai-router.service > /dev/null << EOF
[Unit]
Description=iblai-router - Claude model routing
After=network.target
[Service]
Type=simple
ExecStart=$(which node) $HOME/.openclaw/workspace/router/server.js
Environment=ANTHROPIC_API_KEY=$(grep -o '"key": "[^"]*"' ~/.openclaw/agents/main/agent/auth-profiles.json 2>/dev/null | head -1 | cut -d'"' -f4 || echo "sk-ant-YOUR-KEY-HERE")
Environment=ROUTER_CONFIG=$HOME/.openclaw/workspace/router/config.json
Environment=ROUTER_PORT=8402
Environment=ROUTER_LOG=1
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
# 3. Start the router
sudo systemctl daemon-reload
sudo systemctl enable --now iblai-router
# 4. Verify it's running
curl -s http://127.0.0.1:8402/health | jq .
# 5. Register with OpenClaw
# Paste the /config commands below into your OpenClaw chat or TUI,
# or patch openclaw.json directly (see below).In your OpenClaw session, run:
/config set models.providers.iblai-router.baseUrl http://127.0.0.1:8402
/config set models.providers.iblai-router.api anthropic-messages
/config set models.providers.iblai-router.apiKey passthrough
/config set models.providers.iblai-router.models [{"id":"auto","name":"iblai-router (auto)","reasoning":true,"input":["text","image"],"contextWindow":200000,"maxTokens":8192}]
Or patch your openclaw.json directly:
{
"models": {
"providers": {
"iblai-router": {
"baseUrl": "http://127.0.0.1:8402",
"api": "anthropic-messages",
"apiKey": "passthrough",
"models": [{
"id": "auto",
"name": "iblai-router (auto)",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 200000,
"maxTokens": 8192
}]
}
}
}
}Important: restart OpenClaw after registering the provider. OpenClaw caches available models at startup — without a restart, cron jobs and subagents will fail with model not allowed: iblai-router/auto.
# Option 1: From your OpenClaw session (if commands.restart is enabled)
/restart
# Option 2: Enable restart first, then restart
# In openclaw.json, add: "commands": { "restart": true }
# Then /restart from your session
# Option 3: Restart the systemd service directly
sudo systemctl restart openclawAfter restart, confirm iblai-router/auto is recognized:
# 1. Check the router is healthy
curl -s http://127.0.0.1:8402/health | jq .
# 2. Test a request through the router
curl -s http://127.0.0.1:8402/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: test" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"auto","max_tokens":50,"messages":[{"role":"user","content":"Say hi"}]}' | jq .model
# 3. In your OpenClaw session, verify the model resolves
/model iblai-router/autoIf cron jobs were in error backoff before the restart, they'll resume on their next scheduled run. To force an immediate run:
/cron run <jobId>
Now use iblai-router/auto anywhere you'd use a model ID. Every request routes to Haiku/Sonnet/Opus based on complexity. Check savings anytime:
curl -s http://127.0.0.1:8402/stats | jq .All scoring config lives in config.json (not in server.js). Edit it to match your agent's domain. The server hot-reloads config changes — no restart needed.
Override the config path with: ROUTER_CONFIG=/path/to/my-config.json
{
"models": {
"LIGHT": "claude-3-5-haiku-20241022",
"MEDIUM": "claude-sonnet-4-20250514",
"HEAVY": "claude-opus-4-20250514"
}
}Swap these for any Anthropic model IDs.
Each dimension has a keyword list that shifts the score. Add words relevant to your domain:
{
"scoring": {
"simpleKeywords": ["order status", "tracking number", "return policy", "hours"],
"relayKeywords": ["forward to agent", "escalate", "transfer to"],
"technicalKeywords": ["refund api", "webhook", "stripe", "payment intent"],
"reasoningKeywords": ["analyze", "compare", "synthesize", "methodology"],
"domainKeywords": ["regression", "p-value", "confidence interval"]
}
}Each keyword list pushes the score in a direction. The score determines which model handles the request:
| Keyword list | Effect on score | Routes toward | Why |
|---|---|---|---|
simpleKeywords |
↓ lowers score | LIGHT (Haiku) | Simple lookups, FAQs — any small model handles these fine |
relayKeywords |
↓ lowers score | LIGHT (Haiku) | Pass-through tasks (send a message, check status) need no reasoning |
imperativeVerbs |
↑ raises score slightly | MEDIUM (Sonnet) | Action verbs ("create", "update", "deploy") imply structured work |
codeKeywords |
↑ raises score | MEDIUM→HEAVY | Code generation/review benefits from stronger models |
agenticKeywords |
↑ raises score | MEDIUM→HEAVY | Multi-step workflows ("triage all", "audit", "investigate") need planning |
technicalKeywords |
↑ raises score | HEAVY (Opus) | Domain-specific technical work needs deep understanding |
reasoningKeywords |
↑↑ raises score strongly | HEAVY (Opus) | Analysis, synthesis, and complex reasoning need the strongest model |
domainKeywords |
↑ raises score | HEAVY (Opus) | Specialized domain terms signal expert-level tasks |
The router combines all 14 dimensions (keyword lists + structural signals like token count, code presence, question complexity) into a single weighted score, then maps it to a tier:
score < 0.0 → LIGHT (fast, cheap — handles ~45% of typical agent traffic)
0.0 – 0.35 → MEDIUM (balanced — handles ~40%)
score > 0.35 → HEAVY (full power — handles ~15%)
The key insight: most agent workloads are simple relays or structured tasks. Only ~15% actually need the most capable (and expensive) model. The keyword lists help the router make that distinction in under 1ms.
{
"scoring": {
"boundaries": {
"lightMedium": 0.0,
"mediumHeavy": 0.35
}
}
}Raise lightMedium to send more traffic to LIGHT. Lower mediumHeavy to send more to HEAVY.
{
"scoring": {
"confidenceThreshold": 0.70
}
}Lower = more decisive routing (fewer MEDIUM defaults). Higher = more conservative (more MEDIUM).
Weights control how much each signal matters. They roughly sum to 1.0:
{
"scoring": {
"weights": {
"tokenCount": 0.08,
"codePresence": 0.14,
"reasoningMarkers": 0.18,
"technicalTerms": 0.10,
"simpleIndicators": 0.06,
"relayIndicators": 0.05
}
}
}Increase a weight to make that dimension more influential.
{
"scoring": {
"overrides": {
"reasoningKeywordMin": 2,
"largeContextTokens": 50000
}
}
}Once registered, use iblai-router/auto anywhere OpenClaw accepts a model ID:
| Scope | Config |
|---|---|
| Default for all sessions | agents.defaults.model.primary = "iblai-router/auto" |
| Subagents only | agents.defaults.subagents.model = "iblai-router/auto" |
| Specific cron job | "model": "iblai-router/auto" in the cron job config |
| Per-session override | /model iblai-router/auto |
Tip: Keep your main interactive session on a fixed model (e.g. Opus) where latency and quality matter most. Use the router for cron jobs, subagents, and background tasks where cost savings compound.
journalctl -u iblai-router -fEvery request logs a line like:
[router] LIGHT → haiku | score=-0.112 conf=0.71 | scored | -93% | what is 2+2? ...
[router] MEDIUM → sonnet | score=-0.040 conf=0.58 | ambiguous | -80% | create an issue for the API bug ...
[router] HEAVY → opus | score=0.116 conf=0.95 | reasoning | -0% | prove sqrt(2) is irrational ...
The -93% / -80% / -0% is the savings vs always-Opus baseline for that request.
curl http://127.0.0.1:8402/statsReturns:
{
"stats": {
"total": 847,
"byTier": { "LIGHT": 412, "MEDIUM": 340, "HEAVY": 95 },
"estimatedCost": 0.0034,
"baselineCost": 0.0189,
"startedAt": "2026-02-16T20:36:34.000Z"
}
}estimatedCost: what you actually spent (input tokens × model price)baselineCost: what Opus would have cost for the same traffic- Savings:
1 - (estimatedCost / baselineCost)→ e.g. 82%
Note: these are input-cost estimates based on character count. Actual costs depend on output tokens too, which vary per response. For precise tracking, check your Anthropic dashboard.
Based on typical agent workloads:
| Traffic mix | Tier | % of requests | Cost/M tokens |
|---|---|---|---|
| Simple queries, relays, alerts | LIGHT | ~45% | $1 |
| Issue creation, config, triage | MEDIUM | ~40% | $3 |
| Deep reasoning, architecture | HEAVY | ~15% | $15 |
Blended average: ~$3.40/M vs $15/M for always-Opus = ~77% savings.
Actual savings depend on your workload. More relay/alert work = higher savings. More reasoning = lower savings.
Compare your Anthropic usage dashboard before and after enabling the router. The model breakdown will show traffic shifting from a single model to a mix of Haiku/Sonnet/Opus.
The router's scoring engine is model-agnostic — it classifies request complexity, not model capabilities. You can swap in models from any provider that speaks the Anthropic Messages API format (or use an adapter).
OpenRouter exposes OpenAI, Google, and other models behind an Anthropic-compatible API. Point the router at OpenRouter instead of Anthropic:
# In iblai-router.service, change:
Environment=ANTHROPIC_API_KEY=sk-or-YOUR-OPENROUTER-KEYThen update config.json with OpenRouter model IDs:
{
"models": {
"LIGHT": "openai/gpt-4.1-mini",
"MEDIUM": "openai/gpt-4.1",
"HEAVY": "openai/o3"
},
"apiBaseUrl": "https://openrouter.ai/api/v1"
}Note: The
apiBaseUrlfield in config.json overrides the defaulthttps://api.anthropic.comtarget. The server will proxy requests to whichever base URL you specify.
{
"models": {
"LIGHT": "google/gemini-2.0-flash-lite",
"MEDIUM": "google/gemini-2.5-flash",
"HEAVY": "google/gemini-2.5-pro"
},
"apiBaseUrl": "https://openrouter.ai/api/v1"
}The most cost-effective setup often mixes providers. Use the cheapest model that handles each tier well:
{
"models": {
"LIGHT": "google/gemini-2.0-flash-lite",
"MEDIUM": "anthropic/claude-sonnet-4-20250514",
"HEAVY": "openai/o3"
},
"apiBaseUrl": "https://openrouter.ai/api/v1"
}When mixing providers via OpenRouter, all models must use OpenRouter model IDs (prefixed with provider name).
After changing providers, restart the router to pick up the new API key:
# Edit the service file with the new key
sudo systemctl daemon-reload
sudo systemctl restart iblai-router
# Verify routing targets
curl -s http://127.0.0.1:8402/health | jq .The config.json changes (model IDs, apiBaseUrl) are hot-reloaded automatically — no restart needed for those.
When a new version is released, update your installation in one of three ways:
Update iblai-router to the latest version
Your agent will pull the latest code, restart the service, and confirm the new version is running.
cd ~/.openclaw/workspace/router # or wherever you cloned the repo
git pull origin main
sudo systemctl restart iblai-routerVerify the update:
curl -s http://127.0.0.1:8402/health | jq .cd ~/.openclaw/workspace/router
git pull origin main
bash scripts/install.shThe install script is idempotent — it will update the systemd service, restart the router, and re-register the model provider if needed.
server.js— scoring engine, proxy logic, bug fixesconfig.json— new keywords, updated model IDs, tuned weights
⚠️ If you've customizedconfig.json(added your own keywords, changed weights, swapped models),git pullwill conflict. Either:
- Stash your changes first:
git stash && git pull && git stash pop- Or keep your config outside the repo:
ROUTER_CONFIG=/path/to/my-config.jsonin the systemd service file. This waygit pullnever touches your config.
cd ~/.openclaw/workspace/router
git fetch origin
git log HEAD..origin/main --onelineIf there's output, a newer version is available. If empty, you're up to date.
Check Releases for changelogs and upgrade notes between versions.
sudo systemctl stop iblai-routerAny OpenClaw workloads using iblai-router/auto will fail until you either restart the router or switch them to a direct model. To restart later:
sudo systemctl start iblai-routerIn your OpenClaw session:
# Revert a cron job to direct Sonnet
/cron update <jobId> model=anthropic/claude-sonnet-4-20250514
# Revert subagent default
/config set agents.defaults.subagents.model anthropic/claude-sonnet-4-20250514
# Revert main session
/model anthropic/claude-opus-4-20250514
Ask your OpenClaw agent:
Uninstall iblai-router
Or run it manually:
bash ~/.openclaw/workspace/router/scripts/uninstall.shThen remove the provider registration in your OpenClaw session:
/config unset models.providers.iblai-router
Make sure no cron jobs or agent configs still reference iblai-router/auto — they'll error on the next run.
├── server.js # The proxy (~250 lines, zero deps)
├── config.json # All scoring config (hot-reloaded on change)
└── README.md # This file
This usually means one of two things:
- Model allowlist: If you have
agents.defaults.modelsin youropenclaw.json(used for cache settings or other per-model config), it acts as a model allowlist. You must addiblai-router/autoto it:
{
"agents": {
"defaults": {
"models": {
"iblai-router/auto": {},
"anthropic/claude-opus-4.6": { ... }
}
}
}
}- Restart required: OpenClaw caches available models at startup. After adding the provider to
openclaw.json, restart OpenClaw (see Quick Start above).
If you've done both and still see the error, verify the provider block is in your openclaw.json under models.providers.iblai-router with "api": "anthropic-messages" and at least one model with "id": "auto".
After fixing a model error, cron jobs may be in exponential backoff (up to 1 hour between retries). Force an immediate run:
/cron run <jobId>
Or from the API: trigger a manual run via the cron management endpoint.
# Check the service is actually listening
curl -s http://127.0.0.1:8402/health
# Check logs for errors (wrong API key, network issues)
journalctl -u iblai-router -n 20
# Verify your Anthropic API key works
curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{"model":"claude-3-5-haiku-20241022","max_tokens":10,"messages":[{"role":"user","content":"hi"}]}' | jq .config.json changes (keywords, weights, boundaries, model IDs) are hot-reloaded — no restart needed. But changes to environment variables (API key, port) require a service restart:
sudo systemctl restart iblai-router| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
(required) | Your Anthropic API key |
ROUTER_PORT |
8402 |
Port to listen on |
ROUTER_LOG |
1 |
Set to 0 to disable per-request logging |
ROUTER_CONFIG |
./config.json |
Path to scoring config file |
