diff --git a/docs/working-on-officer.md b/docs/working-on-officer.md index b3e42fc7..e4413cfc 100644 --- a/docs/working-on-officer.md +++ b/docs/working-on-officer.md @@ -7,27 +7,53 @@ agent sessions start. Three directories sit there, and knowing which one a change belongs in is most of the job: ``` -officer/ +$OFFICER_ROOT/ ├── platform/ the application — a git repo ├── capabilities/ what the agent can do — a separate git repo -└── data/ runtime state — NOT version controlled +├── data/ runtime state — NOT version controlled +├── dockers/ containers the app store provisioned +└── secrets/ the key store — 0600, and NOT in your data backup ``` +None of those paths is configured. `src/servers/data-path.ts` derives the root as +`resolve(process.cwd(), '..')` and hangs the rest off it, which is why the pm2 `cwd` pin matters and +why `assertInstallLayout` refuses to boot from the wrong directory. + Officer is a self-hosted platform: an AI agent, a terminal, a file browser, a code editor, email, a bitcoin wallet, a remote desktop and dashboards, behind one web app. **It is built around one owner** — user id 1, role `Super Admin`, who bypasses every permission check — and since 2026-08-07 also admits **additional accounts holding a strict subset of it**, governed by per-role capability grants. -So "which user" has two answers depending on the surface. For the **app** capabilities (gitea, music, -photos, email, calendar…) it is a real question with a real answer. For anything that executes code or -touches the disk — terminal, chat, tasks, files, desktop, browser — it is still always the owner: -those are `kind: 'execution'` in `platform/src/servers/capabilities/registry.ts` and can never be -granted, because they run as the owner's OS user in the owner's home. +So "which user" has three answers depending on the surface. For the **app** capabilities (gitea, +music, photos, email, calendar…) it is a real question with a real answer. For **confined** ones — +terminal, chat, files — it is also real, because the account has its own Linux user and the kernel +enforces the boundary; a grant there means nothing without that user, and `authorize.ts` drops it. +For **execution** — tasks, items, desktop, browser — it is still always the owner, and those can +never be granted at any level. + +That is five kinds, not four: `core`, `app`, `confined`, `execution`, `admin`. Terminal, chat and +files moved from `execution` to `confined` on 2026-08-11 with per-user Linux accounts. This paragraph said "there is no tenancy, no roles, no other users" until 2026-08-07. Four roles exist and five non-owner accounts are live; treat the capability registry as the source of truth over any prose, here or elsewhere. +## What is switched off (2026-08-13) + +A core install runs **six** pm2 processes: `officer`, `officer-anthropic-proxy`, +`officer-claude-code`, `officer-opencode`, `officer-pty`, `officer-headscale`. Everything else is a +plugin, and every plugin router is commented out in `hono.ts` with its capability's `api` claim +commented beside it — they must move together or `assertCapabilityTotality` refuses to boot. + +The implementations are all still on disk. Nothing was deleted; the mounts were switched off pending +extraction into the plugin system. + +Also gone: the four ecosystem files (generated now, at setup, and gitignored), origin validation, +`OFFICER_OS_USERS` (per-user Linux accounts are unconditional), and the Task Logs feature. + +`.env` holds three values — `PORT`, `PUBLIC_URL`, `POSTGRES_URL`. Every key lives in +`$OFFICER_ROOT/secrets/officer-keys.db`, one per purpose. See `docs/secret-store.md`. + `platform/` and `capabilities/` each have their own `CLAUDE.md` with detail. This file is the layer above them: where things live, how to change them safely, and the things that are true of the running system but written down nowhere else.