20 KiB
Gap Card — S21 · Marketplace / Extend
Execution model: in-place incremental refactor of
apps/web+ targeted backend extensions. Mockups directional only (PRD §24). PRD acceptance criteria win over pixels. Every claim grounded in real files (paths + lines below).
1. Screen & purpose
Screen 21 — Marketplace / Extend Waggle (PRD §12.13, lines 648-662; blueprint catalog row 21, _blueprint_extracted.txt:432-439).
The central, power-user extension surface. PRD §10.4 names the Extend layer as Connectors, MCPs, Models, External tools, Marketplace — S21 is the Marketplace node of that layer: a single place to discover, install, update, risk-approve, and audit extensions of six kinds (Skills, Agents, Connectors, MCPs, Models, Templates) without "hunting through settings" (PRD §12.13 acceptance criterion). It is the funnel for the PRO upgrade trigger (skills + connectors + marketplace are gated to PRO; 05g-subsystem-skills-marketplace-wiki.md:3).
This card scopes the Marketplace browse/install/audit surface specifically. The sibling Extend surfaces — Connector Hub (S? / §12.7), MCP Hub (§12.8), Skills Hub (§12.6) — are separate screens that this one cross-links to; their per-domain CRUD lives in their own cards. S21 is the unified catalog + governance view across all extension types.
2. Required states (PRD / Blueprint)
Functional requirements (PRD §12.13):
- Categories: Skills, Agents, Connectors, MCPs, Models, Templates (6 facets).
- Search / filter / sort by category, trust, popularity, source, risk.
- Show per-item lifecycle: installed, update available, risk approval (required), install failed.
- Install actions write to install audit.
- Support workspace / team scoping of installs.
Extension lifecycle states (PRD §14.7, lines 906-914):
Available · Installed · Update available · Installing · Failed install · Risk approval required · Disabled/revoked.
Acceptance criterion (PRD §12.13): "Power users can extend Waggle without hunting through settings." Cross-cuts to §12.8 MCP acceptance ("powerful but always visible, scoped, auditable, and reversible") and the install-audit governance theme (_blueprint_extracted.txt:43-45,95: install audit is the "best basis for Extend governance").
Journeys touching S21: J8 install connector, J9 install MCP (audit recorded), J25 marketplace update → review changelog/risk (_blueprint_extracted.txt:203,206,252).
Mockup (directional): screens_18_21_builders_and_marketplace.png shows S21 as a card-grid catalog with a left category rail and per-card install affordances + trust badges — consistent with the spec; not a pixel target.
3. Current state in repo
Disposition: rework (the existing surfaces are reusable substrate but neither satisfies §12.13 — the catalog is hardwired to 3 of 6 categories and there is no unified Extend view with trust/risk/popularity/scope filters).
Marketplace is doubly represented today (frontend.md §f flags this as an IA cleanup point):
-
apps/web/src/components/os/apps/MarketplaceApp.tsx(258 lines, fully read) — standalone browser. Two tabs ('search' | 'installed',:26). Callsadapter.searchMarketplace/getMarketplaceInstalled/installMarketplacePackage/uninstallMarketplacePackage. Renders a flat package list with ascanBadge(passed/failed Shield/AlertTriangle,:141-145),installedcheck, type/category/source chips (:223-227), and 403→waggle:tier-insufficientUpgradeModal routing (:108-117). Registered inDesktop.tsxappConfigmarketplace(Desktop.tsx:93) +renderAppContentcase (:347), but NO dock entry points at it —dock-tiers.ts:67comment: "Marketplace already a tab inside Skills & Apps — no separate dock entry". SoMarketplaceAppis currently reachable only viawaggle:open-appevents, effectively orphaned. -
apps/web/src/components/os/apps/CapabilitiesApp.tsx(478 lines, fully read) — "Skills & Apps", the live Extend surface (dock keyskills→ appIdcapabilities,dock-tiers.ts:64). 5 tabs:installed | starter | marketplace | tools | audit(:80,358). Themarketplacetab listsSkillPacks viagetMarketplacePacks; theaudittab (AuditTab,:15-58) readsGET /api/audit/installsand renders name/source/outcome/timestamp rows. It has a pack-detail drawer (PackDetail,:249-334) with trust label + bundled-skills + install. This is pack-oriented (curated bundles), not the faceted package catalog of §12.13.
Backend already present (more than the inventory claimed):
- Full marketplace route family:
packages/server/src/local/routes/marketplace.ts—search(FTS5 + faceted,:56),packs,packs/:slug,enterprise-packs(ENTERPRISE),install(PRO + SecurityGate,:180),uninstall(:377),installed(:396),security-check,sourcesGET/POST/DELETE (:446,457,533),categories(:567→PACKAGE_CATEGORIES),sync,security-status,publish(PRO,:685). Sort facet supported via?sort=(:72). - Install-audit READ route EXISTS —
GET /api/audit/installsatpackages/server/src/local/routes/skills.ts:685-703(returns normalized{ entries: [{ capabilityName, capabilityType, source, riskLevel, trustSource, approvalClass, action, initiator, detail }] }). This corrects substrate-types.md §d gap #1, which claimed "No HTTP endpoint surfaces the audit trail." The write path is live too (marketplace.ts:224-319records every SecurityGate verdict;skills.ts:212,315,475).adapter.getAuditInstallsalready wires it (frontend.md, adapterMisc). - Install-audit store:
packages/core/src/install-audit.ts—AuditCapabilityType = native|skill|plugin|mcp|connector|marketplace(:22), full enums for action/trust/approval/risk; read APIgetRecent/getByCapability/getByAction/getAll.
Critical limitation (grounded): the marketplace catalog only supports 3 install kinds — InstallationType = 'skill' | 'plugin' | 'mcp' (packages/marketplace/src/types.ts:185), confirmed by 05g-subsystem-skills-marketplace-wiki.md:11 ("three installable package kinds — skill, plugin, mcp"). PRD §12.13 demands six categories incl. Agents, Connectors, Models, Templates, which have no catalog representation today (connectors are a separate /api/connectors registry with only connect/disconnect; templates are /api/workspace-templates; agents are personas/groups; models are /api/litellm/models + providers). So S21's "one catalog, six categories" is the central rework: a federated catalog read over the existing marketplace catalog + connector registry + template store + persona/agent catalog + model list, NOT a new package table.
4. Frontend work
Strategy: Consolidate the two marketplace surfaces into ONE Extend/Marketplace screen, retire the orphaned standalone, and give the new screen a federated faceted catalog. Keep CapabilitiesApp's Skills-pack flow as the Skills facet; promote a real dock entry.
Components to create:
apps/web/src/components/os/apps/MarketplaceApp.tsx— rework in place (reuse the file/appId so Desktop wiring + tests survive). Expand from 2 tabs to the §12.13 model: a left category rail (Skills / Agents / Connectors / MCPs / Models / Templates / All) + a top filter bar (trust, popularity, source, risk dropdowns + search) + a catalog grid. Reuse the existingscanBadge, 403→UpgradeModal routing (:108-117), and install/uninstall handlers verbatim.apps/web/src/components/os/apps/extend/ExtensionCard.tsx(new) — one card type rendering the §14.7 lifecycle badge (Available/Installed/Update available/Installing/Failed/Risk-approval/Disabled), trust chip, risk chip, source, popularity. Props:{ ext: Extension; onInstall; onUpdate; onRevoke; onOpenDetail }.apps/web/src/components/os/apps/extend/ExtensionDetail.tsx(new, or generalizeCapabilitiesApp'sPackDetail:249-334) — detail drawer with permissions/scope, changelog (for "update available", J25), risk approval CTA, install-audit trail for this item (viagetAuditInstallsfiltered client-side, or a new?capability=query — see §5).apps/web/src/components/os/apps/extend/InstallAuditPanel.tsx(new, or liftCapabilitiesApp'sAuditTab:15-58) — shared Extend governance trail; reused by S21 + Connector/MCP hubs.apps/web/src/lib/extension-catalog.ts(new pure module + co-located.test.ts) — client-side federation/normalization: merge marketplace packages (searchMarketplace), connectors (getConnectors), templates (getWorkspaceTemplates), personas/groups (getPersonas/getAgentGroups), models (getModels/getProviders) into oneExtension[]with a unified{ type: ExtensionType, trust, risk, installed, updateAvailable, source, popularity }shape; derive lifecycle state. Keeps the fat federation logic out of the component (file-org rule: many small files).
Reuse targets: MarketplaceApp install/uninstall + 403 handler; CapabilitiesApp PackCard/PackDetail/AuditTab + lib/skill-pack-display.ts (describeTrust, summariseSkills) + lib/dedupe-packs.ts; components/ui/* (card/badge/tabs/input/select/tooltip); HintTooltip.
Adapter methods/hooks: existing — searchMarketplace, getMarketplacePacks, getMarketplaceInstalled, installMarketplacePackage, uninstallMarketplacePackage, getAuditInstalls, getConnectors, getWorkspaceTemplates, getPersonas, getModels, getProviders (all in lib/adapter.ts, per frontend.md §c). New adapter methods to add for the §16.9 gaps: getMcps, installMcp, testMcp, revokeMcp, syncConnector, revokeConnector (see §5). New hook hooks/useExtensions.ts wrapping extension-catalog.ts (catalog + filters + install/update/revoke actions + react-query caching).
IA cleanup (frontend.md §f): decide one home for marketplace. Recommended: keep MarketplaceApp as the dedicated S21 Extend surface, add a real dock entry under the extend zone-parent (dock-tiers.ts:62-71), and have CapabilitiesApp's marketplace tab deep-link into it (or drop that tab) to remove the double representation.
5. Backend work (PRD §16.9 endpoint-by-endpoint)
| PRD §16.9 endpoint | Status | EXTEND vs NET-NEW + substrate / .mind |
|---|---|---|
GET /api/connectors |
EXISTS | connectors.ts:6. No change. |
POST /api/connectors/:id/connect |
EXISTS | connectors.ts:55. No change. |
POST /api/connectors/:id/sync |
MISSING | NET-NEW thin action in connectors.ts (re-init/re-fetch from connected service). Touches connector credential resolution (vault) + connector definition; record an audit entry (auditStore.record, type connector). No .mind migration. |
POST /api/connectors/:id/revoke |
PARTIAL | EXTEND — alias to existing POST /api/connectors/:id/disconnect (connectors.ts:107, removes vault creds + sub-keys). Same intent, add /revoke route delegating to disconnect + write a revoked audit entry. |
GET /api/mcps |
PARTIAL | EXTEND/NET-NEW — no /api/mcps. MCP catalog lives in @waggle/shared mcp-catalog.ts; installed MCPs surface inside GET /api/capabilities/status (mcpServers[]) and the marketplace catalog (waggle_install_type:'mcp', marketplace/src/mcp-registry.ts). Add a dedicated GET /api/mcps route that joins catalog + installed-state + .mcp.json. Reads existing substrate; no migration. |
POST /api/mcps/install |
PARTIAL | EXTEND — route through the existing marketplace installer (POST /api/marketplace/install, which already handles installType:'mcp' → writes .mcp.json, installer.ts:580). Add an MCP-specific endpoint that resolves an MCP id → marketplace package → install, OR keep marketplace install as the single path and have the FE call it. Audit already recorded. |
POST /api/mcps/:id/test |
MISSING | NET-NEW — no MCP health/test route. Closest analog is GET /api/connectors/:id/health (connectors.ts:16). Add an MCP test route (spawn/handshake the MCP server, report ok/error). No .mind. |
POST /api/mcps/:id/revoke |
MISSING | NET-NEW — no MCP revoke-by-id. Closest: DELETE /api/plugins/:name (skills.ts). Add an MCP revoke route (remove from .mcp.json + record revoked audit). |
GET /api/marketplace |
PARTIAL | EXTEND — bare path = alias of GET /api/marketplace/search with default params (marketplace.ts:56). Add alias or accept both. |
POST /api/marketplace/install |
EXISTS | marketplace.ts:180 (PRO + SecurityGate). No change. |
Plus implied additions for §12.13 (not in §16.9's list but required by FRs):
- Six-category catalog. The §12.13 categories (Agents/Models/Templates) have no marketplace representation (
InstallationTypeisskill|plugin|mcponly,types.ts:185). Two options: (a) widenInstallationType+ catalog schema to addagent|model|template(a marketplace-DB change inpackages/marketplace, NOT a.mindmigration —marketplace.dbis a separate SQLite store) and seed registries; or (b) federate at read time (preferred for incremental scope) — the FEextension-catalog.tsmerges marketplace (skill/plugin/mcp) +/api/connectors+/api/workspace-templates+/api/personas+/api/agent-groups+/api/litellm/models. Option (b) needs no backend change beyond §16.9; option (a) is a later phase if a true unified catalog with publish/install for all 6 kinds is wanted. - Install-audit read for Extend governance. EXISTS —
GET /api/audit/installs(skills.ts:685). (Substrate inventory §d#1 said missing; it is present.) Optional EXTEND: add a?capability=/?type=filter param so the detail drawer can show per-item history without client-side filtering (currently only?limit=). The store already hasgetByCapability()(install-audit.ts:125) — just expose it. - Workspace/team scoping of installs (§12.13). No per-workspace install scoping exists today (installs are global to
~/.waggle/). This is net-new product surface; recommend deferring to Phase 4 polish (PRD §22 risk register flags "marketplace scope creep" —PRD:1435— "Start with catalog + install audit, postpone billing/public marketplace").
.mind migration flag: none required for S21. The audit table (install_audit) already exists in both DDL sites (install-audit.ts:54 + schema.ts:119). Latent bug to flag (substrate-types §d#2): AuditRiskLevel TS includes 'critical' (install-audit.ts:16) but both DDL CHECKs only allow ('low','medium','high') (install-audit.ts:65, schema.ts:130) — a record({riskLevel:'critical'}) throws. The marketplace route sidesteps it (maps CRITICAL→high+blocked, marketplace.ts:228). If S21 surfaces a true "critical risk approval" state that writes critical, this CHECK must be widened first (idempotent ADD/relax via the migration runner's ADD-COLUMN pattern, mind/db.ts:116).
6. Shared types needed (PRD §15 vs lib/types.ts)
ExtensionType(PRD §15.2, line 953:'skill' | 'connector' | 'mcp' | 'model' | 'template' | 'external_tool') — MISSING fromapps/web/src/lib/types.ts(substrate-types §e). Add. Note PRD union hasexternal_toolbut §12.13 categories say "Agents" not "external_tool" — reconcile: §12.13 needs an'agent'category; PRD §15.2ExtensionTypelacksagentand addsexternal_tool. Flag as open question; likely the union should beskill|agent|connector|mcp|model|template(+ optionalexternal_tool).Extensioninterface (new) —{ id, name, description, type: ExtensionType, trust: AuditTrustSource-ish, risk: AuditRiskLevel, source, popularity?, version?, installed, updateAvailable, lifecycle: 'available'|'installed'|'update_available'|'installing'|'failed'|'risk_approval'|'disabled', scope?: Scope }. No PRD §15 interface spells this out; derive from §12.13 + §14.7.Scope(PRD §15.2:'personal'|'workspace'|'team'|'organization') — MISSING, needed for install scoping; add (shared with other Extend/Memory cards).- Existing FE
MarketplacePackage(local interface inMarketplaceApp.tsx:8-18) andSkillPack(types.ts) are narrower thanExtension;extension-catalog.tsnormalizes both intoExtension. - Reuse the canonical audit enums (
AuditTrustSource,AuditRiskLevel,AuditCapabilityTypefrompackages/core/src/install-audit.ts:16-22) rather than re-declaring trust/risk literals in the FE — export them or mirror minimally.
7. Dependencies (screens / phases first)
- PRD phasing: Extend layer = Phase 4 / Sprint 7 (
PRD:241-245,1353-1357). Comes after Work (Home/Workspace), Intelligence (Agents/Skills), so S21 should land in that phase. - Depends on / cross-links:
- Connector Hub (§12.7) and MCP Hub (§12.8) screens — S21 federates their catalogs and shares the
InstallAuditPanel; their/sync//revoke//testbackend routes (§5) are shared deliverables. - Skills Hub (§12.6) — S21's Skills facet reuses
CapabilitiesApp's pack flow. - Agent Center (§12.9), Models (Settings→Models), Templates (workspace-templates) — needed as catalog sources for the 6-category federation.
- Dock IA refactor (
dock-tiers.tsExtend zone) — S21 needs a real dock entry (currently none). - UpgradeModal / tier gating (
waggle:tier-insufficientevent) — already wired; reuse.
- Connector Hub (§12.7) and MCP Hub (§12.8) screens — S21 federates their catalogs and shares the
- Blocks: nothing downstream; it is a leaf surface.
8. Effort
L. The frontend rework is moderate (consolidate 2 surfaces → 1 faceted catalog + extract shared ExtensionCard/InstallAuditPanel + new extension-catalog.ts federation). What pushes it to L: the 6-category federation spans five different backend domains (marketplace, connectors, templates, personas/agents, models) each with a different shape, plus 6 net-new/extend §16.9 routes (connector sync/revoke, mcps list/install/test/revoke) and the FE/BE type reconciliation. Not XL because no .mind migration, no new data store (federate-at-read), audit read route already exists, and install/uninstall + tier-gating + audit-trail plumbing are all already live.
9. Open questions
ExtensionTypereconciliation. PRD §12.13 categories = Skills/Agents/Connectors/MCPs/Models/Templates (6, incl. Agents). PRD §15.2ExtensionType= skill/connector/mcp/model/template/external_tool (6, incl. external_tool, no agent). Which is canonical — addagent, keepexternal_tool, or both (7)?- Federate-at-read vs unified catalog table. Ship S21 by federating existing domains client-side (no marketplace-DB change, fast), or invest in widening
InstallationType+marketplace.dbto natively catalog all 6 kinds (enables publish/install/version-tracking parity for agents/models/templates)? Recommend federate-first; revisit per §22 "postpone public marketplace". - Install scoping (§12.13 "workspace/team scoping"). Installs are global to
~/.waggle/today. Is per-workspace/per-team install scoping in scope for Phase 4, or deferred (it implies new persisted scope state on every installed capability)? - "Update available" + changelog (J25). No version/changelog tracking exists for installed packages beyond a
versioncolumn on the marketplace package. Where does the "update available" signal come from — catalog sync diffing installed version vs latest, or a new field? - MCP test semantics.
POST /api/mcps/:id/test— does "test" mean spawn-and-handshake the MCP server (live), or static manifest/permission validation? Affects whether it can run without launching a process. - Should
MarketplaceApporCapabilitiesAppbe the canonical S21 home (IA double-representation, frontend.md §f)? RecommendMarketplaceAppreworked + real dock entry;CapabilitiesAppkeeps Skills/Tools/Audit and drops itsmarketplacetab.