18 KiB
Gap Card — S05 Artifact Center
Execution model: in-place incremental refactor of
apps/web+ targeted backend extensions. Mockups are directional; PRD acceptance criteria win over pixels (PRD §24). Sources: PRD §12.5 + §16.6, blueprint p.32 (_blueprint_extracted.txt:306-317, 525, 547), mockupscreen_05_artifact_center.png, baseline inventories underdocs/ux-refactor/_inventory/, backend-mapsections/04-feature-map.md.
1. Screen & purpose
The Artifact Center is the outcome layer: it organizes outputs (documents, presentations, spreadsheets, dashboards, research, code, media, designs, other) as first-class relational objects — not file attachments. PRD §12.5 purpose verbatim: "Organize outcomes, not just attachments." The headline acceptance criterion (PRD line 532): searching a topic (e.g. "Germany GTM") returns all relevant outcome objects plus related memories, sessions, tasks, agents, and people — not just files.
Mockup (directional): left filter rail (type / status / workspace / tag facets), a center artifact
table (icon, title, type, workspace, status badge, updated, owner) with a top search bar + view
toggle + pagination, and a right detail panel (preview thumbnail, metadata, related items, actions).
This is a data-heavy table+detail screen, the same shape the blueprint flags as acceptable in light
variant (_blueprint_extracted.txt:484).
The defining difference from today's Files app: an artifact is an outcome with relations
(relatedMemoryIds / relatedSessionIds / relatedTaskIds / relatedAgentIds,
generatedByAgentId, status: draft|final|shared|generated), addressable by a stable id, spanning
all storage backends and all formats. Today's Files app exposes only a raw filesystem tree scoped to
one workspace + one storage tab.
2. Required states (PRD / Blueprint)
PRD §12.5 functional requirements:
- Artifact categories (=
ArtifactKind, PRD §15.2 line 950):document | presentation | spreadsheet | dashboard | research | code | media | design | other. - Topic search returns artifacts + related memories/sessions/tasks/agents/people (the §16.6
GET /api/artifacts/search-related?q=contract). - Detail panel: preview, metadata, workspace, creator, updated time, access, status, tags, related items, actions.
- Actions: open, share, duplicate, move, delete, relate to workspace/memory/session/task.
State model — PRD §14.1 global states (every major screen): Loading, Empty, Populated, Error,
Offline/local-only, Syncing, Permission denied, Partial data, Approval required.
Plus the artifact-specific states (PRD §14 line not enumerated but blueprint :312-314, 458):
Draft, Final, Shared, Generated, External-missing (source unavailable), Permission denied.
So the concrete states to build:
- Loading (skeleton table + skeleton detail).
- Empty ("no artifacts yet" — first-run / no outputs produced).
- Populated (table + facets + detail).
- Error (fetch failed).
- Offline/local-only (sidecar unreachable — mirror FilesApp offline banner pattern).
- Permission denied (team-scoped artifact the user can't view).
- Per-row status badges: Draft / Final / Shared / Generated.
- Source-unavailable (artifact row whose backing file/url is missing — show broken-link affordance).
3. Current state in repo (disposition: create-new for the screen; keep-promote the substrates)
There is NO Artifact entity, type, route, or component anywhere. Grep-confirmed:
- No
Artifacttype inapps/web/src/lib/types.ts(the onlyArtifacthit inapps/web/srciscomponents/os/apps/memory/EvolutionTab.tsx, referring to evolutionartifacts_json— unrelated). - No
artifactstable inpackages/hive-mind-core/src/mind/schema.ts. - No
/api/artifacts/*routes (grep overpackages/server/src/local/routes/*.ts: 0 matches). - Confirmed by
_inventory/substrate-types.md:259-266("NO backing entity anywhere … the single largest entity gap") and_inventory/backend-routes.md:476-484(all 6 §16.6 rows PARTIAL/MISSING).
The closest current surface is the Files app (the current-component hint), which is NOT an artifact center — disposition for it is keep-as-is, do not retrofit:
apps/web/src/components/os/apps/FilesAppTabs.tsx— P16 three-tab (Virtual/Local/Team) wrapper that remountsFilesAppperstorageType. Storage-location switcher, not an outcome browser.apps/web/src/components/os/apps/FilesApp.tsx(735 LOC) — full file-manager: tree + list/grid + preview + upload + rename/move/copy/delete + bulk ops + properties dialog + inlineVersionHistory. It is path/workspace/storage-scoped (adapter.listFiles(workspaceId, currentPath)), has no cross-workspace aggregation, no type/status/relation model, no facet filtering by outcome kind.- Sub-components
components/os/files/{FileTree,FilePreview,FileActions,FileUploadZone,SyntaxPreview, WorkspaceRail}.tsx— operate onFileEntry(lib/types.ts:42-50:name/path/type/size/mimeType/ modifiedAt/createdAt), a raw FS entry, not an outcome object.
Three existing backend substrates the new Artifact layer must aggregate over (reuse, do not duplicate):
- Workspace file registry —
GET /api/workspaces/:id/files(workspaces.ts:594-606) returnsreadFileRegistry(dataDir, id)ofFileRegistryEntry { name, type, summary, sizeBytes, ingestedAt }(routes/ingest.ts:125-130). This is an ingest log, newest-first — closest thing to a per-workspace "produced/ingested things" list, but no id, no status, no relations. - Document version registry —
GET /api/workspaces/:id/documents+/documents/:name/versions(routes/documents.ts, JSON at~/.waggle/workspaces/{id}/documents.json, shapesTrackedDocument/DocumentVersion). Gives versioning + size + createdAt keyed by name; already surfaced in FilesApp'sVersionHistory(FilesApp.tsx:27-54). No type/status/relations. - Workspace storage files —
GET /api/workspaces/:id/storage/files+/storage/read|write|delete(workspaces.ts:885+) — the actual byte store for virtual/local/team.
Verdict: the screen is create-new (ArtifactCenter is in PRD §20.3 "Create" list, line 1289).
The backend is a thin net-new aggregation/normalization layer over the three existing stores — no
new data store required (_inventory/backend-routes.md:604-607).
4. Frontend work
New top-level app (dock id artifacts). Register in Desktop.tsx appConfig + renderAppContent
switch, add AppId 'artifacts' in lib/dock-tiers.ts, and a Work-bucket dock entry (the IA maps
Artifacts to the Work layer — _inventory/frontend.md:360). Do not route — this is a windowed
single-route desktop; opening is by AppId via openApp (useWindowManager).
Components to create (keep files small, ~200-400 LOC each per repo file-org rule):
components/os/apps/ArtifactCenterApp.tsx— shell: search bar + view toggle + facet rail + table + detail panel + pagination. Owns query/filter/selection state. Mirrors the FilesApp three-pane layout idiom (rail / main / detail) so it feels native.components/os/artifacts/ArtifactTable.tsx(orArtifactRow.tsx— blueprint namesArtifactRow,_blueprint_extracted.txt:487) — list rows with icon/title/type/workspace/status badge/updated/owner.components/os/artifacts/ArtifactFacetRail.tsx— type/status/workspace/tag facet filters (left rail in mockup).components/os/artifacts/ArtifactDetailPanel.tsx— preview + metadata + related-items list + actions.components/os/artifacts/ArtifactRelatedList.tsx— renders related memories/sessions/tasks/agents; clicking a related item should raise the relevant window via the existingwaggle:open-appCustomEvent (and/oronContextRaillike FilesApp does,FilesApp.tsx:206-208).
Reuse targets (do not rebuild):
- Status/confidence badges,
Skeleton,Table, view-toggle,Pagination,HoverCard— all exist incomponents/ui/*(shadcn set,_inventory/frontend.md:337-342). - Offline banner pattern + retry — copy from
FilesApp.tsx:384-389. - File preview for an artifact's backing file — reuse
components/os/files/FilePreview.tsx. - Empty-state idiom —
FilesApp.tsx:470-477. - Detail-panel metadata layout idiom — FilesApp Properties dialog (
FilesApp.tsx:667-729). - ContextRail for "show full context of this artifact" —
overlays/ContextRail.tsxalready exists (extendContextRailTargetwith an'artifact'variant).
New hook + adapter methods:
hooks/useArtifacts.ts—{ artifacts, filters, setFilter, selected, select, search, refresh, create, patch, remove, share }; reads/writes through the adapter. Follow theuseMemoryshape (hooks/useMemory.ts).- Extend
lib/adapter.ts(the single sidecar gateway, ~1930 LOC — new §16 methods land here per_inventory/frontend.md:380) with:getArtifacts,getArtifact,createArtifact,patchArtifact,deleteArtifact,searchRelatedArtifacts,shareArtifact.
Props/state notes: ArtifactCenterApp takes { workspaces?, activeWorkspaceId?, onSelectWorkspace?, onContextRail? } (same cross-workspace pattern FilesApp uses). It is cross-workspace by default
(the whole point vs FilesApp) — workspace becomes a facet, not a hard scope.
5. Backend work (PRD §16.6)
No new data store. Every endpoint is a net-new aggregation/normalization route over the existing file registry + document versions + workspace storage. New file:
packages/server/src/local/routes/artifacts.ts, registered inlocal/index.ts. The Artifactidcan be a stable composite ofworkspaceId + source-store + name/path(or a registry-assigned id if a lightweightartifacts.jsonindex is added per workspace, mirroringdocuments.json).
| PRD §16.6 endpoint | Status | Plan (EXTEND vs NET-NEW) + substrate |
|---|---|---|
GET /api/artifacts |
PARTIAL → NET-NEW route | No /api/artifacts domain. NET-NEW GET /api/artifacts in artifacts.ts that fans out over WorkspaceManager.list() and, per workspace, normalizes (a) file registry GET /api/workspaces/:id/files (workspaces.ts:594, FileRegistryEntry), (b) document versions GET /api/workspaces/:id/documents (documents.ts), into a unified Artifact[]. Supports ?workspaceId=&type=&status=&tag=&q= facet filters. Cross-workspace = the differentiator. |
POST /api/artifacts |
PARTIAL → NET-NEW route (thin) | Closest writes that already persist bytes: POST /api/ingest (ingest.ts), POST /api/workspaces/:id/files/upload (files.ts), POST /api/workspaces/:id/documents (documents.ts), POST /api/workspaces/:id/storage/write (workspaces.ts). NET-NEW POST /api/artifacts records artifact metadata (kind/title/status/tags/relations + generatedByAgentId) in a per-workspace artifacts.json index and (optionally) writes the backing file via the storage route. |
GET /api/artifacts/:id |
MISSING → NET-NEW | Resolve composite id → normalized Artifact with relations + preview metadata. Reuse documents.ts version lookup for relatedVersions. |
PATCH /api/artifacts/:id |
MISSING → NET-NEW | Update title/status/tags/relations in the artifacts.json index (move = re-point workspaceId/storagePath; reuse files/move). |
DELETE /api/artifacts/:id |
PARTIAL → NET-NEW route | Closest: POST /api/workspaces/:id/files/delete (files.ts), DELETE /api/workspaces/:id/storage/delete (workspaces.ts). NET-NEW DELETE /api/artifacts/:id removes the index entry and (optionally) the backing file via those. |
GET /api/artifacts/search-related?q= |
MISSING → NET-NEW (the headline endpoint) | Federated search: query the normalized artifact index plus GET /api/memory/search (memory.ts), session search GET /api/workspaces/:wid/sessions/search (sessions.ts), tasks GET /api/tasks (tasks.ts), and fleet/agents (GET /api/agents/active//api/fleet), returning grouped { artifacts, memories, sessions, tasks, agents }. Internally can lean on existing FTS (memory_frames_fts, marketplace FTS5, wiki search). Delivers PRD line 532 acceptance. |
POST /api/artifacts/:id/share (blueprint :525) |
MISSING → NET-NEW | Blueprint adds a /share action not in PRD §16.6 list. Maps to the missing POST /api/share (_inventory/backend-routes.md:551) + team scope. Defer to the Team phase (see §7); gate behind TEAMS tier like /api/team/*. |
Substrate touched: workspace file registry (ingest.ts FileRegistryEntry), document versions
(documents.ts JSON), workspace storage (workspaces.ts storage routes), memory FTS
(memory_frames_fts), sessions JSONL, tasks store, fleet/orchestrator. No .mind migration
required for a metadata-first implementation: artifact metadata + relations live in a per-workspace
artifacts.json index (same pattern as documents.json). If artifacts must later be queryable in SQL
alongside frames, a future additive artifacts table in schema.ts follows the established
idempotent ADD-pattern (mind/db.ts:116-124) — flag, not now.
Governance note: if agent-generated artifacts (generatedByAgentId) need an audit trail, reuse
InstallAuditStore/emitAuditEvent (workspaces.ts:631 already emits workspace_update) rather than
a parallel log.
6. Shared types needed (PRD §15.2 / §15.6 vs lib/types.ts)
Net-new, none exist today (_inventory/substrate-types.md:226, 259-266):
ArtifactKindunion (PRD §15.2 line 950) — add tolib/types.ts(andpackages/shared/src/types.tsif the sidecar route also imports it, to keep one contract).ArtifactStatus = 'draft' | 'final' | 'shared' | 'generated'(from blueprint states:312, PRD §14 artifact states). Note blueprint also impliesexternal-missing/source-unavailable— model as a derived flag, not a status value.Artifactinterface — PRD §15.6 (lines 1039-1056) ∪ blueprint:547:id, title, kind, workspaceId, teamId?, createdBy, generatedByAgentId?, source, status, mimeType?, storagePath?, previewUrl?, summary?, tags[], relatedMemoryIds[], relatedSessionIds[], relatedTaskIds[], relatedAgentIds[], createdAt, updatedAt.RelatedSearchResult— the grouped{ artifacts, memories, sessions, tasks, agents }envelope forsearch-related.
Reconcile, don't fork: define Artifact/ArtifactKind/ArtifactStatus once (shared package
preferred) so the sidecar route and the frontend hook share the contract — avoid the existing
FE↔BE MemoryFrame drift the inventory flags (_inventory/substrate-types.md:246-247). Optionally add
relatedArtifactIds[] to the memory side later (PRD §15.4) so the relation is bidirectional.
7. Dependencies (screens / phases first)
- PRD Phase 2 — Work layer (this screen's home; Memory Center is its sibling, Sprint 4). The
search-relatedfederated endpoint is the binding dependency on Memory (FTS) + Sessions + Tasks. - AppShell / dock IA (Phase 0/1) must exist first so
artifactsregisters as a Work-bucket dock entry (consolidate onAppId, retire staleAppView). - Command Center (Ctrl+K) (Phase 1) should index artifacts (
_blueprint_extracted.txt:515— command index unifies artifacts) — soft dependency; Artifact Center can ship before Ctrl+K wires it in. WorkspaceConfigV2type/statusfields (S-workspace cards) help facet labels but are not blocking.- Team Workspace / RBAC (Phase 5) gates
POST /api/artifacts/:id/share+ permission-denied state. Ship Artifact Center personal-scoped first; share/team-scope is a follow-on. - Agent run → artifact linkage (PRD Journey 7, §15.6
generatedByAgentId) depends on the agent runtime writing artifact records — a downstream integration, not a blocker for the read/browse screen.
8. Effort: L
Net-new full-stack surface: 5-6 new frontend components + a new hook + 7 new adapter methods, plus
a net-new backend aggregation domain (artifacts.ts, ~6 routes) that must normalize three existing
stores into one entity and a federated search across memory/sessions/tasks/agents. No new DB and
heavy component/route reuse keep it out of XL, but the cross-workspace aggregation + the
search-related federation + a brand-new shared Artifact contract make it clearly more than M.
9. Open questions
- Artifact identity & index. Synthesize
idas a composite (workspaceId:store:name), or add a per-workspaceartifacts.jsonindex (mirroringdocuments.json) that assigns stable ids and holds status/tags/relations? (PATCH/relations effectively require the latter.) → maps to PRD Open Q6 (storage: workspace FS vs virtual store vs external refs, PRD line 1421). - What counts as an artifact in v1? Only explicit outputs (generated docs/decks/etc.), or every
ingested file in the registry? The registry mixes ingested inputs with produced outputs — need a
classification rule for
kind/status. search-relatedscope/cost. Federating memory FTS + sessions + tasks + agents per query — cap per-source result counts and run async result groups (PRD §24 perf mitigation), or a single indexed provider? (Mirrors the Command Center search concern.)- Share semantics (blueprint
/sharevs PRD/api/share). IsPOST /api/artifacts/:id/sharein-scope for the first Artifact Center cut, or deferred entirely to the Team phase? - Preview generation.
previewUrl/thumbnails — generate server-side, reuseFilePreviewon-demand client-side, or skip thumbnails in v1 (icon + on-click preview only)? - Bidirectional relations. Do we add
relatedArtifactIds[]to memory frames now (PRD §15.4) or keep relations one-directional (artifact → others) in v1?