The terminal list was always empty — tmux escapes control chars
The field separator was a unit separator (0x1f), which is the obvious choice and silently wrong: tmux OCTAL-ESCAPES control characters in `-F` format output, so...
A list of your live shells, in the panel and beside the window
Terminals joins the Interaction Center to the right of Sales Scripts, gated on a provisioned dev machine — the same gate as the Linux Desktop nav option, read o...
Composed mail broke lines mid-word, for every recipient
Quill 2's getSemanticHTML() -- the value react-quill-new hands to onChange, and so every byte of body a member types -- ends its text conversion with .replaceAl...
A "why can't I accept?" override on the filter bar
Right-aligned on the /leads filter bar, wearing the Leads nav icon with the same prohibited emblem — so the thing on the nav that says "you are blocked" and the...
List, rename and end a member's terminals
GET **************** DELETE and PATCH on /terminals/{id}. Every one of them resolves the Linux account from the CALLER'S OWN SESSION and passes no account name...
Clip the background carousel so its zoom-in stops flashing a scrollbar
The incoming frame animates in from scale 1.04, and its wrapper did no clipping, so the overscale hung ~2% of the viewport past the bottom edge. A transform ove...
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. ...
A password shortcut in the hero, and a narrower gate
Two halves of the same subject. The shortcut. Changing your password was three rooms deep behind the rail — the one thing the room layout made genuinely harder...
Only the member or god may set a member's password
MANAGE_MEMBER_SECURITY passed the change-password gate, which made "can administer members" and "can take over any member's account" the same right. They are no...
Every terminal handshake was 403 behind the edge proxy
The reported symptom was a terminal that opened and immediately said "Disconnected", with nothing to act on. Reproduced end to end: the ticket mints fine (200) ...
Assert the mask obfuscates, and skip the gate for callers with no leads
LeadFieldMaskTest still expected a null e-mail. The mask now obfuscates rather than blanks — a blank field reads as "this lead has no e-mail", which is a differ...
Wire the accept-gate mock into the FFA spend test
acceptNextLead consults LeadAcceptEligibilityService before it reaches any of the credit logic these cases are about, and the test builds the service by reflect...
A new terminal could reattach to an old shell after a refresh
The shell was keyed on the tool window's id, and @kamo/tool-core builds those as `${toolId}-${++idCounter}` from a counter that RESETS on every page load. So th...
Prohibited nav emblem, Assign to Myself, and obfuscated contact masking
**The Leads nav icon says when you cannot accept.** A member who holds leads they have not worked gets a red block emblem over the Leads icon and a tooltip nami...
Serve the widened accept gate, add self-assignment, and close two contact-mask bypasses
**Endpoints for the new gate.** /leads/available-summary and /leads/available now report both reasons a member is blocked — leads owed a note since they were as...
Widen the accept gate, obfuscate masked contact info, let free-for-all leads be claimed
Three related changes to the lead-assignment core. **The accept gate now asks two questions, over every assigned lead.** LeadAcceptEligibilityService replaces ...
Flags on languages, and stop copying platform lists
Completes c20bac57. Languages now carry their flag, the same one the NavTop switcher shows and from the same source — the closed value as well as every row in ...
Record what the Remote Terminal deploy actually taught
Three defects, all the same shape: present in the tree, absent from the thing that serves requests — an IngressRoute in a directory nothing applies, a client pa...
The reaper used `su` too — runuser, and no shell anywhere
Dropping su from the exec path left it in reap_idle, which runs on every terminal connect. Same three objections, and the last one is the one that bites: `su - ...
The ticket request had no route behind it
The window fetched **************** and nothing served it. There is no catch-all under /api/security — every area is proxied by a route file of its own, and the...
Move the terminal IngressRoute to where something applies it
This repo's workflow applies exactly configmap.yaml, deployment.yaml and service.yaml, so a fourth manifest beside them was never applied by anything — the rout...
The terminal's IngressRoute was in a directory nothing applies
It was written into securityservice/k8s/ beside the deployment, which reads as the obvious home and is not one: that repo's workflow applies exactly configmap.y...
Drop `su` — it swallowed SIGWINCH, so no terminal ever resized
Caught by running the protocol against the live machine, not by reading it: after a resize control frame, `tput cols` in the shell still reported the size the t...
A custom-rendered field can be edited again
Completes c20bac57. Field's `renderValue` was returning in place of the whole read view, which included the button that opens the editor. So any field that ren...
Rebuild My Profile as a hero and five rooms
**************** was one 1,999-line component rendering thirteen identical cards down a single column. One SectionCard helper gave all of them the same radius, ...
A refused terminal handshake answered 200
Found by probing the deployed endpoint, not by reading it. Returning false from a HandshakeInterceptor aborts the handshake but sets nothing on the response, so...
Rebuild — the last run died fetching actions/checkout
Run 5861 failed in two seconds, before any compilation: the runner could not reach data.forgejo.org to fetch actions/checkout. Nothing to do with the tree, and ...
A real Linux terminal in a tool window, and a submenu to reach it
The Linux Desktop nav option becomes a menu instead of a launch — Remote Desktop with its sizes, Remote Terminal — exactly as the softphone owns call, voicemail...
State why the 101 is read before anything is written
The agent parses the request with a buffered reader and then pumps the raw socket, so a byte sent ahead of the status line would be stranded in that buffer and ...
Pin the no-pipelining invariant on the PTY upgrade
self.rfile is a BUFFERED reader over the socket and pump reads the RAW socket, so a caller that sent bytes behind its request line would strand them in that buf...
Drive a real PTY and a real socket through the terminal pump
The existing tests pin argv and framing in isolation; these four prove the pieces actually move bytes. A shell is forked under a genuine pty.fork and pumped ove...
A fourth window state — float, drag to detach, drag to reorder
A popup tool window has had three states: docked in the row along the bottom, maximized over the viewport, or minimized to a chat head. This adds FLOATING — det...
Serve Remote Terminal — a real shell over a WebSocket
Bridges a browser to a PTY on the member's own dev machine. Binary frames are the terminal, text frames are control; on the far hop an HTTP 101 onto a length-pr...
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...
Record a dev-machine terminal in the access log
A member opening a shell on desktop-1 now has an event type of its own. That machine holds a cluster-admin kubeconfig and its accounts have passwordless package...
Put asking for control on the screen it would control
The feature worked, and almost nobody would have found it. The only way to ask was an item in a thumbnail's overflow menu — hover the right person in the filmst...
Name a company by its company, with the contact as the qualifier
A record that is both an organisation and a person is now labelled "Harmony Home Loans (Nickolas McGarry)" everywhere one string has to stand for it. Company on...
Send the company alongside the contact wherever a record is labelled
A record that is both an organisation and a person is named "Harmony Home Loans (Nickolas McGarry)" — the company leads, the contact qualifies. That rule lives ...
Send an account's company alongside its contact for customer pickers
Six customer pickers read AccountSummaryDTO — the order editor, the service-job form, the subscription detail and wizard, and the pipeline signups tab — and eve...
The control helper installs itself, so there is one file to get
Setting the helper up meant downloading two files, opening a terminal and running a script with sudo. That is a flow people abandon, and an abandoned install is...
Drop the scope line above the Communication View timeline
"Every call, text, e-mail, note and chat message with the 9 leads matching these filters." — the filter bar sits directly above this timeline and already says w...
Communication View — the whole filtered book as one timeline
Three changes to /leads. Quick search moves into the hero, above the CRM Settings links. In the filter row it was the last control on a line of eleven dropdown...
Hand mouse and keyboard control of a shared screen to someone else
Wires the fork's dormant remote-control feature to the companion agent, and fixes the things that would have made it unusable even once it was reachable. The r...
A companion agent that can actually move the remote mouse
The fork already carries Meet's whole remote-control feature, and none of it has ever been reachable. The receiver half waits on a PostMessage transport for a h...
Static CSS in the overlay — 19 interpolations were hanging every build
kamo-internal has been unable to produce an image since b08f3b34. `next build` did not fail, it HUNG: no output, no error, no timeout. `.next` frozen at 1.3 MB ...
Add JustCall as a phone server type
Adds JustCall to the picker at **************** with its API key and secret, a contacts-import toggle, credential status on the providers tab, and the logo. Th...
A communications timeline over the whole /leads filter, not one lead
GET **************** takes the SAME query string GET the lead detail page draws — across every lead the filter bar matches. "What has been said to the leads I a...
Reap superseded builds unconditionally — the sha check protected the orphan
The reaper added in 199e367e compared each container's commit against github.sha and KEPT the matches, on the theory that a matching sha meant "this run". That ...
Reap builds orphaned by cancel-in-progress — they were starving the real one
Builds had gone from 8 minutes to 30+. I blamed the heap and was wrong. Reading the runner instead of the numbers found it: THREE `next build` processes at 213%...
Encode JustCall query values exactly once
The client built its query with build(true), which declares the values already encoded — so nothing was escaped at all. The character that matters is "+": every...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.