A Go LLM gateway that exposes Anthropic-compatible and OpenAI-compatible endpoints for Claude Code, Codex-style agents, SDK clients, and other tools.
GET /healthzGET /v1/modelsPOST /v1/messagesPOST /v1/chat/completions
The gateway accepts Anthropic-style and OpenAI-style client requests, resolves the requested model through a unified model registry, and forwards the request to an anthropic_compatible or openai_compatible provider backend.
Longer architecture, configuration, and operations notes live in docs/.
go run ./cmd/llm-gateway -config config.example.jsonOptional address override:
go run ./cmd/llm-gateway -config config.example.json -addr 127.0.0.1:8080llm-gateway is a single-binary Go HTTP gateway. It accepts Anthropic-compatible and OpenAI-compatible client requests, normalizes them into an internal protocol model, resolves the requested public model alias through a registry, and forwards the request to a selected provider adapter.
Core components:
cmd/llm-gatewayloads configuration and wires the server.internal/httpapihandles auth, request parsing, routing, retry/failover, and response encoding.internal/modelsstores static aliases, dynamic discovery results, and weighted/sticky routing state.internal/provideradapts the internal protocol to Anthropic-compatible or OpenAI-compatible upstream APIs.internal/healthtracks provider readiness for/readyzand routing decisions.
Request flow:
client request
→ HTTP API handler
→ gateway auth and body limits
→ protocol normalization
→ model registry resolution
→ provider adapter
→ upstream LLM backend
→ protocol-specific response encoder
Streaming follows the same path, but provider adapters return internal stream events that the HTTP layer flushes as Anthropic or OpenAI SSE frames.
See docs/architecture.md for the full component map and request flow. See docs/reference/configuration.md for configuration fields, including provider setup, routing aliases, health checks, and transport options.
Client-to-gateway API key authentication is enabled by default because auth.disable defaults to false. You can disable it for local testing only:
{
"auth": {
"disable": true
}
}When this is enabled, the gateway logs a warning at startup. Do not use this in production: anyone who can reach the gateway can call your configured provider backends and spend your provider credentials.
Point an Anthropic-compatible client at the gateway base URL:
ANTHROPIC_BASE_URL=http://127.0.0.1:8080/v1
ANTHROPIC_AUTH_TOKEN=$LLM_GATEWAY_API_KEYFor Claude Code, you can also configure ~/.claude/settings.json to call this gateway instead of a provider directly:
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:8080/v1",
"ANTHROPIC_AUTH_TOKEN": "${LLM_GATEWAY_API_KEY}",
"ANTHROPIC_MODEL": "code-main",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "code-fast",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "code-main",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "code-large"
}
}Use any configured gateway model alias for ANTHROPIC_MODEL, such as code-main, code-fast, or code-large.
Point an OpenAI-compatible client at the gateway base URL:
OPENAI_BASE_URL=http://127.0.0.1:8080/v1
OPENAI_API_KEY=$LLM_GATEWAY_API_KEYcurl http://127.0.0.1:8080/v1/models \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY"curl http://127.0.0.1:8080/v1/chat/completions \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-main","messages":[{"role":"user","content":"hello"}]}'curl http://127.0.0.1:8080/v1/messages \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet","max_tokens":256,"messages":[{"role":"user","content":"hello"}]}'Streaming:
curl -N http://127.0.0.1:8080/v1/chat/completions \
-H "Authorization: Bearer $LLM_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-main","stream":true,"messages":[{"role":"user","content":"hello"}]}'- One long-lived HTTP client is created per provider.
- Provider transports are configured with high idle connection limits for concurrent gateway traffic; tune per provider with
transport.max_idle_conns,transport.max_idle_conns_per_host, and timeout fields. - Model routing is O(1) through a precomputed registry snapshot.
- Streaming requests flush SSE events and cancel upstream calls when the client disconnects.
- Prompt bodies are not logged by default.