Reshape the AI Providers page into Harnesses, Services and Presets tabs with routes, nav entries and docs
- Dominant language
- JavaScript
- Stars
- 38
- Forks
- 31
- Avg merge
- 22m
- Merged PRs (30d)
- 988
Description
Part of #7561 (epic).
Blocked by #7565, #7566
## Problem / Goal
`client/src/pages/AIProviders.jsx` (1201 lines) presents "one card per record, grouped by readiness" with the connection graph hidden in an overflow drawer (`ProviderConnections.jsx`). Reshape the page around the composed model: **Harnesses**, **Services**, **Presets** tabs, each with URL-addressed selection, ⌘K/voice entries, and docs that explain the five axes.
## Context
- Routes today: `/ai`, `/ai/new`, `/ai/fleet`, `/ai/edit/:providerId`, `/ai/connections`, `/ai/connections/:connectionId`, `/ai/harnesses/:harnessId/connections[/:connectionId]` (`client/src/App.jsx:291-309`); nav entries in `server/lib/navManifest.js`; sidebar presentation in `client/src/lib/navPresentation.js`; the `portos-add-page` skill covers the entry shape and guards.
- Page sections: `ModelsTabsHeader`, `RetiredModelPinsPanel`, `LocalPersistentMindSetupCard`, `FleetHostSetup`, sample providers panel, ad-hoc run panel, four readiness `CollapsibleSection`s of `ProviderCard`, `ProviderForm` (4 tabs: Connection · Models · Generation · Environment), `RuntimeInstallModal`, `ProviderConnections`, `FleetProviderSetup`.
- Readiness sources: `GET /api/providers/readiness` (local daemons), `/runtimes` (binaries), `/status` (benched), `/model-pins`, `credentialInventory` (via services, child 2).
- Docs to touch: `docs/MODEL_TIERS.md`, `docs/STORAGE.md` (ai_connections row), `docs/README.md`, `docs/features/claude-ollama.md` (now a preset example), `docs/plans/2026-09-06-provider-connections-and-harnesses.md` (add a "superseded by" pointer to the epic).
## Proposed approach
1. **Routes.** `/ai` → redirect to `/ai/presets`; `/ai/presets`, `/ai/presets/new`, `/ai/presets/:presetId` (alias `/ai/edit/:providerId` → same editor; keep `/ai/new`); `/ai/harnesses`, `/ai/harnesses/:harnessId`; `/ai/services`, `/ai/services/new`, `/ai/services/:serviceSlug`; `/ai/fleet` unchanged. `/ai/connections*` and `/ai/harnesses/:id/connections*` redirect to the Services/Harnesses equivalents. Every new route gets a `NAV_COMMANDS` entry with voice aliases ("AI harnesses", "AI services", "AI presets") and a `NAV_PRESENTATION` row; navigation parity tests pass.
2. **Harnesses tab.** One card per `PROVIDER_HARNESSES` row: detected version / install-update actions (`RuntimeInstallModal`), enabled toggle (settings-backed, child 3), methods offered, compatible services count, subscription sign-in state (Codex account block moves here), quota card link (`providerUsage` family). `direct` shows as always-on. Below the harness cards, a **Credential bootstraps** section lists configured launch wrappers (slug, command, per-harness name map) with add/edit/remove (`/api/providers/bootstraps`, child 3) and a "Used by N presets" count; the section is collapsed and empty-state-only until one exists.
3. **Services tab.** One card per instance (from child 2): definition label, plan badge, credential state/source with the definition's `keyUrl` "get a key" link, endpoint(s), catalog summary with explicit Refresh, local-runtime readiness checklist (`ProviderReadiness` moves here, keyed by instance), enabled toggle, "Add service" drawer (definition → plan → credential/endpoint), "Presets on this service" list. `ProviderConnectionForm`/`ProviderHarnessForm`/`ProviderConnections` are retired.
4. **Presets tab.** The existing card list, grouped by harness (secondary grouping by readiness state preserved as a badge), plus a compact **compatibility matrix** (harness rows × service columns, cells = enabled/compatible/blocked with reason, click → prefilled "New preset"). Preset editor = `ProviderForm` with the Connection tab replaced by a read-only "Derived from " panel for derived presets (link to the service) and the legacy fields for legacy presets; Models tab reads the service catalog with optional narrowing; the run panel uses the shared selector.
5. **Docs.** New `docs/AI_PROVIDERS.md` (the five axes, composite ids, presets, plans, what federates: nothing), linked from `docs/README.md`; `MODEL_TIERS.md` states tiers live on presets; `STORAGE.md` row renamed to services/presets.
## Acceptance criteria
- [ ] All listed routes render, are reachable from ⌘K and voice, and old URLs redirect (`/ai/edit/:id`, `/ai/connections/:id`); `navManifest` guard tests pass.
- [ ] Harnesses tab toggles persist and immediately change what compose offers on any selector (no reload); adding a bootstrap app makes the compose flow show its select on the next open; Services tab refresh is explicit and never fires on mount.
- [ ] Compatibility matrix cells match `isCompatible` from the server (rendered from `/api/providers/catalog`, not recomputed in the browser).
- [ ] Derived preset editor hides connection-owned fields and links to the service; legacy preset editor is unchanged in capability.
- [ ] Mobile: three tabs stack, cards are single-column at 360px, no horizontal scroll.
- [ ] `docs/AI_PROVIDERS.md` exists and `docs/README.md` indexes it; the 2026-09-06 design record points at the epic.
## Out of scope
Fleet host setup redesign; Usage page; model comparison page.
Contributor guide
Research direction
Start with the blocked child issues #7565 and #7566, then read client/src/pages/AIProviders.jsx, client/src/App.jsx, server/lib/navManifest.js, and client/src/lib/navPresentation.js. Review the listed provider routes, existing page sections, and documentation files before assessing the navigation parity tests. Done means the three tabs, redirects, navigation entries, acceptance behaviors, mobile layout, and documentation updates all meet the stated criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- backend, documentation, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100