Install
openclaw skills install sage-routerLocal-first AI model routing for serious agents. One endpoint. Any provider. The router figures out the rest.
openclaw skills install sage-routerHTTP server on :8788 that routes chat requests to the optimal provider based on intent classification.
POST /v1/chat/completions — OpenAI-compatible; routes automaticallyPOST /v1/messages — Anthropic Messages API compatible; translates to/from OpenAI format internallyGET /health — Provider status, model lists, routing debugAny Anthropic-compatible tool (Cursor, Aider, Claude Code, Zed, Continue, OpenHands) can point at http://localhost:8788 as the API base URL. Both streaming and non-streaming are supported.
Providers are discovered from ~/.openclaw/openclaw.json at startup.
Rules:
sage-router provider entry to avoid recursion${ENV_VAR} values for baseUrl and apiKeyopenai-codex as a virtual provider when the auth profile existsgenerativelanguage.googleapis.commodels is empty in openclaw.jsonanthropic or Anthropic-hosted anthropic-messages providers onto the local Dario proxy at localhost:3456@askalf/dario and autostarts dario proxy when credentials are mounted at /root/.darioSAGE_ROUTER_DISABLED_PROVIDERS=name1,name2GET /health shows:
configured: all discovered providersproviders: reachable providers with model listsdisabled: providers suppressed by envThe router does not perform mid-stream switching. Once a request is sent to a provider, the full response is returned or the attempt fails. If it fails, the next candidate in the chain is tried sequentially. There is no partial-output fallback or streaming handoff between providers.
Flow:
openclaw.jsonlocal-first, operate as local-strict: reject centralized Internet API providers and only allow local/LAN/Tailnet endpoints plus approved decentralized providers such as Darkbloom, with Ollama :cloud models excludedGENERAL, blend static heuristics with persisted empirical latency stats by provider and modelSAGE_ROUTER_MAX_PROVIDER_ATTEMPTS candidates in ordersage-router provider (the router itself, model auto) is scored as a low-priority recursive fallback, never preferredIntent scoring is generic, for example:
Intent is detected by keyword matching on the latest user message. Complexity is estimated by word count.
GET /health — JSON with reachable providers, configured providers, and disabled providersPOST /v1/chat/completions — OpenAI-compatible; routes automaticallyopenai-codex is kept as an optional bridge, not a required first hop.anthropic can stay in openclaw.json while routing locally through dario.systemd unit is template-style and expects local machine values in ~/.config/sage-router/sage-router.env.~/.cache/sage-router/latency-stats.json by default.SAGE_ROUTER_DISABLED_PROVIDERS instead of editing the router.http://sage-router:8788/v1 on umbrel_main_network, set unauthenticated Ollama auto-pull patterns to empty, and keep quota-bound providers disabled until credentials are healthy.BRANCH_PROTECTION.md for the exact required-check setup on GitHub.provider-profiles.json includes a grok-sso template for the OpenClaw xAI auth plugin's local SuperGrok-backed proxy.Install the user service from the repo copy:
mkdir -p ~/.config/systemd/user ~/.config/sage-router
cp systemd/sage-router.service ~/.config/systemd/user/sage-router.service
cp systemd/sage-router.env.example ~/.config/sage-router/sage-router.env
# edit ~/.config/sage-router/sage-router.env for your machine
systemctl --user daemon-reload
systemctl --user enable --now sage-router.service
Notes:
SAGE_ROUTER_HOME to the actual repo path on your machineSAGE_ROUTER_PATH_PREFIX if your Python, Node, or Dario bins are not already on PATHIf an Anthropic provider is detected and Dario is not installed yet, install Dario first:
systemctl --user status sage-router
systemctl --user restart sage-router
journalctl --user -u sage-router -f # live logs
@askalf/dario.~/.dario:/root/.dario for Anthropic-compatible Claude routing.docker compose --profile classifier up -d and SAGE_ROUTER_INTENT_CLASSIFIER_ENABLED=1.SAGE_ROUTER_INTENT_CLASSIFIER_PROVIDER=llamacpp, SAGE_ROUTER_INTENT_CLASSIFIER_BASE_URL=http://llamacpp-classifier:8080, SAGE_ROUTER_INTENT_CLASSIFIER_MODEL=classifier.Sage Router supports named routing profiles in router-profiles.json next to router.py.
Request a profile with any of:
model: "sage-router/<profile>"model: "<profile>"profile, routerProfile, or sageRouterProfileProfile fields currently supported:
route: fast, balanced, best, local-first, realtimethinking: low, medium, highrequiresQuality, requiresReasoning, requiresTools, frontierLargeOnly, frontierOrReasoningTools, suppressIntermediateToolText, qualitySensitive, reasoning, tools, preferTools, json, vision, document, longContextallowProviders, denyProviders, allowModels, denyModels, minParamsBCurrent profiles:
frontier: default high-quality frontier routing profile. Forces best/high, reasoning, quality-sensitive, suppresses tool-call narration, and blocks tiny/free filler models.frontier-large: strict frontier-large-only routing.fast-local: low-latency local-first routing.coding-max: high-thinking code route with weak model exclusions.