ADR 0006 — The app-shaped layout: one bundle, one hidden folder, one visible Drive
In short
Section titled “In short”This decides exactly what is on a machine once Qren is installed: one application, one hidden folder where the application keeps its settings and its data, and one visible folder called Qren holding the client’s own files. Nothing else — no visible framework directory, no scattered background programs, no second place to look. Because the working parts all sit inside the one application, the Mac asks for its permissions once and never starts asking again as features are added, and the whole system carries a single version number, so “what is this client running” has a one-number answer. The visible folder is the client’s work and only their work; the machinery lives out of sight, where Mac applications normally keep it. ADR 0003 named these pieces; this decides where each one physically goes.
Context
Section titled “Context”ADR 0003 settled the shape — one app, one Supervisor, one permission grant — but left the contents open: no bundle identity, no file-by-file layout of the hidden folder, no statement of where the runtime physically sits (§4 put “runtimes” under Application Support), no boundary between one client’s data and another’s, no rule for the engines Qren orchestrates, and no repo layout to produce any of it. Those gaps are cheap to argue and expensive to leave: every one of them becomes a migration once a client is live.
Wave C — the AOS→Qren crossing — is the one moment the layout can be redesigned cheaply: about fifteen friendly instances, zero client contracts, and a rebuild already in flight. After that, changing the bundle identity costs a permission reset per client machine and changing the data layout costs a scripted migration per engagement.
The design note target-tree worked the layout out in full — installed tree, repo tree, a part-by-part crossing map, and five forced decisions (D1–D5), approved in shape by the operator on 2026-08-20. This ADR records the decisions it forces. The crossing map and the migration sketch stay in the design note; they are working material, not decisions.
Decision
Section titled “Decision”The installed layout and the repo that produces it are fixed as follows.
- Bundle identity is
ai.qren.app— LaunchAgent labelai.qren.supervisor, helperai.qren.helper, Keychain itemsQREN_*. One identity holds every TCC grant. (D1) - The runtime ships inside the bundle, at
Qren.app/Contents/Resources/runtime/: relocatable CPython with locked packages, adopted native binaries, the Python package, framework skills, core agent definitions, default config, and instance migrations. One signed artifact carries UI + Supervisor + CLI + runtime; one version number per instance; the updater replaces the whole thing atomically. This amends ADR 0003 §4 (see “Amends” below). (D2) ~/Library/Application Support/Qren/holds plumbing only — replacing~/.aos:instance.yaml(identity, profile,drive_root, credential references),config/,data/instance.db,workspaces/<ws-id>/,engines/,models/,arms/,shadow/,run/,updates/. Invisible, never browsed by a human, and every config key writable only through the Control API.- Logs and caches go where Apple puts them, not inside that folder:
~/Library/Logs/Qren/and~/Library/Caches/ai.qren.app/. ~/Qren/is the Drive and the only visible folder —Personal/plus one folder per workspace homed on this machine. Pure files: no dotfolders, no metadata inside it.drive_rootis configurable per instance.- One
instance.db, and oneworkspace.dbper workspace. Instance scope (principals, workspaces, bindings, engagement state, audit, approval queue) is separate from tenant scope. Tenancy is then enforced by the filesystem as well as by the permission guard, a workspace lifts out as one directory, and the shadow can run per workspace. (D4) - Engines live outside Qren’s tree. Claude Code, Codex CLI and the rest
stay where their vendors put them, on the vendor’s own login. Qren never
relocates or wraps them: it probes them (ADR
0004) and writes an idempotent,
manifest-tracked projection of skills, agents and hooks into their config
directories, tracked in
engines/<engine>/projection.jsonso removal is exact. This is the only place Qren writes outside its own tree. - launchd carries exactly one job —
ai.qren.supervisor— plusai.qren.helper, registered via SMAppService, on appliance installs only. Every other background worker is a supervised child. - Three install profiles: A appliance, M member, D dev. A member
machine gets
instance.yaml,config/,run/and Logs — no workspace data, no Drive, no helper. The member app is a client of an appliance. - The app is a client of the Supervisor over
control.sock— and so are the CLI, Qren Ops, and the chief of staff. No component reaches around the Supervisor to touch the runtime, launchd, or the databases. - Repo top level is deliberate:
docs/ app/ supervisor/ cli/ core/ runtime/ skills/ agents/ arms/ helper/ edge/ packaging/ vendor/ tests/.site/andworkers/move underedge/, with the Pages action path update in the same commit. (D5) - Empty directories are not created. A directory appears when it has contents — an empty one is a promise the tree cannot keep.
Consequences
Section titled “Consequences”- Migration is the Gardener’s job, at install. The new Supervisor finds
~/.aoson first launch, snapshots it, and the Gardener proposes what crosses through the approval queue. Nothing moves unexamined; the old tree is removed only after a health pass and the operator’s confirmation. - TCC grants reset once per machine. Full Disk Access, Microphone,
Screen Recording and Automation are re-granted against
ai.qren.app— at ~15 friendly installs and no client contracts this is as cheap as it will ever be, and capabilities added afterwards cost no new prompts. - Every runtime fix becomes an app release. That is how products behave.
The dev escape hatch is
qren dev link, which pointsResources/runtimeat a repo checkout; profile D only, never shipped. - The venv-rot defect class disappears — there are no per-service virtualenvs to drift, because there is one immutable signed runtime.
- This forbids, without revisiting this ADR:
~/qrenor~/.qrenas home-directory paths; a second LaunchAgent; per-service runtimes; any metadata written inside the Drive; any component talking to launchd, the databases, or the runtime around the Supervisor; and a single shared database spanning workspaces. - The vault → Drive move (D3) is deliberately a later wave: the first
crossing symlinks
~/Qren/Personal/Knowledgeat the existing vault so tools and habits survive the move.
Amends. ADR 0003 §4 lists “runtimes” among the contents of
~/Library/Application Support/Qren/. Decision 2 above moves the runtime
into the app bundle instead; ADR 0003 §4 is otherwise unchanged, and
everything else in ADR 0003 stands.