todo: settings as portable files, per user and per server

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 04:19:40 +00:00
co-authored by Claude Fable 5
parent 8e181ddf3c
commit ff133f88ff
4 changed files with 115 additions and 33 deletions
+34 -33
View File
@@ -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)
+9
View File
@@ -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.
@@ -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.
@@ -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.