Self-hosted local AI router with OpenAI-compatible API, provider fallback, usage tracking, quota tools, and dashboard UI.
Rouwang runs as one Go binary on 127.0.0.1:17171, serves /v1 for AI clients, serves /api for dashboard operations, and embeds a statically exported Next.js dashboard.
- Exposes OpenAI-compatible
/v1/chat/completionsendpoint for AI coding tools. - Routes requests across configured providers and accounts.
- Supports provider management, OAuth/API-key connections, aliases, combos, and fallback chains.
- Tracks usage and quota in local SQLite.
- Provides dashboard pages for endpoint setup, providers, combos, usage, quota, console, CLI tools, playground, translator, profile, and settings.
- Includes translators for OpenAI, Claude, Gemini, Cursor, and Kiro formats.
- Includes RTK token saver package for reducing repeated tool-result payloads.
- Runs locally by default and stores data under
~/.rouwang.
Project is active work-in-progress. Docs under docs/ describe product plan, architecture, milestones, and handoffs. Codebase already contains Go backend modules, Next.js dashboard, tests, Docker setup, and build scripts.
- Go
1.23 chirouter- GORM
- SQLite via
github.com/glebarez/sqlite - Goose migrations embedded with
embed.FS - JWT auth via
github.com/golang-jwt/jwt/v5 - bcrypt / crypto from
golang.org/x/crypto - stdlib
log/slog
- Next.js
16.2.6 - React
19.2.6 - TypeScript
6.0.3 - Tailwind CSS
4.3.0 - TanStack Query
5.100.13 - React Hook Form
- Zod
- Recharts
- Axios
- Single Go binary serving embedded Next.js static export
- SQLite database in configurable data directory
- Docker and Docker Compose support
.
├── cmd/rouwang/ # Go entrypoint and embedded web assets
│ ├── main.go # Loads config, DB, JWT secret, server
│ └── web/out/ # Next.js static export copied here during build
├── internal/
│ ├── authjwt/ # JWT secret handling
│ ├── config/ # Env/config loading
│ ├── database/ # SQLite open + embedded migrations
│ ├── middleware/ # Auth, CSRF, CORS, security, logging, recovery
│ ├── models/ # Shared database models
│ ├── modules/ # Feature modules and route registration
│ │ ├── aliases/
│ │ ├── apikeys/
│ │ ├── auth/
│ │ ├── clitools/
│ │ ├── combos/
│ │ ├── init/
│ │ ├── media/
│ │ ├── oauth/
│ │ ├── playground/
│ │ ├── providers/
│ │ ├── proxypools/
│ │ ├── quota/
│ │ ├── settings/
│ │ ├── usage/
│ │ └── v1/
│ ├── response/ # JSON response helpers
│ ├── routedeps/ # Shared route dependencies
│ ├── rtk/ # RTK token saver
│ ├── server/ # HTTP server and route tree
│ └── translator/ # Provider format translators
├── web/ # Next.js dashboard
│ ├── app/ # App Router pages and layouts
│ ├── features/ # Feature-specific UI/API modules
│ ├── hooks/ # Shared hooks
│ ├── lib/ # API client, utilities, validation, i18n
│ ├── providers/ # React providers
│ └── styles/ # Design tokens, layout, typography, utilities
├── docs/ # Product, spec, architecture, milestones, handoffs
├── design-system/ # Visual design canon and smoke docs
├── mockups-fresh/ # HTML mockups and screenshots
├── scripts/ # PowerShell build/test helpers
├── Dockerfile
├── docker-compose.yml
├── Makefile
└── .env.example
GET /api/health— health check, returns{ "status": "ok" }.- Init and auth routes register without global dashboard-auth wrapper.
Protected by dashboard session auth:
- API keys
- Providers
- Proxy pools
- Aliases
- Media providers
- Combos
- CLI tools
- Playground
- Settings
- Usage
- Quota
- OAuth
/v1/*routes are registered byinternal/modules/v1.- Primary intended endpoint:
/v1/chat/completions. - Used by Claude Code, Cursor, Codex-style clients, and other OpenAI-compatible tools.
Current Next.js pages include:
/login/setup/dashboard/dashboard/endpoint/dashboard/providers/dashboard/providers/setup/dashboard/providers/manage/dashboard/media-providers/dashboard/media-providers/manage/dashboard/proxy-pools/dashboard/combos/dashboard/usage/dashboard/quota/dashboard/console/dashboard/cli-tools/dashboard/playground/dashboard/translator/dashboard/profile/dashboard/settings
In development, Next.js rewrites /api/* and /v1/* to http://127.0.0.1:17171.
- Go
1.23+ - Node.js
22+recommended for frontend build, matching Dockerfilenode:22-alpine - npm
- Docker optional
Copy .env.example if local overrides are needed:
cp .env.example .envSupported env vars in current config:
| Variable | Default | Description |
|---|---|---|
HOST |
127.0.0.1 |
Bind host for Go server. Use 0.0.0.0 in containers. |
PORT |
17171 |
Bind port. |
DATA_DIR |
~/.rouwang |
Directory for SQLite DB and JWT secret. |
COOKIE_SECURE |
false |
Set secure cookies. Use true behind HTTPS. |
ENABLE_REQUEST_LOGS |
false |
Present in .env.example; request-log behavior may depend on middleware implementation. |
Runtime files:
- SQLite DB:
${DATA_DIR}/rouwang.db - JWT secret: generated/loaded under
${DATA_DIR}byinternal/authjwt - DB permissions: data dir created with
0700
go run ./cmd/rouwangServer listens on configured address, default:
http://127.0.0.1:17171
Health check:
curl http://127.0.0.1:17171/api/healthExpected:
{"status":"ok"}cd web
npm install
npm run devNext.js dev server proxies backend calls to http://127.0.0.1:17171 through rewrites.
Run backend and frontend in separate terminals during frontend development.
make buildThis runs:
cd web && npm install && npm run build- Copies
web/outintocmd/rouwang/web/out - Builds Go binary from
./cmd/rouwang
Result depends on Go default output for package build. For explicit binary name:
go build -o rouwang ./cmd/rouwangcd web
npm install
npm run buildProduction Next.js config uses static export:
output: "export"Generated static files live in web/out and must be copied into cmd/rouwang/web/out before building Go binary.
go test ./...or:
make testcd web
npm run typecheck
npm run lintCurrent frontend lint script runs TypeScript typecheck:
"lint": "tsc --noEmit"PowerShell helpers exist:
.\scripts\build.ps1
.\scripts\test.ps1docker build -t rouwang .docker run --rm -p 17171:17171 -e HOST=0.0.0.0 -e DATA_DIR=/data -v rouwang-data:/data rouwangdocker compose up --buildCompose exposes:
http://127.0.0.1:17171
Compose stores data in named volume:
rouwang-data
- Start Rouwang.
- Open dashboard at
http://127.0.0.1:17171. - Complete setup/login.
- Add provider connections.
- Create API key for local AI tools.
- Configure tool base URL to
http://127.0.0.1:17171/v1. - Use generated key as OpenAI-compatible API key.
- Monitor traffic in usage/quota pages.
Example OpenAI-compatible request shape:
curl http://127.0.0.1:17171/v1/chat/completions \
-H "Authorization: Bearer sk_rw_example" \
-H "Content-Type: application/json" \
-d '{
"model": "your-model-or-alias",
"messages": [
{"role": "user", "content": "Say hello"}
]
}'Use dashboard-generated key, not sk_rw_example.
AI client
│
│ POST /v1/chat/completions
▼
Go server
├─ middleware: recovery, security, CORS, CSRF/auth as applicable
├─ v1 module: route, translate, route, fallback, usage accounting
├─ providers module: accounts, credentials, transport
├─ combos module: fallback chains and virtual routing
├─ quota/usage modules: accounting and analytics
└─ SQLite: local persistent state
│
▼
Upstream AI provider
Dashboard architecture:
Browser
│
├─ Static Next.js app served by Go binary
└─ /api/* JSON calls to Go backend
Build architecture:
web/ Next.js static export
▼ copied to
cmd/rouwang/web/out
▼ embedded by
//go:embed all:web/out
▼ served by
single Go binary
- SQLite database stored in
DATA_DIR. - Goose migrations are embedded from
internal/database/migrations/*.sql. - GORM provides DB access.
- Foreign keys, busy timeout, and WAL mode are enabled in SQLite DSN.
SQLite DSN behavior from code:
rouwang.db?_pragma=foreign_keys(1)&_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)
- Default bind is
127.0.0.1, local-only. - Use
HOST=0.0.0.0only when network exposure is intended. - Use
COOKIE_SECURE=truebehind HTTPS. - Dashboard API modules are protected by dashboard session auth.
- Provider credentials and API keys should stay in local data directory or Docker volume.
- Do not commit
.env, database files, generated secrets, or provider credentials.
docs/README.md— spec-plan index and TL;DR.docs/PRD.md— product requirements and goals.docs/SPEC.md— implementation spec and feature pillars.docs/ARCHITECTURE.md— detailed system architecture.docs/OPEN-DECISIONS.md— locked decisions and pending decisions.docs/M*.md— milestone documents.docs/*HANDOFF*.md— session/UI handoff notes.design-system/DESIGN.md— visual design canon.mockups-fresh/— static mockups and screenshots.
| Task | Command |
|---|---|
| Run backend | go run ./cmd/rouwang |
| Run Go tests | go test ./... |
| Build web | cd web && npm install && npm run build |
| Typecheck web | cd web && npm run typecheck |
| Build full app | make build |
| Docker build | docker build -t rouwang . |
| Docker Compose | docker compose up --build |
Build frontend first and copy web/out into cmd/rouwang/web/out:
make web-buildEnsure backend is running at:
http://127.0.0.1:17171
Next dev rewrites /api/* and /v1/* to that address.
Change port:
PORT=17172 go run ./cmd/rouwangThen update client base URL accordingly.
Stop server, back up if needed, then remove configured data directory. Default:
~/.rouwang
This deletes DB and generated secrets.
No license file currently present in repository.