Edition scope: the provider stack below —
~/.openclaw/… credential files,
openclaw.json, and the gateway-pre-start.sh self-heal pass — is OpenClaw / dual
only. None of it exists on the Hermes edition, where provider
credentials are held by Hermes itself (hermes auth add, stored under ~/.hermes) and
the provider ids are Hermes’ own. See
AI Providers on Hermes.The Cloud defaults for speech and embeddings and Plan gates sections are ClawBox’s
own and apply to every edition.Provider lanes at a glance
Where credentials actually go
Configuring a provider writes up to four places:~/.openclaw/agents/main/agent/auth-profiles.json— the real secret. API keys as{type:"api_key", provider, key}; subscriptions as{type:"oauth", provider, access, id, refresh, expires}.openclaw.json → auth.profiles.<provider>:default— metadata only ({provider, mode}). No secret lives here.openclaw.json → models.providers.<provider>— the provider definition (baseUrl, API dialect, model list) for lanes that need one (ClawBox AI, Anthropic, Google, OpenRouter, Ollama, llama.cpp).~/.openclaw/agents/<agent>/agent/codex-home/auth.json(+~/.codex/auth.json) — the ChatGPT-subscription session, synthesized from the auth profile on every gateway start.
agents.defaults.model.primary (e.g. openai/gpt-5.5), with agents.defaults.model.fallbacks behind it (typically ClawBox AI or a local model).
Per-provider credential preference, when a box holds both OpenAI credentials, is the core’s own openclaw models auth order set --agent main --provider openai <profileIds…> — stored in the agent’s auth store, revised by whichever OpenAI save happened last, and cleared when only one OpenAI profile is left.
Compatibility routing (why some lanes use “OpenAI-compat”)
Some native OpenClaw provider plugins expect auth stores ClawBox doesn’t populate. ClawBox therefore routes Anthropic viahttps://api.anthropic.com/v1 and Google via https://generativelanguage.googleapis.com/v1beta/openai — both OpenAI-compatible endpoints with the key inline in the provider definition. Behavior is identical for users; the win is call-time auth that always works. OpenRouter likewise requires an explicit provider definition (https://openrouter.ai/api/v1) — without one, chats silently return empty usage.
ClawBox AI specifics
- Pairing uses a device-code flow against the portal (
clawbox.com) — the wizard shows a short code you confirm in your portal account; the resulting token is stored on-device. - Requests proxy through the portal’s AI endpoint; both models advertise reasoning support including X-High effort (mapped upstream to DeepSeek’s maximum reasoning mode).
- Changing the linked portal account automatically unpairs ClawKeep (backups belong to the account).
- Two tier values are kept side by side and answer different questions: the device badge (
clawai_tier) is what this box should default to, and the plan (clawai_plan_tier) is what the account pays for. Only the second may be read before refusing an entitlement — a Max subscriber whose box is badged Flash is a state the product preserves on purpose.
Cloud defaults for speech and embeddings
On a box linked to ClawBox AI, three capabilities default to the cloud the plan already covers rather than to an engine on the device. The rule is pure and lives in one place (clawai-cloud-defaults-state.ts); the applier runs 45 s after boot and again after any
ClawBox AI save, and GET /setup-api/ai-cloud-defaults publishes the verdict and its reason.
¹ and only once
POST <proxy>/embeddings has answered a probe (cached 6 h on success,
30 min on failure, cleared when the credential changes).
The table is edition-neutral, embeddings included. On the edition where ClawBox owns
the memory index itself rather than the agent, the index client accepts exactly two
endpoints — the loopback embedder proxy on the device, and this box’s own ClawBox AI
embeddings endpoint — checked per request, so the same cloud default applies there. Where
that edition records the owner’s pick it does so as a word in ClawBox’s own store
(memory_shard_embedder), never an address and never a copy of the credential; the older
memory_embeddings_choice_source: "owner" mark is honoured only where that pin stands
beside it, so a box that finished the wizard before the cloud option existed is promoted
rather than pinned to the device for good.
The three rules differ because the three capabilities are not sold the same way: the
transcription route has no tier gate, the cloud voice is Max-only on the proxy and would
otherwise cost a failed round trip before every fall-back, and moving the memory index
invalidates its fingerprint and costs a full reindex — not something to spend on a guess.
Two invariants:
- It only ever promotes. Nothing here moves a capability from the cloud back onto the box; withdrawal is the boot script’s single, plan-gated act.
- An explicit owner choice is never overwritten. Every surface that lets a person pick
records
ownerbeside the pick (tts_choice_source,stt_choice_source,memory_embeddings_choice_source). A box that predates those keys is read by what only a person could have written.
not_linked, plan, route_unavailable or owner, and the UI
prints the matching sentence rather than a bare “not available”. (edition is a fifth
word the catalogue still carries and no shipping edition answers with — it is the
build-time kill switch for cloud embeddings, kept worded in every locale so flipping it
needs no new strings.)
Plan gates
paid-plan-gate.ts is the one place the tier arithmetic lives, and the internal names are
off by one: internal flash is marketed Pro, internal pro is Max.
Every refusal carries the stable code
paid_plan_required — the same word the portal’s own
402 uses.
Reasoning effort
The chat header’s reasoning-effort picker is uniform across every cloud provider —Off, Low, Medium, High — so the control behaves the same whichever model you select. The gateway accepts this ladder for all of them and normalizes it per provider.
Two consequences worth knowing:
- A model with only one level shows no control at all. The header renders the picker only when more than one level is available, which is why the on-device local model has no reasoning dial.
- An unsupported level falls back to that provider’s default, not to the nearest neighbouring level. Switching provider mid-conversation therefore resets the effort to the new provider’s default if the current one is not in its list. The selection is remembered per provider.
minimal, xhigh, max, adaptive) are deliberately not offered in the picker, to keep the control consistent across models.
Local models (Ollama / llama.cpp)
- Local lanes authenticate with a per-install bearer token through a local proxy — nothing is exposed unauthenticated, even on localhost.
- Only one local runtime is active at a time (8 GB Jetson RAM). Ollama gets tuned automatically (quantized KV cache, flash attention, single loaded model).
- A local model can be the primary or the fallback; the wizard’s fallback chain prefers a configured local model, else ClawBox AI.
Self-healing on boot (beta channel)
gateway-pre-start.sh runs before every gateway start and repairs known-bad provider states. On the beta channel (and the next stable release) this includes:
All heals are idempotent — a healthy config is left untouched.
Troubleshooting pointers
401 Incorrect API key (sk-proj-…)after switching to the subscription → Troubleshooting → AI provider errorsConfig validation failed: … Unrecognized key→ stale OpenClaw core;sudo bash install.sh --step openclaw_install- Codex chats crash immediately (
createDiagnosticTraceContext… is not a function) →@openclaw/codexplugin version skew vs core; re-runsudo bash install.sh --step openclaw_install(re-pins plugins) - Model picker rejects a model ID → each lane validates against its own catalog; remember the two OpenAI lanes have different catalogs.

