# v2.3 Provider lifecycle — tasks Implement in phase order from [`design.md`](./design.md). Do not commit unless Sam asks. ## Phase 1 — Config + registry - [ ] 1.1 Add `CODER_PROVIDERS_PATH` to `apps/coder/src/config.ts` (default `/data/coder-providers.json`) - [ ] 1.2 Add `data/coder-providers.json` example + wire in `apps/coder/.env.host` - [ ] 1.3 Implement `provider-config.ts` (Zod schema + load/merge/save) - [ ] 1.4 Implement `provider-config-registry.ts` (`buildResolvedRegistry`, module singleton + reload) - [ ] 1.5 Unit tests: built-in override, custom ACP add, enabled false, invalid entry skipped - [ ] 1.6 Update `agent-probe.ts` to iterate resolved registry (include custom ids, respect enabled) ## Phase 2 — Snapshot lifecycle - [ ] 2.1 Extend `ProviderSnapshotEntry` / status union in coder + web types (`loading`, `unavailable`, `enabled`) - [ ] 2.2 Add `command-availability.ts` (`isCommandAvailable`) - [ ] 2.3 Rewrite `buildProviderEntry`: never return null; handle disabled/uninstalled/loading - [ ] 2.4 Implement tier-2 skip using `available_agents.last_probed_at` + `PROVIDER_PROBE_TTL_MS` - [ ] 2.5 Return `loading` entries synchronously on cache miss; complete via inflight promise - [ ] 2.6 Extend `provider-snapshot.test.ts` for disabled, uninstalled, fresh DB skip, force refresh - [ ] 2.7 Verify warm cache: second snapshot call does not invoke `probeAcpProvider` (mock assert) ## Phase 3 — Generic dispatch - [ ] 3.1 Add `resolveLaunchSpec()` to `acp-spawn.ts` - [ ] 3.2 Wire `acp-dispatch.ts` to use launch spec + env merge - [ ] 3.3 Wire `dispatcher.ts` to load resolved def by agent name - [ ] 3.4 Unit test: custom command argv reaches spawn - [ ] 3.5 Smoke: task dispatch for one custom catalog provider (if installed on host) ## Phase 4 — HTTP API - [ ] 4.1 `GET /api/providers/config` - [ ] 4.2 `PATCH /api/providers/config` (merge + write file + reload registry + clear snapshot cache) - [ ] 4.3 `POST /api/providers/refresh` optional body `{ providers?: string[] }` - [ ] 4.4 `GET /api/providers/:id/diagnostic` (plaintext report) - [ ] 4.5 Extend `apps/web/src/api/client.ts` coder namespace - [ ] 4.6 Confirm BooChat proxy forwards new routes (or document direct :9502) ## Phase 5 — Web UI - [ ] 5.1 Create `apps/web/src/data/acp-provider-catalog.ts` (5–10 curated entries) - [ ] 5.2 `AddProviderModal.tsx` — search, install → patch + refresh subset - [ ] 5.3 `ProviderSettingsDrawer.tsx` — list, status, toggle, refresh, link to add - [ ] 5.4 Entry point from CoderPane / AgentComposerBar (gear or settings link) - [ ] 5.5 Filter `AgentComposerBar` selectable providers (`enabled && ready`) - [ ] 5.6 Loading state while snapshot entries `loading` (poll or one-shot refetch) - [ ] 5.7 `npx tsc -p apps/web/tsconfig.app.json --noEmit` ## Phase 6 — Docs, deploy, closeout - [ ] 6.1 `BOOCODER.md` — config file, refresh contract, enable/disable - [ ] 6.2 Update `docs/DEFERRED-WORK.md` — mark tier-2 cold-probe item addressed - [ ] 6.3 `CHANGELOG.md` entry when tagged - [ ] 6.4 `pnpm -C apps/coder test && pnpm -C apps/coder build` - [ ] 6.5 `sudo systemctl restart boocoder` - [ ] 6.6 Smoke via Tailscale: - `curl http://100.114.205.53:9502/api/providers/snapshot` - PATCH disable goose → absent from composer, visible in settings - POST refresh → models repopulate - Add catalog entry → appears after refresh ## Optional (same batch if time) - [ ] O.1 WS frame `provider_snapshot_updated` (skip polling) - [ ] O.2 `available_agents.enabled` column mirror - [ ] O.3 Diagnostic sheet UI (row click → modal) ## Explicitly out of scope - Port Paseo `ACPAgentClient` / per-provider SDK clients (see design §12) - Full 30+ ACP catalog - MCP `list_providers` tools - Voice providers