SRouter
llms.txt24 starsChanged 16 days agoMITView on GitHub
SRouter is a self-hosted LLM gateway: one OpenAI- and Anthropic-compatible endpoint in front of the provider accounts you already pay for (Claude Code, OpenAI Codex, Qoder, Cline, Grok Web, CodeBuddy global/CN, Google Antigravity, OpenCode Zen). Two halves in one repository: server/ is a Rust/Axum gateway with SQLite storage, client/ is a React 19 dashboard (Bun, Vite, TanStack Router/Query, Tailwind v4). They share only TypeScript generated from the Rust wire types. No Postgres, no Redis, no queue, no workspace root manifest.
We split this llms.txt into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 39
Read (API key): GET /v1/models, /v1/models/{*model}, /v1/models/pricing, GET /v1/settings.
- Very specific: line 49
All client-visible strings, error codes, and header names come from server/src/constants.rs.
≈ “Common” is an estimate: at least 1 in 5 of the 3,225 llms.txt files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
# SRouter
> SRouter is a self-hosted LLM gateway: one OpenAI- and Anthropic-compatible endpoint in front of the provider accounts you already pay for (Claude Code, OpenAI Codex, Qoder, Cline, Grok Web, CodeBuddy global/CN, Google Antigravity, OpenCode Zen).
Two halves in one repository: `server/` is a Rust/Axum gateway with SQLite storage, `client/` is a React 19 dashboard (Bun, Vite, TanStack Router/Query, Tailwind v4). They share only TypeScript generated from the Rust wire types. No Postgres, no Redis, no queue, no workspace root manifest.
Branch note: this file describes the tree on `feat/api-rust-migration` (PR #155), which is what the paths below refer to. Until that PR merges, replace `main` with `feat/api-rust-migration` in the URLs.
## Start here
- [README](https://github.com/seaavey/SRouter/blob/main/README.md): human entry point: quick start, client examples, API table, dashboard, troubleshooting.
- [README (Indonesian)](https://github.com/seaavey/SRouter/blob/main/README-id.md): the same document in Bahasa Indonesia.
- [AGENTS.md](https://github.com/seaavey/SRouter/blob/main/AGENTS.md): contributor rules for AI agents: architecture, non-negotiable invariants, conventions, verification expectations.
- [CONTRIBUTING.md](https://github.com/seaavey/SRouter/blob/main/CONTRIBUTING.md): build, test, bindings, commit conventions.
- [SECURITY.md](https://github.com/seaavey/SRouter/blob/main/SECURITY.md): where credentials live, what counts as a vulnerability, private reporting channel.
## Source map
- [server/src/app.rs](https://github.com/seaavey/SRouter/blob/main/server/src/app.rs): the only router assembly; every guard is applied per mount.
- [server/src/features/](https://github.com/seaavey/SRouter/tree/main/server/src/features): one directory per feature: gateway, providers, catalog, logs, api_keys, admin_auth, provider_auth, database_transfer.
- [server/src/constants.rs](https://github.com/seaavey/SRouter/blob/main/server/src/constants.rs): every client-facing message, error code, error type, and header name.
- [server/src/http/](https://github.com/seaavey/SRouter/tree/main/server/src/http): middleware (api key, admin session, rate limit, csrf, cors, body limit, access log, security headers), listeners, static files.
- [server/src/infrastructure/](https://github.com/seaavey/SRouter/tree/main/server/src/infrastructure): SQLite handle, migrations, stores, upstream client, telemetry.
- [server/migrations/](https://github.com/seaavey/SRouter/tree/main/server/migrations): schema history, currently version 7.
- [server/tests/](https://github.com/seaavey/SRouter/tree/main/server/tests): integration suites; each builds its own temporary database and fake upstreams.
- [server/bindings.ts](https://github.com/seaavey/SRouter/blob/main/server/bindings.ts): generated TypeScript view of the wire types; a byte-identical copy lives at `client/src/generated/typed.ts`.
- [client/src/routes/](https://github.com/seaavey/SRouter/tree/main/client/src/routes): TanStack file routes: `/login`, `/` overview, `/providers`, `/providers/$providerId`, `/logs`, `/usage`, `/keys`, `/settings`.
- [skills/srouter-server/SKILL.md](https://github.com/seaavey/SRouter/blob/main/skills/srouter-server/SKILL.md) and [skills/srouter-frontend/SKILL.md](https://github.com/seaavey/SRouter/blob/main/skills/srouter-frontend/SKILL.md): deep-dive notes per half.
## Run it
- From source: `cargo run --manifest-path server/Cargo.toml` (stable Rust, edition 2024). Listens on `127.0.0.1:3000`, database at `~/.srouter/srouter.db`.
- Docker: `SROUTER_ADMIN_PASSWORD=... docker compose up -d`. Serves API and dashboard on `:3000`, database at `~/.srouter/srouter.db` (mounted to `/data`).
- Dashboard only: `cd client && bun install && bun run dev` (Vite on `:5173`, proxies `/v1` to the server).
## API surface
- Gateway: `POST /v1/chat/completions` (aliases `/v1/chat`, `/v1/chat/completion`), `POST /v1/messages`, `POST /v1/messages/count_tokens`, `POST /v1/images/generations`. SSE streaming; a provider failure mid-stream is an SSE error event, never a dropped connection.
- Read (API key): `GET /v1/models`, `/v1/models/{*model}`, `/v1/models/pricing`, `GET /v1/settings`.
- Operator (admin session + CSRF): model writes under `/v1/models/{*model}`, `PATCH /v1/providers/{id}`, `PATCH /v1/providers/{id}/round-robin`, custom providers (`POST|DELETE /v1/providers`, `/v1/providers/verify`, `/v1/providers/connections/verify`), the provider/log/quota reads (`GET /v1/providers`, `/v1/providers/catalog`, `/v1/providers/{id}`, `/v1/logs` with `/{id}`, `/stats`, `/analytics`, `/events`, `/v1/quota` and its `/v1/qouta` alias), `/v1/keys` CRUD plus `/v1/keys/{id}/credit`, `/v1/users` CRUD plus `POST /v1/users/{id}/token`, `POST|PATCH /v1/settings`, `/v1/admin/{status,setup,login,logout,change-password}`, `/v1/admin/database/{export,import}`.
- Customer console (user session from `POST /v1/portal/login`, which takes an `sr-user-…` token and is public but throttled): `GET /v1/portal/me`, `GET /v1/portal/logs`, `POST /v1/portal/logout`. Read-only and tenant-scoped: a customer sees only the keys and request logs it owns.
- OAuth: `/v1/auth/{qoder,cline,codebuddy,codebuddy-cn,grok-web,openai,antigravity,claude}/...` (admin session to start, callbacks public).
- Errors: OpenAI envelope `{"error": {"message", "type", "code", "param"}}`.
## Invariants an agent must not break
- SQLite is the only backend. A configured `DATABASE_URL` is refused at boot, permanently.
- Production is the only mode the binary boots; `NODE_ENV=development` is refused.
- All client-visible strings, error codes, and header names come from `server/src/constants.rs`; never inline them in a handler.
- Wire fields are snake_case in both directions, and `client/` depends on it. A Rust type change is a wire contract change: run `cargo run --manifest-path server/Cargo.toml --bin export_ts` and commit both generated copies.
- Guards are applied per mount in `server/src/app.rs`; global layer order and the frozen response headers are deliberate.
- Gateway keys store a sha256 hash plus a display prefix; provider credentials are cleartext in the SQLite file; request logs keep metadata only.
- Tests must never open `~/.srouter/srouter.db` or reach a real provider.
- No `TODO`/`FIXME` markers, stubs, or placeholders in `server/src` or `client/src`.
## Verify a change
```
cargo test --manifest-path server/Cargo.toml --locked
cargo fmt --manifest-path server/Cargo.toml -- --check
cargo clippy --manifest-path server/Cargo.toml --all-targets --all-features --locked -- -D warnings
cd client && bun run typecheck && bun run lint && bun run build
```
There is no client test runner. Two server suites (`opencode_live.rs`, `qoder_live.rs`) are network-gated and ignored by default.
## Optional
- [docs/api-v1-contract.md](https://github.com/seaavey/SRouter/blob/backup/pre-apps-api-removal/docs/api-v1-contract.md): the owner-approved Node-to-Rust deviation list, preserved on the `backup/pre-apps-api-removal` branch because the tree no longer carries `docs/`.
- [docs/api-migration.md](https://github.com/seaavey/SRouter/blob/backup/pre-apps-api-removal/docs/api-migration.md): migration status, parity matrix, and the benchmark protocol.
- The deleted Node monorepo is readable at `backup/pre-apps-api-removal` and `backup/pre-packages-removal`.
In this repository3 other files it gives its agents.
- AGENTS.mdAGENTS.md
- srouter-frontendSkill
- srouter-serverSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

