Kaeso 0.2.0 lets self-hosted installs learn about new releases and, with the optional updater, apply them in one click. It also adds installs that sign in with single sign-on alone, CORS for browser apps, and model availability in the project catalogue. Requests that a provider or model would refuse, such as Anthropic Messages requests without max_tokens, are now refused before they are sent, so check any app that relied on Kaeso filling in the limit. The gateway no longer logs the setup link, the console no longer shows an API key's secret a second time, and the documentation is rewritten, with diagrams, code tabs and a changelog page.
- Breaking: Anthropic Messages requests without
max_tokensare now refused with 400, as Anthropic refuses them. Forced tool choice for Claude Fable 5.1, Opus 5.5 and Sonnet 5.5, and OpenAI Responses output limits below 16, are also refused before sending. Apps that relied on Kaeso filling in the output limit must sendmax_tokensthemselves. (#34 (opens in a new tab))
Contributors: @dvnold
Full changes: v0.1.0...v0.2.0 (opens in a new tab)
Added
Gateway
- Web apps can call the model API from a browser:
KAESO_CORS_ALLOWED_ORIGINSlists their origins, which then get CORS headers on/v1, preflights answered without a key, and readablekaeso-*andretry-afterheaders. Nothing changes while it is empty, the default, and*is refused. (#33 (opens in a new tab))
UI library
ThemeSelect, a select for the system, light or dark theme, with its label and choices in the provider's language, besideThemeMenu. The documentation site's sidebar now shows the same language and theme selects as the showcase. EveryThemeProvideron a page follows the same theme choice, so aThemeMenuorThemeSelectin one island changes the others too. (#25 (opens in a new tab))icons.updatein the UI library's icon vocabulary.
Documentation
- A changelog page on the documentation site, after the introduction, made from
CHANGELOG.mdin English, German and Simplified Chinese. It shows every release with its date in the page's language, an address such as/changelog#v0.1.0, Latest and pre-release marks, and links to its GitHub release and to the changes since the release before. The showcase's changelog shows the same releases, marks and links, with its section names in the page's language, and shows unreleased changes only when there are any. (#29 (opens in a new tab)) - Both sites list every page in every language in
sitemap.xml, withhreflangalternates andx-default, and name the sitemap inrobots.txt. Every page has a canonical address and Open Graph and Twitter tags with a preview image. Not-found pages and the showcase's examples and states pages stay out of search results. On phones, both sites open search from a button in the header, for whichAppFrametakesphoneActions. The showcase's View source links,llms.txtand changelog links open the release's tag instead ofdev, and its German and Chinese page descriptions and its German search placeholder are fixed. (#28 (opens in a new tab)) - Diagrams in the documentation are
mermaidcode blocks drawn at build time into a light and a dark SVG in Kaeso's colours and type. They follow the theme, are named for screen readers byaccTitleandaccDescr, and are searchable by their labels; no Mermaid code reaches the browser. A diagram that doesn't parse, or a code block that draws with box-drawing characters, fails the build with its file and line. The UI library addsThemeImage, which follows the theme and prints the light version, andCode flow="text", so long inline code breaks with its sentence. A nested folder's page is named by its title in the sidebar. (#54 (opens in a new tab)) - Code examples in the documentation show as language tabs, such as curl, Python and TypeScript, and the reader's choice carries to every group on the page and on the next page. Next steps show as link cards, and every heading links to itself. In
@logicplanes/kaeso-ui,CodeBlocktakestabandonTabChange, andLinkgains theheadingandcardvariants. (#91 (opens in a new tab)) - A new guide, Automate with the Platform API, walks from creating a project, adding a provider key and a model, and creating an app's key with a service account, to calling the model and reading usage and logs. It takes every key from the environment. (#99 (opens in a new tab))
- Ideas and questions have a home in GitHub Discussions: the issue chooser links to it, an Ideas discussion asks for the idea in a sentence or two, and the contributing page explains the categories and how an agreed idea becomes a feature request. (#31 (opens in a new tab))
- Documentation pages show the current version wherever they write
{{version}}, replaced at build time from the repository's version in text, code and frontmatter, so a release never needs a page edited. A backslash before it keeps it literal.
Self-hosting
- Updates for self-hosted installs: the gateway checks GitHub for new releases twice a day and shows the running and newest versions, with release notes, under Settings › Instance › Updates.
KAESO_UPDATES_CHECK=falseturns the check off. The optional updater (COMPOSE_PROFILES=updater,KAESO_UPDATER_TOKEN) applies a release in one click: it verifies the signed build provenance, pulls images by digest, waits for migrations, and rolls back when the new version doesn't start and the database wasn't migrated. Major releases and releases with manual steps update by hand, and every update is audited. Caddy serves an updating page in three languages meanwhile, and each release carries an attestedrelease.jsonand thekaeso-updaterimage. (#40 (opens in a new tab))
Changed
- The README shows a short recording of the console, in a light and a dark version, instead of a screenshot: connecting a provider key, creating an API key, sending a request and watching it arrive in the request logs.
pnpm demorecords it again on the seeded development stack.
Gateway
- The project catalogue knows whether each model's provider serves it to the project's provider key. Check availability on the Models page (
POST …/models/check) asks the provider, requests teach it too, and a model marked Unavailable is left out ofGET /v1/models. Changing a provider key resets its models to Not checked. Models that models.dev marks deprecated show Deprecated and havelifecycle: "deprecated"in Anthropic listings. A request for a model the provider doesn't serve fails with 404 andparam: modelin the app's format, with a message that names the provider and the model. Kaeso confirms this with the provider's model endpoint first and never retries. (#37 (opens in a new tab))
Console
- Smaller console downloads: a project's overview loads 25 kB less JavaScript and the sign-in page 4 kB less, the documentation site's frame 3.6 kB less, and a page's code is requested while the console starts instead of after its first render.
AppFrameloads its phone navigation sheet once the page is idle or on the first tap, and the charts no longer need d3-scale's colour and number-format modules. (#35 (opens in a new tab))
Documentation
- The documentation follows one binding style guide, with page types, voice, code examples and a checklist. It is now ordered by the reader's journey: introduction, get started, concepts, console, API, self-hosting and development. Moved pages keep their old addresses through redirects, and the concepts overview defines Kaeso's terms once and ends with its pages as next steps. (#73 (opens in a new tab), #74 (opens in a new tab), #83 (opens in a new tab), #97 (opens in a new tab))
- The introduction, quick start, calling models, coding tools and model API pages lead with requests you can run in curl, Python or TypeScript. Coding tools walks through Claude Code, Codex and other tools step by step, and the get started overview lists its pages as next steps. (#49 (opens in a new tab), #90 (opens in a new tab), #93 (opens in a new tab), #94 (opens in a new tab), #117 (opens in a new tab), #133 (opens in a new tab))
- Request flow explains each step with a diagram that fits a phone and says that Kaeso's own 503 answers reach OpenAI-format apps as 500. Format translation lists what Kaeso refuses per target, and the rights page explains its notes once and states each grant rule plainly. (#95 (opens in a new tab), #96 (opens in a new tab), #98 (opens in a new tab))
- The model API, errors and Platform API pages are rewritten and checked against the gateway. The errors page opens with a failing request, shows how to read its
kaeso-request-idand lists one cause per row. The Platform API reference leads with a runnable request and corrects which actions need a recent sign-in, and the API overview is a short list of its pages. (#48 (opens in a new tab), #85 (opens in a new tab), #100 (opens in a new tab), #101 (opens in a new tab)) - The console pages are rewritten as task guides and checked against the console, with labels from its catalogs. This covers organizations and members, provider keys and models, API keys and limits, request logs and the Playground, and account and instance administration. A new section explains recent sign-in, and the overview is a short map of the console's pages. (#51 (opens in a new tab), #103 (opens in a new tab), #104 (opens in a new tab), #105 (opens in a new tab), #106 (opens in a new tab), #107 (opens in a new tab), #108 (opens in a new tab))
- The self-hosting pages are rewritten and corrected against the code. Configuration is the one reference for every setting, and a new page explains how an install works. Domains, email and sign-in are task guides, Upgrades leads with the update by hand and leaves updater internals to the architecture page, and Troubleshooting gives each message its own fix. Corrections include the email delivery limits and that only PostgreSQL keeps the password it was created with. (#50 (opens in a new tab), #75 (opens in a new tab), #121 (opens in a new tab), #122 (opens in a new tab), #123 (opens in a new tab), #124 (opens in a new tab), #125 (opens in a new tab))
- The development guides are rewritten. Local setup is one path from a fresh clone to passing tests, with a new Development stack page and Colima on macOS. Contributing follows the order in which a contributor works, and the testing and releasing pages keep to the commands and steps. (#52 (opens in a new tab), #76 (opens in a new tab), #112 (opens in a new tab), #114 (opens in a new tab), #115 (opens in a new tab))
- The architecture and KPP internals pages are tightened and corrected. Reasoning across formats and codec design have pages of their own, every mapping page opens with what it is for, and the longest sentences become lists and tables. (#53 (opens in a new tab), #119 (opens in a new tab), #120 (opens in a new tab), #128 (opens in a new tab), #129 (opens in a new tab), #130 (opens in a new tab), #131 (opens in a new tab))
- German and Chinese documentation pages use the glossary's terms and the console's labels throughout: German with the formal imperative, Chinese with 实例 for an install and 身份提供商 for the identity provider. Links follow the anchors that changed. (#132 (opens in a new tab), #137 (opens in a new tab), #138 (opens in a new tab))
- The documentation's and the showcase's changelog pages refuse raw HTML, and links other than http, https and mailto, in
CHANGELOG.md. Each site checks every part it renders with the Markdown parser that renders it, and the build fails and names the line, so a changelog entry can never run code on either site. HTML written in a code span or a code block is fine.
Removed
Documentation
- The performance, dependencies and KPP field classes pages are gone. The licence policy lives under Contributing and the field classes under KPP internals, and each old address leads to the page that replaces it. (#111 (opens in a new tab), #113 (opens in a new tab), #127 (opens in a new tab))
Fixed
- German and Chinese read consistently across the console, the UI library, the showcase, the documentation site, the emails and the updating page. German addresses the reader as Sie and Chinese as 您, both follow the translation glossary, and every Platform API message now has a German and a Chinese translation in the console. CI fails on text left in English, on informal address and on mixed punctuation, and a gateway test fails when a Platform API message has no console translation. (#84 (opens in a new tab), #86 (opens in a new tab), #87 (opens in a new tab), #88 (opens in a new tab), #89 (opens in a new tab), #92 (opens in a new tab), #110 (opens in a new tab))
Gateway
- Requests are refused before sending wherever the API or the model would refuse them. Anthropic Messages requests without
max_tokensget Anthropic's 400invalid_request_errorinstead of the model's output limit, while the OpenAI formats still get it; OpenAI Responses requests withmax_output_tokensbelow 16 are refused, also from other formats; Claude Fable 5.1, Opus 5.5 and Sonnet 5.5 requests with a forced tool choice are refused, with a new catalogue field, Accepts a forced tool choice, to change it per model; and adaptive thinking for a Claude model without it is refused. Anthropic-format error bodies carry the request's id inrequest_id, and capability refusals name the app's own field. (#34 (opens in a new tab)) - Rights changes no longer leave a right without one it needs. A change to a member's, service account's or role's rights is refused with
400when it removes a needed right, also when that right already lacked another of its needs. A custom role change that would leave any member, project member or service account who holds the role with a right but without its need is refused with400, in the console too. The message names the right, its need and how many holders it affects, and nobody's rights change. (#41 (opens in a new tab), #42 (opens in a new tab)) - A single sign-on refused by the identity provider, such as with
access_denied, ends its sign-in flow and returns to the sign-in page withnext. When the sign-in began from an organization's sign-in link, it also keepsorg, so that organization's button shows again. Requests refused before they reach a model in another format name the field the app sent, such asmax_completion_tokensormax_tokensrather thanmax_output_tokens. The bundled Caddy has a health check, sodocker compose up -d --waitreturns only once Caddy serves too. (#44 (opens in a new tab)) - Model availability is recorded more reliably. The request log keeps the provider's own 404 message, while the app still gets Kaeso's explanation. A check or request under way while an org admin replaced, assigned, made default or deleted a provider key no longer records the old key's answer over the reset; the check reports such models as
key_changed. A provider that answers 404 toGET /v1/models/{model}, such as an OpenAI-compatible service without that endpoint, no longer makes every model Unavailable. Kaeso marks a model unavailable only when the provider's listing answers and lacks it; otherwise it passes the 404 through and reports the check asinconclusive. (#46 (opens in a new tab))
Console
- The console's audit logs show the actor's profile picture, in the Actor column and in the actor filter, instead of only an initial, and a project's API keys show their owner's picture. (#30 (opens in a new tab))
- Everything typed after ⌘K or Ctrl+K reaches the search of the documentation site and the console's command palette, also while its code is still loading and in the moment before its field has focus.
CommandPalettetakesqueryto show a query its host keeps. (#61 (opens in a new tab)) - Turning two-factor authentication on or off, or changing your password, no longer signs you out when the console was loading something at the same moment.
UI library
- Collapsible, Accordion and the sidebar no longer shift their content while they open or close, so a press during the animation is no longer lost. (#22 (opens in a new tab))
- The component registry in
@logicplanes/kaeso-uilists every component's default variants again, without an extra_DEFAULTentry per component. (#27 (opens in a new tab)) - Dialogs whose content changes, such as a
StepDialog's steps or aLayerDialog's layers, stay centered and resize smoothly instead of jumping.StepDialogtakesresultto show what the last step made in the same dialog, so creating a key or a platform key, or setting up two-factor authentication, no longer opens a second dialog. A dialog stays open while its work is underway:DialogandLayerDialogtakebusy, andStepDialogandAlertDialogare busy while they submit. Closing Create key while the key is being created no longer loses its one-time secret, and no console action can be sent twice. (#38 (opens in a new tab)) - The parts of
@logicplanes/kaeso-uithat load their code on demand recover from a failed download instead of staying broken until a reload. This coversAppFrame's phone navigation and the collapsed sidebar's peek, the sidebar's menus, tooltips, date pickers, and a list's checkboxes and later rows. The next tap, hover, focus or scroll loads the code again, from a fresh address in Chromium and WebKit; nothing retries on its own. WhileAppFrame's sheet is still on its way, Escape, a tap outside or the toggle takes the tap back, and a pointer that leaves the button cancels the peek. (#45 (opens in a new tab)) ScrollArea, and with it the tables in the documentation, scrolls only in its own direction and only when its content overflows, so a table that fits no longer bounces or holds back the page's scroll. InlineCodein the documentation flows with the text around it and has 4px of padding inside the chip, so a comma or closing bracket after it stays beside it.Codetakesflow="cell"for long code in a table cell. (#58 (opens in a new tab))- On touch screens, code blocks keep their first line clear of the copy button, so the end of a one-line command is no longer hidden on a phone. (#78 (opens in a new tab))
- A step dialog that moves on while a select is still closing no longer causes ResizeObserver loop errors. Every resize observer in the library now applies its changes together on the next frame. (#82 (opens in a new tab))
Documentation
- Tables in the documentation keep their words whole and scroll inside a named region when they are wider than the screen, and the previous and next links show their label above the page title. A ScrollArea with an
aria-labelis now a region that screen readers announce. (#24 (opens in a new tab)) - The introduction's diagram runs top to bottom, so it fits a phone in every language. (#80 (opens in a new tab))
- Statements that no longer matched the gateway and the codecs are corrected. Among them are which instance and update settings need a recent sign-in, what effort
nonedoes on Claude, and which OpenAI error bodies reach which apps. (#136 (opens in a new tab))
Self-hosting
- The console image sets the permissions of its files itself, so an image built with a strict umask serves the console instead of restarting silently, and it names any file it can't read. Each release pulls both images for both platforms without signing in and fails with what to do when a package is private, and the guides use
docker compose up -d --waitand show a proxy in Docker on a network of its own. Both sites ship their Content Security Policy in a<meta>and incsp.txtand_headers, with the documentation underscript-src 'self'; style-src 'self', now that ScrollArea and Select no longer add an inline<style>element. (#36 (opens in a new tab))
Security
Gateway
- The gateway no longer logs the setup link, which anyone reading its logs could have used to take over an install before its first user existed; it says to run
kaeso setup-linkinstead. Installs can sign in with single sign-on alone: the sign-in page offers the identity provider's button when it is the only one or comes from an organization's sign-in link (/sign-in?org=…), and can start at the provider without a click.GET /platform/v1/auth/oidc/startlinks straight to the provider. Setup with passwords off asks for none, andkaeso user sign-in-link <email>prints an audited one-time link. Single sign-on returns to the page innext, which must be a console path, and the cross-site refusal names theOriginheader to send. (#39 (opens in a new tab))
Console
- The console no longer shows an API key's secret again after its dialog was closed; until a reload, the next Create key opened on the last key's secret. The secret now leaves the page and the console's memory once the dialog has closed. Every console dialog opens fresh, including transfer ownership, add owner, send test email, change email, change password, export requests and add models, through
DialogScopein@logicplanes/kaeso-ui, which mounts its content anew on each open. The command palette keeps its results while it closes, and the documentation search opens with an empty query. (#32 (opens in a new tab))