Appearance
Configuration Reference
See also: Oceans LLM Gateway, Runtime Bootstrap and Access, Model Routing and API Behavior, Pricing Catalog and Accounting, OIDC and SSO Status
This page owns config syntax and parse-time rules. It does not own the full runtime story after a request starts moving.
Source of Truth
- config parsing and validation:
- provider capability defaults:
- checked-in examples:
Top-Level Sections
serverdatabaseauthbudget_alertsrequest_loggingprovidersmodelsteamsusers
Value Sources
The config supports literal values and env references.
Common patterns:
literal.adminenv.OPENAI_API_KEYenv.POSTGRES_URL
The YAML holds structure. Secrets and deploy-specific values usually come from the environment.
Minimal Local Example
yaml
server:
bind: "127.0.0.1:8080"
database:
kind: libsql
path: "./var/oceans.db"
auth:
bootstrap_admin:
email: "admin@local"
password: "literal.admin"
require_password_change: false
providers:
- id: openai
type: openai_compat
base_url: "https://api.openai.com/v1"
pricing_provider_id: openai
auth:
kind: bearer
token: env.OPENAI_API_KEY
models:
- id: gpt-4o-mini
routes:
- provider: openai
upstream_model: gpt-4o-miniProduction-Shaped Example
yaml
server:
bind: "0.0.0.0:8080"
database:
kind: postgres
url: env.POSTGRES_URL
auth:
bootstrap_admin:
email: "admin@local"
password: env.GATEWAY_BOOTSTRAP_ADMIN_PASSWORD
require_password_change: true
seed_api_keys:
- name: "gateway"
value: env.GATEWAY_API_KEY
providers:
- id: vertex
type: gcp_vertex
project_id: env.GCP_PROJECT_ID
location: global
auth:
mode: service_account
credentials_path: env.GCP_SERVICE_ACCOUNT_JSON
teams:
- key: platform
name: Platform
budget:
cadence: monthly
amount_usd: "500.0000"
hard_limit: true
timezone: UTC
users:
- name: Platform Admin
email: ops@example.com
auth_mode: password
global_role: platform_admin
membership:
team: platform
role: admin
budget:
cadence: monthly
amount_usd: "100.0000"
hard_limit: true
timezone: UTC
models:
- id: gemini-2.0-flash
routes:
- provider: vertex
upstream_model: google/gemini-2.0-flashThe checked-in examples are opinionated. They are not the full config space.
Defaults That Matter
Important defaults from config parsing and domain deserialization:
- model
rankdefaults to100 - route
prioritydefaults to100 - route
weightdefaults to1.0 - route
enableddefaults totrue - route capability flags default to all enabled
- Vertex
locationdefaults toglobal - Vertex
api_hostdefaults toaiplatform.googleapis.com request_logging.payloads.capture_modedefaults toredacted_payloadsrequest_logging.payloads.request_max_bytesdefaults to65536request_logging.payloads.response_max_bytesdefaults to65536request_logging.payloads.stream_max_eventsdefaults to128
The startup meaning of bootstrap-admin and seeded API keys lives in runtime-bootstrap-and-access.md.
server
Important fields:
bindlog_formatotel_endpointotel_metrics_endpointotel_export_interval_secs
For collector assumptions and request-log implications, see observability-and-request-logs.md.
request_logging
request_logging.payloads controls chat-completion request-log payload persistence.
yaml
request_logging:
payloads:
capture_mode: redacted_payloads
request_max_bytes: 65536
response_max_bytes: 65536
stream_max_events: 128
redaction_paths: []Important fields:
capture_modedisabled: skip chat-completion request-log persistencesummary_only: write summary rows withhas_payload=falseand no payload rowredacted_payloads: write summary rows and sanitized payload rows
request_max_bytes: final persisted request payload budgetresponse_max_bytes: final persisted response payload budgetstream_max_events: maximum stored stream events; stream usage and error parsing still sees later framesredaction_paths: additive admin-configured redaction paths anchored from the wrapped payload root
Validation rules:
- byte limits must be greater than zero
stream_max_eventsmust be greater than zeroredaction_pathsuse dot-separated object keys plus*as a full-segment wildcard- malformed paths such as
body..messagesor indexed paths such asbody.messages[0]are rejected at config parse time
The runtime redaction/truncation policy and admin display behavior are owned by observability-and-request-logs.md.
database
The checked-in configs use two runtime shapes:
- local development:
- libsql or SQLite with
path
- libsql or SQLite with
- production-shaped and deploy flows:
- PostgreSQL with
kind: postgresandurl
- PostgreSQL with
Important fields:
kindlibsqlpostgres
path- libsql or SQLite database path
- defaults to
./gateway.db
url- PostgreSQL connection URL
- supports literal and env reference values
max_connections- PostgreSQL pool size
- defaults to
10
If kind is omitted, the gateway infers postgres when url is present and libsql otherwise. database.url is required when kind: postgres.
auth
Important fields:
seed_api_keysbootstrap_admin
Important distinctions:
seed_api_keyscreates data-plane accessbootstrap_admincreates control-plane accessbootstrap_admin.require_password_changechanges first-login behaviorbootstrap_admin.passwordmust beliteral.*orenv.*
For startup behavior and first access after boot, use runtime-bootstrap-and-access.md.
Declarative Teams And Users
teams and users extend the same startup seed path used for providers, models, and API keys.
Important teams fields:
keynamebudget
Important users fields:
nameemailauth_modeglobal_rolerequest_logging_enabledoidc_provider_keymembership.teammembership.rolebudget
Validation rules that matter:
- team keys must be unique
system-legacyis reserved and cannot be configured- user emails are normalized and must be unique
admin@localis reserved for the bootstrap adminusers[*].auth_modesupportspasswordandoidcoidc_provider_keyis required foroidcusers and rejected forpasswordusers- membership roles can be
adminormember - membership role
owneris rejected - budget amounts must be non-negative
Seed semantics that matter:
- listed teams are upserted by
teams[*].key - listed users are upserted by normalized email
- new config-seeded users are created as
invited - listed membership and active-budget state is reconciled for listed users and teams
- omitting a
budgetblock for a listed user or team deactivates that owner's active budget - unlisted teams and users are left untouched
OIDC provider existence is validated at seed time against enabled runtime OIDC providers, not YAML parse time.
budget_alerts
budget_alerts.email controls the background email dispatcher for threshold alerts created by budget enforcement and budget updates.
yaml
budget_alerts:
email:
from_email: alerts@example.com
from_name: "Oceans LLM"
poll_interval_secs: 30
batch_size: 25
transport:
kind: sinkImportant fields:
from_email- defaults to
alerts@local - cannot be empty
- defaults to
from_name- optional display name
poll_interval_secs- defaults to
30 - must be greater than zero
- defaults to
batch_size- defaults to
25 - must be greater than zero
- defaults to
transport.kindsink: persist alert delivery rows without sending emailsmtp: send through SMTP
SMTP transport fields:
hostport- defaults to
587
- defaults to
usernamepasswordstarttls- defaults to
true
- defaults to
username and password must be set together when SMTP authentication is used. password supports the same secret-reference forms as other config secrets.
Provider Types
Supported provider types in the checked-in configs:
openai_compatgcp_vertex
Provider Auth Modes
| Provider type | Auth field | Expected secret material |
|---|---|---|
openai_compat | auth.token | bearer-style token |
gcp_vertex | auth.mode: adc | ADC available in the runtime environment |
gcp_vertex | auth.mode: service_account | credentials_path pointing at service-account JSON or an equivalent mounted secret path |
openai_compat
Important fields:
idbase_urlpricing_provider_idauth.kindauth.token- optional
display.label - optional
display.icon_key
display.icon_key currently accepts the checked-in provider icon codes used by the admin UI:
openaiopenrouteranthropicawsvertexai
Validation rules that matter:
pricing_provider_idcannot be emptypricing_provider_idmust map to a supported internal pricing family
gcp_vertex
Important fields:
idproject_idlocationapi_hostauth.mode- optional
display.label - optional
display.icon_key
Routing and pricing caveats:
upstream_modelmust use<publisher>/<model_id>- pricing identity is inferred from the publisher prefix
- Anthropic-on-Vertex pricing is only supported for
location=global
Model Config
Configured gateway models are either:
- provider-backed models with
routes - alias-backed models with
alias_of
A model cannot be both.
Important fields:
iddescriptiontagsrankroutesalias_of
Route Config
Important fields:
providerupstream_modelpriorityweightenabledcapabilitiescompatibilityextra_headersextra_body
Capability flags default permissively. A route can constrain provider capability. It cannot expand provider truth.
Compatibility metadata is separate from capabilities. Capabilities decide whether a route may execute; compatibility describes explicit request and stream-shape transforms for the selected provider route.
Capability flags include API-family gates such as chat_completions, responses, and embeddings, plus feature gates such as stream, tools, vision, json_schema, and developer_role.
OpenAI-compatible route profile:
yaml
models:
- id: fast
routes:
- provider: openrouter
upstream_model: openai/gpt-4o-mini
compatibility:
openai_compat:
supports_store: false
max_tokens_field: max_tokens
developer_role: system
reasoning_effort: omit
supports_stream_usage: trueOpenAI-compatible profile defaults:
| Field | Default | Supported values |
|---|---|---|
supports_store | true | true, false |
max_tokens_field | max_completion_tokens | max_completion_tokens, max_tokens |
developer_role | developer | developer, system |
reasoning_effort | passthrough | passthrough, omit, reasoning_object |
supports_stream_usage | false | true, false |
The current openai_compat profile fields are Chat Completions transforms. /v1/responses is a separate supported API family and is not adapted by reusing Chat Completions compatibility shims.
Do not use extra_body for compatibility transforms. extra_body remains for additive provider-specific overrides, and the typed compatibility profile remains authoritative when a declared transform conflicts with an additive override.
Route Examples
OpenAI direct routes usually need no compatibility overrides:
yaml
models:
- id: openai-direct
routes:
- provider: openai-prod
upstream_model: gpt-5OpenAI-compatible aggregator routes should declare known Chat Completions quirks explicitly:
yaml
models:
- id: openrouter-fast
routes:
- provider: openrouter
upstream_model: openai/gpt-4o-mini
compatibility:
openai_compat:
supports_store: false
max_tokens_field: max_tokens
developer_role: system
reasoning_effort: omit
supports_stream_usage: trueVertex Google routes use the Vertex provider and a publisher-qualified upstream model:
yaml
models:
- id: gemini-fast
routes:
- provider: vertex-adc
upstream_model: google/gemini-2.0-flash
capabilities:
chat_completions: true
responses: false
embeddings: falseOpenAI-compatible embeddings-only routes should narrow route capability so chat and Responses requests fail early:
yaml
models:
- id: text-embedding
routes:
- provider: openai-prod
upstream_model: text-embedding-3-small
capabilities:
chat_completions: false
responses: false
embeddings: true
stream: falseValidation and Failure Boundaries
Config load catches several classes of failure up front:
- invalid or empty provider fields
- unsupported pricing-provider mappings
- invalid alias references
- invalid route or provider wiring
Later failures are usually runtime problems such as:
- request resolution failure
- missing providers
- capability mismatch
- exact-pricing gaps
Current Gaps
- Hardened SSO-backed identity matching is still deferred.
- Declarative teams, password users, development-style OIDC users, memberships, and active budgets are part of the current seed contract.
- The remaining SSO-backed reconciliation work is tracked in issue #65.
What This Page Does Not Own
- startup behavior and first access:
- request routing and
/v1/*behavior: - cross-cutting request cause and effect:
- spend windows and budget policy:
- hardened OIDC status: