--- id: multi-user/a-plugin-s-permission-should-be-on-for-every title: "A plugin's permission should be on for every role by default, off only on request" theme: multi-user status: open created: 2026-08-22 date_source: stated order: 21 --- **A plugin's permission should be on for every role by default, off only on request.** The owner's call, 2026-08-22. Installing a plugin should make it reachable by every role; taking it away from a role is then a deliberate act. Today the opposite is true: install a plugin and nobody but the owner can see it until someone grants it, role by role. **This inverts a default that two files argue for explicitly, so it needs his decision on the record — which this is.** `permissions/schema.ts` states it plainly: *"A MISSING ROW MEANS NO ACCESS. There is no row that denies; absence denies… an empty table is a platform where members can reach nothing but their own account, which is the correct state for a server that has just been installed."* And `authorize.ts` opens with *"the failure mode of a permissive default is not a bug report — it is someone else's session."* Both were written about the platform's own surface, not about plugins, which is the distinction this item turns on. Two facts that bound how far the change reaches, both from `authorize.ts`: - **It can only ever mean `app` (and `confined`) permissions.** `execution` and `admin` are stripped even when a row grants them, and `confined` is dropped for an account with no Linux user. A plugin declares `app`, so the blast radius is the grantable surface and nothing below it. - **There is no way to represent "no" today.** An opt-out model needs one — either a negative row, or grants written for every role at install time so that absence keeps its current meaning. The second needs no resolver change and keeps the table readable as the whole truth; it does mean a role added later starts with nothing until backfilled. **Which of the two is his call, not mine.** Related and unresolved: `multi-user/a-plugin-s-settings-routes-are-reachable-by` — a plugin granted to a Member already exposes its `/_config`, and making plugins on-by-default makes that reachable by default too. These two should land together, or the second stops being a latent hole and becomes an open one.