Replies: 1 comment
|
I verified every claim in this proposal against current master (47f9438), and the strongest supporting evidence is one the proposal does not cite: the host itself documents this exact move as deferred work. 1. All cited claims check out
2. The maintainers' own note says this is the intended direction
So the proposal is not a departure from the design — it is the comment's stated plan. The 3. Implementation shape is small and host-side-only The cleanest minimal-diff path, following the seam's existing patterns:
Blast radius: one option field + one descriptor field + one union arm. The client side needs zero changes — 4. A lifecycle advantage over the static allowlist Registrations are fiber-scoped effects ( 5. Redaction is inherited, verified Both read paths already pass This is also the settings instance of a broader pattern: downstream plugins keep hitting fixed surfaces that the two adjacent seams already advertise as extensible — event-type registration ( |
Uh oh!
There was an error while loading. Please reload this page.
Summary
A Host plugin can register a settings namespace via
ctx.settings.register(ns, schema)(packages/settings/settings/src/index.ts:426), and the settings seam serves it fully — layering, validation, persistence,settings/document-updated. But the apiproxy settings RPC domain then makes that namespace invisible to and unwritable by configuration clients:describefilters byexposedNamespaces()(packages/host/apiproxy/src/api-proxy.ts:3269), andmutate/update/replacerefuse withsettings-not-exposed(:2009).exposedNamespaces()(:1953) is a fixed union of:settingsNs(ctx.llm.listConfigurableProviders()),WEB_SETTINGS_NAMESPACESlist (:126),PRODUCT_SETTINGS_NAMESPACESset (:256).There is no plugin-reachable seam to join it. The result: a plugin that ships a settings card (via the public
settings.plugin.itemlist slot — the same slot the three built-in cards self-register into) cannot read or write its own namespace throughctx.settingsScope.bind({ namespace }), the exact channel the built-in cards use.describehides it, so the scope reportsunavailable;mutaterefuses the write.Why this matters
The plugin configuration page is explicitly extensible on the UI side (
settings.plugin.item, replaceRisk: none in the slot catalog), and the settings seam is explicitly extensible on the storage side (settings.registerfrom any Host plugin). The RPC exposure boundary breaks the chain in the middle: the first two seams advertise a plugin-owned settings card as a supported composition, the third makes it impossible.Concrete use case: a plugin that routes delegated subagents to a user-chosen provider/model. The route belongs in dsh settings (layered user/base/default,
settings.yamlpersistence, live apply). Today the plugin must stand up its own loopback HTTP endpoint overctx.webServer.registerand bridge to its owner scope — which works precisely because the owner scope is not fenced — duplicating whatsettingsScopealready does for built-in namespaces.Proposal
Let namespace registration carry an exposure opt-in, e.g.
and have
exposedNamespaces()union in the namespaces whose registrations asked for it, instead of (or in addition to) the hardcoded lists.Notes on the obvious concerns:
redactSecrets), and secret writes ride the credentials domain; an exposed plugin namespace inherits both.validateoption gate every write; exposure adds no new mutation power, it only stops refusing a channel the registrant owns Host-side anyway (the owner scope canupdate/replaceits own namespace today, unfenced — the fence currently only blocks browser-reachable convenience, not Host capability).Alternatives considered (and why they're worse)
WEB_SETTINGS_NAMESPACES: it's a compiled-in constant, not a config entry — unreachable without forking the host bundle.Acceptance sketch
settings.register('my-plugin', schema, { expose: ... })sees its namespace insettings.describeresponses and can write it viasettings.mutate.ctx.settingsScope.bind({ namespace: 'my-plugin' })behaves exactly like the built-in cards (ready status, writes land insettings.yaml,settings/document-updatedfires).All reactions