{"id":51070638,"url":"https://github.com/ryankung/rotom","last_synced_at":"2026-06-23T10:01:37.147Z","repository":{"id":354308897,"uuid":"1222598162","full_name":"RyanKung/rotom","owner":"RyanKung","description":"Local OpenAI- and Anthropic-compatible API gateway backed by Codex OAuth.","archived":false,"fork":false,"pushed_at":"2026-06-10T03:17:30.000Z","size":1599,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-17T15:04:20.722Z","etag":null,"topics":["anthropic","api","claude-code","codex","grok","openai","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RyanKung.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T14:19:05.000Z","updated_at":"2026-06-10T02:15:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/RyanKung/rotom","commit_stats":null,"previous_names":["ryankung/codexia","ryankung/rotom"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/RyanKung/rotom","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyanKung%2Frotom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyanKung%2Frotom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyanKung%2Frotom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyanKung%2Frotom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RyanKung","download_url":"https://codeload.github.com/RyanKung/rotom/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RyanKung%2Frotom/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34684686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-23T02:00:07.161Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","api","claude-code","codex","grok","openai","rust"],"created_at":"2026-06-23T10:01:35.252Z","updated_at":"2026-06-23T10:01:37.141Z","avatar_url":"https://github.com/RyanKung.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"rotom logo\" width=\"144\"\u003e\n\u003c/p\u003e\n\n# rotom\n\n[![CI](https://github.com/RyanKung/rotom/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/RyanKung/rotom/actions/workflows/ci.yml)\n[![Release](https://github.com/RyanKung/rotom/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/RyanKung/rotom/actions/workflows/release.yml)\n\nUse your Codex, Grok, Kiro, or Cursor OAuth login from any tool that speaks the\nOpenAI or Anthropic API.\n\nrotom is a small local gateway. You log in once, run `rotom serve`, and point\nClaude Code, the OpenAI/Anthropic SDKs, or any compatible client at the local\naddress.\n\n## Demo\n\nClaude Code running through Grok and GPT:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"demos/claude-grok-4.3.gif\" alt=\"Claude Code using grok-4.3 through rotom\" width=\"720\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"demos/claude-gpt-5.5.gif\" alt=\"Claude Code using gpt-5.5 through rotom\" width=\"720\"\u003e\n\u003c/p\u003e\n\n## Quick Start\n\n```bash\ncargo install rotom\nrotom login                                   # pick a provider, finish in browser\nrotom serve --bind 127.0.0.1:14550 --api-key local-secret\n```\n\nPoint Claude Code (or any Anthropic-compatible client) at the gateway:\n\n```bash\nexport ANTHROPIC_BASE_URL=http://127.0.0.1:14550\nexport ANTHROPIC_AUTH_TOKEN=local-secret\nexport ANTHROPIC_MODEL=\"gpt-5.5\"\n\nclaude\n```\n\nThat's it. Quick sanity check:\n\n```bash\nclaude -p \"Reply with the single word OK\"\n```\n\n\u003e Point `ANTHROPIC_BASE_URL` at the server root, **not** `/v1` — clients append\n\u003e `/v1/messages` themselves. `ANTHROPIC_AUTH_TOKEN` is your local `--api-key`,\n\u003e not an upstream token. Use a model that `/v1/models` lists (e.g. `gpt-5.5`).\n\n## Logging In\n\n`rotom login` lists the providers and runs the chosen flow. Skip the prompt with\na flag:\n\n| Provider     | Command                        |\n| ------------ | ------------------------------ |\n| OpenAI/Codex | `rotom login --provider openai`|\n| Grok (xAI)   | `rotom login --provider grok`  |\n| Kiro         | `rotom login --kiro`           |\n| Cursor       | `rotom login --cursor`         |\n\n- **Codex / Grok**: browser login, then paste the redirected\n  `http://localhost:.../auth/callback?...` URL back into the terminal.\n- **Kiro**: browser login via Kiro's portal callback (Google/GitHub).\n- **Cursor**: browser approval that rotom polls for — no localhost callback.\n\nCredentials are stored per provider in `~/.rotom/auth.json` (override with\n`ROTOM_AUTH_FILE` or `ROTOM_HOME`). Logging in to one provider never replaces\nanother, and `serve` exposes every logged-in provider at once. If a daemon is\nalready running, restart it to pick up a new provider:\n\n```bash\nrotom daemon restart\n```\n\n## Models\n\n```bash\nrotom models                      # everything rotom exposes\nrotom models --provider grok      # one provider\n```\n\nCommon ids include `gpt-5.5`, `grok-4.3`, Kiro's `claude-*` family, and\n`cursor/auto`. rotom fetches the live registry where the provider supports it\nand falls back to built-in aliases otherwise.\n\nUnknown Anthropic ids like `claude-sonnet-*` are rewritten to a fallback\n(default `gpt-5.5`). Override with `--model-fallback` or `ROTOM_MODEL_FALLBACK`.\n\n## Use With SDKs\n\nOpenAI-compatible:\n\n```bash\ncurl http://127.0.0.1:14550/v1/chat/completions \\\n  -H 'content-type: application/json' \\\n  -H 'authorization: Bearer local-secret' \\\n  -d '{\"model\": \"gpt-5.5\", \"messages\": [{\"role\": \"user\", \"content\": \"hello\"}]}'\n```\n\nAnthropic-compatible:\n\n```bash\ncurl http://127.0.0.1:14550/v1/messages \\\n  -H 'content-type: application/json' \\\n  -H 'x-api-key: local-secret' \\\n  -H 'anthropic-version: 2023-06-01' \\\n  -d '{\"model\": \"gpt-5.5\", \"max_tokens\": 1024, \"messages\": [{\"role\": \"user\", \"content\": \"hello\"}]}'\n```\n\n## Running As a Service\n\nRun a background daemon instead of `rotom serve`:\n\n```bash\nrotom daemon install --bind 127.0.0.1:14550 --api-key local-secret\nrotom daemon start\nrotom daemon status      # also: restart / stop / uninstall\n```\n\nmacOS uses a LaunchAgent; Linux uses a systemd user unit. On Windows, use WSL.\nThe `--api-key` is stored in `~/.rotom/config.json` rather than embedded in the\nservice definition.\n\n## Other Commands\n\n```bash\nrotom status                      # version, token expiry, auth, endpoints\nrotom refresh                     # refresh OAuth tokens for all providers\nrotom config                      # interactive config (~/.rotom/config.json)\nrotom update                      # update to the latest release\n```\n\n`--bind` accepts a comma-separated list and CIDR selectors, e.g.\n`--bind 127.0.0.1:14550,192.168.1.0/24:14550`. Token refresh and status are also\navailable over HTTP at `/v1/auth/refresh` and `/v1/status`.\n\n## Supported Endpoints\n\nOpenAI:\n\n- `GET /v1/models`, `POST /v1/chat/completions`\n- `POST /v1/responses` (+ retrieve / delete / cancel / input_items / compact /\n  input_tokens)\n- `POST /v1/images/generations`\n\nAnthropic:\n\n- `GET /v1/models`, `POST /v1/messages`, `POST /v1/messages/count_tokens`\n- Message batches: `POST/GET /v1/messages/batches` (+ get / cancel / delete /\n  results)\n- `x-api-key` or `authorization: Bearer ...` auth, SSE streaming for text and\n  tool use\n\nImage generation is exposed both as `POST /v1/images/generations` and as the\nResponses hosted tool `{\"type\":\"image_generation\"}`; generated images are\nreturned as base64.\n\n## Provider Notes\n\nThese upstreams are not all plain model APIs, so rotom adapts requests and\nquietly drops controls the upstream cannot honor.\n\n- **Codex**: accepts `temperature` / `max_tokens` and similar fields but does\n  not forward them (Codex rejects them upstream). `/v1/responses` keeps a local\n  replay behavior for existing clients.\n- **Grok**: uses xAI's native Responses API and forwards supported controls\n  (`temperature`, `top_p`, `max_output_tokens`, `stop`, ...).\n- **Kiro**: mapped to Kiro's `GenerateAssistantResponse` schema (text, tools,\n  tool results, history, inline base64 images/documents). Remote image/document\n  URLs are rejected, not fetched.\n- **Cursor**: an agent runtime, so client tools are **bridged** rather than\n  executed by rotom — they are exposed to Cursor as a `rotom-tools` MCP server,\n  Cursor's tool calls come back as standard `tool_call`/`tool_use` items for your\n  client to run, and the results feed back into the same stream. Cursor's own\n  built-in tools are declined. Requests default to agent mode; override with\n  `ROTOM_CURSOR_AGENT_MODE`. Multimodal and sampling controls are not forwarded.\n\n## Disclaimer\n\nrotom is an unofficial compatibility tool. It is not affiliated with, endorsed\nby, or supported by OpenAI, Anthropic, xAI, Kiro, or Cursor.\n\nYou are responsible for complying with the terms and account restrictions of\nyour upstream provider. In particular, do not assume personal OAuth access can\nbe shared, resold, or exposed as a multi-user hosted service. The LGPLv3 license\ndoes not change those upstream restrictions.\n\n## License\n\nCopyright (c) 2026 rotom contributors.\n\nLicensed under the GNU Lesser General Public License v3.0 only. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryankung%2Frotom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fryankung%2Frotom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryankung%2Frotom/lists"}