Files
waggle-os/docs/ux-refactor/gap-cards/S15-memory-import.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

17 KiB

Gap Card — S15 Memory Import

UX-refactor planning artifact. Execution model is in-place incremental refactor of apps/web

  • targeted backend extensions. Every claim is grounded in a real file (cited inline). Mockup is directional (PRD §24) — PRD acceptance criteria win over pixels.

1. Screen & purpose

S15 = the Memory Import step of onboarding (PRD §12.12 step 4; Blueprint screen 15, _blueprint_extracted.txt:727). It is the "Capture" surface where a new user connects/imports their existing AI history (Claude, Claude Code, Cursor, Hermes, Codex, ChatGPT, Gemini, Perplexity…) and work tools (Files, Notion, Google Drive, Slack) so Waggle's persistent memory starts non-empty.

PRD anchors:

  • §12.12 step 4 "Memory Import — connect/import from AI tools, files, and work tools" (PRD:637).
  • §16.5 Harvest API: POST /api/harvest/preview, POST /api/harvest/commit, GET /api/harvest/sources, POST /api/harvest/sources/:id/sync (PRD:1098-1101).
  • Privacy gate: "No memory import without review/approval" (PRD:1207) and "Nothing imports without explicit review/approval" (PRD:646). S15 produces the preview; the approval/commit decision is S16 Memory Review (_blueprint_extracted.txt:731).

Mockup screen_15_memory_import.png (directional) shows a 3-region layout:

  • Left rail — onboarding step list (Welcome / Why us / Tool discovery / Import memory [active] / Review & confirm) + a "Your data is private" footer card.
  • Center — "Import your memory" with two grids: AI Assistants & Coding Tools (Claude, Claude Code, Cursor, Hermes, Codex, Other AI Tools — each a Connect action) and Files & Workspace Tools (Files, Notion, Google Drive, Slack — Connect actions). A primary Continue button bottom-right.
  • Right rail — "What we import" (Conversations / Documents / Decisions / Artifacts / Code) and "You're in control" (review-before-import, never-shared, disconnect-anytime).

Note the mockup is Connect-centric (OAuth/connector tiles) whereas the live onboarding step is upload-centric (file pickers). This is the core directional gap (see §2/§3).


2. Required states (PRD/Blueprint)

PRD §14.1 global states apply (Loading / Empty / Populated / Error / Offline-local-only / Syncing / Permission-denied / Partial / Approval-required). Concretely for S15:

State Trigger Source of truth
Idle / source grid step entered, no source picked mockup center grids
Source auto-detected sidecar finds local Claude Code at ~/.claude POST /api/harvest/scan-claude-code{found,itemCount,path}
Preview / parsed file uploaded or source connected; items parsed POST /api/harvest/preview{itemCount, types, preview[]}
Importing (live progress) commit running SSE GET /api/harvest/progress {phase∈saving|cognifying|wiki-compile, current, total}
Imported / done commit returned POST /api/harvest/commit {saved, cognified, wikiCompiled, ...}
No real embedder (degraded) commit returns cognifySkippedReason|wikiSkippedReason = 'no_real_embedder' harvest commit response (05c §8)
Resume available prior run interrupted GET /api/harvest/runs/latest-interrupted
Connector consent / OAuth "Connect" on Notion/Drive/Slack/Gmail GET /api/connectors, POST /api/connectors/:id/connect, GET /api/oauth/:provider/authorize
Error parse/commit/connect failure per-call catch
Skipped user declines (Journey 2, PRD:683-686) navigates to next onboarding step
Privacy headline always mockup right rail; existing copy in HarvestTab.tsx:362-365

Approval boundary (load-bearing): S15 ends at preview; the explicit approve-before-persist gate is S16 Memory Review. The live code today commits directly from S15 (no separate review screen) — a PRD-compliance gap, see §3.


3. Current state in repo (exact files + what they do)

Two existing surfaces already implement most of S15's upload path against the harvest substrate:

