Stop a support ticket opening a plain chat window full of JSON
Two faults, one symptom. Assignment makes the agent a member of the ticket's media session, so the incoming-message notification reached them and ChatNotificati...
Declare the calendar tokens at :root, and rebuild the event dialog
The tokens were declared on the calendar wrapper element, which reads as the tidy thing to do and is wrong. MUI dialogs and menus render through a portal into d...
Actually override the operator label ink
The previous attempt raised specificity, which was the wrong diagnosis: tailwind.config.js sets `important: true`, so every declaration in .operator-label ships...
Rebuild the event dialog around when, not around fields
Ten identically weighted outlined fields in a column, in the order the columns happen to sit in the table: title, description, location, calendar, all-day, star...
Auto Assignment strategy, and open an assigned conversation automatically
Topics settings gains the fourth strategy. The list rows and the edit dialog share the same label, and the key shipped to kamo-translation-dictionary first — me...
Make every line of the hero readable
The kicker and the three readout labels were painted by .operator-label's own dark ink, not by the colour set beside it: a class and an sx rule carry the same s...
Make the pinned-app eyebrow actually white
The previous attempt overrode .operator-label's ink with a class-qualified sx rule, which could never have worked: tailwind.config.js sets `important: true`, so...
A pinned app's chip launches the app, not its settings
The leading chip of a pinned band was linking to the app's settings landing — the same place its first entry already goes. It now borrows that app's nav option ...
Restore CRLF endings on the three session files
The previous commit rewrote them with LF, inflating a ~56-line change into a 700-line whole-file diff. Content is unchanged; this puts the endings back so the h...
One writer of the *** TTL, and it is the activity tracker
/api/user-info wrote the session TTL straight to Redis, bypassing every service-side rule — and useUserInfo polls it every five minutes forever, so that one lin...
Pin an Enabled App to the home launchpad
Each Enabled Apps topic now carries a pin toggle, in the Settings sub-option menu and on its section header on the settings landing page. A pinned app gets its ...
Give Mobile Copilot setup its own full-width page
The phone-provisioning surface was the third tab of the Interaction Center slideout, which capped it at a 500px rail — too narrow to show the install code and t...
Rebuild the calendar around the current moment
The page was a functional grid with the chrome doing the talking: a 3px rainbow rule under the toolbar, a second one over the content, gradient buttons, and fou...
Give each account tab the default order it should open in
The three tabs opened in whatever order the API happened to return, which for members meant the newest sign-ups were buried and for team members meant no order ...
Scope the default-lead-source readiness banner to Residential Mortgage markets
The vendors/products tab showed the "Finish the mortgage vertical to designate a default lead source" warning on every market tab, including Product/Service and...
Centre the selection bar on the contact list, not the page
The bar that appears when rows are selected is absolutely positioned at left 50% with a translateX(-50%), but its nearest positioned ancestor was the whole page...
Stop defaulting new contacts into the shared org book
The create dialog targeted the book flagged isOrgDefault, so every member's contacts landed in the one book the whole organisation could read — half of why the ...
Split the access log and its detection rules into sub-tabs
The rules that decide what gets flagged were an accordion below the grid — collapsed by default, so the configuration was something you had to know was there, a...
Administrator bar panels rendered their key paths, not their copy
TipPanel took the panel's DOM id in a prop called `id` and then built its message keys from that same `id`, so every panel asked for **************** and next-i...
Let the access log fill its pane and page from the server
The tab bar already says "System Access Logs", so the h4 above the stats was the page's name twice. Dropping it also lets the pane use the shell every other Sec...
Back-to-home arrow on the main workspace headers
Carries the settings-page arrow across the rest of the app: Accounts, Leads, Commerce, Marketing (all four tabs, via the shared layout), Knowledge Base, HR, Net...
Stop the list scrolling when it already fits
Three things added height that was not content, so a list short enough to fit still got a scrollbar: - the infinite-scroll sentinel was rendered unconditionall...
Explanatory panels on every administrator bar link
Somebody who created their organization ten minutes ago meets nine links they have no way to read. Hovering or focusing one now unfurls a panel that answers, in...
Restore the administrator bar changes reverted by 3926d1d8
3926d1d8 carried AdminQuickLinks.tsx back to its ae45fc9c^ blob, undoing the org plural label, the short Blocks/Logs names and the gap removal. Same content as ...
String row ids, org-coloured controls, page icon, centred error bar
Creating a book and selecting it answered "Not found". CockroachDB unique_rowid() ids are 64-bit — a real one is 1200081912680906758 — and JSON.parse rounds any...
Tighten the administrator bar — org label, short audit names, no gap
Three changes to how the bar reads at nine links: The team-members entry now wears the org's own plural label from Behavior & Labeling, so an org that calls th...
Back-to-home arrow left of every settings page title
Settings pages had no way back to the launchpad short of the nav rail. SettingsView's optional backHref now defaults to home and renders unconditionally, so the...
The rest of essential setup on the administrator bar
Security Roles, Departments and Job Titles join the configuration group, left of the audit pair. They are the three Essential Setup tabs the bar was missing — B...
Access blocks in the administrator bar, audit links to the trailing edge
Access Blocks and System Access Logs are the two screens on the bar that answer 'who got in and who did not' rather than configuring anything, so they group tog...
Name and edit address books, and rebuild the page around them
Adding a book POSTed a hard-coded placeholder name with no prompt, and nothing anywhere could rename one — so every book an org had was called the same thing, p...
Administrator bar above the launchpad cards
Five screens an org administrator opens constantly — team members, behavior & labeling, stats & costs, apps & features, system access logs — each two or three c...
Stop /api/user-info renewing the TTL for idle users
This route writes the *** TTL straight to Redis, so it bypassed the gating in SecurityService, MediaService and ChatService entirely — and useUserInfo polls it ...
Hash with BLAKE3 only, so skipping the upload actually saves time
Dedup worked — the server logged 'linked WITHOUT upload' and 358 MB never left the machine — but the member still waited, because computing SHA3-256 alongside B...
Skip the upload when the platform already has the file
Sending the same video to three people meant three full uploads. Dedup collapsed them into one stored object, but only once each transfer had finished — so the ...
Show generated preview storage as its own line
Thumbnails and preview images now count toward the organization's total, so the client should be able to see what they cost rather than find them folded into an...
Recover a received attachment whose first request was rejected
A video arriving in a conversation could not be played until the page was reloaded, while a video the member had just sent always played. Both copies were byte-...
Let a member keep a video or audio attachment, not just play it
The player answers one intention. Wanting the file on disk is a different one, and video and audio were the two attachment kinds with no way to do it — a docume...
Show branding and Docstive document storage
Both are written straight to the object store with no size recorded in the database, so they read as zero until a sweep measures them. They now have their own l...
Show text message attachment storage
MMS attachments live inline in the database as data: URIs rather than as files, so they had no size record and were never counted. They now have their own line.
Show every storage category separately
Call recordings, voicemails, chat attachments, HR resources and marketing materials each get their own line instead of sharing one "Documents and images" row wi...
Say why mailbox storage can read zero
Mailbox bytes count only the mail Kamo actually hosts. An organization on Microsoft 365 or Google Workspace has its messages on that provider's disks, so its Ma...
Show storage usage on the account stats tab
The tab said "No usage data available for this period" for every organization. billingApi.getCurrentUsage() is a stub returning { meters: [] }, and UsageMeters ...
Popover X closes the window, not just the popover
Dismissing the popover already had two affordances (click outside, Escape), so an X that only dismissed it was a duplicate and left no way to get rid of the hea...
Split Available on the catalog verdict, and stop Stage publishing an app
The account Apps tab derived Available / Not Available from development stage, so it contradicted the platform catalog the moment an operator published or withh...
Split Apps & Features into Available / Not available / Deprecated
One flat list mixed apps the platform offers with ones it does not and ones it has retired, so the operator had to read every chip to tell them apart. The buck...
Load Allowed Apps from an endpoint tenants can actually read
appCatalogApi.list() is platform-owner-only, so on any tenant org the Branch Types editor showed no apps and the save guard — which exists to stop an empty cata...
Rebuild after the Apps & Features strings reached the dictionary
Run 545 failed the i18n key guard on 60 keys. Not a code defect — the kamo-internal commit was pushed at 14:10 and the dictionary strings landed at 14:18, so th...
Drop the unused stageLabel helper
Stage names are rendered from message keys, so the English-only helper had no caller left.
Route the Apps & Features copy through next-intl
kamo-internal serves 22 locales and every user-facing string has to come from a message key — hardcoded English breaks every non-English operator. The tab and t...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.