From ff133f88ff1bcc3a997f5e739c670b20c74538d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 22 Aug 2026 04:19:40 +0000 Subject: [PATCH] todo: settings as portable files, per user and per server Co-Authored-By: Claude Fable 5 --- TODO.md | 67 ++++++++++--------- todo/settings/_index.md | 9 +++ ...-s-settings-should-export-and-import-as.md | 40 +++++++++++ ...e-same-for-system-settings-owned-by-the.md | 32 +++++++++ 4 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 todo/settings/_index.md create mode 100644 todo/settings/a-user-s-settings-should-export-and-import-as.md create mode 100644 todo/settings/the-same-for-system-settings-owned-by-the.md diff --git a/TODO.md b/TODO.md index f9418d1e..6d111040 100644 --- a/TODO.md +++ b/TODO.md @@ -20,38 +20,39 @@ the owner's OS user and can never be granted. Indirection there really is accide ## Themes -**85 open, 22 closed**, across 28 themes. +**87 open, 22 closed**, across 29 themes. -| Theme | Open | Closed | -| --- | --- | --- | -| [Affordances](todo/affordances/) | 1 | 0 | -| [Speaking into a session from the backend](todo/agent-delivery/) | 2 | 0 | -| [Backburner](todo/backburner/) | 2 | 0 | -| [Background jobs](todo/background-jobs/) | 2 | 0 | -| [Chat interface](todo/chat/) | 1 | 0 | -| [Code editor](todo/code-editor/) | 1 | 0 | -| [Components — the shared UI layer](todo/components/) | 1 | 0 | -| [File watchers](todo/file-watchers/) | 1 | 0 | -| [Fleet — one command across every server](todo/fleet/) | 5 | 2 | -| [Headscale](todo/headscale/) | 0 | 5 | -| [Infra (alpha)](todo/infra/) | 6 | 0 | -| [Known bugs](todo/known-bugs/) | 4 | 1 | -| [Mobile apps](todo/mobile-apps/) | 3 | 0 | -| [Multi-user](todo/multi-user/) | 18 | 3 | -| [Notifications](todo/notifications/) | 1 | 0 | -| [Plugin ecosystem — before it opens to third parties (2026-08-18)](todo/plugin-ecosystem/) | 3 | 0 | -| [Plugin infrastructure](todo/plugin-infrastructure/) | 2 | 0 | -| [Plugin repos — what writing their READMEs turned up](todo/plugin-repos/) | 10 | 9 | -| [Plugin system — gaps the email extraction found (2026-08-18)](todo/plugin-system/) | 3 | 0 | -| [Prompt library](todo/prompt-library/) | 1 | 0 | -| [Shell — spotlight and the dock](todo/shell/) | 1 | 1 | -| [Sub-agents — agents spawning agents](todo/sub-agents/) | 1 | 1 | -| [Sudo terminal modal](todo/sudo-terminal-modal/) | 1 | 0 | -| [Tooling — the list about the list](todo/tooling/) | 1 | 0 | -| [Transmission](todo/transmission/) | 6 | 0 | -| [URL state — routing, query strings and selection](todo/url-state/) | 4 | 0 | -| [Waiting on the owner to run it](todo/waiting-on-owner/) | 2 | 0 | -| [Workspaces & Panels](todo/workspaces-panels/) | 2 | 0 | +| Theme | Open | Closed | +| ------------------------------------------------------------------------------------------ | ---- | ------ | +| [Affordances](todo/affordances/) | 1 | 0 | +| [Speaking into a session from the backend](todo/agent-delivery/) | 2 | 0 | +| [Backburner](todo/backburner/) | 2 | 0 | +| [Background jobs](todo/background-jobs/) | 2 | 0 | +| [Chat interface](todo/chat/) | 1 | 0 | +| [Code editor](todo/code-editor/) | 1 | 0 | +| [Components — the shared UI layer](todo/components/) | 1 | 0 | +| [File watchers](todo/file-watchers/) | 1 | 0 | +| [Fleet — one command across every server](todo/fleet/) | 5 | 2 | +| [Headscale](todo/headscale/) | 0 | 5 | +| [Infra (alpha)](todo/infra/) | 6 | 0 | +| [Known bugs](todo/known-bugs/) | 4 | 1 | +| [Mobile apps](todo/mobile-apps/) | 3 | 0 | +| [Multi-user](todo/multi-user/) | 18 | 3 | +| [Notifications](todo/notifications/) | 1 | 0 | +| [Plugin ecosystem — before it opens to third parties (2026-08-18)](todo/plugin-ecosystem/) | 3 | 0 | +| [Plugin infrastructure](todo/plugin-infrastructure/) | 2 | 0 | +| [Plugin repos — what writing their READMEs turned up](todo/plugin-repos/) | 10 | 9 | +| [Plugin system — gaps the email extraction found (2026-08-18)](todo/plugin-system/) | 3 | 0 | +| [Prompt library](todo/prompt-library/) | 1 | 0 | +| [Settings — portable, and readable by an agent](todo/settings/) | 2 | 0 | +| [Shell — spotlight and the dock](todo/shell/) | 1 | 1 | +| [Sub-agents — agents spawning agents](todo/sub-agents/) | 1 | 1 | +| [Sudo terminal modal](todo/sudo-terminal-modal/) | 1 | 0 | +| [Tooling — the list about the list](todo/tooling/) | 1 | 0 | +| [Transmission](todo/transmission/) | 6 | 0 | +| [URL state — routing, query strings and selection](todo/url-state/) | 4 | 0 | +| [Waiting on the owner to run it](todo/waiting-on-owner/) | 2 | 0 | +| [Workspaces & Panels](todo/workspaces-panels/) | 2 | 0 | ## Records — no items, kept for the reasoning @@ -63,6 +64,8 @@ the owner's OS user and can never be granted. Indirection there really is accide ## Newest ten - `2026-08-22` **A plugin's permission should be on for every role by default, off only on request** — [multi-user/a-plugin-s-permission-should-be-on-for-every](todo/multi-user/a-plugin-s-permission-should-be-on-for-every.md) +- `2026-08-22` **A user's settings should export and import as a plain file** — [settings/a-user-s-settings-should-export-and-import-as](todo/settings/a-user-s-settings-should-export-and-import-as.md) +- `2026-08-22` **The same for system settings, owned by the Super Admin** — [settings/the-same-for-system-settings-owned-by-the](todo/settings/the-same-for-system-settings-owned-by-the.md) - `2026-08-21` **No way to see which affordances are reaching your agents, or to turn one off** — [affordances/no-way-to-see-which-affordances-are-reaching](todo/affordances/no-way-to-see-which-affordances-are-reaching.md) - `2026-08-21` **Generalise it: deliver a turn to a named session, from anywhere in the backend** — [agent-delivery/generalise-it-deliver-a-turn-to-a-named](todo/agent-delivery/generalise-it-deliver-a-turn-to-a-named.md) - `2026-08-21` **The cost of resuming grows with the transcript** — [agent-delivery/the-cost-of-resuming-grows-with-the-transcript](todo/agent-delivery/the-cost-of-resuming-grows-with-the-transcript.md) @@ -70,5 +73,3 @@ the owner's OS user and can never be granted. Indirection there really is accide - `2026-08-21` **Show how long a turn took, beside its cost and tokens** — [chat/show-how-long-a-turn-took-beside-its-cost](todo/chat/show-how-long-a-turn-took-beside-its-cost.md) - `2026-08-21` **Map every custom component, centralise it, and let a theme override it** — [components/map-every-custom-component-and-centralise-it](todo/components/map-every-custom-component-and-centralise-it.md) - `2026-08-21` **Watch a directory, and attach actions to what lands in it** — [file-watchers/watch-a-directory-and-attach-actions-to-what](todo/file-watchers/watch-a-directory-and-attach-actions-to-what.md) -- `2026-08-21` **Settings to choose which server each feature uses** — [fleet/settings-to-choose-which-server-each-feature](todo/fleet/settings-to-choose-which-server-each-feature.md) -- `2026-08-21` **'A deploy verifies PM2, not that the app still works'** — [fleet/a-deploy-report-verifies-pm2-not-that-the-app](todo/fleet/a-deploy-report-verifies-pm2-not-that-the-app.md) diff --git a/todo/settings/_index.md b/todo/settings/_index.md new file mode 100644 index 00000000..706dffd9 --- /dev/null +++ b/todo/settings/_index.md @@ -0,0 +1,9 @@ +--- +theme: settings +heading: "Settings — portable, and readable by an agent" +kind: theme +--- + +Settings as files rather than rows: movable between instances, diffable, and editable by an agent +without a database client. The instance count is what makes this real — `docs/servers.md` lists seven +platforms running, and every one of them is configured by hand. diff --git a/todo/settings/a-user-s-settings-should-export-and-import-as.md b/todo/settings/a-user-s-settings-should-export-and-import-as.md new file mode 100644 index 00000000..1d24759e --- /dev/null +++ b/todo/settings/a-user-s-settings-should-export-and-import-as.md @@ -0,0 +1,40 @@ +--- +id: settings/a-user-s-settings-should-export-and-import-as +title: "A user's settings should export and import as a plain file" +theme: settings +status: open +created: 2026-08-22 +date_source: stated +order: 1 +--- + +**A user's settings should export and import as a plain file** — and possibly be read and written from +one instead of from the database at all. Wanted 2026-08-22. Two goals, both stated by the owner: carry a +configuration onto another instance without redoing it by hand, and let an **agent** work on it, which a +file allows and a jsonb column does not. + +**Explicitly NOT the screen workspace layouts.** Those are per-machine furniture; they are not what +travels. + +**It is closer than it looks, because the data is already a document.** `user_settings` is one row per +user holding a single `settings` jsonb, and `server_config` is key/value jsonb — no per-setting columns +to serialise, and nothing to invent a format for. What needs deciding is what is *in* the export, and the +neighbours are the reason it needs deciding at all: + +- `dashboards` and the `ws-layout-*` keys — the layouts, excluded by the owner. +- `user_state` — a second jsonb beside settings, but state rather than preference. Almost certainly out. +- `dock_configs` — a preference, and portable. Probably in. +- `user_integrations` / `server_integrations` — **the hard one, below.** + +**Credentials are the part that cannot be waved through.** Integration rows hold tokens, encrypted at +rest by `crypto.ts` under a per-purpose key that lives in this install's secret store. So an export has +exactly three options, and each is a real decision: carry ciphertext (which will not decrypt anywhere +else, making the import silently useless), carry plaintext (a settings file with live tokens in it, on +disk and probably in git), or **carry the shape and leave the secret to be re-entered** — which is the +only one that is both portable and safe, and it should be the default. + +If it goes as far as "read and write from a file instead of the database", note what the database is +giving today that a file is not: one writer, atomic updates, and a per-user row that cannot be confused +with another's. None of those are hard to keep, but a file per user in a known directory has to say how +it handles two writers — and this platform now runs several agents in one checkout, so that is not +hypothetical. diff --git a/todo/settings/the-same-for-system-settings-owned-by-the.md b/todo/settings/the-same-for-system-settings-owned-by-the.md new file mode 100644 index 00000000..7091402c --- /dev/null +++ b/todo/settings/the-same-for-system-settings-owned-by-the.md @@ -0,0 +1,32 @@ +--- +id: settings/the-same-for-system-settings-owned-by-the +title: "The same for system settings, owned by the Super Admin" +theme: settings +status: open +created: 2026-08-22 +date_source: stated +order: 2 +--- + +**The same for system settings, owned by the Super Admin.** Wanted 2026-08-22, in the same breath as the +per-user export — the server's own configuration should be a file too, so a new instance can be brought +up matching an existing one instead of being clicked into shape. + +This is the half with the larger payoff, because it is the half that is currently repeated per machine. +`docs/servers.md` lists **seven platforms running**, each configured by hand, and nothing anywhere +records what a given server's settings actually are. A file makes that answerable, diffable between two +hosts, and reviewable in git. + +`server_config` is already key/value jsonb, so the export is close to free. Two things make it a +different problem from the user one rather than the same problem twice: + +- **Some system settings are legitimately per machine** — anything naming a host, a port, a path or a + device. An import that overwrites those turns a working server into a copy of another one. The export + needs to distinguish portable configuration from machine identity, and that split does not exist + anywhere today. +- **Ownership is the Super Admin, and only the Super Admin.** `execution` and `admin` permissions are + stripped for every other role even when granted, so the route carrying this is owner-only by the same + rule — worth stating so nobody makes it a role grant later. + +Do this alongside `settings/a-user-s-settings-should-export-and-import-as` — one format, two scopes. +The credential rule from that item applies unchanged: carry the shape, never the secret.