Context
The dwapp bridge surface (peerd-distributed/apps/bridge.js) is deliberately small and frozen — "growing it is a security event, not a convenience." That's the right Phase-1 posture. This issue is about how to grow it when growth becomes necessary (a second room, content put/get, an app-visible sign(), notifications, …) without sliding into ambient authority.
The pattern
An extension-manifest / Sandstorm-powerbox / Cloudflare-OS-blueprint hybrid: the app declares the shapes of what it needs; the platform mediates each grant; the app can never use what it didn't declare.
Concretely:
DWAPP_META gains a needs list — publisher-signed, versioned, size-capped like the rest of the card (peerd-distributed/apps/meta.js). Each need is a {kind, params?, description} from a closed, versioned vocabulary (e.g. room is the one implicit need today; future: rooms:2, content-store, sign, …). Shapes only — a need is never a grant.
- Render needs at install and launch. The install consent dialog (already per-install, never remembered) lists them, Cloudflare-OS-blueprint-style with the author's description per need — so "what can this thing ask for" is visible before any bytes run.
- Consent per need at first use, granted narrowly (peerd already does this for the one existing need: room grants are keyed per content-hash × per room). New needs follow the same template: specific, remembered-or-not per kind, audited.
- The bridge refuses undeclared ops — even post-consent. The signed card thus commits the app's maximum authority. This composes beautifully with an invariant peerd already has: grants are keyed by content hash and reset on version change, so an update that grows
needs is both visible (signed card diff, new seq) and re-consented automatically.
Why this beats the alternatives
- vs. growing ambient bridge ops: every new op would be available to every dwapp ever installed, silently.
- vs. a runtime-only powerbox (request capabilities dynamically with no declaration): loses the "reviewable maximum authority" property; the card is where peerd already puts signed, versioned app claims.
- Cloudflare OS's binding annotations add a nice UX detail worth copying: per-need author-provided name/description/suggested-value, so the consent moment is comprehensible to a non-technical user.
Open questions
- Vocabulary governance: closed enum in
meta.js, versioned with the card schema; unknown kinds must fail closed (refuse install? or install with the need inert and visibly unsatisfiable?).
- Should
hello()'s DID disclosure become a declared need? Today it's implicit in opening the app; under this model it's arguably identity:read — which also intersects with the derived-subidentity issue (if per-dwapp identities land, the disclosed DID is fork-scoped and the stakes drop).
- Whether the seeded commons app (
apps/seed.js) declares needs retroactively (it should — it's the reference dwapp).
Nothing here is urgent — it becomes the required design the first time anyone proposes bridge op #14.
Context
The dwapp bridge surface (
peerd-distributed/apps/bridge.js) is deliberately small and frozen — "growing it is a security event, not a convenience." That's the right Phase-1 posture. This issue is about how to grow it when growth becomes necessary (a second room, content put/get, an app-visiblesign(), notifications, …) without sliding into ambient authority.The pattern
An extension-manifest / Sandstorm-powerbox / Cloudflare-OS-blueprint hybrid: the app declares the shapes of what it needs; the platform mediates each grant; the app can never use what it didn't declare.
Concretely:
DWAPP_METAgains aneedslist — publisher-signed, versioned, size-capped like the rest of the card (peerd-distributed/apps/meta.js). Each need is a{kind, params?, description}from a closed, versioned vocabulary (e.g.roomis the one implicit need today; future:rooms:2,content-store,sign, …). Shapes only — a need is never a grant.needsis both visible (signed card diff, newseq) and re-consented automatically.Why this beats the alternatives
Open questions
meta.js, versioned with the card schema; unknown kinds must fail closed (refuse install? or install with the need inert and visibly unsatisfiable?).hello()'s DID disclosure become a declared need? Today it's implicit in opening the app; under this model it's arguablyidentity:read— which also intersects with the derived-subidentity issue (if per-dwapp identities land, the disclosed DID is fork-scoped and the stakes drop).apps/seed.js) declares needs retroactively (it should — it's the reference dwapp).Nothing here is urgent — it becomes the required design the first time anyone proposes bridge op #14.