Skip to content

ADR 0003 — One app, one service, one permission grant

This decides how Qren arrives on a Mac. It installs as one ordinary application a person double-clicks, with a single background service behind it — the supervisor — instead of the fifteen separate moving parts the earlier system used. That matters because the Mac then asks for its permissions once (files, microphone, screen recording), and adding features later does not start the asking again. The only folder a person ever sees is the one holding their own files; the machinery lives out of sight where Mac applications normally keep it. Someone who simply joins another person’s workspace installs the application and nothing else. This is the last cheap moment to fix the layout: about fifteen friendly machines, no client contracts yet.

AOS grew developer-shaped: a visible source tree at ~/aos, instance data at ~/.aos, and one launchd service per background capability. Costs: every new capability triggered new macOS permission prompts (“allow, allow, allow”), fleet ops meant herding fifteen plists per machine (the aos#180 incident — a service killed by a probe to the wrong port — is the canonical failure), and member-grade users would have inherited a hacker layout that should never ship. Wave C (the AOS→Qren migration) makes this the one moment the layout can be redesigned cheaply: ~15 friendly instances, zero client contracts.

The product installs as an app, not a framework:

  1. Qren.app — the product. UI, embedded runtime, updater. The only thing a human ever installs.
  2. One Supervisor — a single user-level LaunchAgent under the Qren bundle identity. Every internal worker (bridge, transcriber, schedulers, agent sessions) runs as a supervised child of it — never as its own launchd service. macOS TCC permissions (Full Disk Access, Microphone, Screen Recording, Automation) attach to the one bundle identity and are granted once; new capabilities do not mean new prompts.
  3. Privileged helper (appliance profile only) — a root LaunchDaemon registered via SMAppService for operations that genuinely need elevation. Signed, auditable, designed — never agents driving sudo. Member installs never receive it.
  4. ~/Library/Application Support/Qren/ — all plumbing: config, databases, runtimes, state. Replaces ~/.aos. Invisible and Mac-native.
  5. ~/Qren/ — the Drive — the only user-visible folder: the client’s actual files, workspace-scoped, shared by humans and agents at filesystem speed (ADR 0002).
  6. Member installs are the app only — client mode: portal/tailnet connection to the appliance, plus optionally the local capture helper for companion meetings. No framework, no supervisor fleet, no home-dir folders on member machines.
  7. The source tree is a developer concern — a repo checkout exists only on dev machines; the product never ships a visible framework directory again. ~/qren and ~/.qren as home-directory paths are dead on arrival; the Wave C migration targets this layout, not a rename.
  • The Supervisor is a single point of failure by design; launchd KeepAlive
    • watchdog supervise the Supervisor itself, and one throat to choke beats fifteen plists for fleet operations.
  • The Wave C migration and the file restructure are one project: code crosses from the aos repo only by earning its place, arriving into the app-shaped layout (evolve / adopt / design-fresh triage).
  • Existing installs migrate by one scripted atomic wave per the component-lifecycle rule.
  • Agent workers inherit TCC from the bundle identity; spawning must keep child processes attributable to it (responsible-process semantics) or prompts return.
  • The installer/onboarding flow is rebuilt once, against this layout.