OpenClaw
Route OpenClaw through the gateway with config alone, including from a hardened container. Where you can install, anyray-connect writes it for you.
Console Providers, or PUT /admin/provider-keys (provider keys).
For the Claude example below, an Anthropic key. A sole provider needs no routing config.
Console Users → Agents → Add agent mints an ark_svc_… key
(client keys), one per deployment. Set it as ANYRAY_CLIENT_KEY;
rotation is a new key plus a restart. The dialog's OpenClaw tab leads with a prompt for a
coding agent, the agent-host runbook.
Copy it from the agent's Setup tab in the console. The list follows this agent's routing:
its own lanes on Routing → Targeted routing when it has them, otherwise the organization's.
An alias for a model that routing already serves by its own id is listed under that id.
It goes at ~/.openclaw/openclaw.json or OPENCLAW_CONFIG_PATH. Read-only mount: set
OPENCLAW_CONFIG_READONLY=1.
{
models: {
providers: {
anyray: {
// Bare origin, no `/v1`: anthropic-messages appends `/v1/messages`.
baseUrl: 'https://gateway.example.anyray.ai',
// Required. Without it OpenClaw uses openai-completions.
api: 'anthropic-messages',
apiKey: '${ANYRAY_CLIENT_KEY}',
headers: {
'x-anyray-api-key': '${ANYRAY_CLIENT_KEY}',
// OpenClaw drops its implicit beta headers on a non-Anthropic host.
'anthropic-beta': 'interleaved-thinking-2025-05-14',
// Labels the traffic as OpenClaw. User and team come from the key.
'x-anyray-metadata': '{"tool":"openclaw"}',
},
// A custom provider lists its own models.
models: [
{
id: 'claude-sonnet-5-5',
name: 'Claude Sonnet 5.5 (Anyray)',
reasoning: true,
input: ['text', 'image'],
contextWindow: 1000000,
maxTokens: 128000,
},
],
},
},
},
mcp: {
servers: {
// Reads back content the optimizer replaced with a marker.
anyray: {
url: 'https://gateway.example.anyray.ai/mcp',
transport: 'streamable-http',
headers: { 'x-anyray-api-key': '${ANYRAY_CLIENT_KEY}' },
},
// Your organization's shared connectors.
'anyray-connectors': {
url: 'https://gateway.example.anyray.ai/mcp/org',
transport: 'streamable-http',
headers: { 'x-anyray-api-key': '${ANYRAY_CLIENT_KEY}' },
},
},
},
agents: {
defaults: {
// Nothing routes until the primary model resolves to this provider.
model: { primary: 'anyray/claude-sonnet-5-5', fallbacks: [] },
// Only anyray/* models can be picked, by /model or by failover.
models: { 'anyray/*': {} },
},
},
}
/v1/messages, /mcp, and /mcp/org on the gateway, plus OpenClaw's own hosts (catalog
refresh, chat channels).
openclaw config validate
openclaw models status --json
openclaw mcp probe anyray --json
validate checks the file against OpenClaw's strict schema. In models status, every entry
of allowed and fallbacks starts with anyray, and allowed holds the ids the config
lists. An empty allowed means any model goes. Newer OpenClaw builds read the list from
agents.defaults.modelPolicy.allow, so put the same patterns there. probe should
list anyray_retrieve and anyray_recall; if not, run openclaw mcp reload (or
openclaw gateway restart for a gateway running in another process). Then check the Agents
card:
| Card says | Meaning |
|---|---|
| Active | Every runtime on the key can read content back |
| Active · forwarded unchanged | The key routes, but no runtime on it reached the anyray MCP server, so its turns go through unchanged |
| MCP disconnected | The deployment serves retrieval for tool loops, but no runtime on the key reached the anyray MCP server for the turns it cannot serve |
| OpenClaw ✓ · Codex: MCP missing | One runtime on the key can read content back and another cannot. The pill names the one to fix |
Getting api and baseUrl right
api | baseUrl shape | OpenClaw appends | Use it for |
|---|---|---|---|
anthropic-messages | Bare origin, no /v1 | /v1/messages | Claude, and any vendor the gateway serves on /v1/messages (below). Keeps cache_control and thinking blocks |
openai-completions | Ends in /v1 | /chat/completions | GPT, which the gateway does not serve on /v1/messages |
Omit api and OpenClaw defaults to openai-completions, which on a bare origin posts to
/chat/completions: the gateway answers 404.
What the mcp block adds
Without the anyray server a turn goes through unchanged, and nothing is trimmed behind a
[anyray: … retrieve ctx_…] marker. A deployment whose admin opted tool loops into
served retrieval answers those reads
itself, except on a turn with extended thinking, which a reasoning: true model may send. Once
registered, the server handles every turn. anyray-connectors serves your org's shared
connectors.
Retrieval reference.
anyray-connect machines get both
written for them, plus a plugin that stamps a per-conversation session id (without it the gateway
groups sessions by conversation prefix).
You already have an openclaw.json
Anyray has to be OpenClaw's only route, or a provider left beside it keeps answering on its own. Back up the file, then:
- Move each model it uses onto Anyray: Claude and Grok models use the
anyrayentry, GPT modelsanyray-openai. - Rename every model reference to that entry's id.
- Add
'<id>/*': {}for each entry toagents.defaults.models. - Delete the other providers and any
modelPolicyblock.
A model Setup does not list needs routing first: a lane for this agent and that model when it has lanes, a provider on its own route under Routing → Agent routing when it has one, otherwise an alias under Providers → (that provider) → Mapping. An alias on that route's own provider works too. Then re-open Setup and copy the new config.
Other models and vendors
Ready-made entries for Opus, GPT, and Grok (xAI or Oracle OCI)
are in config variants. /v1/messages serves anthropic, bedrock, oracle, x-ai, nebius, tensormesh,
litellm, truefoundry, and anyray-upstream; openai does not.
With several provider keys, set a routing config (console Routing, see routing examples) or model aliases under Providers → (that provider) → Mapping. With neither, requests fail (troubleshooting). Then re-open the agent's Setup tab for the new model list.
You already pointed a provider at your own upstream
On an entry carrying your own x-anyray-custom-host or x-anyray-auth-mode pin, anyray-connect
keeps baseUrl, apiKey, and your headers, adding only x-anyray-api-key and
x-anyray-metadata. To hand the entry to Connect, remove those pins and re-run it, with
--upstream <url> --upstream-key <key> for a personal upstream.