Skip to content

Apply declarative plugin settings on change, like every other toggle in bb #2307

Description

@ariofrio

The workflow

Reproduces on a stock install, no third-party plugins. Go to Settings → Provider retry (/settings/plugins/provider-retry), which declares one select through bb.settings.define (server.ts#L40-L49). Change Maximum automatic wait from "6 hours" to "24 hours", leave the page, and hit a subscription limit.

The retry is still capped at six hours. The dropdown moved, nothing saved it, and nothing said so — the setting only applies if you noticed Save settings at the bottom of the form. Because the effect lands in scheduling behavior rather than on screen, a missed save is discovered a turn or a day later, if at all.

Every other toggle in bb applies on the spot, including bb's own (<Switch onCheckedChange={setDimsInactiveSplits} />, SplitDimmingSetting.tsx#L18-L20) and both first-party plugins that own their settings UI. Nothing tells a user which kind of toggle they're looking at.

What happens today

PluginSettingsForm holds edits in a local drafts map and PUTs only on submit — desktop and mobile. Two consequences beyond the extra click:

  1. Unsaved switches are discarded on navigation, with no prompt — deliberate, and pinned by PluginSettings.test.tsx#L165.
  2. A plugin wanting normal behavior must leave the declarative API. Custom instructions and Keep Awake both did, and each then hand-wrote a CLI (bb instructions, bb keep-awake) to replace the bb plugin config they gave up.

What you would expect

Settings commit when the control commits, with an inline "Saving… / Saved" status where the button is:

  • boolean / select / project — immediately, optimistic. The control is the commit.
  • string (non-secret) — debounced ~500 ms.
  • string + secret: truekeep an explicit commit. Write-only, "empty means unchanged", lands in a 0600 file; autosaving keystrokes persists half-typed keys.

Both patterns already exist here and are worth copying rather than reinventing: debounce + queued writes + status in custom-instructions/app.tsx#L46-L69, optimistic + revision-guarded rollback in keep-awake/app.tsx#L62-L92.

Propagation already works, unchanged. updateSettings broadcasts plugins-changed on every effective change, and the comment there already names useSettings as the consumer (plugin-service.ts#L1998-L2001); the registry invalidates the ["plugin-settings"] prefix (realtime-cache-registry.ts#L1276). A flipped switch would take effect at the moment it's flipped, with no new plumbing.

Three things needing a decision, not just a patch:

  1. A form mixing secrets and switches ends up with a button governing one field. Needs a UI answer.
  2. needs-configuration plugins are reloaded on every effective change (plugin-service.ts#L2015) — with a debounced field that's a reload every 500 ms while someone types an API key.
  3. Two tests encode the draft model (L46, L165) and mobile's Discard loses its referent. I read those as arguments for the change, but they're deliberate and a PR should say so rather than quietly delete them.

Context and alternatives

No plugin-side workaround. Descriptors have no hidden flag and the form renders whenever plugin.hasSettings, so a settingsSection slot renders below a form still showing every control. The only escape is abandoning bb.settings.define — a bad trade for a plugin whose settings are three switches. Affects every plugin with declarative settings, desktop and mobile. Among bundled plugins that is Provider retry, Workflows, and GitHub in 0.39.0, plus the Claude Code and Codex providers on main.

Searched; not duplicates: #2191 (open, placeholder on string descriptors), #1238 (closed, multiline), #1766 (closed, settings destroyed on source replacement), #1620 (open, Usage limits surface).

One question first: #1238 was authored and closed by @smsunarto with no comment or review, and its opening line makes this same observation from the other direction — a plugin needing more than the form offers "had to abandon the descriptor API entirely and ship its own settingsSection surface". Is this form settled enough to change, or is something already planned? Happy to prototype on a fork; per CONTRIBUTING.md I won't open a PR without sign-off.

Verified against main at 8bd6acc; desktop app, bb 0.39.0, macOS 15. Every line cited was read at that commit, and bb plugin config provider-retry confirms the schema is live on 0.39.0. The rendered form itself I traced through the code rather than screenshotting, on desktop and mobile both — flag it as unverified UI if that matters for triage. Investigation thread: thr_67q64zmixq.

AGENT GENERATED: by Claude

Metadata

Metadata

Assignees

No one assigned

    Labels

    pluginsPlugin SDK, runtime, marketplaceuiApp shell, sidebar, composer, rendering

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions