Repository navigation
Releases: bespinian/keera-gateway
Release list
v0.9.0
Full Changelog: v0.8.0...v0.9.0
v0.8.0
What's new
- Model aliases can name their provider. An alias may hold slashes, as in
anthropic/claude-sonnet-4-5. Each part between slashes follows the usual
alias rules: lowercase letters, digits and inner hyphens.
GET /v1/models/{alias}takes the alias with the slash escaped or not. The
panel,keera modeland the catalogue files accept such aliases. - "Issue another" after creating a key. The panel can open the form again
right away. It keeps the project and expiry of the key just issued, but not
the user, so a key does not go to the wrong person by mistake.
Changes
- Card payments carry a transaction fee. Every top-up, manual or
automatic, adds CHF 0.18 plus 1.55% of the credit, the 1.55% at least
CHF 0.20: CHF 0.38 on CHF 10, CHF 1.73 on CHF 100. It is paid on top of the
credit and VAT, and is not credited. PostFinance Checkout shows it as its own
line. - The smallest top-up is CHF 1, down from CHF 10.
- Fees are shown wherever payments are:
- The panel's top-up form shows the fee and the total under the amount.
- The payment lists in the panel and
keera billing paymentshave a fee
column. keera billing topupsays what you pay in total and how it splits.- The control API gives
fee_microson each payment, andfee_fixed_micros,
fee_bpandfee_min_microson the credit account.
- Panel:
- Billing amount fields go up in steps of CHF 1.
- The note under the bill is gone.
- Organisations are sorted by date created, newest first.
- The Keera Decider image in
composeis built on Python 3.14.
Upgrading
- Tell your customers about the fee before you upgrade. Automatic top-ups
will charge saved cards the fee from the first top-up after the upgrade. - The gateway applies the migration
0005_v0.8.0.sql. It adds
payments.fee_micros, which is 0 for every payment made before. - Replace all replicas together. A v0.7.0 replica that checks a payment
made with a fee finds that the amount does not match. It closes the payment
without adding the credit, even though the card was charged. If this happens
during the rollout, an operator has to add the credit by hand.
v0.7.0
v0.6.0
Everything is in CHF
Keera Gateway now uses one currency: Swiss francs. Prices, budgets, bills, credit, reports and metrics are all in CHF.
What changed
- Anthropic and OpenAI prices are now in CHF. The built-in table used to list their prices in USD. They are now converted at 0.92 CHF per USD. The Swiss providers' prices stay the same.
- One total on the bill.
keera billing, the panel and the CSV export used to show one total per currency. They now show a single total in CHF. - No exchange rate to set. With payments on, each call takes its list price straight from the organisation's credit.
- No provider notes.
keera model providersand the provider tiles in the panel no longer show the note under each provider. The long form is still in docs/providers.md.
Breaking changes
- Removed settings:
KEERA_CURRENCYandKEERA_BILLING_CHF_PER_USD. Remove them from your environment. The gateway no longer reads them. - Removed header:
X-Keera-Budget-Currency.X-Keera-Budget-Remainingis always in CHF. - Control API:
- The billing report has one
totalobject in pl - Bill rows and totals no longer have a
currencyfield. - Usage, requests, sessions, overview, traffic mas no longer have a
currencyfield.
- The billing report has one
- CSV exports:
- The
currencycolumn is gone from the billing from_credit_chfis nowfrom_credit.cost_<currency>is nowcostin the requests
- The
Upgrading
- The gateway runs the migration
0003_v0.6.0.sqlrencycolumn frombilling_lines`. - Old bill lines are not converted. Anthropic and OpenAI lines recorded before the upgrade keep their USD amounts, and reports now show those amounts as CHF. Credit that was alrealways in CHF.
- Check prices you set by hand. If you set USD prices on a model that uses your own provider key, they are now read as CHF. Models on the deployment's own keys take their prico they need no change.
v0.5.0
Highlights
People can be in more than one organisation
A person can now belong to several organisations and have a different role in each. When an organisation adds someone with keera user add or in the panel, they get an invitation until they first join.
- Panel: if you're in more than one organisation, its name at the top becomes a menu. Pick an organisation to switch to it, or pick an invitation to join it.
- CLI: keera org list shows your organisations and invitations. keera org switch picks the one later commands act on. KEERA_ORG overrides it for one shell or pipeline.
- A browser remembers the organisation it was last in. keera login goes back to the one that machine was last in.
- Operators can work in every organisation. keera org switch --all goes back to all of them.
- Each switch is written to the audit log as auth.switch_org.
- Disabling a person or changing their role applies to one organisation only. Leaving the directory, or keera logout --all, ends their sign-ins in all of them.
See docs/sso.md.
Decision models for routers and gate filters
A new model kind, decision, is for classifiers like Laya served by laya-serve. In one pass it returns a probability for each possible answer, and it writes no text. Only instruction routers and gate filters can use one. Clients can't call it, and /v1/models doesn't list it.
The compose deployment now includes Keera Decider: Laya on CPU, already listed in models.yaml. make dev starts it.
See docs/routers.md.
Activity screens for members
- Members can now see the Live map, Sessions and Requests, limited to their own keys. Administrators still see the whole organisation.
- Sessions and Requests can be filtered by model, project, key, person and status: a single code like 402, or a group like 5xx. A filter set on one screen carries over to the other.
- Clicking a number column ranks the whole time window on the server: cost, tokens, requests, duration, or time to first token.
- The Sessions screen can update live.
- The API has new parameters: status, outcome, sort and facets=1 on /control/v1/sessions, and sort on /control/v1/requests.
Users and keys
- New user details page.
- The Users screen shows each person's identity provider and when they were last active (their latest sign-in or request).
- The Keys screen has a User column, project and user filters, and a time-range picker for its usage columns.
Breaking changes
- CLI commands no longer take --org. They act on the organisation chosen with keera org switch, or set in KEERA_ORG. The exceptions are keera billing grant and keera billing invoiced, where --org is now required.
- keera billing invoiced on --org is now keera billing invoiced --org . Use --off to switch an organisation back to paying in advance.
- New filters start in shadow mode, in both the CLI and the panel. --enforce is renamed to --no-shadow. Use keera filter add … --no-shadow to enforce from the start.
- Some SSO users have to sign in again. Refresh tokens now belong to the identity, not to each user row. When the upgrade runs, it ends the panel sessions and keera login tokens of everyone who had a stored refresh token.
- Each person keeps the identity provider they first signed in with. A sign-in with the same email address through a different provider is refused, and the error names the provider to use. Identities that already shared an address before this release keep working.
- The "OpenAI-compatible" entry in the client catalogue is now "cURL". Requests made with curl are filed under it.
Other changes
- When an organisation's guardrail has a list of allowed models, any model the organisation adds is now put on that list automatically.
- keera billing payments shows the latest 50 payments by default. Use --limit to change that.
- Loopback and link-local addresses now count as private network addresses. Limited organisations can't reach them. With KEERA_UPSTREAM_PRIVATE set, a backend on the same host now has to be listed there, such as 127.0.0.1.
- A locked model now returns 404 from /v1/models/{alias}, just as it's already left out of the list.
- If a PostFinance payment succeeds after Keera had marked it as failed, it is now still credited.
- Deleting an organisation also removes its saved card, both in Keera and at PostFinance.
- Messages API errors now carry a type that follows the HTTP status, such as billing_error for 402.
- Panel: date-range pickers are now on the right, the live map legend is gone, and the accent colour has changed slightly.
- Dependency updates: golang.org/x/{sync,sys,text} and flake.lock.
Upgrading
The gateway applies migration 0002_v0.5.0.sql when it starts. After upgrading:
- Expect some SSO users to have to sign in again (see Breaking changes).
- If you use KEERA_UPSTREAM_PRIVATE with a backend on the same host, add its loopback address to that setting.
- Update any scripts that pass --org so they use keera org switch or KEERA_ORG instead.
v0.4.0
Highlights
- Billing on the deployment's own provider keys. Set KEERA_PROVIDER_API_KEY and every organisation's models of that provider use the deployment's key. Each organisation is billed at the provider's list price. KEERA_PROVIDER_DISCOUNT records your own discount, so operators see the provider cost and the margin. No one else sees the margin. keera billing and Administration → Billing show the monthly bill, also as CSV. See docs/billing.md.
- Pay in advance by card. With a PostFinance Checkout account, organisations buy credit in CHF by card, TWINT or PostFinance Pay. Keera never sees the card. keera billing topup, auto-topup, credit, payments and forget-card cover the rest. When the credit runs out, calls on the deployment's keys get 402 credit_exhausted, and the organisation's own models keep working. Operators can grant credit (keera billing grant) or bill an organisation by invoice (keera billing invoiced on). Settings: KEERA_POSTFINANCE_SPACE_ID, _USER_ID, _AUTH_KEY, KEERA_BILLING_CHF_PER_USD and KEERA_BILLING_VAT. See docs/billing.md#pay-in-advance.
- Self-service sign-up. With KEERA_OIDC__SIGNUP=true, someone whose sign-in matches no organisation can create one or accept an invitation. A new organisation starts limited: it cannot use models, MCP servers or sandboxes inside your network until its first card payment. Such requests are refused with org_limited. Operators can lift the limit earlier with keera org set --lift-limit or Organisations → Lift limit. See docs/sso.md#letting-people-sign-up.
- CSCS is a new inference provider, next to Infomaniak, stepping stone and Phoeniqs.
- Codex in Connect client. The panel and keera connect codex write a ~/.codex/config.toml that points at the gateway over the Responses API.
- Cache-write and long-prompt prices. Anthropic, and OpenAI from gpt-5.6 on, charge more for prompt tokens they write to their cache. Keera now bills these tokens at the cache-write rate. Models that cost more for a long prompt, such as claude-haiku-5-5 above 100,000 tokens, are charged the higher prices past that length. The provider table contains both, and a catalogue entry can set its own long_prompt.
On the deployment's keys
A model on a deployment key works differently from one with an organisation's own key:
- It takes no API key of its own and always goes to the provider's own address.
- Its prices are the list prices. Model ids that are not in the price table are refused.
- Hosted tools such as web search are removed from requests. So are fields that cost extra, like speed, inference_geo and expensive service_tier values. X-Keera-Removed-Fields lists what was removed.
- OpenAI Responses requests are sent with store off. Requests that use previous_response_id, conversation or background are refused.
- The provider has 15 minutes to start answering. If a client hangs up, the gateway keeps reading until the usage record arrives, so nothing goes unbilled.
- Filter and router calls to such a model are billed too, and so are keera model|filter|router check.
Security
- KEERA_UPSTREAM_PRIVATE lists the host names inside your network that organisations may reach, such as keera-engine. Every other private address is blocked, even behind a public name that resolves to it. Sign-up requires this setting.
- The default KEERA_UPSTREAM_DENY now also blocks Alibaba Cloud's metadata address and Azure's WireServer.
- Administrators can only give a sandbox class an image from the catalogue file, one under a prefix in KEERA_SANDBOX_IMAGES, or the image the class already has. Sandbox pods pull with the deployment's credentials, so any other image needs an operator.
- A sign-up provider that accepts any domain refuses sign-ins without email_verified: true.
- Sign-up cannot be combined with ADMIN_GROUPS on any provider. The gateway refuses to start if both are set.
- Misspelt KEERA_PROVIDER_* settings and incomplete payment settings stop the start.
Panel and CLI
- --price-cache-write on keera model add|set, and a Cache write price field in the panel. The panel also shows long-prompt prices.
- For a model on a deployment key, the panel hides the API key field and says that use is billed to the organisation.
- keera org list marks limited organisations.
- The CLI's help is shorter and links to the docs for details.
- The first-run checklist's set-up message is simpler.
Docs and development
- New: docs/billing.md. docs/sizing.md is now Retention and sizing in docs/install.md.
- docs/gateway.md notes that Redis Cluster is not supported. Use a single Redis endpoint.
- compose/models.dev.yaml is gone. make dev now generates it from compose/models.yaml into build/.
Breaking changes
- Start with a new database. The schema changed in place, so a v0.3.0 database cannot be upgraded.
- Claude subscriptions are off by default. Set KEERA_CLAUDE_SUBSCRIPTIONS=true to keep them. Without it, existing subscription models and keys are refused with subscriptions_off, and a catalogue file that contains a subscription model stops the start.
- Sandbox class images are restricted for administrators, as described above. Add custom registries to KEERA_SANDBOX_IMAGES.
- compose/models.dev.yaml was removed. Anything that pointed KEERA_MODELS_FILE at it needs a new path.
v0.3.0
v0.3.0
Highlights
- Passkeys. People with no account in your identity provider can sign in
with a passkey. A deployment can also run with no identity provider at all.
An administrator adds someone withkeera user add <email> --passkeyand
sends them the one-time set-up link. Off unlessKEERA_PASSKEYS=true. See
docs/sso.md#passkeys. - The directory is asked again every 15 minutes. Keera keeps the refresh
token from the sign-in, encrypted, and uses it while the person is active.
Someone removed from the directory loses their sessions andkeera login
tokens within 15 minutes, not when they expire. Role changes apply in that
time too. - Teams are now projects. Every key is in a project. A new organisation
starts with one calleddefault. A project can have a description. - Rename things. Operators rename organisations (
keera org set --name).
Administrators rename projects (keera project set). Anyone renames their
own keys (keera key set). The panel has a pencil for each. - My clients. A new panel screen lists the clients that called with your
keys, and which key each used. Connect client sets up a new one, with
every model and router your key may use. - Simpler Claude subscription setup. An administrator issues a member a
subscription key, andkeera connect claude-code --subscriptionon the
member's machine takes it over. The command respects managed settings that
already set the gateway's address. It also writesmodelOverridesand turns
tool search back on, so Claude Code knows each model's context and features.
See docs/subscriptions.md.
Security
- Where the gateway may connect.
KEERA_UPSTREAM_DENYlists addresses the
gateway never sends a request to. By default: loopback, link-local (cloud
metadata) and AWS's IPv6 metadata address. DNS names are checked by the
address they resolve to. Redirects from backends and MCP servers are no
longer followed. See docs/install.md#where-the-gateway-may-connect. - A stored model or MCP credential only goes to the hosts it was entered for.
Moving a backend to a new host needs the key again, or--no-api-key. - The sign-in callback only works in the browser that started the sign-in.
- An MCP key that may call only some tools no longer reaches the server's
resources, prompts, completions ortasks/list. - MCP tool calls now count against the key's rate limits, and against budgets
when the key has filters. KEERA_METRICS_TOKENmay not be the same as the operator key.- Only an administrator issues keys. A member can no longer choose a key's
lifetime when rotating it.
Panel and CLI
keera key createmakes a key that lasts 90 days, as the panel does.
--expires nevermakes one that does not expire.keera key rotateasks you to type the key's name first.--yesskips that.--orgworks onkeera guardrail,limitandbudget, and a project or
key can be named by its name there.- Answers carry
X-Keera-Budget-ScopeandX-Keera-RateLimit-Scope, which say
which level a limit comes from. - Users hides disabled people until you tick Show disabled.
- Overview is now Dashboard. Buttons that create something say Add.
- Filters, Routers, MCP and Sandboxes fold into one sidebar entry until the
organisation uses them. - Claude Code's dated model ids, such as
claude-haiku-4-5-20251001, reach the
matching subscription model. - The binary reports the tag, the short commit, and
-dirtywhen built from a
changed tree.
Performance
- Streams flush once per read from upstream rather than once per token. This
was most of the CPU a stream cost. - Renaming the model in each streamed chunk no longer allocates.
/metricsno longer holds a lock while a slow reader reads.
Fixes
- The live request log works with several gateway replicas.
- The image builds from a plain clone. It writes
vendor/itself when it is
missing. - Every latency histogram in
/metricsnow has its_sum. - An unknown
KEERA_LOG_LEVELorKEERA_LOG_FORMATstops the start, instead
of being ignored. - Organisation names are unique, ignoring case.
keera logoutmakes the one sign-in left the default.- A project or prompt can be called
help.
Sandboxes
- The podman driver is for local development and tests only. Use
kubernetesin production. - The variables the gateway passes to the sandbox entrypoint are documented,
for images that replace it. - Pi's version is pinned with a lock file.
Breaking changes
- Start with a new database. The schema changed in place, so a v0.2.0
database cannot be upgraded. - Team is now project, everywhere.
keera teamiskeera project,
--teamis--project, the guardrail scopeteamisproject, and
keera usage --by teamis--by project. In the control API,/v1/teams
is/v1/projectsandteam_idisproject_id. - A key's
aliasis now itsname.keera key create --aliasis
--name, and so is the field in the control API. - Only administrators issue keys. Members ask for their first key, then
rotate it themselves. - Keys from
keera key createexpire after 90 days unless--expires
says otherwise. - The gateway no longer connects to loopback. A model on
127.0.0.1needs
KEERA_UPSTREAM_DENYwithout the loopback entries.make devdoes this. - Scripts that rotate keys need
--yes.
v0.2.0
v0.2.0
Highlights
- Claude subscriptions. People on a Claude Team or Enterprise plan can use
Claude Code through Keera, and their plan pays. Keera still applies
guardrails, records usage and shows how much of the plan each person uses.
The person's Claude sign-in goes to Anthropic unchanged and is never stored.
See docs/subscriptions.md. - Everything belongs to an organisation. Models, MCP servers, sandbox
classes and guardrails are now per organisation. Nothing is shared between
tenants. The catalogue files are now templates that each new organisation
starts with. - Model catalog. Models → Model catalog lists every model the providers
offer, with context window, list prices, release date and where it is
served. You can search, filter and sort it, and add a model from it in one
click. - Phoeniqs is a new provider, served from Switzerland.
Playground
- Every message is now sent with one of your own active keys, so it follows
that key's guardrails, rate limits and budgets, and shows in its usage. - Attach images.
- Show the model's reasoning.
Security
- Sandboxes get a repository token only for repositories in the guardrail's
allowed_repos. This is checked again on every token refresh. - Each identity provider can only sign in people from its own email domains
(KEERA_OIDC_<N>_DOMAINS). - The user endpoint no longer changes the role of a person who already exists.
Usekeera user rolefor that. - The gateway won't start if
KEERA_SECRET_KEYorKEERA_METRICS_TOKENis
shorter than 16 characters. - Releases reach SLSA level 3. Verify them with
gh attestation verify ... --signer-workflow bespinian/keera-gateway/.github/workflows/release-build.yml. - Added SECURITY.md.
Fixes
- Purging old usage keeps the spend windows that are still open, so budgets
stay correct. - A Redis rate-limit bucket's clock never moves backwards.
- The release pipeline was missing a permission.
Breaking changes
- Single sign-on: the unprefixed
KEERA_OIDC_*settings are gone. List
providers inKEERA_OIDC_PROVIDERSand configure each one with
KEERA_OIDC_<N>_*. SSO now requiresKEERA_PUBLIC_URL. If you have more
than one provider, each one needsKEERA_OIDC_<N>_DOMAINS.
KEERA_OIDC_REDIRECT_URLandKEERA_OIDC_ADOPT_BY_EMAILwere removed. KEERA_SECRET_KEYis required.KEERA_MODELS_FILEandKEERA_SANDBOXES_FILEonly seed new
organisations. To change an existing one, use
keera model apply <file> --org <id>orkeera s>.- Sandboxes:
KEERA_SANDBOX_MODELwas removed. A sandbox's agent now uses
the first chat model its key may use. The `KEERA_
were removed, so the Kubernetes driver must run inside the cluster where it
creates sandboxes. - Compose:
compose.cpu.yamlis gone, and llama.cpp is now the default in
compose.yaml. Runpodman compose up -d, and a
GPU host. - A size, duration or on/off setting that can't be
default. An invalid Redis URL, sandbox driver, forge or default role stops
the gateway from starting.
Other
- Go 1.27.1.
- Code and documentation cleanup.