Skip to content

ADR 0006 — The app-shaped layout: one bundle, one hidden folder, one visible Drive

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.

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.

The installed layout and the repo that produces it are fixed as follows.

  1. Bundle identity is ai.qren.app — LaunchAgent label ai.qren.supervisor, helper ai.qren.helper, Keychain items QREN_*. One identity holds every TCC grant. (D1)
  2. 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)
  3. ~/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.
  4. Logs and caches go where Apple puts them, not inside that folder: ~/Library/Logs/Qren/ and ~/Library/Caches/ai.qren.app/.
  5. ~/Qren/ is the Drive and the only visible folderPersonal/ plus one folder per workspace homed on this machine. Pure files: no dotfolders, no metadata inside it. drive_root is configurable per instance.
  6. One instance.db, and one workspace.db per 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)
  7. 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.json so removal is exact. This is the only place Qren writes outside its own tree.
  8. launchd carries exactly one jobai.qren.supervisor — plus ai.qren.helper, registered via SMAppService, on appliance installs only. Every other background worker is a supervised child.
  9. 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.
  10. 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.
  11. Repo top level is deliberate: docs/ app/ supervisor/ cli/ core/ runtime/ skills/ agents/ arms/ helper/ edge/ packaging/ vendor/ tests/. site/ and workers/ move under edge/, with the Pages action path update in the same commit. (D5)
  12. Empty directories are not created. A directory appears when it has contents — an empty one is a promise the tree cannot keep.
  • Migration is the Gardener’s job, at install. The new Supervisor finds ~/.aos on 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 points Resources/runtime at 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: ~/qren or ~/.qren as 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/Knowledge at 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.