Skip to main content

OpenClaw

Route OpenClaw through the gateway with config alone, including from a hardened container. Where you can install, anyray-connect writes it for you.

1
Store a provider key on the gateway

Console Providers, or PUT /admin/provider-keys (provider keys). For the Claude example below, an Anthropic key. A sole provider needs no routing config.

2
Mint an agent key

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.

3
Write the config

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.

openclaw.json
{
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/*': {} },
},
},
}
4
Allow egress

/v1/messages, /mcp, and /mcp/org on the gateway, plus OpenClaw's own hosts (catalog refresh, chat channels).

5
Validate, then run one turn
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 saysMeaning
ActiveEvery runtime on the key can read content back
Active · forwarded unchangedThe key routes, but no runtime on it reached the anyray MCP server, so its turns go through unchanged
MCP disconnectedThe 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 missingOne runtime on the key can read content back and another cannot. The pill names the one to fix

Getting api and baseUrl right​

apibaseUrl shapeOpenClaw appendsUse it for
anthropic-messagesBare origin, no /v1/v1/messagesClaude, and any vendor the gateway serves on /v1/messages (below). Keeps cache_control and thinking blocks
openai-completionsEnds in /v1/chat/completionsGPT, 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:

  1. Move each model it uses onto Anyray: Claude and Grok models use the anyray entry, GPT models anyray-openai.
  2. Rename every model reference to that entry's id.
  3. Add '<id>/*': {} for each entry to agents.defaults.models.
  4. Delete the other providers and any modelPolicy block.

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.