3a. Onboarding step (the real S15)

  • apps/web/src/components/os/overlays/OnboardingWizard.tsx — step index 3 = memory-import (STEP_NAMES at :35). Holds import state (importSource/importPreview/importing/importDone :64-72), handlers handleFileImport (:156-166adapter.harvestPreview), handleImportCommit (:168-177adapter.harvestCommit, then goToStep(4)), Claude-Code auto-detect on mount (:182-191adapter.scanClaudeCode) and handleClaudeCodeHarvest (:193-202). Renders <ImportStep step===3> at :519-531.
  • apps/web/src/components/os/overlays/onboarding/ImportStep.tsx (192 LOC) — the actual S15 UI. 6 SOURCE_TILES (chatgpt/claude/gemini/perplexity/cursor/unknown, :18-33) as file pickers (accept=".json,.txt,.md,.csv" :113), Claude-Code detect banner (:62-86), preview list + "Import N items" (:125-155), done state (:157-162), and a text pointer to "Memory → Harvest for 14+ more sources" (:167-173).
  • apps/web/src/components/os/overlays/onboarding/types.ts:38-52ImportStepProps.

3b. Post-onboarding harvest hub (the "Memory → Harvest" surface)

  • apps/web/src/components/os/apps/MemoryApp.tsxHarvest tabapps/web/src/components/os/apps/memory/HarvestTab.tsx (685 LOC). The full-featured sibling: connected-sources list with auto-sync toggle/remove (:505-559), 15-source selector (SOURCE_ICONS :35-51), upload and paste modes (:582-639), preview with type-count chips (:642-679), live SSE progress bar (:420-447), resume/discard banner (:330-360), identity-suggestion nudge post-commit (:452-470), dedup/enrichment summary (:472-502), no_real_embedder not yet surfaced as a distinct affordance.
  • apps/web/src/components/os/apps/memory/ImportReminderBanner.tsx — nudge to revisit import.

3c. Adapter methods (the contract surface, apps/web/src/lib/adapter.ts)

harvestPreview (:1684), harvestCommit (:1689), getHarvestSources (:1694), scanClaudeCode (:1699), extractHarvestIdentity (:1710), plus (per frontend inventory) subscribeHarvestProgress, getLatestInterruptedHarvestRun, resumeHarvestRun, abandonHarvestRun, removeHarvestSource, toggleHarvestAutoSync. Connector side: getConnectors, getConnectorHealth, connectConnector, disconnectConnector.

Disposition: rework (promote-and-extend, do NOT create-new)

The harvest engine and most of the upload UX already exist and are wired to the right endpoints. S15 needs to be reworked to (a) match the mockup's connect-grid IA, (b) split commit out into S16 Memory Review to satisfy the PRD "no import without review/approval" gate, and (c) reconcile the two near-duplicate surfaces (ImportStep vs HarvestTab) onto one shared component so onboarding and the standalone hub don't drift. This is squarely the locked in-place refactor model — reuse harvest.ts substrate, extend the frontend.


4. Frontend work

Reuse targets (do not rebuild): HarvestTab.tsx is the canonical, feature-complete harvest UI — its SSE progress, resume banner, identity nudge, and dedup summary should be the shared core. ImportStep.tsx is the lighter onboarding shell. The connector tiles in the mockup map to the existing ConnectorsApp/connectors/BrandTile.tsx patterns.

Concrete components:

  1. Extract a shared MemorySourcePicker + HarvestPreview + HarvestProgress from HarvestTab.tsx (currently a 685-LOC monolith; CLAUDE.md §coding-style favors small files) into components/os/apps/memory/ so both HarvestTab and the onboarding ImportStep consume one source of truth.
    • Props: sources: SourceTile[], onPreview(data,source), onConnect(connectorId), preview, progress, result, mode: 'onboarding'|'hub'.
  2. Rework ImportStep.tsx to the mockup's two-grid layout: AI Assistants & Coding Tools (Claude, Claude Code, Cursor, Hermes, Codex, ChatGPT, Gemini, Perplexity, Other) + Files & Workspace Tools (Files=/api/ingest upload, Notion/Drive/Slack/Gmail = connector "Connect"). Add the right-rail "What we import" + "You're in control" panels (copy already exists in HarvestTab.tsx:362-369).
    • Distinguish tile kind: upload (harvest file picker), scan (Claude Code local), connect (connector OAuth). Hermes/Codex are AI-tool launch/hook surfaces (LauncherApp/tool-detect) — for v1 they can be upload/"Other" or marked "coming soon" (open question OQ-1).
  3. Move the commit decision to S16 Memory Review. S15's "Continue" should carry the parsed preview forward; the explicit approve → harvestCommit happens on S16. Update OnboardingWizard.handleImportCommit (:168-177) to defer commit, or have S15 stage previews and S16 commit them. (Satisfies PRD:646/1207.)
  4. Surface no_real_embedder as a soft inline affordance ("semantic search/wiki won't update until you add an embedding key") using the cognifySkippedReason/wikiSkippedReason already in the commit response — currently unsurfaced in both UIs.
  5. Connector consent flow for Files & Workspace Tools tiles: reuse adapter.connectConnector + OAuth redirect (/api/oauth/:provider/authorize); show "review permissions" before connect (PRD:1207, Journey 8).
  6. State coverage: add explicit Loading/Error/Offline/Permission-denied/Approval-required renders per PRD §14.1 (HarvestTab has most; ImportStep is missing loading/offline).

