Changelog
What's new.
Every improvement to the platform, as it ships.
· kamo-shared-library
Every SI speaks by its personality, and the tables for background sound, voice consent and caller phrase memory
PhoneStyle compiles an SI's traits into spoken phone rules (contractions and address forms, warmth, humor, energy, hedging, empathy, curiosity, register, regional wording) plus the numbers the voice pipeline applies: a filler cap per call (D3, off until the A/B), the gap between listening sounds (D4), laughter and emotion range (D6), the resting tone and the end-of-turn patience. An SI with no personality yet speaks with the registry defaults (D2). AiAmbienceSetting (D7), AiVoiceCloneConsent (D12) and AiCounterpartyMemory are declared so KamoInitializer can recreate kamoai-service's new tables.
· MediaService
SIs play Texas Hold'em with members, and every member's Cheddar works again
SITP TPGAMES (owner 2026-10-26). Cheddar wallet: - The wallet's only door (universe-gateway -> universe-persistence) has had no endpoints since the KamoUniverse game was parked on 2026-09-28, so every Hold'em buy-in since has failed ('the Cheddar wallet is not answering'), for people and SIs alike. CheddarLedger writes the same three tables in the kamouniverse database directly (same cluster, this service's own DB user), with the persistence service's rules: one transaction per movement, unique idempotency key (replay = applied false), signed ledger line; a debit is a conditional update so two buy-ins cannot overdraw. CheddarWalletClient now uses it. - The one-time signup grant (1,000,000, key signup_grant:<id>), which only the parked 3D world ever made, is made the first time a member's wallet is touched through a games app they have - person or SI the same. CheddarSiGrants opens every non-retired SI's wallet ahead of time (hourly, singleton, paged by the SI roster's member ids; nothing else touched). Cheddar has no purchase path, so no SI ever buys it with money. Hold'em SI: - HoldemSiBrain: Monte Carlo equity over HandEvaluator vs the live opponents, pot odds, style CAUTIOUS/BALANCED/BOLD and skill CASUAL/CLUB/SHARP, 300 ms cap. Its only input is the SI's per-recipient HoldemTableView: own two cards and public information, never other cards or the deck. - HoldemSiPlayer: event-driven (HoldemTurnEvent after each published frame, ~1.4-2.3 s pause inside the 30 s clock). Sits when a person invited it and is seated, acts through HoldemGameService.act with expectedSeq, rebuys at most 3 times a day per table, sits out with a sitting-out person and leaves when no person is left: SIs never play among themselves. Redis claim per table; style/skill per SI per table in Redis. - HoldemSiEligibility every step: Hold'em app, PLAY_HOLDEM (SI's, or the inviting/seated person's: No Insubordination), runtime not paused. - POST /tables/{id}/si-play (style, skill), the calling SI only. - ChessFaces reads the theme host outside the transaction (ratchet), cached. Tests: CheddarLedgerTest 4 (H2), HoldemSiBrainTest 5, HoldemSiFairnessTest 3 (the SI's view holds no other player's cards and no deck; hidden cards cannot change the decision; the player has no door to raw hand rows), HoldemSiPlayerTest 7; games suites 240 green.
· MCPGatewayService
Mail_send takes an HTML body's plain-text version and one text file written by the caller (TPRECAPS)
The SI's meeting recap now carries the meeting's full transcript; past the body's limit it goes as a .txt attachment. textBody (with bodyFormat HTML) becomes the multipart/alternative text part; textAttachmentName + textAttachment become one attachments part (name kept to safe characters, .txt). The attached text is planned with the body for disclosure. Golden tool lists regenerated (mail_send only).
· EmailService
A message's sender facts for SI identity checks; SI_AUTH_REQUEST belongs to no app
The provenance answer now also says what the message itself claims about its sender: From, Reply-To, the server that handed it to ours, and the SPF/DKIM/DMARC results recorded in its headers (header-only read, nothing marked). SI_AUTH_REQUEST is ungated: anyone may be asked by an SI to confirm a request was really them.
· kamo-shared-library
SI_AUTH_REQUEST notification kind and the SI authentication log entities
Owner 2026-10-26: direct orders reaching an SI over a channel that proves nobody's identity are confirmed by the member in Kamo first. Appends **************** (belongs to no app), declares si_auth_requests / si_auth_request_events (hand-applied DDL in kamoai-service **************** and support_ticket's media_session_guid index.
· kamo-internal
Choose who can invite an SI to meetings, on its Call options
Kamo Meet "Invite an SI" (owner order 2026-10-26): Only the people who supervise it (default) / Its supervisors and teammates / Anyone in your organization, with a plain-words explanation of each. Saved through AIService; MediaService enforces it.
· MediaService
Invite an SI from inside the meeting; who may invite an SI is the SI's own option
Kamo Meet "Invite an SI" (owner order 2026-10-26): - GET **************** for a signed-in person IN the meeting (creator, recorded participant, or handed this room's token by the meet sidecar from their own session: MEETPRES mark), the org's active SIs they may invite, grouped SUPERVISED / AVAILABLE, with photo (photo -> avatar), job title and availability (available, not online but can join, on another call, paused, unavailable). Never an SI in or on its way into this meeting (live participant, auto-join invitation, live ai_call into it); one that left is listed again. - POST .../invitable-sis/{memberId}: brings it in now through M1's one-instance path (participant upsert, exclusive dial claim; kamoai-service's unique live-call index behind it): concurrent clicks or two people place one call. - MeetSiInvitePolicy: supervisors (org graph reporting line, org owner) always; others per the SI's meeting_invite_policy (SUPERVISORS default | TEAM | ORGANIZATION). Enforced on M1 and meeting create for people, and M3's picker offers only invitable SIs (with "supervised"). SIs keep the TP12 SI-to-SI rule. - Room lookup on **************** theme host via ViewerThemeDomain outside any transaction.
· AIService
Who may invite this SI to meetings, on its Call options
Kamo Meet "Invite an SI" (owner order 2026-10-26): meetingInvitePolicy (SUPERVISORS default | TEAM | ORGANIZATION) read and changed beside the SI's other call and meeting options, same rights; stored in **************** (DDL **************** applied). MediaService enforces it.
· kamo-shared-library
MeetingInvitePolicy — who may invite an SI into a meeting; declare ai_member_call_options
Kamo Meet "Invite an SI" (owner order 2026-10-26). An SI's supervisors (its reporting line over manager and SI-supervisor edges, the org owner) may always invite it; its own meeting_invite_policy says who else may: SUPERVISORS (default), TEAM (named team, same manager, its reports) or ORGANIZATION. Fails closed off the graph. AiMemberCallOptionsRow declares the hand-made ai_member_call_options table (and the new column) so KamoInitializer can build it from code.
· MCPGatewayService
Games_* - an SI plays chess with members
SITP TPGAMES. Eleven tools over MediaService's chess endpoints, gated as a member's board is (Chess app + PLAY_CHESS, again downstream): games_list, games_get_state (diagram, FEN, legal moves, move text, record), games_invite (optional skill), games_join, games_decoder, games_move (SAN or squares, validated server-side), games_offer_draw, games_decoder_draw, games_resign, games_rematch, games_set_skill. The SI's moves are otherwise played for it by MediaService's engine; the model does the talking. Internal writes: no approval class, NOT_DISCLOSING; reads NOT_CONTENT. chat_read names the game on a GAME_INVITE card. Approval phrases + CHESS_GAME noun; games_ prefix; goldens regenerated (11 added). Tests: GamesPackTest 7, ChatPackTest +1; full suite 1968 green.
· EmailService
A plain-text version beside the HTML, and an SI's recap letter for a supervisor when the SI has no mailbox (TPRECAPS)
/api/email/send takes an optional textBody: the body is then multipart/alternative (text, then the HTML), inside mixed when there are attachments. POST **************** (KamoAI secret, multipart like /api/email/send) sends a letter its caller built as the organization's transactional mail: NoReply@ its domain only when that domain's SPF authorizes us, else the platform's under its name, with the text version and up to two files.
· kamo-shared-library
Declare ai_call_recap and ai_member_recap_options for the SI call recap email (TPRECAPS)
One row per SI phone call that had a conversation, so its recap reaches the supervisor once; and an SI's two recap options, both on by default. Hand-applied DDL (kamoai-service **************** declared here so KamoInitializer can recreate it.
· MCPGatewayService
Every SI has a clock: time_now, time_convert, time_calc
Owner report 2026-10-26: asked the time on a call, an SI said it had no clock. The clock and calendar every person has: the time now in the SI's zone or any other (with the day of the week), a time said in another zone, and date arithmetic. Reads, no right, no record.
· MCPGatewayService
A teammate's proven email to an SI is their request and their order
Owner report 2026-10-26: the owner emailed their SI to call them; the email was never an order ([ORDER] no order) and every later check-in read it as outside mail and asked the owner for approval. Mail EmailService proves a teammate's own mailbox sent to the SI is now inside mail (sentByTeammate, internal taint) and a wake or citation like a chat message: author, recency, this run and taint all checked. A forged From stays outside mail.
· MediaService
An SI member plays chess with members, its moves chosen by Kamo's engine
SITP TPGAMES (owner 2026-10-26: an SI asked to play chess did not know how). - ChessSiPlayer: event-driven (ChessTurnEvent after each committed change). A member's invitation: the SI joins and its mind is woken once (a chat notification on the card's conversation) to greet them. A member's draw offer: accepted unless the SI is ahead by more than half a pawn. Its turn: ChessAi (alpha-beta + quiescence, time-budgeted) picks the move at the SI's level and it is played as the SI through ChessGameService.move, the same validated path as a click. ~0.7 s pause, one pending task per game, 200 per pod, Redis claim across pods, FEN re-checked before the write. - ChessSiEligibility, every move: Chess app on, PLAY_CHESS applied, runtime not PAUSED/BLOCKED/RETIRED. - Recovery sweep (singleton, 30 s) for a turn a restart or pause missed. - No SI-vs-SI boards (invite refused; nobody is played for). - Skill per game (CASUAL/CLUB/MASTER, default CLUB) in Redis, no DDL; POST /games/{id}/si-level; written moves (SAN or e2e4) on /move. - The board shows the opponent's photo (opponentAvatarUrl was always null), opponentIsSi and siLevel. - Fix: one ChessAi shared by every request raced its own deadline fields. Tests: ChessSiPlayerTest 11, ChessSiRulesTest 15, query parse 1; chess and games suites green (100).
· EmailService
Prove a teammate sent an SI's email, so an emailed request can count as their order
An internal endpoint answers whether a message in a member's own mailbox was sent by a teammate: its From reaches a member of the same org, and that member's own Sent folder holds the same Message-ID addressed to the recipient. A forged From never passes; read only.
· kamo-internal
Pipeline shows when each deal and loan opened, and sorts by it
Deals and loans show "Opened <date, time>" in the member's zone. For loans imported from Arive that is Arive's creation time — before, every imported deal sorted as opened on the day of the import.
· SecurityService
Pipeline loans opened in Arive carry Arive's creation time, not the import's
· kamo-shared-library
Loan summaries carry when an MLOS loan really opened (openedAt)
· kamo-internal
Prospects — pre-application deals leave the open pipeline
A deal whose loans are all at intake, qualification or pre-approval (no application taken yet) shows under its own Prospects view and count. Open, its KPIs and the stage rail now count only applications in progress; Kamo's own drafts stay in Open. Nothing about the loans changes.
· kamo-internal
Pipeline shows pre-application stages, every outcome, and archived loans
- statuses: Application Intake, Qualification, Pre-Approved; Approved Not Accepted, Closed for Incompleteness, Rescinded, Pre-Approval Denied / Not Accepted — one shared list instead of two hard-coded copies - board and deals: archived loans leave the open pipeline (shown under past, marked Archived); unfunded outcomes count as cancelled - "submitted" is no longer statusId >= 2 (ids are identities, not order) - Arive stage map offers the pre-application statuses
· SecurityService
Kamo holds every Arive loan, at the status Arive really has it
- import and inbound events adopt every loan — open, funded, adverse or archived — instead of only "active" ones - no per-loan Get Loan or crmReferenceId stamp: each is a Zapier task on the client's plan (20,000+ for one import); the GUID recognises the loan - Arive's dates are applied as the system of record (cleared where Arive has none, e.g. an application date on a pre-application file) - a stage behind Kamo's is realigned, on the record, instead of refused - draft-only guards (borrower edits, own submit, SI credit pull / AUS) cover the pre-application stages; "submitted" is no longer statusId >= 2
· kamo-shared-library
Pre-application statuses, every HMDA outcome, archive, and Arive's real dates
Arive loans were mapped from stage names alone: every pre-application stage became Application Taken, every archived loan Withdrawn (funded ones too), every adverse action Denied, and dates were stamped with the import day. - LoanFileStatus (appended — ordinal column): APPLICATION_INTAKE, QUALIFICATION, PRE_APPROVED; outcomes APPROVED_NOT_ACCEPTED, INCOMPLETE, RESCINDED, PREAPPROVAL_DENIED, PREAPPROVAL_NOT_ACCEPTED - state machine: optional pre-application arrows; each outcome only from the statuses it can follow - LoanFile.archivedAt: archive is a flag beside the status, not an outcome - Arive: ADVERSE stage + AriveAdverseReason map to their own outcome (both ways); Loan Setup = Application Taken, Disclosed = In Processing; dates from Arive (TRID date, signed docs, funding wire, stage dates), never today - realignToExternal: the external MLOS is the system of record for the stage - HMDA action taken from the real outcome; in-progress files have none - commerce / transaction rollup / close horizon handle the new statuses
· kamo-internal
External MLOS lives on the mortgage market and on each loan
- Settings → POS markets → mortgage market: new "External MLOS" tab (Arive via Zapier, MeridianLink) with connection, stage map, transaction window and the import of active loans; the lead-market MLOS picker is replaced by a pointer to it - loan application: a status bar showing the loan's place in the external MLOS (linked / sending / needs fields / refused), resend and open-in-MLOS; sections the MLOS owns are read-only with a note saying where to edit them - pipeline deal card: external MLOS chip - lead page: Arive/MeridianLink actions removed - proxy routes move to ****************
· DaemonService
MeridianLink poll applies to loan applications, not leads
Changed loans are matched through MLOS_LOAN_LOS_LINKS and sent to securityservice by connection; unknown loans are adopted only where the LO unit maps to a single org.
· SecurityService
Mirror every loan application to the market's external MLOS, both ways
Arive and MeridianLink connect to the MORTGAGE (MLOS) market instead of a lead market, and sync loan applications instead of leads. - LoanLosSyncService: queue + 20s singleton tick; creates the loan in the external MLOS once its required fields exist, pushes stage changes, backs off on failure, offers resend / open-in-MLOS / a per-loan status view - LoanLosSyncInterceptor: sections the external MLOS owns (borrowers, property, loan terms for Arive) answer 409 in Kamo; saves enqueue a sync - LosLoanApplyService walks the pipeline forward to the MLOS's stage (never backwards), tagging the move so it is not echoed or emailed - LosLoanAdoptionService: a loan created in the MLOS becomes a Kamo loan application on the borrower's account, grouped into one transaction with that borrower's other loans opened within the connection's window (30 days) - Arive inbound: loans recognised by Kamo reference, GUID, then loan number; paged import of active loans (Find Loans / Get Loan zaps) - connection endpoints move to **************** - lead-level LOS controllers and services removed
· kamo-shared-library
Sync external MLOS (Arive, MeridianLink) at the loan, not the lead
The lead-level LOS link is replaced by a loan-level one: every loan application is mirrored to the market's external MLOS and back, linked one-to-one by MLOS_LOAN_LOS_LINKS and driven by the MLOS_LOS_SYNC_QUEUE. - LoanLosProvider SPI (create / push / missing fields / locked sections / open link) with Arive (via Zapier) and MeridianLink implementations - AriveLoanMapper: full loan -> Create Loan (94 inputs, co-borrower), stage updates, adverse action, paged Find Loans / Get Loan, and Zapier's row text back into a loan patch - LoXmlFieldMapper maps the loan application, not the lead - AriveConnectionConfig: stage map to loan status, transaction window (30d), sync-since and import progress - pipeline transitions carry a syncSource so echoes are not re-sent and borrowers are not emailed for an MLOS-driven move - lead-level adapters, patches and LeadService LOS hooks removed
· SecurityService
Coded terminology — RxNorm, ICD-10-CM, CVX and HCPCS loaded from their publishers; pickers, real code checks, and the ONC high-priority interaction screen
Loaders (ehr.terminology): RxNorm Current Prescribable Content (NLM, MD5 verified against NLM's page; **************** drug->ingredient resolved through components/generics/packs, drug->dose form, DEA schedule from DCSA), ICD-10-CM order file (billable flag, short/long titles, prefix closure), CVX + vaccine groups (CDC), HCPCS Level II quarterly (CMS; modifiers and CPT never loaded). Releases record source URL, publisher version, effective dates and checksum; only COMPLETE releases answer; supersession ends a release where the next starts. Paced JDBC batch writes; daily 09:30 UTC refresh under the fleet lease; on-demand load for platform admins. Search: token-prefix index (no trigram/GiST on Yugabyte), ranking rules pinned by tests; /status, /drugs, /diagnoses, /vaccines, /procedures, /lookup. Validation: ClinicalCodeChecker refuses codes a loaded release lacks (ICD by date of service; header codes refused on claims, warned elsewhere; CVX must be Active for a dose given here; RxCUI must exist; prescriptions must name an exact product when RxNorm is loaded and take RxNorm's schedule when stricter), falling back to format-only — and saying so — when no release covers the date. Interactions: the 15-pair ONC high-priority list (Phansalkar et al., JAMIA 2012) as data with its citation, members resolved to ingredient RxCUIs from the loaded RxNorm; 14 pairs screened (the QT pair's members are not published in the paper). Findings are high-risk warnings needing the override reason; the DRUG_INTERACTION gap stays open with a 'Screened only against ...' sentence, so isComplete() stays false. Allergies coded in RxNorm now also match by ingredient.
· kamo-internal
Message patients from the chart, consent first; reminders, confirmations and video visits on the schedule
- Messages tab: contact consent card (texts, e-mail, do not contact — when and how, history), a composer that asks the server before sending (consent, and a minimum-necessary prompt for clinical words the writer must confirm), and what was sent with its delivery status; the timeline refreshes - Day schedule and the chart's appointments: reminder outcome in words, confirmation (by text reply, or marked by the desk), and for video visits Start video visit (members-only join route), Send patient link (text / e-mail / their preference) and Copy patient link, with a warning when the practice's meeting settings would keep the patient out - Walk-in video visits get the same controls on the visit - Practice setup: a Reminders view — on/off, up to three lead times, channel, location, reply-C confirmation, quiet hours, the practice's own words with the allowed fill-ins, and a preview - Recalls: Send a text or e-mail, in the practice's suggested words, logged on the recall when it goes
· MediaService
A medical practice's video visit room, created server to server
POST /api/internal/meet/telehealth (X-Internal-Auth = internal.auth.secret, MeetInternalAuth) creates a meeting on the organization's own provider and live domain, hosted by the clinician and scheduled for the visit's start (so guest-link expiry counts from the visit). Guest access and the lobby are on for the room; the answer adds guestsAllowed=false when the org's Kamo Meet settings keep every guest out, so the practice is warned before a patient is sent a link that cannot admit them. Title is only "Video visit": meeting lists are outside the chart's care-relationship gate.

Your universe is waiting.
Start free in minutes. Add products whenever you are ready — no migration, no new logins.
Free forever — no credit card required