Skip to content

Spawn falls back to Codex unconditionally when a project has no remembered provider, even if Codex has no models configured #2306

Description

@technicalpickles

Per bb guide providers: "If the project has no remembered choice, bb uses the explicitly requested provider or Codex, then resolves the model marked default by that provider on the target machine."

That fallback is unconditional. On a host where Codex is registered as a provider but has zero models available (bb provider models codex → "No models available"), any threads.spawn into a project with no remembered default fails outright:

HTTP 503: Unable to load codex models to resolve the default. Try again once the host is connected and the provider is ready.

This happens even when other providers (Claude Code, pi) are fully configured and working on the same host.

Expected: if Codex isn't usable (no models, not authenticated, whatever), the default-provider resolution should fall through to another configured/working provider instead of hard-failing. Codex being the unconditional default seems wrong for a host that never set it up in the first place.

Repro:

  1. Have a provider like Codex registered but unconfigured (no models available on the host)
  2. Have at least one other provider (e.g. Claude Code) fully working
  3. threads.spawn (directly or via a plugin) into a project with no remembered provider/model default

Environment: bb 0.39.1-nightly.32567325585.1, macOS 26.5.2

Context: discovered via bb-plugin-dispatch

Found this while filing slogsdon/bb-plugin-dispatch#2. That plugin's destination-thread spawn (spawnThread in server.ts) intentionally omits providerId/model and just passes projectId, prompt, and environment to threads.spawn:

async function spawnThread(bb: BbPluginApi, projectId: string, prompt: string): Promise<string> {
  const spawned: any = await bb.sdk.threads.spawn({
    projectId,
    prompt,
    environment: { type: "host", hostId: await defaultHostId(bb), workspace: { type: "unmanaged", path: null } },
  } as any);
  ...
}

So the plugin itself has no opinion on provider for the destination thread — it relies entirely on bb's own default-provider resolution. The plugin's separate intake lane (used for classify/expand, a different hidden thread) works fine because it explicitly spreads a saved providerId/model/executionInputSources into its own spawn call. It's only the unconfigured default path, hit when dispatching into a project bb has no remembered choice for, that surfaces this.

Filing this here since the unconditional Codex fallback is bb's behavior, not something the plugin can work around without hardcoding a provider of its own (which would defeat the point of "inherit the host's defaults").

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions