Skip to content

feat(config): explicit provider availability in config init#51

Merged
dbtlr merged 4 commits into
mainfrom
feat/provider-readiness-config-init
Jun 24, 2026
Merged

feat(config): explicit provider availability in config init#51
dbtlr merged 4 commits into
mainfrom
feat/provider-readiness-config-init

Conversation

@dbtlr

@dbtlr dbtlr commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What & why

sk config init filtered its provider picker down to providers it detected as available at that instant. Detection was ad-hoc per-provider sniffing that disagreed with how credentials are actually resolved at runtime:

  • Detection vs. runtime driftresolve_api_key resolves an Anthropic key from explicit → providers.anthropic.api_key (config) → ANTHROPIC_API_KEY (env), but detection only checked the env var. A user whose key lived in config had a provider that worked but never appeared.
  • Detection was a gate, not a hint — the picker hid providers based on ambient filesystem/env state, so options blinked in and out with no way to declare intent.

This reframes the picker from capability-filter to intent-declaration: always show every provider, each labeled with an honest readiness state, and source that label from the same resolver the runtime uses so the two can't drift again.

Changes

  • resolve.rs — extract a shared config_api_key helper and add a non-consuming can_resolve_api_key probe that mirrors resolve_api_key's config→env chain. resolve_api_key's observable behavior is unchanged.
  • providers/config.rs — add ProviderReadiness { Ready, NeedsSetup, NotInstalled } + provider_readiness(); remove the is_provider_available gate and the env-only api_provider_has_credentials sniffer. CLI providers → PATH check; API providers → cred probe; codex → the same load_codex_creds loader the runtime calls.
  • cli/config.rs + main.rsrun_init now offers every provider with a readiness label across all three paths (--provider, non-TTY, interactive). Selecting any provider — even non-ready — writes the config (invoking the command is the intent) and prints next-step guidance. Threads ResolvedConfig in from main.rs.
  • docs/providers.md — documents the three readiness states.

Readiness states

Label Meaning
ready CLI binary on PATH, or API credentials resolve
needs setup API provider you can pick now; config is written, you add the key after
not installed CLI provider whose binary isn't on PATH yet

Known nuance (documented, not a bug)

At fresh init there's no config file yet (init refuses to overwrite an existing one), so Anthropic readiness reflects the env var only. The config-file-key path matters on surfaces that run against an existing config (re-init, future doctor, runtime); unifying on the resolver makes those correct and prevents the drift that caused the original issue.

Testing

  • 226 unit + 41 smoke tests pass; cargo fmt --check and cargo clippy --all-targets -- -D warnings clean.
  • New: can_resolve_api_key parity tests (probe agrees with resolve_api_key), provider_readiness mapping, and the readiness_hint/next_step_hint helpers.
  • Per-task adversarial reviews + a final whole-branch review (which concretely verified the anti-drift invariant) returned no Critical/Important findings.

Follow-up (out of scope)

doctor/checks.rs still references load_codex_creds independently — a candidate to unify onto provider_readiness later. The spec already scoped doctor integration as a follow-up.

🤖 Spec + plan brainstormed, built via subagent-driven TDD, and reviewed before this PR.

@dbtlr dbtlr merged commit 3fec3c0 into main Jun 24, 2026
12 checks passed
@dbtlr dbtlr deleted the feat/provider-readiness-config-init branch June 24, 2026 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant