v0.9.0
Released October 21, 2026. Supported until April 21, 2027.
v0.9.0 ships 30 behavior changes, 6 security updates, 42 new features, 24 bug fixes, and 3 deprecations. Most of the gateway changes take effect once a data plane is on 0.9.0: an exhausted project budget and the project and system token rate limits cover every key of a project, including an application's first calls, a data plane left with no project gateways refuses requests, and request logs no longer carry credential headers. Audit records name the signed-in person behind a console change. Some data planes are checked before they are upgraded, and an installation that sets otelGateway.serviceAccount.create to false without a service account name fails to upgrade (Upgrading to 0.9.0). Behavior between the management plane and the data plane changed in this release. The most severe security issue cleared is high.
A fully detailed version of these release notes (including artifact versions) is included in the Admin Console.
The full release notes are opened from the Admin Console, as described in Check the management plane version.
Upgrade and rollback
- The release carries no breaking change. 38 changes name operator steps of their own, given with each change in the full release notes in the Admin Console.
- The upgrade rolls through without dropping traffic.
- Rollback to v0.8.1 is unconditional.
Behavior changes
Consoles
Legacy Bring Your Own Key (BYOK) lists now show only active keys, leaving out revoked keys and keys with a pending rotation.
Removing a project-scoped BYOK key revokes it in its own project and keeps the configured routing weights and order of the remaining keys. Project owners can remove shared BYOK keys that other members created in the Developer Console.
The seed-signin-info script writes through the management plane API and keeps earlier sign-in versions instead of replacing them. It reads VALET_URL and VALET_TOKEN (an admin credential) instead of DATABASE_URL.
Alert destinations now belong to a customer, not only to a workspace name. On upgrade, a destination whose workspace name was ever reused, matches no live workspace, or is held by more than one cannot be attributed: it stops being listed, edited, and receiving alerts, though nothing is deleted. Each workspace's Alert Destinations page is checked after the upgrade, and anything missing is recreated under the workspace that should own it.
The Developer Console's landing page is now called Home and lives at /home. Links to /dashboard redirect there.
The app switcher in each console is now a single button that opens the other console in the same tab. In the Developer Console it appears only for users with an organization-level permission; other project admins open the Admin Console by its address.
Gateway
A data plane that has ever hosted a project gateway refuses requests, with no_gateways, once it has none left, including after a restart. Each such data plane is given a gateway for the projects it should serve before it is upgraded (Upgrading to 0.9.0). Available once the data plane is on 0.9.0 or later.
An exhausted project budget now stops every key of the project, or moves it to the budget's fallback model, including a key created since the last budget refresh, such as an application's first calls. Projects with an exhausted budget are checked before the data plane is upgraded. Available once the data plane is on 0.9.0 or later.
A project or system token rate limit now also covers API keys that have no route of their own yet, including an application's first calls and calls that fail over to a fallback model. It is on by default, and setting POLICY_PROJECT_RATE_LIMIT_ENABLED to false on the management plane turns it off. Each key counts against the full limit separately, a key that calls both ordinary and fallback models can reach twice the limit per hour, and each data plane counts on its own. Available once the data plane is on 0.9.0 or later.
With Request Logs set to Metadata only, the management plane receives a fixed set of fields: request ID, user, API key ID and name, resolved model, endpoint, hostname, status, latency, token counts, cost, the routing response headers, and the data plane's budget, fallback, rate limit, and attribute routing decisions. Request headers, request parameters, attribute values, the X-Title or User-Agent name, and the key prefix, hash, and address are no longer sent, so usage by calling application shows these requests as unknown; Full keeps them. See Control request log data. Available once the data plane is on 0.9.0 or later.
For callers admitted with a project OIDC token whose sub is a valid email address, Request Logs, metrics, and traces record a stable digest of that address as the user instead of the address itself: e_ followed by the first 24 hex characters of its SHA-256. An opaque sub is recorded as o_ followed by its unpadded base64url value. Available once the data plane is on 0.9.0 or later.
Management plane API
Saving fallback chain entries requires enabled models and providers. A project or API key policy is also limited to the project's assigned models when the project has assignments, and an API key policy needs a live project on its client group. Organization-wide policies need no assignments.
Audit records for changes made through the Developer Console, and for Admin Console calls that send X-Acting-Session-Token, now name the signed-in user and their email instead of the console's service key, whose ID moves to metadata.via_key. Audit log filters and SIEM rules that match a console's key ID on the user field move to metadata.via_key.
Granting or revoking super_admin now fails with Internal, and changes nothing, when its audit record cannot be written. The audit_write_failures_total metric counts those failures.
An audit record is now written in the same transaction as the change it records, so a change that fails or is refused leaves one record with success set to false. Changes made through the workspace API are audited too.
The Developer Console no longer writes its own audit records for key rotation, management key creation and deletion, and project telemetry changes. The server's ROTATE_CLIENT_KEY, ISSUE_MY_KEY, REVOKE_MY_KEY, CREATE_TELEMETRY_CONFIG, and UPDATE_TELEMETRY_CONFIG records cover them, so filters on telemetry.project_config.set and telemetry.project_config.disable move to the new action names. A data plane upgrade outcome is now one FINISH_DATAPLANE_UPGRADE record, with the final phase in metadata.phase. See Changes in 0.9.0.
An Admin Console change that the server also audits leaves two records, the console's and the server's, and both now name the signed-in user. To count each change once, the records that carry metadata.via_key and the server's action names, such as UPDATE_DATAPLANE, are kept.
Audit records of Developer Console calls now carry the browser's user_agent, and the X-Forwarded-For chain the console received, in metadata.forwarded_for. source_ip stays the console's address, and metadata.forwarded_for is only as trustworthy as the ingress in front of the console.
Removing a provider from a project's allow-list fails with FAILED_PRECONDITION while the project still has models from that provider, so those models are unassigned first.
Existing metrics_reader keys can now read their organization's usage per user, team, or API key. Removing metrics_reader from a key that must not see that usage also removes its access to the metrics API, which needs the same grant.
A fallback policy saved before retry conditions were configurable now reads back the five conditions the gateway applies to it, timeout,rate-limit,server-error,connect-failure,overloaded, instead of its stored retry_on. Saving that value back keeps the same retries, and a change to retry_on now takes effect for such a policy.
An API key's client that was created without a project now belongs to its key's project once a fallback or traffic split policy of the key is saved, so it is then listed only in that project, not in every project.
Traffic split policies now read back with entries as well as split. An update that sends both keeps whichever differs from the saved policy, and one that changes both so they disagree is refused.
Listing fallback or traffic split policies without a target now also returns the per-key policies saved in the Developer Console, so the Admin Console's Fallback Policies page shows them too. That page does not load with more than 5,000 fallback policies, and target_scope_types on a list call leaves per-key policies out.
Saving a per-key fallback policy, or turning one back on, is refused when one of its models, or that model's provider, is not available to the key's project. Keys in the default project are not limited this way.
Adding or removing a provider on a project's allow-list through the API now needs the project provider permission, which Project Owner and Super Admin hold, as the Admin Console already required. Provider Admin, Model Admin, and custom roles with only the providers permissions no longer give it.
UpdateApiKey called without user_id for a key that does not exist now returns NotFound or a field error, where it returned InvalidArgument with the message user_id is required.
Observability
Metrics a data plane pushes over OTLP (router_*, Envoy stats, and gen_ai_*) now carry service.instance.id, k8s.pod.name, and k8s.namespace.name, so each replica writes its own series, including at backends.custom[] destinations. Before the upgrade, the metrics backend's per-metric series limits are checked to allow one series per egress replica, plus a temporary doubling while pods roll; Tetrate-managed observability already allows for this. Dashboards and alerts on these metrics are then re-baselined: rates drop because false counter resets no longer inflate them, and gauges, now per pod, are summed or maxed across pods.
With the metrics signal on, the data plane chart adds a ClusterRole that lets the otel-gateway service account get, list, and watch pods in every namespace, to identify the pod behind each pushed metric. An installation that sets otelGateway.serviceAccount.create to false now fails to upgrade unless otelGateway.serviceAccount.name names an existing service account, where it fell back to the namespace's default service account before.
Alert events now record the customer they were raised for, decided when the report is ingested rather than when the alert is delivered. On upgrade, a pending alert whose workspace name was reused or removed is never delivered, and the underlying problem raises a fresh alert on the next doctor report. A report for a workspace name held by more than one live workspace raises no alerts until the name clash is resolved.
Security updates
Management plane API
Revoking a BYOK key now also tries to remove its stored provider secret, and a failed cleanup does not stop the revocation.
Open OAuth client registration (/oauth/register) is now bounded: 10 clients an hour per source and 300 per replica, with a 429 and Retry-After beyond that, request bodies capped at 16 KB, and clients deleted that never complete an authorization within a day or go unused for 90 days. The in-app limit is per replica and keyed on forwarded headers, so per-IP blocking for /oauth/register belongs at the WAF or gateway in front of it.
The project Model Context Protocol (MCP) OAuth client operations no longer read or change the OAuth clients set up in the Admin Console, which every project signs in through; those are managed only through the new shared-client operations. Changing the token or authorization URL of an OAuth client that has a client secret now requires the secret in the same request.
Gateway
Request logs sent to the management plane no longer include credential headers such as Authorization, Cookie, Set-Cookie or x-api-key, in any mode. Available once the data plane is on 0.9.0 or later.
With the default rate limit image, the gateway's rate limit server now requires a client certificate signed by the Envoy Gateway CA, where it accepted connections without one. Values that set the rate limit deployment's container env, and callers other than the gateway, need a change before the upgrade (Upgrading to 0.9.0).
The gateway and the MCP profiles API now pick a server's OAuth client by the same rule as the Developer Console: the profile's project first, then the clients set up in the Admin Console. The gateway sends a user's token only when it was issued through that client, so a user asked to authorize again signs in again from the project the calls are made in.
New features
Consoles
Administrators can edit or clear a tag's description from the Tags tab.
Workspace members can manage their own alert destinations from a new Alert Destinations page, adding, editing, and testing Slack channels and generic webhook receivers without an administrator. The page needs the new alert destination permissions, and a secret is stored when saved and never shown again.
Audit Logs record calls the management plane refuses for missing permissions on the identity, tenancy, API key, AI key, model catalog, MCP, RBAC, and Developer Console request log APIs, with action AUTHORIZATION_DENIED, the caller, the operation, and the customer the call named. Refusals on other endpoints are not recorded yet.
Management plane API
GET /v1/policy/api-key-ids lists the IDs of API keys that carry a tag, or of keys with no tags (untagged=true), and POST /v1/policy/api-key-tags/lookup returns the tags on up to 200 keys in one call.
GET /v1/api-keys takes project_id and application_keys_only filters, and each key now says whether it serves an application, so an application's key can be found and disabled to stop that application.
The owner of an API key can set and turn off the fallback and traffic split policies of that key, without a project role.
Traffic split policies can target one API key and hold one weighted split for each primary model in the new entries field. A per-key split is refused when a model or its provider is not available to the key's project, except in the default project.
User directory responses include the team name alongside its ID, without a separate team lookup.
The MCP catalog operations accept a platform MCP role, so a platform admin can manage the catalog without full admin rights, and a customer's admins can list the enabled catalog servers. Deleting or disabling a catalog server can now be refused while profiles or projects still use it.
A new operation returns the OAuth client that signs a project in to an MCP catalog server: the project's own client, or else the shared one from the Admin Console.
Project admins can add and remove the providers on their own project's allow-list.
Platform admins can manage the Admin Console's shared MCP OAuth clients through the API, and complete a sign-in through one, which returns only an access token. A project client can no longer share a provider with a shared client.
GetSystemSetting takes an optional include_config_event flag for guardrails.enabled, which returns the status of the latest push of that setting to the data planes in the last 24 hours.
A call made with an admin key can name the signed-in person behind it in the X-Audit-Session-Token header, and the audit record then names that person and their email. The header grants no access.
Audit log queries accept search, a case-insensitive match over the actor's email, user ID, and type, the action, the resource type and ID, the correlation ID, the endpoint, the source IP, and the error message, and order_by, which sorts by actor, action, resource, source, or outcome.
Announcements and sign-in page content can be managed through the API, and the published content can be read without signing in. Managing the versions needs the admin scope or one of the new Platform Content Creator, Editor, or Deleter roles.
Administrators can list, export, create, edit, deactivate, and import email domain policies through the API. The API answers only a signed-in administrator, and only where bonus claims are on: ENABLE_BONUS_CLAIM set to "true" on the management plane API, with corporate login off.
The owner of an API key can read and change the key's global fallback and token rate limit through the API. The settings apply to every key of the key's client, and each change is audited.
GET /v1/usage/stats reads an organization's usage over time, with distinct users, per user, team or API key.
GET /v1/me/usage/stats reads the caller's own usage over time, per API key, filtered by key or project.
SSO providers now carry scopes, attribute mapping, the discovery URL, and the organization name and slug, and RegisterSSOProvider creates a provider without overwriting one. For organization administrators of a single-customer deployment to manage SSO, RBAC_AUTH_DB_MODE is set to single in global.env.common, not only in auth.env.
CreateOrUpdateSSOProvider takes validate_config, which refuses, without saving, a role mapping with an unknown role, a SAML role sync that cannot work, or IdP client credentials that the IdP refuses. An IdP inside a private network needs ALLOW_PRIVATE_OIDC_DISCOVERY set to "true" on the api chart; the Admin Console setting of the same name does not apply to these checks.
Admins can set a user's role with POST /v1/users/{user_id}/role. The change applies at once, and any change other than a promotion to a higher level signs the user out.
GET /v1/me/projects now returns member_role on each project: the caller's own role as a member of that project, empty when the project is visible without membership.
An administrator can disable or re-enable one application's API key by sending the key ID alone to UpdateApiKey.
Request log statistics can be grouped by caller_type, which separates identity provider callers from API key callers, and by application, which shows each application's usage under its key's current name. A management plane earlier than 0.9.0 rejects these group_by values with InvalidArgument.
Each request log carries caller_type (idp for an identity provider application, api_key for any other caller), and QueryRequestLogs and GetRequestLogStats take a caller_type filter with the same values. A management plane earlier than 0.9.0 ignores the filter and returns every caller's requests.
Data planes now carry stored_url, the URL stored for the data plane, and the new ClearSystemSetting unsets the proxy URL setting or one data plane's stored URL. Both are deprecated in this release.
EnsureDefaultProject creates an organization's default project, when it does not exist yet, with the enabled providers, MCP servers, and models, and returns it. An existing default project is returned unchanged, so an emptied allow-list stays empty.
Projects now carry preferred_endpoint_url, the address a project owner starred, as tenancy.v1 projects do.
ListDataplaneURLs accepts project_id, customer_id, and include_unaddressed. Each entry now lists every address it answers on and its source, whether the data plane has called home, the data plane or project gateway it is for, and the gateway's attachment state.
Project owners can choose the endpoint the consoles show for a project with SetPreferredEndpoint. Projects now carry public_endpoint_url and preferred_endpoint_url.
SDK
The Go, Python and TypeScript SDKs now include a client for gateway authentication policies and their identity-mapping rules.
The Go, Python, and TypeScript SDKs now include a client for budget, rate limit, fallback, traffic split, and attribute routing policies, user groups, and API key tags, as Policy() in Go and policy in Python and TypeScript.
Gateway
The data plane's Controller exports liaison_finalizer_cleanup_abandoned_total, counting deleted routes whose cleanup gave up and may have left resources behind, and liaison_finalizer_cleanup_retries_total for cleanups it is retrying.
The data plane can keep chosen x-tars- request headers, listed in REQUEST_LOG_EXPORT_HEADERS, in the request log, so a caller's attribution headers reach usage reporting. The data plane reads the list once at startup, and a name that could carry an identity provider token is removed from the log. Available once the data plane is on 0.9.0 or later.
CLI
tetrate agentrouter api mcp catalog list-available lists the MCP catalog servers available to a customer.
tetrate agentrouter api mcp catalog oauth-client shows the OAuth client that serves an MCP catalog server in a project.
tetrate agentrouter api projects mine now takes --page-size and --page-token, so pages after the first can be fetched.
The tetrate agentrouter api list commands that return results in pages, such as projects list, customers list, and the policy and guardrails list commands, now take --page-size and --page-token.
Observability
Data plane health findings can raise alerts to a workspace's Slack channels or webhook receivers, routed by whether the finding pages or only notifies. Alerting is off by default and is turned on with ALERTING_ENABLED; the first alerts cover whatever is wrong at that moment.
An alert now clears itself once its finding has been absent for 15 minutes and the cluster reports in again; a cluster that stops reporting keeps its alerts open. Destinations can also be PagerDuty, alongside Slack and webhook.
Bug fixes
Management plane
In a single-tenant deployment, a management plane restart or a role change on the Users page or at SSO sign-in no longer removes a user's platform billing, bonus claims, model and MCP roles.
With EVENT_REAPER_ENABLED on, a data plane that stops polling no longer collects configuration updates without limit. After EVENT_REAPER_STALE_PENDING_RETENTION (default 7 days) only the newest update per item is kept, and the data plane still gets current configuration when it reconnects.
Gateway
An application that calls with a token from its identity provider is now held to its key and project rate limits after it gets its own route, where those limits stopped holding a few seconds after its first call. Available once the data plane is on 0.9.0 or later.
Requests to /v1/messages served by an OpenAI-schema model now report and bill cached prompt tokens at the cached rate. Before, they were billed at the full input rate, and streamed requests could record no input tokens at all.
A fresh data plane install with multiple AI Gateway controller replicas no longer restarts some of them during startup.
A route rollout on a busy data plane no longer fails and retries with "no AIGatewayRoutes found for deployed route", which tetrate agentrouter doctor reported as a route deployment with no routes.
Metadata-only trace export now keeps the OpenTelemetry GenAI attributes: operation, provider, request and response model, and token usage.
Deleting or disabling an API key now reliably removes its routing from the data plane, where a racing routing update could restore it. Such leftovers now raise a RoutesDrifted warning.
A route rollout no longer leaves the previous rollout's retry policies behind on the data plane when one of its routes was already removed, and no longer logs "failed to delete AIGatewayRoute … not found" for it.
The rate_limit_exceeded reply on a key's first calls, before the key's own limits reach the data plane, now names the project or system rate limit policy, where rate_limit was null.
A request no longer fails with an empty 500 in the few seconds after its API key gets a route of its own, which every token caller goes through shortly after its first call.
Management plane API
Listing policies by target_key_id finds the per-key fallback and traffic split policies saved in the Developer Console, and those of a disabled key. The first per-key fallback policy saved through the API no longer fails for a key that never had one.
These changes are now audited: data plane changes made through the workspace API, guardrail pattern and fallback-policy changes, refused gateway attaches, data plane upgrade outcomes, and the data plane URL, token revocations and MCP catalog entries a data plane writes.
The warning for a gateway with no URL no longer says the gateway serves nothing. It now says the gateway serves through the catch-all while it is the only gateway on its data plane, and stops serving once another gateway joins.
One API key name longer than 50 characters no longer makes the hourly usage rollup fail for every key in that hour.
CLI
The doctor's scheduled health check no longer runs out of memory on a data plane with a few hundred API keys, which stopped every run partway and left the Admin Console showing the last report. The job is now capped at 1Gi of memory instead of 512Mi (tareDoctor.resources in the data plane's values), and the check reports the keys it could not check instead of counting them as healthy.
tetrate agentrouter doctor now also catches a container that was OOMKilled and has since restarted, where it caught only one still in the killed state. Such a kill stops being reported an hour later, and OOMKilled and CrashLoopBackOff are reported as tracked findings with a stable identity across runs.
Consoles
The Audit Logs page now loads quickly on a management plane with millions of audit records, where it could time out with "Couldn't load this page". The upgrade adds two indexes to audit_logs, and audit writes wait while they build, about a second per million records.
The sign-in page shows its default content when the published sign-in content cannot load, instead of an empty panel.
Agent apps that sign in through the Developer Console now get the URL of the oldest data plane that has one, not an empty URL when the oldest data plane has none.
Data plane
Removing BYOK keys that are already gone no longer makes the data plane rebuild every key's routes, and the periodic drift check no longer pauses configuration updates while it reconciles. The full resync on every sixth drift check (the default) can still pause them until it finishes.
Gateway authentication on a gateway that also serves an MCP server with its own OAuth, API key, or external auth now takes effect. It used to conflict with the MCP server's policy, apply to none of the gateway's routes, and show as Broken in tetrate agentrouter doctor; the MCP server's routes now keep their own auth, and gateway authentication covers the rest.
Helm charts
A management plane image tag given as a number, such as global.imageTag=123, now renders as that tag instead of an invalid image reference.
Observability
Changing the configuration of the data plane or management plane OpenTelemetry collector (otel-gateway) now restarts its pods, so the change takes effect. The collectors restart once during this upgrade, and with a single replica telemetry can be delayed for a few seconds.
Deprecations
Consoles
The seed-signin-info script is deprecated and is removed no earlier than 0.10, in favor of ContentService.CreateContentVersion and PublishContentVersion.
Management plane API
stored_url on data planes and ClearSystemSetting are deprecated and go with the stored data plane URL in a later release, replaced by listing each data plane's hostnames under global.gateway.hostnames in its serve-helm values (data plane 0.7 or later). See Declare a data plane's hostnames.
Auth
The auth service is deprecated and is removed no earlier than 0.11, as sign-in, SSO, sessions, and permissions move to the management API.
Known issues
Gateway
v0.9.0 does not carry two security updates from v0.7.2 and v0.8.1, which shipped after it: its Envoy proxies are exposed to the critical Brotli decoder vulnerability CVE-2026-111497, and its gateway and proxy images still trust the AAA Certificate Services and emSign ECC Root CA - G3 root certificates. An upgrade from v0.7.2 or v0.8.1 to v0.9.0 removes both fixes.