0039: Pair runs in a helper inside the app
On this page
Status: accepted
Context
A call needs to:
- capture the screen;
- use the microphone and speakers;
- inject input;
- open network sockets;
- draw cursors over other apps.
On macOS each of these is a privacy permission that belongs to an app the person can see. Apple attributes a helper's requests to the app that started it ("responsible process"), and a nested .app doesn't get an identity of its own. leashd is a launch agent; it holds no window and isn't exempt from Local Network privacy. The Tauri shell holds no domain logic (ADR 0001).
Decision
-
The helper. Calls run in a sidecar binary,
leash-pair, inside Short Leash's bundle:Contents/MacOSon macOS, next to the app on Windows.- The app starts it for each session and stops it when the session ends.
- It talks to leashd over leashd's local API (unix socket or named pipe), with the
ipctypes. - It never disclaims responsibility, so macOS attributes every request to Short Leash.app.
-
The screen on macOS.
- On macOS 14 and later, the screen comes from the system's screen picker (
SCContentSharingPicker, through libwebrtc's capturer). That needs no Screen Recording permission and has no monthly reminder. - On macOS 13, Short Leash falls back to Screen Recording.
- On macOS 14 and later, the screen comes from the system's screen picker (
-
Permissions on macOS, each asked when first needed, not at install:
Permission Needed for Asked when Microphone voice the first session Accessibility posting a guest's input the first time the host gives control; Pair also offers a button straight to the right pane, because macOS doesn't ask twice Local Network a peer on the same network the first time a call reaches one Short Leash.app's
Info.plistdeclaresNSMicrophoneUsageDescriptionandNSLocalNetworkUsageDescription, and its entitlements addcom.apple.security.device.audio-inputfor the hardened runtime. -
The screen on Windows: libwebrtc's capturer. No permission is needed for capture or
SendInput. -
The UI: overlays (guest cursors, the control frame) are click-through windows kept out of the captured image. The in-call bar, waiting room and viewer chrome are ordinary Short Leash panels (ADR 0031).
Consequences
- One identity: people see one app asking for permissions, Short Leash, with Short Leash's words.
- Grants survive updates only with a stable signature. Releases are Developer ID–signed and notarised; ad-hoc local builds lose them on every rebuild.
- To confirm in the Phase 2 preview build: grants surviving an update, the Local Network prompt, and that prompts name Short Leash.
- Smaller blast radius: a crash in capture or WebRTC takes down the helper, not leashd or the window. The helper is also the only process that opens call sockets (ADR 0037).