Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,11 @@ environment pull-request show <id>`. Diff commands require an explicit target
(alias `--host`) or `--environment <id>` to inspect the machine where work
will run; the selectors cannot be combined. With neither selector they
intentionally inspect the primary machine.
- Pi's native cycling preference is available through `bb pi models list`,
`bb pi models set <model-id...>`, and `bb pi models enable-all`. Each accepts
optional `--machine <id-or-name>` and `--json`; without a machine it targets
the primary host. These commands update Pi's global `enabledModels` and do
not accept a cwd.
- Known ACP agents can appear automatically when their CLI is installed on the
host; for example `opencode`, `omp`, Grok Build's `grok` CLI, or Hermes'
`hermes` CLI on PATH appears as provider `acp-opencode`, `acp-omp`,
Expand Down
29 changes: 29 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,35 @@ so a configured agent shows the generic tool glyph, and bb drops the field when
it reads the old array. A setting entry wins over a config entry with the same
`id`.

## Pi enabled models

Settings → Plugins → Pi provider → Models edits Pi's global `enabledModels` on
the primary machine. The editor lists authenticated models, supports search
and per-model switches, and updates BB's picker and model cycling immediately
after Save. **Enable all** removes the native preference; **Reset** restores the
last saved selection.

For CLI use:

```sh
bb pi models list [--machine <id-or-name>] [--json]
bb pi models set <model-id...> [--machine <id-or-name>] [--json]
bb pi models enable-all [--machine <id-or-name>] [--json]
```

Without `--machine`, the command targets the primary machine. SDK clients call
the Pi plugin through `sdk.plugins.callRpc` with plugin id `provider-pi` and
method `readModelSettings` or `writeModelSettings`; each input carries
`hostId`, writes also carry `enabledModelIds` (`string[]` or `null`), and the
call supplies an `outputSchema` for the snapshot as required by
`sdk.plugins.callRpc`. Neither CLI nor SDK accepts a cwd because this editor
changes Pi's global
preference, not a workspace settings file.

This preference controls ordinary picker/cycling visibility, not execution
authorization. A model already selected by a thread remains available as a
selected-only model.

## Custom Models

Register extra picker models by editing top-level `customModels` in
Expand Down
102 changes: 102 additions & 0 deletions docs/model-preferences-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Provider-native model preferences

Status: accepted and implemented for Pi

## Decision

Pi's global `enabledModels` setting remains the authority for Pi's preferred
model set. BB exposes a product editor for that native preference; it does not
create a second BB model-policy document.

The editor lists authenticated models on the host selected by Settings. It
shows model switches, search, enabled count, **Enable all**, **Reset**, and
**Save**. Host routing is supplied by the Settings host context. The editor
never asks for a machine, cwd, file path, pattern, revision, or conflict
resolution.

The CLI offers the same global operation through `bb pi models`; its optional
`--machine` flag follows BB's remote-targeting convention. SDK clients use the
Pi plugin's `readModelSettings` and `writeModelSettings` RPC methods through
`sdk.plugins.callRpc`. Neither surface accepts cwd.

## Invariants

### Preferences are not authorization

`enabledModels` controls Pi's picker and model cycling. It does not authorize
execution. A selected thread model outside the preferred set remains in BB's
selected-only catalog and can continue to run.

A future execution restriction would be a separate BB-owned policy with an
explicit denial result. It must not reuse this preference.

### Pi owns matching

Pi model identifiers and `enabledModels` patterns are opaque outside the Pi
bridge. The bridge uses Pi's native resolver, including ordered patterns,
globs, bare IDs, aggregator IDs containing slashes or colons, and thinking
suffixes. Core model contracts carry only ordinary model IDs and never gain Pi
pattern fields.

The product editor intentionally writes exact authenticated model IDs. Existing
native patterns are resolved internally to switch state but are never exposed
or rewritten until the user saves a changed selection.

### Empty resolution is unrestricted

Pi treats absent or empty `enabledModels` as unrestricted. It also treats a
configured pattern set that resolves no models as unrestricted rather than
deny-all. BB preserves that behavior: the picker cannot become empty because a
stale native pattern stopped matching.

**Enable all** removes the global `enabledModels` field. The editor prevents a
user from disabling the final authenticated model.

### Selected-only models remain available

Model discovery partitions the authenticated catalog:

- models selected by Pi's native preference appear in `models`, in Pi's
resolved order;
- authenticated models outside that preference appear in
`selectedOnlyModels`;
- duplicate IDs are not introduced.

The distinction preserves an existing thread's selection without presenting
that model during ordinary cycling.

### Hosts are isolated

The selected host determines credentials, authenticated models, and the global
Pi settings file. A host with no authenticated models reports that state; it
must never show another host's cached catalog.

Saving clears the server's model-catalog memo and broadcasts a model change so
web and mobile picker queries refetch immediately. The Pi bridge reloads native
settings before every model-list resolution, so a save does not require a BB
restart.

### Writes preserve the settings document

The Pi bridge updates only global `enabledModels`. It takes the same
host-local lock Pi uses (`proper-lockfile` on the settings path), preserves
unrelated JSON fields and file mode, writes a temporary file beside the real
file (through a symlinked `settings.json`, not over the link), and atomically
renames it over the settings file. Invalid settings or write failures fail the
save rather than replacing unknown content; a settings file pi could not load
is reported and read as empty for listings, so the picker keeps working.

The bridge reads only the global file. A project's `.pi/settings.json`
`enabledModels` applies in pi only once the project is trusted, a decision
the bridge cannot see, and a repository must not be able to steer the picker.

## Ownership

| Concern | Owner |
| -------------------------------------------- | -------------------------------------------- |
| Authenticate and enumerate Pi models | Pi model runtime in the Pi bridge |
| Resolve native `enabledModels` semantics | Pi native resolver in the Pi bridge |
| Atomically update global Pi settings | Pi bridge on the selected host |
| Route the selected host | BB Settings context / CLI machine resolution |
| Cache invalidation and client notification | BB server provider plugin API |
| Search, draft, reset, save, and empty states | Pi provider plugin app |
6 changes: 6 additions & 0 deletions packages/templates/src/templates/bb-guide-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ Providers are agent backends (e.g., codex, claude-code). Each supports different
List available providers
bb provider models [providerId] [--machine <id-or-name> | --environment <id>]
List models for a provider
bb pi models list [--machine <id-or-name>] [--json]
List authenticated Pi models and enabled state
bb pi models set <model-id...> [--machine <id-or-name>] [--json]
Replace Pi's global enabled models
bb pi models enable-all [--machine <id-or-name>] [--json]
Enable every authenticated Pi model

Use these before spawning threads if you are unsure which provider or model to use.
`--host` is an alias for `--machine`. Machine and environment selectors are
Expand Down
44 changes: 44 additions & 0 deletions plugins/provider-pi/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.pi-extension-state {
display: grid;
gap: 0.5rem;
min-width: 0;
color: var(--foreground);
font-size: var(--text-xs);
line-height: var(--text-xs--line-height);
}

.pi-extension-state__metadata,
.pi-extension-state__widget {
display: grid;
gap: 0.375rem;
min-width: 0;
padding: 0.625rem 0.75rem;
border: 1px solid var(--border);
border-radius: 0.625rem;
background: var(--surface-recessed);
}

.pi-extension-state__title {
overflow: hidden;
font-weight: 600;
text-overflow: ellipsis;
white-space: nowrap;
}

.pi-extension-state__status {
display: flex;
align-items: center;
gap: 0.5rem;
min-width: 0;
overflow: hidden;
color: var(--muted-foreground);
text-overflow: ellipsis;
white-space: nowrap;
}

.pi-extension-state__widget {
overflow-x: auto;
font-family: var(--font-mono);
line-height: 1.45;
white-space: pre;
}
Loading
Loading