Postfix-bulk accepts any sender from EmailService [skip ci]
The relay is now a platform outbound host that every organization's campaign mail may go through, as whatever From that organization sends as. Only the null sen...
Sign hello.kamocrm.com with its own customer key, by the From domain itself
Campaign mail leaves as hello.kamocrm.com through postfix-bulk. It gets its own DKIM key (selector customer, published as customer._domainkey.hello), and use_es...
Postfix-bulk, a second outbound relay for campaign mail, with delivery results fed back
Campaign mail now leaves through its own relay on k3m1 (egress 47.181.8.87) as hello.kamocrm.com, so complaints about bulk mail never touch the reputation of ma...
Dial 911 and 933 from every extension, with an MLTS email notice
Extensions could not reach 911: no outbound route matched 911 or 933, so from-internal fell through to bad-number and played "cannot be completed as dialed" wit...
Report each account's coder allowance to the console
The Linux Desktop menu is getting two meters β how much of the member's numbers. transcripts do not carry them, and neither OTel metric is about the subscripti...
Say whether a terminal is working or waiting for its member
Every terminal in the listing now carries `state`: busy, or waiting. It is the one question somebody asks of a window they cannot see, and it is what a minimize...
Let a coder session run at the model and effort the member picked
for a new session and for a resumed one alike, since `--model` and `--effort` are per-session flags either way. They are the ONLY part of the command a caller ...
A coder terminal wears the name coder gave the conversation
running had long since been titled "Startup fee implementation and Harmony account adjustment". Two separate things were swallowing that name. **The listing.**...
Budget the last four services to gain a second replica
BillingService, EmailService, KamoLOS and SecurityService now run two pods, each having put its shared-effect scheduled sweeps behind a distributed lease first....
Budget the six services that just gained a second replica
AIService, KBService, ESigService, VOIPService, DocsService and TranslateService now run two pods, so a drain of either node must evict them one at a time rathe...
Measure whether a deploy actually costs anyone a request
Every fix in this programme is a claim about what happens during a rollout. Until now those claims were untested: MediaService shipped with strategy Recreate at...
coder sessions on the dev machine, listed and resumable
is here, because the machine is the only thing that knows any of it. ## The session index home, exactly as their terminals are whatever tmux is running. No ta...
Budget every drain, and fail a deploy that regresses rollout safety
PodDisruptionBudgets for the 25 Deployments that now genuinely run two replicas. minAvailable: 1 lets a drain evict one pod and wait for its replacement instead...
Pin the session id, and link the terminal session into VS Code
`--session-id <uuid>` is chosen at prepare time rather than left to the CLI, which is what makes the editor hand-off deterministic: the id is known before the s...
Host a Send-to-AI dispatch in a Remote Terminal
composed prompt β and answers with an opaque TOKEN. A terminal that connects command typed into it. THE TOKEN IS THE WHOLE SECURITY DESIGN. `bootstrap=<command...
List, rename and end a member's terminals
GET /terminals?user=X, POST /terminals/<id>/kill, POST /terminals/<id>/title. THERE IS NO DATABASE BEHIND THIS, and that is the design rather than a shortcut. ...
Give the agent a PTY endpoint for Remote Terminal
GET /pty upgrades the connection to `kamo-pty` and becomes a shell: one PTY per browser tool window, `su - <user>` into `tmux new-session -A`, frames pumped bot...
64G swap on the dev machine, and catch access that fails intermittently
The blank white page was the VM out of memory. 16Gi of guest RAM with NO swap means "out of memory" goes straight to the OOM killer: applications die mid-work, ...
Open Send To AI in a VS Code session tab, not a Konsole window
A dispatch now starts a BACKGROUND session and hands VS Code its session id, instead of running the CLI in a terminal window: Passing the prompt to the URI in...
Swap the voicemail greeting to KamoCRM-LeaveVM
24.9s, down from 27.9s. Uploaded alongside the previous recording rather than over it, so rolling back is a one-line change to KAMO_VOICEMAIL_GREETING plus a di...
Give every kamocrm extension WebRTC, and gate outbound calling
All 21 kamocrm team members now hold an 8XXX extension on the k1m1 PBX (Chris renumbered off 7255 to 8134). Two changes here back that. WebRTC endpoint blocks ...
Recorded-call notice on extension-to-extension calls
Completes the third call path. Staff-to-staff calls never touch the attendant β they go from-internal -> ext-local, where the Dial belongs to FreePBX β so [from...
Recorded-call notice on direct-dialled extensions too
A caller who dials an extension over the greeting now hears the notice as well. That path went through from-did-direct, where the Dial belongs to FreePBX's ext-...
Recorded-call notice to both parties at once, then a bridge tone
When an agent answers a queued call, the caller hears the client notice and the agent hears the agent notice at the same time, then a shared 1000Hz tone marks t...
Swap the inbound greeting to KamoCRM-Main-Intro-3
Third take, 40s (down from 60s). Uploaded alongside the previous two rather than over them, so rolling back to either is a one-line change to KAMO_ATTENDANT_INT...
Apps, media, edge manifests and network policy
- config.ini carries a [zone] block from day one so a second region is a config edit, not surgery. Secrets are substituted by an entrypoint at container start...
CouchDB and RabbitMQ on k3m1
CouchDB q=8 / n=1, verified live. q is fixed at database creation and KamoPBX creates a database per account plus monthly MODBs, so q is sized now for the event...
Phase 0 infrastructure gate
- TURN over TLS on 5349 with a real cert (turn-kamocrm-com-cert). Without turns:, a customer behind a 443-only egress firewall has no media path. Verified e...
Swap the inbound greeting to KamoCRM-Main-Intro-2
Uploaded as a new file rather than overwriting the old one, so rolling back is a one-line change to KAMO_ATTENDANT_INTRO plus a dialplan reload β no re-upload n...
Queue timeout and "press 0" both fall through to voicemail
Replaces the hand-rolled Dial()+Goto queue loop with app_queue. The deciding factor is DTMF: digits are NOT matched against the dialplan while Dial() is running...
Hold-music queue ringing 8000 and 8080 simultaneously
Eight hold tracks uploaded as the `kamocrm-hold` MOH class, shuffled. The random ordering comes from `random=1` on the row in FreePBX's `music` table, which is ...
Recorded greeting, dial-by-extension, 1/2 to operator
Replaces the music-on-hold hold pattern with the recorded intro: - **************** plays the greeting AND listens at the same time, so a caller can dial ove...
Inbound auto-attendant β music on hold + dial-by-extension
Inbound calls had nowhere to go: the `incoming` table was completely empty, so even a delivered call would have dead-ended. Adds the attendant context plus the ...
Bounce a bare visit to the Kamo login, and end the session on tab close
Closing the KamoDesktop tab left a live session sitting on the machine. Guacamole keeps its auth token in localStorage (GUAC_AUTH), which survives closing the t...
An access canary that actually logs in, and alerts that reach a person
Two gaps, both proven against the live cluster today. FIRST: every existing KamoDesktop alert measures whether a COMPONENT is alive. All four were green during...
Dispatch a bug report into sage's open VS Code
URI handler that creates a conversation in a RUNNING window and pre-fills the input, which is the only way to reach the editor sage already has open instead of ...
Provision MARKETING_EVENTS for visitor conversion signals
Marketing tracking codes credit a partner for the signups, organizations and paid accounts their link produced, and those three moments happen in services that ...
Swap the hero reel to kamo13
kamo13.mp4 uploaded to MinIO at public/kamo13.mp4 (30 MB, sha256 174aaec6β¦, verified byte-identical to the local source after transfer β this link has a history...
Deploy a streaming server and an ABR ladder for the hero reel
MediaMTX serves live channels over HLS, WebRTC, RTSP and RTMP, and loops the marketing reel as an always-available channel via alwaysAvailableFile β no ffmpeg s...
Workstation-side mount script for the KAMOTEAM share
NFSv4 over the NodePort, mounted soft with a systemd automount so an unreachable cluster returns an error instead of hanging every process that touches the fold...
KAMOTEAM shared folder on every desktop
desktop-1 hosts /srv/kamoteam and exports it over NFSv4; every VM user gets ~/Desktop/KAMOTEAM as a symlink (via /etc/skel for new accounts and the agent for ex...
Alert on OOMKills, and on the occupancy that precedes them
Nothing was watching memory. MediaService was OOMKilled every few hours for most of a day and EmailService six times, and the way anyone found out was a chat wi...
Block outbound SSH except sage, resolve k1m1/k3m1, bundle the agent dir
Outbound tcp/22 is rejected for every uid except root and sage, keyed on socket owner so future accounts are covered without re-running anything. Reapplied at b...
Standard toolchain, taskbar pins and passwordless installs for all users
Adds krita and maven **************** were already present), pins Chrome, VS Code, Kate, Spectacle and Krita to the taskbar for every user, and lets dev users i...
Agent secrets in CI, guacamole liveness, availability alerts
Alert expressions verified against the live Prometheus. Uses kube-state-metrics rather than kubevirt_* β the KubeVirt metrics endpoint is not scraped here, so r...
Idempotent agent installer, shared by cloud-init and live installs
Staged under /opt/kamo-desktop-agent so install-agent.sh has a distinct source and destination. Covers netplan-by-driver, cloud-init network disable, xrdp sessi...
Add the provisioning agent and its unit tests
Python 3 stdlib only. Every mutation runs subprocess with an argv list, never a shell string; passwords go to chpasswd on stdin so they stay out of /proc.
Enforce storage quota on inbound delivery, and stop shipping the DB password
Object storage already refuses content that would take an organization past its ceiling, which covers every domain going through the object store. Inbound mail ...
Enforce storage quota on inbound delivery, and stop shipping the DB password
Object storage already refuses content that would take an organization past its ceiling, which covers every domain going through the object store. Inbound mail ...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.