# v2.3 Provider lifecycle — tasks Implement in phase order from [`design.md`](./design.md). Do not commit unless Sam asks. > **✅ SHIPPED across `v2.5.4`–`v2.5.13` (reconciled 2026-05-31).** All 6 phases done; the 3 Optional items (O.1–O.3) deferred (tracked in `docs/DEFERRED-WORK.md`). Verified in tree: `provider-config.ts`, `provider-config-registry.ts`, `command-availability.ts`, `provider-diagnostic.ts`, `acp-provider-catalog.ts`, `components/coder/AddProviderModal.tsx`, Settings→Providers tab. ## Phase 1 — Config + registry — ✅ `v2.5.4-provider-lifecycle-phase1` - [x] 1.1 Add `CODER_PROVIDERS_PATH` to `apps/coder/src/config.ts` (default `/data/coder-providers.json`) - [x] 1.2 Add `data/coder-providers.json` example + wire in `apps/coder/.env.host` - [x] 1.3 Implement `provider-config.ts` (Zod schema + load/merge/save) - [x] 1.4 Implement `provider-config-registry.ts` (`buildResolvedRegistry`, module singleton + reload) - [x] 1.5 Unit tests: built-in override, custom ACP add, enabled false, invalid entry skipped - [x] 1.6 Update `agent-probe.ts` to iterate resolved registry (include custom ids, respect enabled) ## Phase 2 — Snapshot lifecycle — ✅ `v2.5.5-provider-lifecycle-phase2` - [x] 2.1 Extend `ProviderSnapshotEntry` / status union in coder + web types (`loading`, `unavailable`, `enabled`) - [x] 2.2 Add `command-availability.ts` (`isCommandAvailable`) - [x] 2.3 Rewrite `buildProviderEntry`: never return null; handle disabled/uninstalled/loading - [x] 2.4 Implement tier-2 skip using `available_agents.last_probed_at` + `PROVIDER_PROBE_TTL_MS` - [x] 2.5 Return `loading` entries synchronously on cache miss; complete via inflight promise *(client-side poll deferred to Phase 5; cache miss returns `loading` then settles)* - [x] 2.6 Extend `provider-snapshot.test.ts` for disabled, uninstalled, fresh DB skip, force refresh - [x] 2.7 Verify warm cache: second snapshot call does not invoke `probeAcpProvider` (mock assert) ## Phase 3 — Generic dispatch — ✅ `v2.5.6-provider-lifecycle-phase3` - [x] 3.1 Add `resolveLaunchSpec()` to `acp-spawn.ts` - [x] 3.2 Wire `acp-dispatch.ts` to use launch spec + env merge - [x] 3.3 Wire `dispatcher.ts` to load resolved def by agent name - [x] 3.4 Unit test: custom command argv reaches spawn (built-in dispatch byte-identical) - [x] 3.5 Smoke: task dispatch for one custom catalog provider (if installed on host) ## Phase 4 — HTTP API — ✅ `v2.5.12-provider-lifecycle-phase4` - [x] 4.1 `GET /api/providers/config` - [x] 4.2 `PATCH /api/providers/config` (merge + write file + reload registry + clear snapshot cache) - [x] 4.3 `POST /api/providers/refresh` optional body `{ providers?: string[] }` - [x] 4.4 `GET /api/providers/:id/diagnostic` *(ships as JSON `{ diagnostic: string }`, not plaintext — see design §8 delta)* - [x] 4.5 Extend `apps/web/src/api/client.ts` coder namespace - [x] 4.6 Confirm BooChat proxy forwards new routes (blanket `/api/coder/*` forward) ## Phase 5 — Web UI — ✅ `v2.5.13-provider-lifecycle-phase5` - [x] 5.1 Create `apps/web/src/data/acp-provider-catalog.ts` (5–10 curated entries) - [x] 5.2 `AddProviderModal.tsx` — search, install → patch + refresh subset *(at `components/coder/`)* - [x] 5.3 Provider management UI *(shipped as a **Settings → Providers tab** in `SettingsPane.tsx`, not a standalone `ProviderSettingsDrawer` — design §7.1 "or section under existing settings")* - [x] 5.4 Entry point from CoderPane / AgentComposerBar (gear or settings link) - [x] 5.5 Filter `AgentComposerBar` selectable providers (`enabled && ready|loading`) - [x] 5.6 Loading state while snapshot entries `loading` - [x] 5.7 `npx tsc -p apps/web/tsconfig.app.json --noEmit` ## Phase 6 — Docs, deploy, closeout — ✅ `v2.5.13` / docs `v2.5.14` - [x] 6.1 `BOOCODER.md` — config file, refresh contract, enable/disable - [x] 6.2 Update `docs/DEFERRED-WORK.md` — tier-2 cold-probe item marked addressed - [x] 6.3 `CHANGELOG.md` entries (per-phase tags, not a single tag) - [x] 6.4 `pnpm -C apps/coder test && pnpm -C apps/coder build` - [x] 6.5 `sudo systemctl restart boocoder` - [x] 6.6 Smoke via Tailscale (snapshot / disable goose / refresh / add-catalog) ## Optional — ⬜ DEFERRED (tracked in `docs/DEFERRED-WORK.md`) - [ ] O.1 WS frame `provider_snapshot_updated` (skip polling) — **deferred**; `AgentComposerBar:219` polls instead (comment notes the absence) - [ ] O.2 `available_agents.enabled` column mirror — **deferred**; `enabled` read from config memory only (no DB column) - [ ] O.3 Diagnostic sheet UI (row click → modal) — **deferred**; the plaintext/JSON diagnostic API + Settings surface shipped, the modal polish did not ## Explicitly out of scope - Port Paseo `ACPAgentClient` / per-provider SDK clients (see design §12) - Full 30+ ACP catalog - MCP `list_providers` tools - Voice providers