Adapter: no new methods required for the upload path — all harvest + connector methods already exist (§3c). New methods needed only if backend adds /api/harvest/sources/:id/sync and a connector /sync (see §5).


5. Backend work (PRD §16.5 + adjacent)

Cross-referenced against docs/backend-map/sections/05c-subsystem-harvest.md, 03b-api-memory.md, and the route inventory.

PRD §16 endpoint Status Note / what to EXTEND vs NET-NEW Substrate
POST /api/harvest/preview EXISTS routes/harvest.ts{data,source}{itemCount,types,preview[]} (05c §6). No change. personal .mind
POST /api/harvest/commit EXISTS routes/harvest.ts — full ingest: parse → FrameStore.createIFrame(gop='harvest',src='import') → cognify → wiki recompile; SSE heartbeats; resumable run-store (05c §4). No change. memory_frames (personal.mind) + KG + wiki
GET /api/harvest/sources EXISTS routes/harvest.ts{sources: HarvestSource[]}. No change. harvest_sources
POST /api/harvest/sources/:id/sync PARTIAL → EXTEND (net-new thin route) No per-source /sync action exists (route-inventory §16.5). Sources are registered via POST /api/harvest/sources and toggled via PATCH /api/harvest/sources/:source; actual re-sync runs through POST /api/harvest/commit. Add a thin POST /api/harvest/sources/:source/sync that resolves the source row and calls the existing commit path. Path-key mismatch to resolve: PRD uses :id; current sources are keyed by :source name (DELETE/PATCH both use :source, harvest.ts). Pick :source for consistency with siblings. harvest_sources + commit pipeline

