Skip to content

v0.13.1 — Release gate goes green: sharded, self-cleaning, right-sized staging

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Aug 13:56
· 92 commits to main since this release
3400140

New

  • One URL configures every email Kortix sends. Signup confirmations, magic links, invites and alerts all flow through the same EMAIL_URL transport with the same sender identity and templates — self-hosted installs configure email once. Supabase auth mail now goes through the same path instead of GoTrue's own SMTP.
  • One-click OAuth for MCP connectors. Connecting an MCP server that requires OAuth 2.1 now works end-to-end from the UI or via kortix connectors authorize — discovery, dynamic client registration and token exchange included.
  • Secrets get an exposure and usage model. Each secret declares how it may be exposed and which usages are assigned to it, enforced by one mechanism across every sandbox provider.
  • Session sharing is now the owner's call: managers keep lifecycle control (stop, restart), but only the session's owner can share it or mint public links.

Fixed

  • Revoked API tokens now actually stop working. A personal access token that had been revoked could still authenticate on every surface (REST, the LLM gateway, git proxy, preview proxy, connectors) because the validation query never checked the revocation timestamp. Revoked tokens are now rejected everywhere.
  • Deleting an account now stops and removes every one of its sandboxes — across every account the user owns and every non-terminal state — instead of only stopping the ones under the earliest-joined account.
  • A runaway agent turn can no longer take the API down. Each session's audit-event stream is bounded (900 events per minute); past that ceiling only the high-volume streaming-delta class is dropped while lifecycle, usage and billing events keep flowing.
  • API writes are much faster under load. Audit events are written asynchronously in batches off the request path (they were a synchronous insert into a 14-index table on every request), and the account list no longer makes one admin-API call per member to resolve owner emails. Audit reads flush the queue first, so the audit log stays read-your-writes.
  • A waking sandbox no longer looks like an error. Every surface (web, CLI, SDK) now treats the sandbox-starting state as "waking" with retry, instead of surfacing a 503. Resuming a stopped box also dropped two provider round trips.
  • Gateway reliability: long streaming turns are no longer killed at 255 seconds by a runtime idle timeout; Bedrock requests with trailing prefill or redacted reasoning no longer fail; the gateway's provider shaping now runs on the new AI-SDK-native transport path, which is the default everywhere.
  • Slack: another bot @-mentioning Kortix now works; linking the bot no longer demands owner/admin (it delegates only your own authority); user lookups were sent in a form Slack silently ignored — fixed.
  • Prompt queue and composer: forwarded prompts can no longer strand, Stop can no longer leak into the next turn, fresh sessions paint instantly in one ordered batch, and the boot-time composer shows the session's real agent.
  • Deleted sessions are no longer readable by id. Listing a project's group grants is manager-only, matching the write routes.
  • Sandboxes learn the managed model set from the API on every boot, so a model the picker offers is one the runtime knows.
  • Keyboard scrolling in a session is treated as scroll intent: Cmd+Up no longer snaps back to the end. A session.error is now attributed to the turn that failed.
  • Starter reflector and reviewer agents run without approval prompts. Self-hosted boxes get a daily Docker prune timer.
  • Session titles and conversation counts are recorded again. The per-session metadata mirror was silently never written (the internal call carried no user identity, so the sandbox rejected it) — session names and conversation counts now populate for new sessions.

Security

  • The sandbox egress pin trusts the edge-populated client IP rather than spoofable forwarding headers; the App public proxy honors a token's project/session scope; trigger-session manager visibility no longer extends to session-bound agent tokens.
  • The browser test suite was broadcasting a deployment-protection bypass secret to third-party hosts on every run; it now authenticates once via a scoped cookie and the secret reaches no third party.
  • nodemailer upgraded across two majors to clear open advisories, including one high.

Internal

  • Roles have one store. The RBAC cutover made role_assignments the only authorization store — legacy tables became views, mirror triggers were dropped, and 3,100 lines of parallel code were deleted.
  • The production release gate is now reliable and fast. It runs as 6 API shards + 3 browser shards, cleans up its own test debris, tolerates a traffic-degraded-but-serving gateway, can be rehearsed against staging without opening a release PR, and the test client never replays a non-idempotent request through an edge-laundered error. Staging was right-sized for it, and a workflow-gating bug that had silently frozen the staging frontend for a week is fixed.
  • Container image builds are ~7× faster. Staging and dev images build natively per architecture with a registry layer cache (API image: ~3 minutes, was ~20), and the arm64 frontend image is now genuinely arm64.
  • CREATE INDEX CONCURRENTLY migrations ship with a lock_timeout that can land on a live database, and CI blocks any new one that sets it too low.

