Gateway keys and connect

Optional local vault for API-key seats: rotation and failover. Account seats (Cursor, Claude plan, Codex) keep their login.

Goal#

Give Orchemax's local gateway your upstream API keys (with failover when one key or provider hits a rate limit), then point only the seats that use keys at that gateway. Seats with a vendor login + token plan (Cursor, Claude Code subscription, Codex, …) stay on that login — the gateway does not replace it.

Gateway only where it applies#

Seat kind Examples Model traffic
Account / plan Cursor, Claude Code (Pro/Max), Codex Vendor login. Default agents.auth: account. No gateway connect.
API-key / BYO OpenCode, OpenClaude, Command Code, Copilot with key, Cursor BYOK Keys in machine-home keys.env → gateway ring.

Orchemax still sits under every seat for MCP, bus, locks and usage. Only model routing through :8788 is optional and seat-specific.

How rotation works (API-key seats)#

  1. You put one or more keys per provider in machine-home keys.env (OPENROUTER_API_KEY=…, several comma-separated values = a ring).
  2. You register providers in ai.yaml (orch gateway setup --live …).
  3. You start orch gateway (default http://127.0.0.1:8788).
  4. Those agents talk only to Orchemax. Orchemax picks the next live provider / next key on 429 / quota errors — the agent does not manage rotation.

Account seats skip step 4 on purpose.

API-key seat (OpenCode / OpenClaude / …)
        │  Base URL = http://127.0.0.1:8788/v1
        │  API key  = orch_gk_…   (virtual; not your secret)
        ▼
orch gateway  (:8788)
        │  per-provider ring: key1 → key2 → key3 on 429
        ▼
OpenRouter / Groq / Cerebras / …

Cursor / Claude (plan) / Codex
        │  their own login
        ▼
vendor model API   (orch underneath for MCP/bus — not model routing)

Upstream keys live only in machine-home (keys.env). The API-key agent never sees them. Several keys in one variable (OPENROUTER_API_KEY=a,b,c) = automatic rotation.

Steps#

1. Put keys where Orchemax reads them#

Prefer the vault file (not Windows User env):

%LOCALAPPDATA%\Orchemax\keys.env (override with ORCH_HOME)

OPENROUTER_API_KEY=sk-or-…
CEREBRAS_API_KEY=…
GROQ_API_KEY=…

Or add one key at a time (probed before save):

orch gateway keys add openrouter

2. Register providers (once)#

orch gateway setup --live \
  --name openrouter \
  --url https://openrouter.ai/api/v1 \
  --model openrouter/auto \
  --key-env OPENROUTER_API_KEY \
  --tier cheap \
  --priority 10

Repeat for other providers. Lower priority is tried first. Check with orch gateway show — each line should say key=set and ai.mode=live.

Workshop orch.yaml must not pin ai.mode: stub or it overrides the user catalog.

3. Start the gateway#

orch gateway

Leave it running while you use API-key agents.

4. Point API-key agents at Orchemax (by protocol)#

Hundreds of agents share two wires. Orchemax does not ship a writer per CLI:

orch gateway connect              # OpenAI-compat paste (default)
orch gateway connect openai       # same
orch gateway connect anthropic    # Anthropic Messages paste (API-key seats only)
orch gateway connect opencode --allow-user-scope   # optional: write OpenCode's JSON

Aliases such as openclaude, commandcode, copilot, cursor still print the openai block. Alias claude → anthropic.

Command Code is special: orch gateway connect commandcode --allow-user-scope writes ~/.commandcode/providers.json with "apiKey": "$ORCH_GATEWAY_KEY" (not a pasted orch_gk_…). That CLI rejects plaintext keys ("Provider 'orch' has no API key"). The heal is driven by catalog hint BYOKProvidersRel (any CLI with the same $ENV_VAR providers.json schema can set it) — not an agent-name allowlist. Gateway-routed seats with that hint sync the file on launch.

Do not run connect for Cursor / Claude / Codex plan seats (they keep vendor login). Any OpenAI-compatible BYO agent: paste Base URL http://127.0.0.1:8788/v1 and the printed orch_gk_… virtual key. Models come from GET /v1/models (real upstream ids).

Protocol matrix

Protocol Connect Who
OpenAI-compat openai (default) OpenCode (or opencode --allow-user-scope), OpenClaude, Command Code, Copilot BYOK, Cursor BYOK, …
Anthropic Messages anthropic / claude Claude Code with API key + agents.auth.claude: gateway
Account / plan — Cursor subscription, Claude plan, Codex — no connect

For an OpenAI-compat connect you get:

  • Base URL → http://127.0.0.1:8788/v1
  • API key → Orchemax virtual key (orch_gk_…), not your upstream secret
  • Models → GET /v1/models on the gateway (real provider ids)

5. Verify rotation is alive#

orch gateway status
orch gateway usage

status shows per-provider live/cooldown and key-ring position (2/3). usage shows calls and savings after real traffic.

Example: OpenCode with rotation#

# 1) Several keys = a ring (comma). Or run `orch gateway keys add …` repeatedly.
#    File: %LOCALAPPDATA%\Orchemax\keys.env
OPENROUTER_API_KEY=sk-or-aaa,sk-or-bbb
GROQ_API_KEY=gsk-…

# 2) Catalog (once per machine)
orch gateway setup --live --name openrouter --url https://openrouter.ai/api/v1 \
  --model openrouter/auto --key-env OPENROUTER_API_KEY --tier cheap --priority 10
orch gateway setup --live --name groq --url https://api.groq.com/openai/v1 \
  --model llama-3.3-70b-versatile --key-env GROQ_API_KEY --tier cheap --priority 20

# 3) Proxy up + paste OpenAI-compat into any BYO agent
orch gateway
orch gateway connect                 # print Base URL + virtual key
# optional OpenCode file write:
# orch gateway connect opencode --allow-user-scope

# 4) Check the ring after a few calls
orch gateway status

Plan-billed seats#

If agents.auth.<preset> is account (default for Cursor, Codex, and Claude without an Anthropic API key), connect only prints ORCH_GATEWAY_* and keeps the vendor login. That is correct — leave it. Field notes and anti-patterns: common seat tune-ups — account / plan login.

To force gateway routing on a seat that can do API keys:

agents:
  auth:
    claude: gateway   # only with Anthropic API key configured

Undo#

orch gateway keys remove <provider> <hint>

Unset the agent's base URL / key override, or set agents.auth.<preset>: account.