The catalog repo
The catalog is open data in its own repository,wyolet/relay-catalog, separate from the engine. It is a tree of YAML under data/:
/catalog, so a fresh container boots with a populated catalog and no network fetch.
Because the data lives in its own repo, provider, model and pricing updates ship on their own schedule: you can move to a newer catalog without upgrading Relay.
Naming a model in a request
Themodel field of an inference request resolves against the catalog. These forms are accepted:
Names are normalized before lookup, so dotted and hyphenated forms match (
gpt-5.5 and gpt-5-5 are the same name). A dated snapshot name the model lists (for example gpt-4o-2024-08-06) selects that snapshot.
When a model has bindings on several hosts and you don’t pin one, Relay uses the first binding it finds that your policy grants and whose host has a usable host key in the policy. The order between hosts is not configurable, so pin a host when it matters, or grant only the host you want. Pin a host with @host in the model name, or send X-WR-Upstream-Host: <host>; Relay appends the header’s host to the model name unless the name already contains @. A pin limits routing to that host; it does not grant access the policy doesn’t give. See Policies for how grants are written.
GET /v1/models lists the models your credential can reach. GET /api/catalog/resolve?ref=<ref> on the control API shows what a policy grant such as anthropic@anthropic or @ollama-self expands to.
Model aliases
A model can declare aliases inspec.aliases: extra names that resolve to it. Aliases are checked last, after every catalog name and its provider- and host-qualified forms miss, so they never shadow a real model. An alias may contain one * after a literal prefix (claude-fable-5[*]). When a request matches an alias, Relay routes to the model and sends the name from the request upstream unchanged; this is how a client can send claude-fable-5[1m] to a provider that understands that suffix.
Aliases are lookup keys only: they are not valid in policy grants, and usage records the model’s catalog name. To add an alias to a catalog model without losing it on the next catalog update, use an overlay.
Ownership
Every row has an owner, and the owner decides who may change it.
Providers, hosts, models, host bindings and pricing are shared catalog data: no user, team or project owns one. Under
RELAY_AUTHZ=rbac, writing them takes the admin or catalog-editor role, and system-owned rows stay admin-only. Host keys, relay keys, policies and rate limits can belong to a tenant.
An API edit to a catalog row marks it dirty (metadata.dirty), and catalog upgrades skip dirty rows from then on. To change a catalog model and keep receiving upstream updates to the fields you did not touch, use an overlay instead.
Self-hosted upstreams (Ollama)
The catalog ships anollama-self host for an Ollama server you run, with noAuth: true and bindings for the models Ollama serves, but no base URL, so it is unroutable until you set one. As an admin, read the host and send it back with spec.baseURL set:
/v1/chat/completions for openai). A host whose endpoint differs from the shape’s default path can set spec.path; an explicit empty path means the base URL is the full endpoint.
A noAuth host needs no host key, and Relay sends no auth header to it. Because no host key gates it, a policy reaches it only through an explicit grant such as @ollama-self or <provider>/<model>@ollama-self; a policy with an empty model list does not cover it.
For any other OpenAI-compatible server, create your own Host with its baseURL (and noAuth: true if it takes no key), the Model rows, and a HostBinding per model with adapter: openai, through the control API or relay apply.
System rate limits
A few rate limits ship with Relay itself, not with the catalog:inference-api-proxy and inference-api-proxy-anonymous for proxy mode, and otlp-export for the OTLP receiver. See Rate limits for what each does and how to change it.
Editing the catalog locally
You can point Relay at a local clone of the catalog data instead of the bundled release, for example to add a provider or model the published catalog doesn’t have:Pinning a catalog version
To move between published catalog releases without rebuilding or remounting anything, setRELAY_CATALOG_VERSION to a relay-catalog release tag, or to latest to track the newest release compatible with your Relay version:
catalog-source settings section). If they differ, including on a fresh database, it seeds that release and updates the marker. The bundled tree is used when its version matches; otherwise the release is downloaded. Changing the variable and restarting is a catalog upgrade. latest is resolved again on every boot. Unset, the images seed their bundled /catalog once into an empty database; RELAY_CATALOG_VERSION=off disables version pinning.
Re-seeding preserves your changes:
- Rows you edited through the control API are marked dirty and skipped.
- Overlays are merged over the new catalog rows when the snapshot is rebuilt, so fields you did not override pick up the new release.
- Rows you created yourself are never touched.
metadata.catalogDetachedAt on it, and from then on the row is governed as yours: you can edit or delete it without changing the governance:* settings. Look for the field on API reads to find these rows and decide whether to keep, repoint or delete them. If a later release ships a row with the same name again, the upgrade clears the field and updates the row, unless you edited it, in which case it stays yours. Only a RELAY_CATALOG_VERSION upgrade sets or clears the field; POST /api/apply and API edits leave it as it is.
Releases are downloaded from https://catalog.wyolet.com by default and extracted only when they match the release’s published sha256; a mismatch or a missing checksum counts as a failed download. If the download fails and the database already has a catalog, Relay logs the failure and keeps serving the existing data, so an unreachable catalog server never blocks boot. Use RELAY_CATALOG_URL to fetch from a mirror in airgapped environments. Catalog server describes the HTTP layout releases are served from, how to point Relay and the Go SDK at another server, and how to run one.