What's Changed

  • chore(release): VERSION → 0.13.1 [skip ci] by @github-actions[bot] in #6569
  • docs(learnings): CIC under a 5s lock_timeout cannot land on live prod (v0.13.0 deploy incident) by @markokraemer in #6570
  • perf(sandbox): warm OpenCode instance in fast image by @Ino-Bagaric in #6571
  • perf(sandbox): precompile fast OpenCode tools by @Ino-Bagaric in #6572
  • infra(selfhost): bake a daily docker-prune timer into the box by @markokraemer in #6573
  • infra(selfhost): drop a deployment name from the prune comment by @markokraemer in #6574
  • perf(sandbox): align fast runtime base with Ubuntu by @Ino-Bagaric in #6575
  • fix(slack): let another bot @-mention Kortix — the gate blocked every bot, not just us by @kubet in #6577
  • fix: every managed model works in every sandbox + session.error renders in place + keyboard scroll intent by @markokraemer in #6576
  • fix(sandbox): disable slower fast boot experiment by @Ino-Bagaric in #6578
  • ci(release-gate): 6 api shards + serial-tail shard, 60-min cap, dry-run dispatch against staging by @markokraemer in #6580
  • test(ke2e): fix tests typecheck break from #6554 (iam.flow.ts:1739) by @markokraemer in #6581
  • test(ke2e): preflight tolerates traffic-degraded gateway, 180s deployed flow budget, no cross-shard shared-state collisions by @markokraemer in #6582
  • test(e2e): harden the recurring deployed-target browser specs; quarantine the non-deterministic ones into a nightly lane by @markokraemer in #6584
  • ci(release-gate): E2E_EXCLUDE_TAGS='@quarantine' on the browser shards (companion to #6584) by @markokraemer in #6587
  • Bound the per-session audit event rate so one runaway turn cannot take the API down by @markokraemer in #6583
  • fix(starter): reflector + reviewer agents run without approval prompts by @markokraemer in #6589
  • fix(api,ke2e): account deletion stops+removes every sandbox, revoked tokens stop authenticating, gc reclaims sessions+tokens by @markokraemer in #6586
  • Give CONCURRENTLY migrations a lock_timeout that can actually land on live prod by @markokraemer in #6588
  • fix(slack): a bot @-mention still did nothing — the identity gate refuses it, silently by @kubet in #6590
  • feat(connectors): one-click OAuth 2.1 for MCP servers (RFC 9728 + 8414 + 7591 + 8707) by @markokraemer in #6579
  • Canonical RBAC cutover: role_assignments is the only store — legacy tables → views, old engine + parity harnesses deleted by @markokraemer in #6594
  • fix(daemon): managed-model overlay never blocks the spawn; reconcile once before readiness by @markokraemer in #6592
  • fix(sessions): session sharing is the owner's call, not a manager's by @markokraemer in #6593
  • perf(sandbox): arm Platinum secrets during create by @Ino-Bagaric in #6596
  • feat(email): one EMAIL_URL configures every email Kortix sends by @markokraemer in #6585
  • perf(sessions): stop paying two provider round trips to resume a stopped box by @markokraemer in #6595
  • fix(gateway): disable Bun idleTimeout stream-kill + Bedrock request/response fixes by @markokraemer in #6599
  • fix(email): nodemailer 7.0.13 -> 9.0.5 (open advisories, incl. one high) by @markokraemer in #6597
  • test(ke2e): GW-1 tolerates a traffic-degraded gateway (aligns with #6582 preflight) by @markokraemer in #6603
  • docs(runbook): switching dev/staging/prod auth email onto the send-email hook by @markokraemer in #6601
  • fix(db): unblock dev deploys — reconcile retired role_permissions actions before the cutover's catalog-FK VALIDATE (runtime override) by @markokraemer in #6602
  • fix(slack): link-bot documented the one input form Slack cannot send by @kubet in #6606
  • docs(learnings): reconcile a retired constraint value by remapping, never deleting by @markokraemer in #6605
  • docs(runbook): hook-enable PATCH clears custom SMTP; promote-safety proof by @markokraemer in #6608
  • Never render sandbox readiness 503s as errors — waking state + retry across all surfaces by @markokraemer in #6610
  • refactor(gateway): AI-SDK-native /language-model path for lossless opencode passthrough (flag-gated, dormant) by @markokraemer in #6609
  • fix(slack): link-bot should not require owner/admin — it delegates only your own authority by @kubet in #6612
  • infra(staging): API 3×2vCPU/4GiB — the release gate saturates 2×1vCPU tasks by @markokraemer in #6613
  • feat(secrets): exposure/usage model — one enforcement mechanism on all providers by @markokraemer in #6611
  • refactor(gateway): wire API in-process gateway + session env to enable the native path (flag off) by @markokraemer in #6615
  • fix(slack): users.info was sent as JSON, so Slack never saw the user param by @kubet in #6616
  • fix(queue): forwarded prompts cannot strand, Stop cannot leak, bubbles keep one identity by @markokraemer in #6598
  • perf(api): take audit writes and the owner-email fan-out off the request path by @markokraemer in #6618
  • perf(ci): dev single-arch + layer cache + fix the frontend-skip by @markokraemer in #6619
  • perf(ci): build staging images natively per arch, with a layer cache by @markokraemer in #6622
  • fix(gateway): re-apply gateway-side provider shaping (codex store:false + 3 more) on the native path by @markokraemer in #6623
  • ci(dev): explicit Deploy Dev action instead of per-push storm by @markokraemer in #6621
  • fix(web): boot-time composer shows the session's real agent; panels survive boot→ready by @markokraemer in #6625
  • deploy-staging: Cloudflare auth failure must not freeze the staging frontend by @markokraemer in #6626
  • ci(dev): auto-deploy latest + cancel-stale (builds are fast now) by @markokraemer in #6627
  • ke2e: never replay a create through an edge-laundered 5xx (fixes all 22 release-gate failures) by @markokraemer in #6628
  • fix(web): boot composer reads the stashed agent pick before /start answers by @markokraemer in #6629
  • fix(gateway): upgrade @ai-sdk/amazon-bedrock 5.0.24→5.0.59 (parse redacted reasoning; fixes GPT-on-Bedrock 502) by @markokraemer in #6630
  • refactor(gateway): make the AI-SDK-native path the default everywhere (verified across all providers) by @markokraemer in #6631
  • Unblock the release browser gate, and stop leaking the Vercel bypass secret by @markokraemer in #6632
  • gate: 1 api worker per shard — 19 concurrent collapsed the staging write path by @markokraemer in #6634
  • gate: survive a transient 503 at world bootstrap; staging API floor 6 tasks by @markokraemer in #6636
  • gate: fix the four session residuals, and stop reruns colliding with themselves by @markokraemer in #6638
  • edge: laundered 503 parses as an AI-SDK error; Worker deploy survives a dead credential by @markokraemer in #6639
  • staging: raise the request deadline to 55s (cross-region DB) by @markokraemer in #6641
  • gate: boundary-asserting skips and named quarantines are legitimate --require-all outcomes by @markokraemer in #6643
  • gate: a one-step assert-then-skip flow counts as asserted by @markokraemer in #6645
  • IAM-12: poll effective-permission probes through the cross-task IAM cache window by @markokraemer in #6648
  • perf(boot): remove fresh-session Git network round trips by @Ino-Bagaric in #6647
  • perf(boot): deliver exact Git delta during sandbox creation by @Ino-Bagaric in #6650
  • docs(boot): record deployed Git timing by @Ino-Bagaric in #6651
  • perf(boot): make Git bundle reuse durable by @Ino-Bagaric in #6652
  • docs(boot): record durable Git cache benchmark by @Ino-Bagaric in #6653
  • chore(runtime): bump OpenCode 1.17.11 -> 1.18.19 everywhere by @markokraemer in #6655

Full Changelog: v0.13.0...v0.13.1