Add generic provider env contribution hook for plugins - #3035
Merged
Conversation
This was referenced Sep 4, 2026
SawyerHood
force-pushed
the
bb/provider-env-contribution
branch
from
September 4, 2026 04:39
56a5f8d to
969ab39
Compare
SawyerHood
marked this pull request as ready for review
September 4, 2026 05:14
SawyerHood
added a commit
that referenced
this pull request
Sep 4, 2026
Stack layer 3 of 3 (top). Prerequisites: #3035 (provider env contribution hook) and #3036 (Account Pool hub) below it in this stack. ## Human comments ## What was wrong The Account Pool hub existed, but Claude Code sessions were not routed to it automatically: the plugin still exposed one global bearer key, had no per-thread bypass, and could not replace an unauthenticated machine's local Claude health with the readiness supplied by an enabled pool account. This is the BB-90 stack layer on `bb/account-pool-hub` and `bb/provider-env-contribution`. ## What changed - Registered the Account Pool's Claude Code environment contribution with the exact server-relative hub route and a secret bearer token minted lazily per machine. The resolver contributes nothing when no account is enabled or the thread is bypassed. - Replaced the global hub key with per-machine 0600 token files loaded once into a single-process cache, constant-time bearer matching across every current and grace token, serialized mint/use/rotation updates, a ten-minute rotation grace window, and removal of the obsolete global key file. Last-use persistence is throttled to once per machine per minute, expired grace tokens are pruned with the next write, and status never returns token values. - Added `bb pool token rotate --machine <id-or-name>` and `bb pool bypass <thread-id> [--off]`, with matching plugin RPC operations and discoverability updates in the CLI skill, generated guide source, and configuration docs. - Tracked the last 24 hours of routed threads and made unsafe disablement visible in `bb pool status`, including proxied hosts that are relying on the pool, plus a plugin warning log when a disable leaves those threads on hosts without usable local Claude credentials. The dispose-time inspection is guarded against failures and bounded to two seconds. - Added the single experimental SDK member `bb.providers.experimental_contributeEnvHealth`, with fake-host support, Plugin Guide documentation, API audit notes, API map inventory, and SDK version 0.4.45. The server presents an `unauthenticated` or `expired` Claude provider as ready/`Proxied` only when the same live plugin also has an env resolver and the Account Pool has an enabled account. - Reused the lower stack layers' env command payload and hub drain. This PR does not change the server-to-daemon wire, so it does not bump `HOST_DAEMON_PROTOCOL_VERSION`. ## Not in this PR - BB's plugin SDK has no system-notice append surface or fitting backend thread action. `bb.sdk.threads.send` would create a real provider turn, so this PR does not fake the requested disable-time thread notice or bypass action. The safety gap is instead explicit in `bb pool status` and the disable log. - Disabling a plugin reloads the Claude bridge, which rebuilds the session but discards the previous attachment before it can emit the same cosmetic rebuild warning used by an in-place bypass change. In e2e thread `thr_stxrb938ec`, the fresh `provider.env-resolved` event without pool entries and the successful `LOCAL AGAIN` response demonstrate the actual disable behavior. The bypass path in that thread does retain the attachment and emits the expected rebuild warning. - A packaged remote daemon cannot be enrolled into an isolated dev app. The multi-machine path is verified by the daemon-side runtime test that expands `serverPath` against its loopback machine-auth URL, plus a live 200 response from the dev hub's `HEAD /api/hello`; this does not claim a live remote thread. ## How you verified - Added Account Pool regressions for empty resolver/health output, exact per-host contributions and secret masking, distinct machine tokens, bypass through CLI and RPC, token rotation and grace expiry, the single-process cache and last-use write throttle, secret-free status, proxied and unauthenticated routed-host warnings, bounded/failure-safe disable logging, and the existing authenticated streaming/drain paths. These behaviors had no implementation before this change; all 16 tests pass. - Added server and fake-plugin-host coverage proving health is ignored without an adjacent env resolver and marks only credential-blocked provider health ready when a contribution is active. - `pnpm exec turbo run typecheck --filter=@get-bb/plugin-sdk --filter=@bb/server --filter=@bb/plugin-api-map --filter=bb-plugin-account-pool --continue` — 9 tasks passed. - `pnpm exec turbo run test --filter=@get-bb/plugin-sdk --filter=@bb/server --filter=@bb/plugin-api-map --filter=bb-plugin-account-pool --continue --force` — 11 tasks passed; Account Pool 13 tests, SDK 22 files, API map 11 files, and server 227 files / 2205 tests. - Review follow-up: `pnpm exec turbo run typecheck test --filter=bb-plugin-account-pool --filter=@bb/server --filter=@get-bb/plugin-sdk --continue --force` — 13 tasks passed; Account Pool 16 tests, SDK 22 files, and server 227 files / 2205 tests. - `pnpm exec turbo run typecheck test --filter=@bb/agent-runtime --continue --force` — typecheck passed and 22 files / 319 tests passed, including loopback `serverPath` expansion and secret event masking. - `node .github/workflows/check-plugin-sdk-version.mjs` — passed with the SDK surface change and version bump. - `git diff --check origin/bb/account-pool-hub...HEAD` — passed. - In the isolated dev app, Claude Code thread `thr_stxrb938ec` returned `POOL OK` through the hub with an expanded loopback URL and masked token in `provider.env-resolved`; quota utilization moved from unknown to 28%/34%. Bypass returned `DIRECT OK` with no pool env and the rebuild warning. Plugin disable returned `LOCAL AGAIN` using local credentials with no pool env, and the plugin was re-enabled. Per-machine token rotation also completed, and a live hub hello request returned HTTP 200. BB-90 has the reduced JSON evidence and both rendered UI screenshots attached. Part of #1552 Task: BB-90 > AGENT GENERATED --------- Co-authored-by: Sawyer Hood <kirbyhood@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
SawyerHood
added a commit
that referenced
this pull request
Sep 4, 2026
Stack layer 4 of 4 (top). Prerequisites: #3035, #3036, and #3042 below it in this stack. ## Human comments ## What was wrong Account Pool had no settings UI or interactive Claude login path, so users had to provision accounts through the CLI. The plugin could also report `needs-configuration` when empty, but the app frontend loader discarded every plugin frontend outside `running`; that made the configuration UI that an empty pool needs impossible to load. Part of #1552. ## What changed - Added an Account Pool settings section with the minimal account list, ready/held/exhausted/error/disabled status, 5-hour and 7-day percentages, enable/disable, confirmed removal, machine import, and a password-field API-key flow. - Added Claude Code-compatible PKCE login with a ten-minute in-memory session, manual callback paste parsing, state validation, token exchange, profile enrichment, protected account storage, and user-readable errors that do not expose upstream payloads. - Exposed login through typed plugin RPC and two plugin-owned CLI commands: `bb pool account add --provider claude --login` prints the authorization URL and session ID, then `bb pool account login-complete --session <id> --code-stdin` completes it without putting the pasted code in process arguments. - Generalized the plugin CLI proxy's protected stdin handling so any `--<name>-stdin` flag becomes `--<name> <single-line-value>` with the existing 16 KiB limit; core contains no Account Pool-specific routing. - Published account mutation notifications and refreshed the settings list after mutations. - Allowed frontend bundles for `needs-configuration` and `degraded` plugins, with regression coverage for all supported settings statuses. - Updated the plugin guide, built-in bb CLI skill, and configuration documentation. There is no server/host-daemon wire change, so `HOST_DAEMON_PROTOCOL_VERSION` is unchanged. ## How you verified - `pnpm exec turbo run typecheck test --filter=bb-plugin-account-pool --filter=@bb/cli --filter=@bb/app --filter=@bb/templates --continue --force` — 14/14 tasks passed: Account Pool 28 tests, CLI 530 tests, app 3,853 tests (4 skipped), templates 43 tests. - `pnpm --silent bb plugin build plugins/account-pool` — emitted server and app JS/CSS/meta bundles. - `pnpm install --frozen-lockfile --offline` — lockfile accepted without resolution changes. - Live dev-app proof: captured the empty state, started the PKCE/manual-paste flow, verified the API-key input is `type=password`, imported the machine OAuth account, ran Claude Code thread `thr_qr935hirfw` to an `ok` response through the pool, observed 5-hour/7-day utilization, removed the account in the UI, and confirmed its mode-600 secret file was deleted. Screenshots and command artifacts are attached to BB-92. - The isolated headless QA browser reached Claude's Cloudflare “Performing security verification” page, so live OAuth completion stopped at the brief's human-browser boundary. The exact state is attached; successful exchange/profile/storage and all three paste shapes are covered against fake HTTP servers. Part of #1552 > AGENT GENERATED
SawyerHood
added a commit
that referenced
this pull request
Sep 4, 2026
…rite (#3053) Standalone follow-up to the Account Pool stack (#3035, #3036, #3042, #3049); based on main. ## Human comments ## What was wrong Account Pool selected accounts using only shared 5-hour and 7-day quota observations, even though Anthropic applies separate weekly limits to model families such as Fable. Scoped `7d_<bucket>` headers were recorded as opaque diagnostics and never governed selection, the OAuth usage endpoint was not polled, and Claude Code request metadata could retain an account UUID belonging to a different OAuth account after routing. Part of #1552. ## What changed - Replaced opaque bucket exhaustion diagnostics with fixed Fable, Sonnet, Opus, Haiku, and other weekly quota slots carrying utilization, reset, status, observation time, and source. - Added five-minute idle OAuth usage refreshes, immediate refresh after add or enable, scoped usage-limit parsing, and lazy account UUID backfill through the OAuth profile endpoint. Refresh failures preserve the last known state. - Parsed the request model once and made eligibility and reset tie-breaking use its governing family bucket. Scoped 429 responses now rotate accounts without globally exhausting the rejected account. - Stored account UUIDs during Claude Code import and OAuth sign-in, and guarded request rewriting to the selected account for recognized stringified-JSON and `user_*_account_<uuid>_session_*` metadata forms. Unrecognized, absent, non-JSON, or UUID-less requests remain byte-identical. - Added dynamic family columns to `bb pool account list` and updated the CLI skill, plugin guide, and configuration docs. - Added focused migration, usage parsing/refresh, family routing, scoped-header/429, UUID import/sign-in/backfill/rewrite, passthrough, CLI, and app regression coverage. There is no Plugin SDK or server/host-daemon wire change, so neither protocol version changed. ## How you verified - `pnpm exec turbo run typecheck test --filter=bb-plugin-account-pool --continue --force` — 6 tasks passed; 4 test files and 35 tests passed. The new routing, scoped-429, refresh, migration, and UUID tests fail against the prior implementation and pass with this change. - `pnpm exec turbo run typecheck test --filter=@bb/templates --continue --force` — 7 tasks passed; 7 test files and 43 tests passed. - `pnpm exec turbo run typecheck --filter=@bb/server --continue` — 5 tasks passed. - `pnpm --silent bb plugin build plugins/account-pool` — server and app bundles built successfully. - `git diff --check origin/main...HEAD` — passed after rebasing onto current `origin/main`. - Isolated dev-app proof with two OAuth accounts and `switchThreshold=0.70`: Account A had shared 7d at 43% but Fable at 80%; Account B had Fable at 7%. A real `claude-fable-5-1` turn completed through Account B, then a real `claude-sonnet-5` turn completed through Account A, proving family-only exhaustion does not disable the account globally. A redacted shape probe on a further real turn found `metadata.user_id` present without a recognized account UUID component, so the production path correctly preserved it byte-for-byte. The probe was removed, both imported test accounts were removed from the isolated store, and the dev app was stopped. Evidence is attached to BB-94. Part of #1552 > AGENT GENERATED
ymichael
added a commit
that referenced
this pull request
Sep 9, 2026
## Human comments ## What was wrong [PR #3035](#3035) made plugin-contributed provider environments available on every command, but Pi reconciled only model and reasoning changes while ACP ignored later `turn/start` options. Their long-lived child processes therefore kept the environment from session creation even after BB accepted and recorded new credentials or endpoints, so a later turn could use the wrong account or fail with stale credentials. ## What changed Pi now compares the effective turn environment with its construction environment and uses its existing rollback-safe rebuild and resume path when values differ. ACP now retains its construction parameters, merges current launch and turn environments, and restarts through its existing resume path; it reports context loss only when fallback changes the provider thread id. Identical environments do not trigger replacement, and legacy empty replay payloads keep their existing no-change behavior. The rebase preserves current main's deterministic Pi skill-input coverage and drops the now-obsolete timeout-only commit for the deleted process-backed test. No public contract, CLI, documentation, or host-daemon wire behavior changed, so no protocol bump is required. ## How you verified - Added red-first Pi and ACP regressions that reproduce stale child environments and pass after the fix. - Full provider suites passed: Pi 157/157 tests and ACP 312/312 tests. - Focused post-format reruns passed: Pi turn options 7/7 and ACP bridge 96/96. - `pnpm exec turbo run test typecheck --filter=bb-plugin-provider-pi --filter=@bb/provider-bridge-acp --force` passed all eight Turbo tasks. - `bb plugin build plugins/provider-pi` and `bb plugin build plugins/provider-acp` emitted their packages successfully. - Targeted formatting for the four normally formatted source/test files and `git diff --check origin/main...HEAD` passed. The three-line fake-Pi fixture addition follows formatter output; the remainder of that legacy fixture is unchanged. No linked issue; this is a follow-up to #3035. > AGENT GENERATED
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack layer 1 of 3 (bottom). No prerequisite; layers 2 (account-pool plugin) and 3 (pool wiring) build on it.
Human comments
What was wrong
Plugins could register providers and derive provider options, but there was no validated, per-provider hook for contributing environment variables on each daemon command. As a result the server had nothing to resolve, the versioned host wire carried no contribution metadata, the daemon could only build its fixed shell environment, and Claude did not rebuild its resident SDK session when a turn's merged environment changed. This implements BB-89.
What changed
bb.providers.experimental_contributeEnv(providerId, resolve)with public context and entry types, zod boundary validation, fake-host support, Plugin Guide coverage, the API audit entry, and Plugin API map inventory. The Plugin SDK version is now 0.4.44.contributedEnvcommand payloads and bumpedHOST_DAEMON_PROTOCOL_VERSIONto 180.serverPathvalues against the daemon's loopbackBB_SERVER_URL, and persistedprovider.env-resolvedevents with contributed secrets masked. If that base URL is unavailable, the daemon drops only the unresolved entry, records it as masked, and emits a configuration warning naming the variable and plugin instead of preventing thread startup.Execution settings changed; the Claude session was rebuilt to apply them.Ordinary context-preserving session replacements remain hidden.How you verified
node .github/workflows/check-plugin-sdk-version.mjspnpm exec turbo run typecheck test --filter=@get-bb/plugin-sdk --filter=@bb/plugin-api-map --filter=@bb/domain --filter=@bb/host-daemon-contract --filter=@bb/thread-view --filter=@bb/provider-bridge-protocol --filter=@bb/agent-runtime --filter=@bb/provider-bridge-acp --filter=bb-plugin-provider-codex --filter=bb-plugin-provider-claude-code --filter=bb-plugin-provider-pi --filter=@bb/server --filter=@bb/host-daemon --continue --force(all typechecks passed; 33/34 test tasks passed, with one load-sensitive Pi test timing out)pnpm exec turbo run test --filter=bb-plugin-provider-pi --force(21 files and 121 tests passed sequentially, including the timed-out test)pnpm exec turbo run typecheck test --filter=@bb/agent-runtime --filter=bb-plugin-provider-claude-code --continue --forcepassed both typechecks, 22 agent-runtime files / 319 tests, and 25 Claude files / 357 tests.pnpm exec turbo run test:integration --filter=@bb/agent-runtime --forcepassed 9 files and 64 tests, including the refreshed live Claude coverage.pnpm parity --old <dbc16017c9 checkout> --new . --allowlist <empty external allowlist>(48 passed, 0 failed, 4 process-only cells skipped)scripts/bb-dev-app current, installed a throwaway path plugin, and verified Claude Code, Codex, and ACP Cursor received the marker, secret, and loopback-expanded URL while the event masked the secret.Fixes BB-89