Adjacent endpoints S15 actually calls (not in §16.5 but load-bearing — all EXIST):

  • POST /api/harvest/scan-claude-code — local ~/.claude dry-run scan (EXISTS, harvest.ts).
  • GET /api/harvest/progressSSE progress (EXISTS).
  • GET /api/harvest/runs/latest-interrupted, POST /api/harvest/runs/:id/abandon, resume via commit {resumeFromRun} (all EXIST).
  • POST /api/harvest/extract-identity — post-commit identity suggestions (EXISTS) — feeds S16/Profile, not S15 proper.
  • POST /api/ingest — for the "Files" tile (base64 file → text + frames, EXISTS, ingest.ts).
  • GET /api/connectors, POST /api/connectors/:id/connect, GET /api/oauth/:provider/authorize|callback — for Notion/Drive/Slack/Gmail "Connect" tiles (all EXIST; connectors defined under packages/agent/src/connectors/* incl. notion-connector.ts, gdrive-connector.ts, slack-connector.ts, gmail-connector.ts). A connector POST /api/connectors/:id/sync is MISSING (route-inventory §16.9) — net-new if the workspace-tools tiles must pull data immediately, but for S15 a "Connected" state without immediate pull is acceptable for v1.

.mind migration flag: None required for S15's import path. Harvest writes plain memory_frames via the existing createIFrame signature — no schema change. (The broader Memory Center migration for explicit confidence/provenance/kind per PRD §15.4 — a single additive metadata TEXT column on memory_frames — is owned by the Memory Center / S16 Review cards, not S15. Provenance today is a text prefix [Harvest:<source>] in content, per 05c §4, which S16 can parse for the "source/confidence" review chips.)


6. Shared types needed (PRD §15 vs lib/types.ts)

S15's wire shapes are harvest-specific and live in packages/hive-mind-core/src/harvest/types.ts (UniversalImportItem, HarvestSource, HarvestRun, ImportSourceType, ImportItemType — 05c §1). The frontend currently re-declares lossy local interfaces (HarvestSource/PreviewResult in HarvestTab.tsx:16-33; claudeCodeDetected shape inline). Gaps vs apps/web/src/lib/types.ts:

  • No shared HarvestSource/HarvestRun/PreviewResult/ImportSourceType in lib/types.ts — each surface hand-rolls them. Promote a canonical HarvestSource, HarvestPreview, HarvestCommitResult, ImportSourceType into lib/types.ts (mirror the hive-mind-core shapes) so ImportStep and HarvestTab share one contract.
  • PRD §15.2 Scope / MemoryKind / Confidence unions are not S15's concern (they belong to S16/Memory Center) — S15 only needs the import-item/source/run types.
  • adapter.harvestPreview/harvestCommit are typed Promise<any> (adapter.ts:1684,1689) — tighten to the new shared result types (CLAUDE.md / ts-rules forbid any).

7. Dependencies (screens/phases first)

  • Belongs to PRD Phase 2 "Work layer" → Onboarding flow (PRD:233) / Roadmap Sprint 5 (PRD:1335-1342). Sequenced after S12 First Launch, S13 Who Are You, S14 Tool Discovery.
  • Tightly coupled to S16 Memory Review — S15 produces the preview; S16 owns the approve→commit gate. The commit-deferral rework (§4.3) cannot land without S16 existing. Plan S15 + S16 as a pair.
  • Feeds S17 Create Workspace (Journey 18: Memory Review finds projects → pre-fill workspace, PRD:812-817) — downstream, not blocking.
  • Connector tiles depend on the Extend-layer Connector Hub patterns (Phase 4) for OAuth/consent; for S15 v1 the existing connectors.ts + oauth.ts routes are sufficient (no Connector Hub UI dependency).
  • Shared-component extraction (§4.1) should land before reworking ImportStep so both surfaces converge rather than diverge further.

8. Effort: M

Backend is near-zero (one thin /sync alias; everything else EXISTS). The weight is frontend: extract a shared harvest component from a 685-LOC monolith, rebuild ImportStep to the two-grid connect layout, wire connector-OAuth tiles, surface no_real_embedder, and re-sequence commit into S16. Not L because no new substrate/migration and the engine is done; not S because it touches two surfaces + the S15/S16 approval split + type promotion.


9. Open questions

  1. Hermes / Codex / Cursor tiles (mockup) — these are AI-coding tools surfaced via the AI-OS launcher/tool-detect + hooks (LauncherApp, /api/tools/detect), not harvest export adapters (Cursor falls through UniversalAdapter; Hermes/Codex have no harvest adapter, 05c §1 union). For v1: render as upload/"Other" file pickers, or as "Connect via hooks" using the AI-OS launcher, or "coming soon"? PRD §12.12 says "connect/import from AI tools" without specifying the mechanism.
  2. S15/S16 commit split — confirm the intended boundary: does S15 commit-and-S16-reviews-the-result, or S15-stages-previews-and-S16-commits? PRD:646/1207 ("nothing imports without review/approval") argues for the latter; current code commits at S15. (PRD Open Question — not listed in §23 but implied.)
  3. Connector "Connect" without immediate pull — for Notion/Drive/Slack in S15, is a "Connected" state (creds stored) sufficient, or must data pull happen in-onboarding (requires net-new POST /api/connectors/:id/sync, §16.9 MISSING)? Maps to PRD §23 Q4 ("which connectors/MCPs are real in v1 vs seeded/mock").
  4. Two-surface reconciliation — should the post-onboarding harvest surface stay in MemoryApp → Harvest tab, or be promoted to the PRD's Memory Center "Sources" tab (PRD §12.4 tabs include "Sources")? Affects where the shared component lives.
  5. no_real_embedder UX — block import, warn-and-proceed, or prompt for an embedding key inline? (Cognify/wiki silently skip today; semantic recall degrades.)