Retire a model the provider won't route, and stop quoting it at members
Follow-up to the router-catalogue fix. That stops unroutable models being LISTED; this stops one already in an org's catalogue from breaking the assistant and n...
List the Hugging Face models the router will actually serve
Chat goes to the Inference Providers router **************** but discoverModels asked the HUB for models that are "warm" somewhere — a different and much larger...
Drop the security level control from the batch settings
It was a disabled Select behind a "locked" tooltip, and a chip in the collapsed summary. Both reported a value the admin never chose: security level is derived ...
Format the phone numbers on the customer's quote
The page a customer opens printed every number exactly as stored — "9495550134" on the letterhead, and the same again under Your Contact. This app had no phone ...
Format the phone numbers on the printed quote
The document printed every number exactly as stored — "9495550134" on the letterhead, and the same again under Your Contact. Formatting goes through `app/lib/ph...
Show Getting Started to the System Member too
The button asked for organization ownership AND CONFIGURE_SYSTEM. The System Member is provisioned as an Administrator in every organization — all 34 of its mem...
The Getting Started API had no route to answer it
The launchpad button never appeared, and neither did any progress: the Java controller existed, the client existed, and the Next route between them was never wr...
Probe the bridge's real health, not a port that is always open
kamo-meet let one person into a meeting and then ended it the moment a second joined. The bridge had been hard-unhealthy for 41 hours: an in-place container res...
The logo caption sits under the logo, and says the domain is not reserved
Two unrelated symptoms, both in the brand band. **The caption printed over the logo when the slots stacked.** The preview was clamped with `max-h-full`, and th...
Stop the server asserting a tab title it cannot know
An org with no domain of its own still ended up titled "KamoCRM" after a refresh, briefly showing its real name first. generateMetadata resolves the tab's org ...
Stop refusing a domain because somebody else typed it first
Creating an organization 409'd on any existing row for the domain, which meant the first organization to enter "acme.com" locked out every other one — including...
Upload the compact logo that was previewed, not the file that was picked
The compact ("simple") logo slot is SVG-only — the backend writes whatever lands in it to a fixed <theme>/img/logo.svg key regardless of the file's real type, a...
Stop the attention flasher reverting an org's tab title to the platform's
A child org with no domain of its own showed "KamoCRM", flashed to its real name, then flashed back to "KamoCRM" and stayed there. TabAttention wrote `document...
Let the tab icon follow a simple-logo change instead of pinning the one captured at mount
TabAttention badges the browser tab, and it read the favicon ONCE in a mount effect. That effect runs before DynamicMetaLoader's config.json fetch has resolved,...
Give the generated favicons the same revalidation requirement as every other theme asset
Replacing an org's simple logo updated every surface that reads img/logo.svg and left the browser tab on the old mark. Generation was never the problem: provisi...
Enter the new organization here, not on a domain with no DNS
Creating an organization handed the creator a button pointing at `https://internal.<the domain they typed>/`. That host does not resolve: the domain is one they...
The scan's colours, the colour window, and the stacked slots
Five reports from the brand section, and the first two turn out to be the same bug wearing two faces. **Colours were never adopted.** The rule latched a `color...
A transient database fault must not 500 the request
The lead Communications tab reported "We couldn't load this lead's communications" for org 1168485648209608710 on 2026-08-28. The endpoint returned 500 five tim...
The document must not scroll behind the workspace
The authed shell is a full-viewport layout — nav fixed, content absolutely positioned to exactly 100vh — with one scroller inside it (.kamo-page-scroll). <body>...
Fill the content box exactly, scroll inside it
The pages grew to their content and pushed past the box the chrome gives them, so the document scrolled behind the shell and left dead background below the form...
Stop the form column stretching to the grid row height
The two-column layout gave the form column no align-self, so it stretched to the row height — and the row is as tall as the TALLER column. Once the form flows i...
One scrollbar, and actually use the full content width
AuthedChrome already owns the ONE scroll container for a page (.kamo-page-scroll, overflow:auto; height:100%), and PageWrapper exists specifically to stop a pag...
Next/link for Back to home, not a raw anchor
check-client-navigation fails the image build on a raw <a> to an internal route: a hard navigation tears down every open tool popup window and any unsent email ...
Whole-branch review fixes — provisioning, reachability, label data loss, a11y, dead code, org-context race, hex case
Seven findings from the final whole-branch review of the org-launch and Getting Started wizard feature, fixed together since several interact: - B1: **********...
Resolve the shared "skip" string against its full key
Six step components called t("skip") against an unscoped useTranslations(), which requests a top-level "skip" key that doesn't exist — next-intl then renders th...
Close the wizard Save-without-validation hole (review round 1)
Four findings from spec/code review, addressed: 1. CRITICAL - nothing gated the shell's Save button on step validity, so a member could blank the organizati...
Inert, not aria-hidden + pointer-events-none, for gated sections
CreateOrgForm's section() helper hid the four sections gated on "no branch type chosen yet" with aria-hidden plus a pointer-events-none className. aria-hidden o...
Dropping a gathered honeycomb in the goal removes every head in it
Jiggling mid-drag fires the gather gesture, which pulls every same-size head into the dragged head's cluster and anchors the honeycomb on the head under the poi...
Require an open god-mode window, not eligibility alone, for CONFIGURE_SYSTEM
hasRight was granting the bypass on the raw GD session flag, which SessionPlatformFacts's own javadoc names as the exact anti-pattern it exists to prevent: GD i...
Gate the web-alias path on parent context, not model alone
withBranchType previously turned useWebAlias on whenever the SELECTED MODEL allowed ROOT or a custom alias, ignoring the three parent-org preconditions BasicsSt...
Stop treating an already-transparent background as black, and remove the region not the colour
Two reported faults with one root cause: colour-based removal overwrote the alpha channel outright and never read the incoming one. An HTML canvas stores premu...
Switching conversations no longer stacks windows behind the maximized pane
Takes @kamo/tool-core 0.1.5, where leaving the maximized pane became two gestures instead of one. A navigator row click hands the pane to another conversation a...
Restore the verification screen's wallpaper, drop its ***, modernise its status plate
Three things wrong with /verification, all visible on one screen. The wallpaper never loaded. PostCompletionScreen called **************** but that parameter i...
Give the new tab a session, instead of one that bounces to login
"Open in new tab" was `window.open(location.href, '_blank', 'noopener,noreferrer')`. The session id is not in a cookie — it lives in sessionStorage, per tab, be...
Let a seeded org omit its year established
createOrg took the year as a primitive int, so every seed had to supply one even though YEAR_EST is nullable and the field is optional platform-wide. Integer, s...
YearEst is optional on the org, so admit the null that arrives
Year established is nullable on the Organization entity and SecurityService serializes the null explicitly, so the declared `number` was never the whole wire sh...
KB audience tiers are cumulative, matching KbReaderScope
The retrieval filter matched a reader's tier exactly: a TEAM_MEMBER had to match aiVisibleToTeamMembers and nothing else. So an article an author had deliberate...
Centre the launchpad tiles that are only an icon and a name
A leaf app pane in its compact form shows no sub-item rows and no description, so the icon/title row was heading a column with nothing in it — pinned to the top...
Restore the image-proxy and wallpaper work 266357d0 reverted, and land the permissions change it was meant to carry
266357d0 was built with the wrong index. Its tree came from a stale local HEAD rather than from the staged one, so it carried none of the permissions work its m...
GET /master takes VIEW_NOTES, like every other read here
It was the one read in this controller that took no right, deliberately: the two master notes were called fixtures of the home launchpad rather than the Notes a...
The invoice takes REVOKE DELETE, not REVOKE UPDATE
attachPdf writes PDF_BLOB_ID after the finalize transaction commits, on purpose: rendering inside it would hold the document-counter row lock across a MinIO rou...
Stop force-cache pinning "this org has no wallpapers" forever
The console backdrop and the member Wallpaper editor both read the tenant's `config.json` for `backgroundImageCount`, and both asked for it with `cache: 'force-...
The grid fetched every page twice, then blanked itself to do it
Opening /leads showed the rows, dropped back to a loading state, and showed them again. It was fetching twice. STOMP raises onConnect on the INITIAL connect ex...
Stop the image proxy serving an hour-old copy of another org's branding
Theme asset URLs are stable and say nothing about their contents: an org's simple logo is always `<alias>/img/logo.svg`. Every org is also seeded with the base ...
Make seeded and uploaded branding revalidate, so an org stops being served the base theme it was seeded with
A new organization is seeded with the base theme — the platform's own logo and backgrounds copied to the new org's keys — and those keys never change when the o...
Format every phone number a signature prints
The company lines went out as whatever the org record stored — "5555555555" — next to a member's line in the same block, so a signature could show a formatted n...
One formatter for every number, US and international alike
The formatter every phone surface shared kept the LAST TEN DIGITS of whatever it was handed and dressed them as a NANP number, so "+44 20 7946 0958" rendered as...
A window only announces its own conversation
The messageReceived handler dispatches chat:message-received, which is what makes ChatNotificationListener raise a chat window, and plays the arrival tone. Neit...
A relay only forwards its own conversation
ChatSessionSubscriptionManager publishes to a topic named after the session it subscribed FOR, never after the session the frame came from. That is safe only wh...
Filter every durable consumer to its own subject
A durable created through NatsMessageService.subscribe carried no filter subject, so it received the WHOLE stream regardless of the subject it was asked for. Th...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
