Skip to content

Kaeso 0.3.0. Released 21 October 2026, with 96 changes.

Released
Changes
96 changes
In this release
Added, Changed, Fixed and Security
The release on GitHub (opens in a new tab)

Kaeso 0.3.0 adds six built-in providers, so DeepSeek, SpaceX (xAI's API), Together AI, Groq, OpenRouter and Mistral can be added with a key and called from any app format. It tightens access: only owners transfer ownership, single sign-on admits only linked accounts and verified email domains, and forwarded addresses are trusted only from loopback by default. Five changes need action when you upgrade, listed under breaking, and most of the rest make requests, streams, budgets and the console faster or more accurate.

  • Breaking: Only owners can transfer ownership: custom roles and individual grants lose the right, and the content logging right is renamed logs.content.manage, so grant it again where people switch content logging. (#229 (opens in a new tab))
  • Breaking: The gateway trusts X-Forwarded-For only from loopback by default. Set KAESO_TRUSTED_PROXIES when a reverse proxy sits outside the Compose package, or every client shares the proxy's address in logs and throttles. (#247 (opens in a new tab))
  • Breaking: Single sign-on signs in only accounts linked to the organization's identity provider. Existing members whose accounts predate their organization's single sign-on must link them once under Account, Security. (#252 (opens in a new tab))
  • Breaking: Single sign-on admits only email domains the organization has verified with a DNS TXT record. Publish the record and choose Verify domains under Security before relying on single sign-on after upgrading. (#264 (opens in a new tab))
  • Breaking: Single sign-on no longer trusts private-network identity providers by default, so set KAESO_AUTH_OIDC_ALLOW_PRIVATE_NETWORKS to true for one. Turn off required verified addresses only for providers that never send the claim. (#270 (opens in a new tab))

Contributors: @dvnold

Full changes: v0.2.2...v0.3.0 (opens in a new tab)

Added

UI library

  • The console draws a provider's own mark wherever it names the provider, and the providers added in this release have marks of their own. (#216 (opens in a new tab))
  • The UI library adds CommandList, a searchable list that stays fast with thousands of rows, and ProviderPicker and ModelPicker are built on it. (#257 (opens in a new tab))

Documentation

  • The documentation explains how providers work in one concept page, and adds a supported providers page that lists each provider's formats, host and where its keys come from. (#217 (opens in a new tab))

Changed

  • The console no longer reloads every loaded page of a long list when the window regains focus, and a change under an organization no longer reloads every list inside it. (#221 (opens in a new tab))
  • Provider logos follow each provider's brand guidelines in one colour per theme, and Anthropic and Groq show a letter where their terms don't allow the logo in an interface. (#223 (opens in a new tab))
  • A request for a model the provider no longer serves is refused locally with the same 404, and the provider is asked again only once the last answer is five minutes old. (#228 (opens in a new tab))
  • The console asks the gateway for less: one list per resource, no lookups one at a time, and a live request log that keeps up with bursts of more than 100 requests. (#233 (opens in a new tab))
  • The gateway keeps serving from its caches while it cannot hear Valkey invalidations, and concurrent misses share one load instead of each querying PostgreSQL. (#235 (opens in a new tab))
  • Large and long requests use less memory and CPU, because the gateway shares one copy of each request and translates large bodies off its async worker threads. (#236 (opens in a new tab))
  • Every console page lines up on one edge, and boxes start and end on the gutter with their text 12 pixels further in, on phones as well as desktops. (#237 (opens in a new tab))
  • Limit checks no longer wait behind large cache reads and writes on Valkey, because bulk transfers use their own connections. (#242 (opens in a new tab))
  • When a provider refuses the project's provider key, apps get a 502 provider error without the key details, and the provider's reason is kept, redacted, in the request log. (#244 (opens in a new tab))
  • The gateway trusts X-Forwarded-For only from loopback by default, so set KAESO_TRUSTED_PROXIES for a reverse proxy outside the Compose package. (#247 (opens in a new tab))
  • Every model and provider choice in the console is searchable and grouped, and the Providers page lists only the providers the organization has keys for. (#258 (opens in a new tab))
  • The key dialog links each provider's API key page, and Add models warns when a provider has no key yet or when a bulk add would be large. (#259 (opens in a new tab))
  • The key dialog opens SpaceX's API keys page directly, and it links Mistral's key page with a hint that Mistral keys have no fixed prefix. (#275 (opens in a new tab))
  • Every built-in provider shows its own logo in the console, including Anthropic and Groq, and SpaceX's mark stays readable at small sizes. (#279 (opens in a new tab))
  • The console reads every provider's name, key page, key prefix and formats from the gateway's list, so providers the gateway adds appear without a console update. (#290 (opens in a new tab))

Gateway

  • Streams to one provider spread over several HTTP/2 connections, so hundreds of concurrent requests no longer queue behind one connection's stream limit. (#222 (opens in a new tab))
  • Model requests find their catalogue entry and each provider's record in constant time, however many models and providers are configured. (#224 (opens in a new tab), #230 (opens in a new tab))
  • The models.dev sync check reads only its timestamps and content hash on each run, instead of loading the whole stored snapshot every five minutes. (#225 (opens in a new tab))
  • A burst of requests that finds a lost budget counter rebuilds it from PostgreSQL once instead of once per request. (#251 (opens in a new tab))
  • A fresh install starts with the models and prices that models.dev listed at the release, 561 models across the providers Kaeso calls. (#316 (opens in a new tab))

KPP

  • Long tool loops from Chat Completions apps on Claude or the Responses API restore kept reasoning in one pass per request, so requests late in a conversation translate faster. (#227 (opens in a new tab))

Console

Documentation

  • The Release workflow can be re-run after a partial release, and it checks its release commit against an independent run of the version script before pushing only the tag. (#220 (opens in a new tab))
  • The published crates kaeso-kpp and kaeso-codecs are packaged, documented and checked for API breaks on every change, and the KPP decoders are fuzzed nightly. (#231 (opens in a new tab))
  • Code may carry a comment only where a careful reader would otherwise get it wrong, such as a workaround or a security invariant, and CI rejects leftover task notes in comments. (#254 (opens in a new tab))

Self-hosting

  • Release images ship a gateway binary built with link-time optimisation, which is 28 percent smaller; local builds and CI keep the faster release profile. (#273 (opens in a new tab))

Fixed

  • Anthropic-format streams no longer fail when an OpenAI-compatible provider sends running usage on every chunk, as vLLM-based providers do. (#219 (opens in a new tab))
  • Hard budgets and token rates reserve a worst case for each concurrent request, so a burst of expensive requests cannot overrun them, and a long stream keeps its reservation. (#232 (opens in a new tab))
  • Replies and streams that finish without usage are charged an estimate instead of nothing, and the request log marks the usage as estimated. (#238 (opens in a new tab))
  • Tool calls and errors from OpenAI-compatible providers are no longer dropped, merged or taken for a finished reply, and non-object tool arguments are refused for Anthropic apps instead of changed. (#246 (opens in a new tab))
  • Project pages say when their keys, members, service accounts or limits could not load, instead of showing an empty list. (#248 (opens in a new tab))
  • Writes to Anthropic's one-hour prompt cache are charged at their own price, twice the input price, instead of the five-minute price. (#249 (opens in a new tab))
  • A revoked API key or ended session stops working at once across instances, and shared cache entries are signed with a key derived from the master key, so planted entries are ignored. (#250 (opens in a new tab))
  • A stream error from a provider stops the provider request, so it no longer keeps generating and charging after the error is reported. (#253 (opens in a new tab))
  • Replies from OpenAI-compatible providers with unusual usage, ids or finish reasons reach every app intact, and a stream that ends before its finish is reported as an error. (#256 (opens in a new tab))
  • Release links are https only, request logs no longer load remote images, and the docs and showcase send strict transport security, nosniff and a referrer policy. (#263 (opens in a new tab))
  • Responses streams whose text or tool arguments arrive only in their final events reach apps in other formats instead of an empty reply. (#267 (opens in a new tab))
  • Server-sent events whose first field name starts with a byte order mark are written so that they read back the same. (#268 (opens in a new tab))
  • Shutdown closes connections still open after the grace period, startup retries an unreachable PostgreSQL, and log and usage writes no longer lose rows. (#269 (opens in a new tab))
  • Three earlier changes that later merges had undone are back in place: Chat reply translation, key safeguards and signed cache entries. (#276 (opens in a new tab))
  • DeepSeek stops at the output limit apps in every format send, because its chat profile now uses max_tokens, and budgets hold enough for SpaceX reasoning. (#278 (opens in a new tab))
  • Reasoning from DeepSeek, Groq, Together AI, OpenRouter and SpaceX reaches Anthropic and Responses apps and the Playground, and the request log stores it as reasoning rather than raw blocks. (#283 (opens in a new tab))
  • The Playground refuses a model the provider does not serve with the same 404 and message as the model API, and the request log shows that message from the first failure. (#288 (opens in a new tab))
  • Finished Playground replies no longer show up as 499 errors, and a failed or cut-off reply says why in its column. (#289 (opens in a new tab))
  • Certificate checks no longer trust the distrusted emSign roots and intermediates, as the advisories against the certificate stack require. (#293 (opens in a new tab))
  • OpenRouter errors carry the upstream provider's reason, such as a shared rate limit, to Anthropic and Responses apps and the request log, instead of only Provider returned error. (#294 (opens in a new tab))
  • Request log messages appear in the person's language, with backtick spans set as code, and the request sheet states each outcome once. (#295 (opens in a new tab))
  • Account pages explain why an organization's only owner cannot leave, order sessions by last use with readable client names, and describe two-factor authentication the same way everywhere. (#297 (opens in a new tab))
  • Numbers, dates, context sizes and prices read the same way across the console, in English, German and Chinese. (#298 (opens in a new tab))
  • Members and projects can be searched, archived items have their own tab, and inviting people keeps the address that was typed. (#299 (opens in a new tab))
  • The model picker filters by provider at any number of providers, opens with an empty search, and greys out models the provider does not serve. (#300 (opens in a new tab))
  • Single sign-on shows the sign-in callback to register before a connection exists, each domain's verification state, and why it cannot be required yet. (#302 (opens in a new tab))
  • Audit logs name every action and target in words, show the time zone, and keep the target column readable at every width. (#303 (opens in a new tab))
  • The Playground keeps its conversation while the tab is open, Clear can be undone, and replies show tokens and costs in the same form as the request logs. (#304 (opens in a new tab))
  • Add models shows prices, how many models match, and exactly how many Add every current would add, and the Models page shows each provider's logo once per group. (#305 (opens in a new tab))
  • Instance admins see each user's organizations and can reopen What's new, and the instance pages show dates, badges and update states that make sense. (#309 (opens in a new tab))
  • Enter confirms text in an input method without submitting a dialog, and Enter in a search field inside a dialog keeps filtering. (#311 (opens in a new tab))
  • The Providers page keeps a search's result when a refresh fails and explains why the first key cannot be added, and folded values are labelled for screen readers. (#312 (opens in a new tab))
  • Inviting people stops at an invalid address still being typed, splits a pasted row of addresses into one tag each, and keeps focus after a role change. (#313 (opens in a new tab))
  • Step dialogs keep what was typed when someone clicks outside them, and confirmations opened over a sheet dim the page behind them. (#315 (opens in a new tab))
  • Copyable values show in full, Enter submits dialogs, field edges reach 3 to 1 contrast, and sheets keep their content while they close. (#280 (opens in a new tab))
  • Provider keys name their provider in dialogs and menus, the providers list keeps every detail on narrow screens, and large organizations can search it. (#282 (opens in a new tab))
  • Usage charts name each UTC day by its own date in every time zone and mark the period that is still running. (#284 (opens in a new tab))
  • The request log keeps the model and provider readable at every width, and its model filter follows the chosen provider. (#285 (opens in a new tab))
  • Sign-in shows a wrong password under the field, opens the app when you are already signed in, and carries your address into a password reset. (#286 (opens in a new tab))

Console

  • Console pages line up on the gutter and show their shape while they load, and request logs fit a phone with the Status header shown whole. (#239 (opens in a new tab), #240 (opens in a new tab))
  • The sign-in page loads about 2 kB less JavaScript before its first paint, which keeps it inside its size budget. (#272 (opens in a new tab))
  • The playground's controls are translated in the console's development server, as they already are in the production build. (#287 (opens in a new tab))
  • The command palette searches the organization's projects, members and keys on its pages, and recent requests show their project and time to tell them apart. (#306 (opens in a new tab))
  • Organization pages show each provider's own name, order and formats from the first frame instead of briefly showing raw ids. (#314 (opens in a new tab))

UI library

  • Tables, lists, date presets and form errors work with a keyboard and a screen reader, and selected rows and menu hints meet contrast requirements. (#261 (opens in a new tab))
  • Charts that show a loading state first draw once their data arrives, so the overview's Requests chart no longer stays empty. (#277 (opens in a new tab))
  • Checkbox and radio edges reach 3 to 1 contrast in light and dark mode, the same as field edges. (#307 (opens in a new tab))
  • Closing a sheet whose row has gone no longer takes the focus from a dialog opened meanwhile. (#318 (opens in a new tab))

Documentation

  • The requirements page lists every host an install connects to, and the quick start creates the master key with the release's gateway image. (#243 (opens in a new tab))

Security

  • Each release's compose file pins the Kaeso images by digest, and manual upgrades can verify them with gh attestation verify. (#218 (opens in a new tab))
  • The updater refuses to create a container with more rights than the one it replaces, and it pulls only Kaeso images by digest. (#226 (opens in a new tab))
  • Only owners can transfer ownership, custom roles and grants can no longer include that right, and the content logging right is renamed logs.content.manage. (#229 (opens in a new tab))
  • Caddy and the updater run unprivileged, the databases drop their Linux capabilities, and every service has memory, process and log limits. (#234 (opens in a new tab))
  • Single sign-on signs in only accounts linked to the organization's identity provider, and existing members link their account once under Account, Security. (#252 (opens in a new tab))
  • Sign-in links ask for the second factor, account changes need a code, and email changes can be cancelled from the old address. (#255 (opens in a new tab))
  • Only a person re-enables a key that a person disabled, keys cannot create platform-access keys, and instance admin changes to people need a recent sign-in. (#262 (opens in a new tab))
  • Single sign-on admits only addresses at email domains the organization has verified with a DNS TXT record. (#264 (opens in a new tab))
  • Single sign-on refuses link-local and cloud metadata addresses, issuers with queries, reuse of a stored secret for a changed issuer, and unverified email addresses, and private networks are off by default. (#270 (opens in a new tab))
  • The sign-in page shows its own message for an SSO failure instead of text taken from the address, so a crafted link cannot show arbitrary text. (#271 (opens in a new tab))
  • Advisories against the certificate stack are resolved, so the gateway rejects certificates chained through distrusted emSign intermediates. (#292 (opens in a new tab))

More releases