step 4/4: the docs say permissions too, and capability means one thing again
44 files of prose — CLAUDE.md, AGENTS.md, TODO.md, 20 docs, both plugin design
documents, and the comment surface the earlier steps could not reach.
Applied against an explicit keep-list, not swept, because the word turned out to
have SIX meanings in this repository rather than the three the offscale doc
recorded:
permissions renamed (steps 1–2)
$OFFICER_ROOT/capabilities/ KEPT — the item store, and now the only thing
the word means that is ours
sidecar routing keys renamed to `handles` (step 3)
Lightning wallet KEPT — a domain term, and on the wire to the mobile apps
terminfo queries KEPT — XTGETTCAP, in the pty sidecar
InvoiceShelf KEPT — per-resource { write, bulkDelete } flags
The sweep still falsified two things, both caught by checking rather than by
review, and both in prose that discusses more than one meaning at once:
CLAUDE.md began claiming the item store lives at `$OFFICER_ROOT/permissions`.
It does not; that directory is on disk and full of skills and tools.
And the offscale doc's own note about the collision became
"Named `permissions`, NOT `permissions`" — a sentence that had eaten the thing
it existed to warn about.
Both restored, and the note rewritten to say what is now true: capability means
one thing of ours, and three that belong to somebody else's vocabulary.
Verified live after restart: self and admin permission endpoints 200, gated
route 200, agent-status 200, 9 grants intact with 6 permissions offered.
tsgo clean, 797 tests, 787 pass, same 7.
The rename is done. Four steps, no data lost, no client break that survived
the step it was introduced in.
This commit is contained in:
@@ -8,13 +8,13 @@ vocabulary left between them. Every HTTP sidecar shares one `createSidecarProxy`
|
||||
happened is the part this document is actually about — fixed ports, the platform reading a table instead
|
||||
of being told at runtime, and `.env` feature toggles. Ports are still ephemeral and still announced.
|
||||
|
||||
Not to be confused with `sidecar-audit-2026-07.md`, which is the *audit* of the
|
||||
Not to be confused with `sidecar-audit-2026-07.md`, which is the _audit_ of the
|
||||
current state (what's misplaced, and where). This is where it's going.
|
||||
|
||||
## The premise that makes it simple
|
||||
|
||||
**The tailnet is the perimeter.** Everything moves behind Tailscale and devices are admitted by hand —
|
||||
friends and family included. Authentication *inside* that boundary is solving a problem we don't have, so
|
||||
friends and family included. Authentication _inside_ that boundary is solving a problem we don't have, so
|
||||
this design has no token work in it at all. Sidecars trust their caller exactly as they do today; the trust
|
||||
boundary just moves from loopback to the tailnet.
|
||||
|
||||
@@ -22,7 +22,7 @@ Until that lands, things stay exposed as they are now. The security model is del
|
||||
|
||||
## The design
|
||||
|
||||
1. **`ecosystem.config.cjs` is the source of truth.** PM2 starts every sidecar. They stay *peers* of
|
||||
1. **`ecosystem.config.cjs` is the source of truth.** PM2 starts every sidecar. They stay _peers_ of
|
||||
`officer` — never children. This is not a style preference: officer used to spawn the agent itself,
|
||||
which made it a grandchild, and PM2's tree-kill took the owner's chat session down on every restart.
|
||||
That was the worst thing about working on the platform, and it is fixed. Don't reintroduce it.
|
||||
@@ -43,7 +43,7 @@ The point of the exercise, and the reason it's worth doing:
|
||||
- `sidecar/connect.ts` — the dial-out-and-register loop, plus its per-sidecar reconnect backoff copies
|
||||
- every port announcement: `music:server`, `slskd:server`, `vault:server`, `opencode:server`,
|
||||
`pty:server`, `email:server`, `wallet:server`, `headscale:server`, … and `vnc:started`
|
||||
- most of `sidecar-registry.ts` — discovery, the pending-command map, capability lookup
|
||||
- most of `sidecar-registry.ts` — discovery, the pending-command map, permission lookup
|
||||
- officer's proxying for anything that isn't auth or layout state
|
||||
|
||||
## Migration order
|
||||
@@ -60,14 +60,14 @@ least urgent anyway.
|
||||
|
||||
- **Ecosystem file, or a shared table?** The platform parsing `ecosystem.config.cjs` couples the app to
|
||||
PM2 being the thing that started it, which matters for containerising this later and for `bun dev`.
|
||||
The alternative is one plain TypeScript table (name, script, port, capability, enabled) that
|
||||
The alternative is one plain TypeScript table (name, script, port, permission, enabled) that
|
||||
`ecosystem.config.cjs` generates its `apps:` array from and the platform imports directly — same single
|
||||
source of truth, no supervisor coupling. **Recommended, not yet decided.**
|
||||
- **Where do the things that are neither auth nor layout go?** The job/queue engine, the capabilities/items
|
||||
- **Where do the things that are neither auth nor layout go?** The job/queue engine, the permissions/items
|
||||
store, the chat session list, the file browser. Each needs a named home or officer quietly stays fat.
|
||||
- **Does the registration socket survive?** Not needed for discovery once ports are static. Possibly worth
|
||||
keeping for liveness — or replace it with a health probe on the known port.
|
||||
- **Capabilities.** Today a sidecar announces `capabilities: ['music']` and officer looks up by capability,
|
||||
- **Permissions.** Today a sidecar announces `permissions: ['music']` and officer looks up by permission,
|
||||
not by name — which is what let the agent's PM2 name change from `officer-claude` to `officer-agent`
|
||||
without touching a caller. In a static table it collapses to a column. Keep it; it's cheap.
|
||||
- **The non-owner account class may become dead weight.** `NON_OWNER_PATHS`, the music-only account
|
||||
@@ -81,7 +81,7 @@ Recorded so they aren't re-litigated:
|
||||
- **Platform spawns the sidecars.** Rejected — that's the tree-kill bug again. PM2 starts them; the
|
||||
platform only reads the topology.
|
||||
- **Platform mints a token, tells every sidecar it's valid, apps then call sidecars directly.** This was
|
||||
the original points 6–8. Dropped with the tailnet decision. Worth knowing *why* it was weak even on its
|
||||
the original points 6–8. Dropped with the tailnet decision. Worth knowing _why_ it was weak even on its
|
||||
own terms: it replicates session state across ten processes, and breaks whenever one restarts, is down
|
||||
at login, or has to be told about a logout.
|
||||
- **A dedicated public auth sidecar** issuing short-lived asymmetric tokens, with sidecars verifying via
|
||||
|
||||
Reference in New Issue
Block a user