| 1 | # Provider, model, and settings contract for v0.9.1 |
| 2 | |
| 3 | This note records the live-code answers used for the v0.9.1 cutover. A provider |
| 4 | is a route/account boundary. A model is a provider-qualified choice. Provider |
| 5 | setup and adding a model are deliberately separate operations. |
| 6 | |
| 7 | ## Live state definitions |
| 8 | |
| 9 | 1. **Configured, enabled, current, saved, and default are distinct.** A provider |
| 10 | is configured when `config::provider_is_configured` finds the active route, |
| 11 | usable auth/external consent, or meaningful explicit provider configuration |
| 12 | (`provider_is_configured` in `crates/tui/src/config.rs`; grep the symbol |
| 13 | rather than trusting a line number). An enabled model is a |
| 14 | `(provider identity, model id)` entry in `Settings::enabled_models`; the |
| 15 | current model is `App::{api_provider,model,auto_model}`; a saved |
| 16 | provider-specific preference is `Settings::provider_models`; and the startup |
| 17 | default is `Settings::default_provider` plus the provider-scoped preference |
| 18 | (with `default_model` retained only as the DeepSeek compatibility fallback). |
| 19 | Startup resolves these layers in `App::new` (`tui/app.rs:2964-3220`). |
| 20 | |
| 21 | 2. **Duplicate IDs remain provider-qualified.** `ModelPickerRow` carries both an |
| 22 | `ApiProvider` and wire model ID. Cross-provider rows render as |
| 23 | `Provider display name · model-id`, and apply events preserve the provider |
| 24 | (`tui/model_picker.rs:203-213,1247-1255`). No bare model ID is treated as a |
| 25 | globally unique owner. |
| 26 | |
| 27 | 3. **Non-catalog cases are conservative.** The active custom/unknown/local tag |
| 28 | remains a selectable current row when the route accepts passthrough IDs. |
| 29 | Retired aliases are normalized for display without losing the pre-apply |
| 30 | value. `auto` is synthetic and is never persisted as an enabled model. |
| 31 | Self-hosted/keyless means only that authentication is unnecessary; it does |
| 32 | not imply reachability or health. Row selectability and explanations come |
| 33 | from the route-specific readiness snapshot |
| 34 | (`tui/model_picker.rs:434-459,934-1018`). |
| 35 | |
| 36 | 4. **Discovery is intentional.** The ordinary `Configured` view filters on the |
| 37 | enabled/owned bit. `Catalog`, `Recent`, `Coding`, `Cheap`, and `Long context` |
| 38 | are explicit discovery views; a typed query also searches the full lake |
| 39 | (`tui/model_picker.rs:83-151,357-377,1257-1276`). Applying a catalog row adds |
| 40 | that provider/model pair to the enabled set, so subsequent ordinary opens |
| 41 | show it without exposing the rest of the catalog. |
| 42 | |
| 43 | 5. **Cross-provider apply has a bounded effect.** Merely moving focus previews |
| 44 | destination route facts and changes nothing. Enter validates the destination, |
| 45 | switches only the current session route, saves that provider's model |
| 46 | preference, and additively enables the pair. It does not rewrite the global |
| 47 | startup provider/model unless the separate save-as-default API is used |
| 48 | (`tui/ui.rs:9495-9880`, `settings.rs:1461-1499`). Escape emits only picker |
| 49 | browsing memory and does not mutate session or settings |
| 50 | (`tui/model_picker.rs:1604-1611`). |
| 51 | |
| 52 | 6. **Existing configuration paths stay available.** The native `ConfigView`, |
| 53 | `/config`, `/config <key>`, `/config <key> <value>`, `--save`, diagnostics, |
| 54 | root/legacy config resolution, and CLI overrides remain consumers of the |
| 55 | same `Config` and `Settings` structures (`commands/groups/config/config.rs`, |
| 56 | `tui/views/mod.rs:1192-1770`). The modal is an additional typed editor, not a |
| 57 | replacement storage format. |
| 58 | |
| 59 | 7. **First-run safety is narrower than education.** Trust/workspace scope, |
| 60 | permission posture, external-credential consent, and any credential needed |
| 61 | by the chosen route are runtime gates. Mode/Fleet/Workflow explanations, |
| 62 | theme selection, and catalog browsing are optional education and must remain |
| 63 | skippable. Onboarding cannot imply that a keyless route is healthy. |
| 64 | |
| 65 | 8. **Provider names appear only for provider facts.** Auth environment variables, |
| 66 | endpoints/protocols, provider telemetry, external credential sources, and |
| 67 | legacy compatibility name the exact provider. Generic cache, retry, |
| 68 | permission, model-validation, and recovery copy uses the active provider or |
| 69 | neutral wording. |
| 70 | |
| 71 | 9. **Readiness comes from one resolved snapshot.** UI labels use |
| 72 | `provider_readiness::resolve_for_model`, which combines effective config, |
| 73 | credential/consent state, live session health, protocol capability, and the |
| 74 | selected model (`provider_readiness.rs`, `tui/model_picker.rs:971-1018`). |
| 75 | `configured`, `ready`, `managed`, and `unavailable` are not synonyms. |
| 76 | |
| 77 | 10. **Migration is additive.** `enabled_models` is optional and serde-defaulted, |
| 78 | so old files load unchanged. At startup, all existing `provider_models` and |
| 79 | the current provider/model are seeded into the in-memory enabled map. The |
| 80 | next successful selection writes both the old provider preference and the |
| 81 | additive enabled set (`settings.rs:356-365,1429-1485`, |
| 82 | `tui/app.rs:3196-3216`). Unknown provider keys remain inert; wire spelling is |
| 83 | preserved and duplicate IDs are deduplicated case-insensitively. |
| 84 | |
| 85 | ## Persistence rule |
| 86 | |
| 87 | The ordinary chooser is the union of `auto`, the current route/model, explicit |
| 88 | enabled pairs, existing provider-scoped saved preferences, and provider-config |
| 89 | models. Provider configuration alone never imports that provider's catalog. |
| 90 | Catalog search remains available even when the ordinary set contains only one |
| 91 | model. Cancel never writes. Successful apply writes the smallest |
| 92 | provider-qualified state needed to make the user's choice repeatable. |
| 93 |