9.1 KiB
Warm-Hive PR4 — Marketplace + shared install store ("sync") — Build Plan
Source design:
docs/design_handoff_waggle_app/SCREENS.md §09. Recon:docs/redesign-warm-hive/pr4-recon/(5 docs). Branch:feature/warm-hive-pr4(off main @ 876807ca). Status: plan — decisions §3 need founder ratification before feature code.
1. The design contract (screen 09)
Skills + connectors + MCP as one shelf, agent-searchable. Two variations, one store:
- A — Browse & ask: centered agent-search bar → suggestion box (connector + skill + tool, each with a "why" + install) · "N in this workspace" count bar · All/Skills/Connectors/MCP filter · card grid (kind badge, name, desc, install count, Add).
- B — Inline in chat: the same picker mid-conversation — offer a missing connector with a vault-aware approval ("token → your vault") → connected follow-up.
- CRITICAL — "sync": one store powers grid + agent-pick + inline. Type-aware one-click: skill Add→Adding…→Added (instant) · connector Connect→Signing in…→Connected (~1.1s, token→vault) · MCP Enable→Enabling…→Enabled. Each fires a toast + updates the count bar. Installing in any view reflects in all.
2. Current state (grounded in recon — the engine exists; the gap is surface + a store)
| Layer | Reality today | File anchors |
|---|---|---|
| Match engine | searchCapabilities(need) → ranked candidates across native tools / skills / marketplace, each with matchReason ("why") + installAction. Reachable ONLY as the acquire_capability chat tool, which returns markdown and discards the structured proposal. |
packages/agent/src/capability-acquisition.ts:179; tool skill-tools.ts:406 |
| Install backends (3, separate) | skills = FS markdown reloaded into agentState.skills; connectors = vault credential connector:<id>; MCP = .mcp.json + live McpRuntime (PRO-gated, SecurityGate-scanned). No unified installed-set. |
routes/{skills,connectors,mcps}.ts; packages/marketplace/src/{db,installer}.ts |
| Install verbs | skill/pkg POST /api/marketplace/install (PRO) · MCP POST /api/mcps/install (PRO) · connector POST /api/connectors/:id/connect (token→vault, ungated). All write the append-only install_audit (no workspace_id). |
routes/marketplace.ts:181, mcps.ts:189, connectors.ts:96 |
| FE grid | Phase-4B "Extend" surface: 6-facet rail, keyword search, vertical list of ExtensionCard, federates-at-read into local useState (discarded on unmount). Only marketplace skill/MCP pkgs install in-place; connectors/MCP = "Open in Hub" deep-links. Legacy tokens. |
MarketplaceApp.tsx (418 LOC), extend/ExtensionCard.tsx, lib/extension-catalog.ts |
| Variation B precursor | CapabilityRequestCard (inline chat) — skill/marketplace only, own private phase state, no connector/vault approval, no shared state with grid. Approval channel is boolean-only (can't carry a token). |
chat-blocks/CapabilityRequestCard.tsx, capability-request-parser.ts, confirmation.ts |
Net: the matching brain + the 3 install paths are done and tested. PR4 is (a) a shared FE install store the three surfaces subscribe to, (b) Variation A UI (agent-search bar + suggestion box + count bar + grid with type-aware verbs/micro-states), (c) one new route exposing the existing engine, (d) Variation B completion (connector/MCP + vault approval).
3. Decisions — RATIFIED (founder, 2026-06-16): D1 FE-derived global count · D2 collapse to 4 shelves · D3 in-place (OAuth→Hub fallback) · D4 sync = grid+pick+inline. D5–D7 defaults stand.
| # | Decision | Recommended (v1) | Why / cost of the alternative |
|---|---|---|---|
| D1 | "N in this workspace" count bar | FE-derived global count from existing per-type list endpoints | Real per-workspace tracking needs a new workspace_id migration across 3 backends + the OSS-excluded install_audit — large, and the substrate isn't workspace-partitioned. Honest label: "installed" not "in this workspace" if global. |
| D2 | Facets | Collapse to the design's 4: All / Skills / Connectors / MCP | Matches screen 09 ("one simple shelf"). Agents/Models/Templates keep their dedicated hubs (already deep-links). Keeping the 6-domain superset diverges from the design. |
| D3 | Connector/MCP in the grid | In-place Connect/Enable reusing the real vault/runtime + SecurityGate; OAuth-only connectors fall back to the Connector Hub | Design clearly wants in-place. Must NOT bypass security/OAuth gating. Token-paste connectors + MCP Enable work inline; OAuth-only can't finish inline. |
| D4 | Sync scope | Grid + agent-pick + inline-chat via an FE store; re-hydrate on nav so external Hub installs reconcile | Refactoring ConnectorsApp/MCPHubApp/skills-center to also push to the store is a much bigger blast radius — defer. |
| D5 (default) | Suggestion "why" | engine's deterministic matchReason (free, honest, no model call) |
LLM-generated why is prettier but adds a model call + latency. |
| D6 (default) | Card install count | omit the social downloads count (local-single-user ≈ 0; honest-stats ethos) — show only a real Installed badge |
— |
| D7 (default) | PRO-gated items | show as installable with an upsell on click (current behavior; moat: skills/MCP are the upgrade trigger) | — |
4. Architecture
- Shared store (the spine): new
apps/web/src/providers/InstallProvider.tsx+useInstallStore()— aninstalledMap +installingSet keyed byextension-catalognamespaced ids; a type-aware install dispatcher (skill→installPack/skill; connector→connectConnector(vault); mcp→installMcp; pkg→installMarketplacePackage); a count selector; optimistic flip + reconcile (roll back on 403/SecurityGate, route to Upgrade/Approval). Hydrate fromGET /api/skills,/connectors,/mcps,/marketplace/installed(no new read route for v1). - One new server route:
POST /api/marketplace/agent-search{need}→ wraps the existingsearchCapabilities()(lift the dep assembly fromlocal/index.ts:620), returns the structured proposal + apickOnePerKind()grouping (connector+skill+tool). MirrorsGET /api/skills/suggestions. tsx-only → musttsc -p packages/server. - Reuse:
extension-catalog.tsnormalizers (flipinstallable:truefor connector/mcp once the store can install them);CapabilityRequestCardfor inline; warm componentscomponents/os/warm/*+ warm tokens.
5. Phased plan (TDD; commit per phase; FE tsc -p apps/web/tsconfig.app.json + vitest each)
- Phase A — shared install store (
InstallProvider/useInstallStore): hydrate, type-aware dispatcher, count selector, optimistic+reconcile, toasts. Unit-tested in isolation. The spine everything else binds to. - Phase B — Variation A grid:
ExtensionCardtype-aware verbs (Add/Connect/Enable) + idle→in-progress→done micro-states reading the store;MarketplaceAppsources from the store, adds the count bar + 4-shelf filter (D2) + card grid + warm tokens; in-place connector/MCP (D3). Rewrite the 11 phase4b tests to the new contract. - Phase C — agent-search:
POST /api/marketplace/agent-search(+pickOnePerKind) wrappingsearchCapabilities; the centered AskBar + suggestion box (connector/skill/tool, each "why" + install via the store) + example chips. - Phase D — Variation B inline: extend
CapabilityRequest.kindtoconnector/mcp; vault-aware approval row (token→vault; approval channel stays boolean, FE callsconnectConnectordirectly — no token on the approval channel); route installs through the shared store so chat ↔ grid ↔ count bar stay in sync; consolidateApprovalGate/InlineApprovalCard. - Phase E — review + live smoke: adversarial review workflow; live smoke (grid install reflects in count bar + inline; agent-search returns real picks; 0 console errors).
6. Key risks (from recon)
- 11 phase4b tests pin current testids + the
{type,limit:30}call shape → Phase B rewrites them (expected, not collateral). - Optimistic flips must reconcile with server truth (install can 403 / SecurityGate-block after the flip) — across grid AND inline; count bar must not show a gate-rejected item.
- Don't bypass Hub security/OAuth — in-place Connect/Enable reuse the real gated paths; OAuth-only → Hub fallback.
install_auditis OSS-excluded + append-only — never the source of truth for installed state; read per-type list endpoints.- Honest-stats / mind-isolation ethos — global count labeled honestly (D1); omit social download counts (D6).
- Server routes run via
tsx(not typechecked bynpm run build) → explicittsc -p packages/servergate on the new route.
7. Verification gates (per phase + final)
tsc -p apps/web/tsconfig.app.json 0 · tsc -p packages/server 0 (new route) · FE vitest green (incl. rewritten phase4b) · npm run lint · live smoke: install in grid → count bar + inline both reflect; agent-search returns connector+skill+tool with "why"; vault-aware inline approval; 0 console errors.