Pivot from v2 (2026-05-09): the orchestrator moves from Hetzner to the Mac. The Mac runs one control center that owns every Mac touch. Hetzner, HeyBrian, voice, and the CLI all become clients of it. Apply the breathing-border rule once — at the control center — and it covers every Brian action on Mac, forever.
v2 had Hetzner orchestrating: a Python daemon on Hetzner spawned the SSH/SCP, the Mac just rendered. Problem: HeyBrian (which lives on the Mac) and voice and any future on-device caller had no clean way to plug in. Each became a separate painter — exactly the disease v2 was trying to cure.
v3 fixes that by making the Mac the orchestrator. One chokepoint. One UI. One audit log. One toggle panel. Anyone who wants to do anything on Mac sends a request to the control center; the center decides how to execute and renders the UI itself.
brian_controller_ui_v2.lua on port 8765. Adds /v2/action, /v2/capabilities, /cpanel.POST /v2/action {action, params, source, session_id, hmac} → looks up handler, gates by toggles, fires UI, dispatches, logs.~/.brian/capabilities.json listing every capability with: name, executor, params schema, toggle (on/off), source allowlist, audit level./cpanel: connection status, capability toggles, recent activity, active session list with pause/stop, secret rotation.~/Library/Logs/Brian/control_center.jsonl — every request, every dispatch, every result. Drop-in for HeyBrian's logger.| Capability | Executor | Notes |
|---|---|---|
run |
hs.task (local shell) |
replaces "ssh + cmd" — runs inside Mac, no remote-shell needed |
click |
cliclick (or hs.eventtap fallback) |
router picks based on TCC + accessibility availability |
screencap |
screencapture |
region/cursor/window flags |
type |
cliclick t: or hs.eventtap.keyStrokes |
router picks |
keystroke |
hs.eventtap.keyStroke |
system shortcuts |
chrome.tabs |
AppleScript tell app "Google Chrome" |
enumerate across profiles |
chrome.activate |
AppleScript + AXRaise | proven recipe |
chrome.navigate |
AppleScript set URL | |
chrome.eval |
AppleScript execute javascript | the LinkedIn-API trick |
say |
/usr/bin/say |
gated by ~/.brian/no_speech flag |
notify |
hs.notify |
banner |
clipboard.get / set |
pbpaste / pbcopy |
|
imessages.recent / send |
DB query + Messages.app | |
front_app / activate |
AppleScript | |
applescript / jxa |
escape hatch | for anything not yet wrapped |
The router's job: when a caller asks for click, decide cliclick vs eventtap based on which has the right TCC grants right now.
~/.brian/secrets/<client>.key (mode 0600). Each request signs (ts, nonce, body). 60s window. Nonce LRU.http://localhost:8765/cpanel from the Mac browser. Sets a session cookie (HTTP-only, SameSite=strict). All toggle changes go through that cookie.mac_access_gateway.py — already POSTs to /v2 for UI lifecycle. Add: POST /v2/action for every actual operation, drop the ssh/scp paths entirely. (run capability replaces them.)say() directly via TTSManager. Pivot: it calls /v2/action {action: "say", params: {text}}. Same for screencap, click, etc.mac_helper_client.py) — replaces queue-based IPC with /v2/action.Every action gets a row in control_center.jsonl:
{"ts":..., "source":"hetzner", "session_id":..., "action":"click", "params":{x:423,y:462}, "result":{ok:true, took_ms:38}, "ui":{shown:true, dismissed_after_ms:1200}}
The cpanel reads this for the live activity feed.
| v2 piece | v3 fate |
|---|---|
brian_controller_ui_v2.lua UI rendering |
KEEP — becomes the heart of the control center |
HMAC POST to /v2 (start/step/stop/heartbeat) |
KEEP — extends to /v2/action |
Hetzner brian-mac-controller daemon |
DROPPED — Mac is the orchestrator now |
mac_gatekeeper ProxyCommand |
DROPPED — there's no SSH path to gate; control center does the work in-process |
| PGID kills | MOVES to control center — it spawns local subprocesses, owns their PGID |
| Migration order (6 callers) | KEEPS — each caller becomes a thin client, same end state |
| Tarball + delete legacy | KEEPS |
| Capability docs | EXPANDS — also documents toggles + source allowlist |
This pivot retires roughly half the planned Hetzner-side work. Net win.
/cpanel showing connections, toggles, activity, sessions.mac_access_gateway.py drops local SSH/SCP, calls /v2/action.mac_helper_client.py) wired in — replaces queue.mac_legacy_v1.tar.gz.Each section ends with a smoke test + a docs page in capabilities/.