Use your Codex, Grok, Kiro, or Cursor OAuth login from any tool that speaks the OpenAI or Anthropic API.
rotom is a small local gateway. You log in once, run rotom serve, and point
Claude Code, the OpenAI/Anthropic SDKs, or any compatible client at the local
address.
Claude Code running through Grok and GPT:
cargo install rotom
rotom login # pick a provider, finish in browser
rotom serve --bind 127.0.0.1:14550 --api-key local-secretPoint Claude Code (or any Anthropic-compatible client) at the gateway:
export ANTHROPIC_BASE_URL=http://127.0.0.1:14550
export ANTHROPIC_AUTH_TOKEN=local-secret
export ANTHROPIC_MODEL="gpt-5.5"
claudeThat's it. Quick sanity check:
claude -p "Reply with the single word OK"Point
ANTHROPIC_BASE_URLat the server root, not/v1— clients append/v1/messagesthemselves.ANTHROPIC_AUTH_TOKENis your local--api-key, not an upstream token. Use a model that/v1/modelslists (e.g.gpt-5.5).
rotom login lists the providers and runs the chosen flow. Skip the prompt with
a flag:
| Provider | Command |
|---|---|
| OpenAI/Codex | rotom login --provider openai |
| Grok (xAI) | rotom login --provider grok |
| Kiro | rotom login --kiro |
| Cursor | rotom login --cursor |
- Codex / Grok: browser login, then paste the redirected
http://localhost:.../auth/callback?...URL back into the terminal. - Kiro: browser login via Kiro's portal callback (Google/GitHub).
- Cursor: browser approval that rotom polls for — no localhost callback.
Credentials are stored per provider in ~/.rotom/auth.json (override with
ROTOM_AUTH_FILE or ROTOM_HOME). Logging in to one provider never replaces
another, and serve exposes every logged-in provider at once. If a daemon is
already running, restart it to pick up a new provider:
rotom daemon restartrotom models # everything rotom exposes
rotom models --provider grok # one providerCommon ids include gpt-5.5, grok-4.3, Kiro's claude-* family, and
cursor/auto. rotom fetches the live registry where the provider supports it
and falls back to built-in aliases otherwise.
Unknown Anthropic ids like claude-sonnet-* are rewritten to a fallback
(default gpt-5.5). Override with --model-fallback or ROTOM_MODEL_FALLBACK.
OpenAI-compatible:
curl http://127.0.0.1:14550/v1/chat/completions \
-H 'content-type: application/json' \
-H 'authorization: Bearer local-secret' \
-d '{"model": "gpt-5.5", "messages": [{"role": "user", "content": "hello"}]}'Anthropic-compatible:
curl http://127.0.0.1:14550/v1/messages \
-H 'content-type: application/json' \
-H 'x-api-key: local-secret' \
-H 'anthropic-version: 2023-06-01' \
-d '{"model": "gpt-5.5", "max_tokens": 1024, "messages": [{"role": "user", "content": "hello"}]}'Run a background daemon instead of rotom serve:
rotom daemon install --bind 127.0.0.1:14550 --api-key local-secret
rotom daemon start
rotom daemon status # also: restart / stop / uninstallmacOS uses a LaunchAgent; Linux uses a systemd user unit. On Windows, use WSL.
The --api-key is stored in ~/.rotom/config.json rather than embedded in the
service definition.
rotom status # version, token expiry, auth, endpoints
rotom refresh # refresh OAuth tokens for all providers
rotom config # interactive config (~/.rotom/config.json)
rotom update # update to the latest release--bind accepts a comma-separated list and CIDR selectors, e.g.
--bind 127.0.0.1:14550,192.168.1.0/24:14550. Token refresh and status are also
available over HTTP at /v1/auth/refresh and /v1/status.
OpenAI:
GET /v1/models,POST /v1/chat/completionsPOST /v1/responses(+ retrieve / delete / cancel / input_items / compact / input_tokens)POST /v1/images/generations
Anthropic:
GET /v1/models,POST /v1/messages,POST /v1/messages/count_tokens- Message batches:
POST/GET /v1/messages/batches(+ get / cancel / delete / results) x-api-keyorauthorization: Bearer ...auth, SSE streaming for text and tool use
Image generation is exposed both as POST /v1/images/generations and as the
Responses hosted tool {"type":"image_generation"}; generated images are
returned as base64.
These upstreams are not all plain model APIs, so rotom adapts requests and quietly drops controls the upstream cannot honor.
- Codex: accepts
temperature/max_tokensand similar fields but does not forward them (Codex rejects them upstream)./v1/responseskeeps a local replay behavior for existing clients. - Grok: uses xAI's native Responses API and forwards supported controls
(
temperature,top_p,max_output_tokens,stop, ...). - Kiro: mapped to Kiro's
GenerateAssistantResponseschema (text, tools, tool results, history, inline base64 images/documents). Remote image/document URLs are rejected, not fetched. - Cursor: an agent runtime, so client tools are bridged rather than
executed by rotom — they are exposed to Cursor as a
rotom-toolsMCP server, Cursor's tool calls come back as standardtool_call/tool_useitems for your client to run, and the results feed back into the same stream. Cursor's own built-in tools are declined. Requests default to agent mode; override withROTOM_CURSOR_AGENT_MODE. Multimodal and sampling controls are not forwarded.
rotom is an unofficial compatibility tool. It is not affiliated with, endorsed by, or supported by OpenAI, Anthropic, xAI, Kiro, or Cursor.
You are responsible for complying with the terms and account restrictions of your upstream provider. In particular, do not assume personal OAuth access can be shared, resold, or exposed as a multi-user hosted service. The LGPLv3 license does not change those upstream restrictions.
Copyright (c) 2026 rotom contributors.
Licensed under the GNU Lesser General Public License v3.0 only. See LICENSE.


