Mac app

GUS on a Mac — GUS.app

The native Mac bridge: GUS.app lets the control plane observe and operate a Mac desktop — Accessibility, input, screenshots — under the same governance as everything else in GUS. The idea: the box is the sandbox. A resident Mac is a dedicated agent machine, which is what makes broad standing approvals rational there — the blast radius is the box, and the box holds nothing precious.

The pieces

PieceWhat
GUS.appThe menu-bar shell: live status, Start/Stop, the first-run permissions window, and the in-app chat with the Call button. It launches the helper from inside the bundle.
GusMacHost (helper)The part that actually drives the desktop: Accessibility observe/click/focus, synthetic keyboard and mouse input, ScreenCaptureKit screenshots. It runs as the app's helper, so the permissions you grant GUS.app are the grants the helper works under.
Control planeRuns natively as a launchd agent on the Mac and talks to the helper over a local socket. Files and shell execute locally in the control plane, inside the jail the Mac service enforces before every call — they never cross the socket.

Every desktop action settles with a verbatim receipt (clicked element "Save", typed 42 chars, opened "Mail"), and the service fails any job whose receipt drifts from the expected form. If the helper is absent, desktop calls refuse plainly and loudly — nothing pretends a desktop exists.

What runs where

PieceHolds
Control plane (launchd agent)Vault, Governor ledger, policy, approvals — and the Mac pack
Runtime / agent (launchd agent)No secrets, no policy path; it asks the control plane over the comm socket, and cannot create, resolve, or forge an approval
Heavy inferenceRemote API providers, or models on your own machines — your choice, as everywhere in GUS

State lives under ~/.gus/: the vault, governor ledger, jobs, approvals, policy, gate log, and panel token, with restrictive permissions (0600/0700) where it matters.

First run

Install GUS.app from the DMG (drag to Applications). The first-run window opens itself and walks a live checklist:

  1. Accessibility — required for observing and driving the desktop; the window deep-links to the exact System Settings pane.
  2. Screen Recording — optional: text observations work without it; screenshots need it.
  3. Node ≥ 22 presence check.
  4. Install GUS services — one button creates the ~/.gus layout, seeds a policy only if none exists (the seeded template approves no file or shell access at all until you edit its work folders), renders the launchd plists, and loads them.

Then finish setup in the panel (the five-step wizard), and set mac.workDirs in ~/.gus/state/policy.json to the real project folders the agent may touch.

The app's menu shows live status (running/stopped + front app), Start/Stop, Setup & Permissions, and a link to the setup panel. The Watch view in the panel shows the resident Mac's latest screen frame beside the timeline of actions and gate decisions — frames are fetched only while the view is open, served only on the machine, and never stored.

Building the DMG

On the Mac (Xcode Command Line Tools installed):

sh hosts/mac-app/build-dmg.sh

The script checks its toolchain first and fails loudly by name when something is missing. It builds the Node and Swift parts, assembles GUS.app (app + helper + the bundled control-plane payload), ad-hoc codesigns it, and writes hosts/mac-app/dist/GUS-<version>.dmg with an /Applications symlink for drag-install.

Gatekeeper, honestly: ad-hoc signing is not notarization. First launch is right-click → Open. Notarized distribution needs an Apple Developer account and is a later, deliberate step. Releases can also be published by GUS itself, under a one-time approval — see publishing releases.

Updating

Check for Updates in the app handles the whole loop: GUS fetches the latest signed release, verifies it, swaps the app, and relaunches — no manual quit-drag-replace dance. Underneath, updates follow the same rules as everywhere in GUS: signed manifests verified before staging, the new version tried against your recorded automations before promotion, automatic rollback if anything fails, and your data — ledger, vault, approval history — never part of a rollback. Only code and permission-config roll back; data never does.