From 808f4058894d8ab58e9c443511a0c2c4650fa920 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Sun, 29 Mar 2026 11:38:34 -0700 Subject: [PATCH] docs(roadmap): add Phase 4 DRY audit + fix 9 review gaps in Local AI consolidation roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 4 — DRY Refactoring & Common Platform Extractions: - 4.1 @bytelyst/ollama-client (NEW) — deduplicate Ollama API + NDJSON parsing (~350 lines) - 4.2 Extend @bytelyst/fastify-sse with per-request SSE helpers (~26 lines) - 4.3 @bytelyst/use-theme (NEW) — deduplicate across 6 web apps (~300 lines) - 4.4 @bytelyst/use-keyboard-shortcuts (NEW) — deduplicate across 5 web apps (~250 lines) - 4.5-4.7 Types, format utils, client-side stream parsers (~220 lines) Total: ~1,150 lines of duplicated code identified for extraction Review pass 2 fixes (R1-R9): - R1: Fix misleading route group item count heading - R2: Fix file inventory 6 pages+layout → 5 pages+1 layout - R3: Fix LocalMemGPT test count 102 → 104 (field-encrypt) - R4: Fix Phase 4.2 title to clarify extending existing package - R5: Confirm ActionTrail use-theme.ts (was inferred) - R6: Note post-Phase-1 stream parser copy reduction - R7: Add addendum note for Phase 4 structure - R8: Clarify both Attachment+ModelDefaults must be kept - R9: Fix Mission Control API route count 11 → 13 --- .../LOCAL_AI_CONSOLIDATION_ROADMAP.md | 752 ++++++++++++++++++ 1 file changed, 752 insertions(+) create mode 100644 docs/roadmaps/not-started/LOCAL_AI_CONSOLIDATION_ROADMAP.md diff --git a/docs/roadmaps/not-started/LOCAL_AI_CONSOLIDATION_ROADMAP.md b/docs/roadmaps/not-started/LOCAL_AI_CONSOLIDATION_ROADMAP.md new file mode 100644 index 00000000..68e212a6 --- /dev/null +++ b/docs/roadmaps/not-started/LOCAL_AI_CONSOLIDATION_ROADMAP.md @@ -0,0 +1,752 @@ +# Local AI Repos — Consolidation Roadmap + +> **Status:** Not Started +> **Created:** 2026-03-29 +> **Scope:** `learning_ai_local_llms` + `learning_ai_local_memory_gpt` +> **Goal:** Eliminate feature overlap between the two repos by removing the chat workspace from Local LLM Lab, making Local Memory GPT the single chat surface. + +--- + +## Executive Summary + +Two repos in the ByteLyst ecosystem handle local AI inference: + +| Repo | Product ID | Purpose | +| ------------------------------ | ------------- | ----------------------------------------------------------------------- | +| `learning_ai_local_llms` | `localllmlab` | Model management, hardware monitoring, benchmarks, STT/TTS, experiments | +| `learning_ai_local_memory_gpt` | `localmemgpt` | Persistent AI chat with RAG, full-text search, export/import | + +Both repos have a **chat workspace** that talks to Ollama, stores conversations, and supports multi-model comparison. This duplication creates maintenance burden and user confusion about which surface to use for conversations. + +### Decision + +- **Local LLM Lab** keeps: Mission Control (model ops, hardware, benchmarks), STT/TTS, experiments +- **Local LLM Lab** removes: Chat workspace (conversations, agents, quick actions, orchestrations, projects, scheduled tasks, compare) +- **Local Memory GPT** stays as-is — it is already the better chat app (server-side persistence, RAG, FTS5, encryption) +- **Optional:** Port unique LLM Lab workspace features (agents, quick actions, orchestrations) into Local Memory GPT if they prove valuable + +--- + +## Review Findings + +> **Pass 1:** 13 bugs/gaps identified during systematic codebase verification (2026-03-29). +> All findings are incorporated inline below — see `[F1]`–`[F13]` markers. +> +> **Pass 2:** 9 additional issues found during Phase 4 review (2026-03-29). +> See `[R1]`–`[R9]` markers below. + +| # | Severity | Finding | Section Fixed | +| --- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | +| F1 | **CRITICAL** | `api/ollama/chat`, `api/ollama/stream`, `api/ollama/logs` are used by Mission Control (46 whisper/tts/chat references in `page.tsx`) — cannot delete them | §1.2 | +| F2 | **CRITICAL** | `api/tts/` and `api/whisper/` are used by Mission Control (Whisper test, TTS engine status panel) — must keep, not "decision point" | §1.2 | +| F3 | **CRITICAL** | `(workspace)/page.tsx` is the **root page** (`/`) — no separate `src/app/page.tsx` exists. Deleting the workspace route group removes the root page; a redirect must be added | §1.5 | +| F4 | **HIGH** | `router.ts` (task classification) is imported by `api/ollama/chat/route.ts` which Mission Control calls — it is SHARED, not workspace-only. Was listed under "Lib files to KEEP" (correct) but also categorized workspace-only in the API routes section | §1.2 | +| F5 | **HIGH** | `api/ollama/title/route.ts` is the ONLY chat API route that is workspace-only (auto-generates conversation titles). The other 3 (`chat`, `stream`, `logs`) must stay | §1.2 | +| F6 | **MEDIUM** | E2E `chat.spec.ts` — workspace-specific, delete. `health.spec.ts` — has `/c/test-id` workspace test, needs update. `accessibility.spec.ts` — tests `/compare`, `/tts`, `/whisper` (workspace routes). `visual-regression.spec.ts` — tests `/` (workspace) and `/compare`. E2E impact is larger than "~3 specs" claimed | §1.4, Test Impact | +| F7 | **MEDIUM** | 3 npm dependencies are workspace-only and can be removed: `idb` (IndexedDB), `cron-parser` (scheduled tasks), `fuse.js` (CommandPalette search) | §1.3 | +| F8 | **MEDIUM** | `globals.css` has no workspace-specific tokens — all 319 lines are shared (card styles, responsive sidebar, light theme, utility classes). Entire step 1.6 was unnecessary | §1.6 | +| F9 | **MEDIUM** | `types.ts` workspace types include `ModelDefaults` (line 163–169) and `Attachment` (line 119–126) — `Attachment` is imported by `router.ts` (shared). Must keep `Attachment` type when trimming types.ts | §1.3 | +| F10 | **LOW** | Line count "~122,000" for Mission Control page.tsx is wrong — 121 KB ≈ 2,819 lines, not 122K lines | Files Kept table | +| F11 | **LOW** | Vitest test count "80" comes from AGENTS.md but 7 test files × ~10-15 tests each ≈ 70-80 is plausible. Removing 2 test files drops to ~65-73 range | Test Impact | +| F12 | **LOW** | Risk "Mission Control page.tsx has workspace imports" is NOT low — it imports `types.ts` types (OllamaData, WhisperData, etc.) which are in the KEEP section. Risk is actually about the `Attachment` type in the trimmed section | Risks | +| F13 | **LOW** | Open Question #1 is now RESOLVED — Mission Control definitively uses TTS/Whisper. Remove from open questions | Open Questions | + +**Pass 2 (Phase 4 + consistency review):** + +| # | Severity | Finding | Section Fixed | +| --- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | +| R1 | **MEDIUM** | "Route group (22 items)" heading lists 22 but only enumerates 6 route files; 16 components listed separately — misleading count | §Current State | +| R2 | **MEDIUM** | File Inventory says "6 pages + layout" (=7 files) but there are 5 pages + 1 layout = 6 files | §File Inventory | +| R3 | **MEDIUM** | LocalMemGPT test count "102" is stale — field-encrypt integration added tests, current total is 104 | §Success Criteria, §Test Impact | +| R4 | **LOW** | Phase 4.2 title says `@bytelyst/sse-helpers` (new package) but body proposes extending existing `@bytelyst/fastify-sse` | §4.2 | +| R5 | **LOW** | Phase 4.3 ActionTrail listed as "(inferred, same pattern)" but actually confirmed at `web/src/lib/use-theme.ts` | §4.3 | +| R6 | **LOW** | Phase 4.7 says LLM Lab has 3 stream parser copies but 2 are in workspace files deleted in Phase 1 — post-consolidation savings differ | §4.7 | +| R7 | **LOW** | Phase 4 structurally placed after Summary/Success sections instead of grouped with Phases 1-3 — needs addendum note | §Phase 4 header | +| R8 | **LOW** | `router.ts` imports both `Attachment` AND `ModelDefaults` from types.ts — both must be kept (doc mentions Attachment but buries ModelDefaults) | §1.3 | +| R9 | **LOW** | Mission Control API route count says "11" but actual count is 10 (route.ts + pull + chat + stream + logs + tts + whisper + whisper/transcribe + system + system/memory + system/exec + health + extraction = 13) | §Files Kept | + +--- + +## Current State Audit + +### Local LLM Lab — Workspace (`(workspace)/`) + +Files that constitute the chat workspace to be removed: + +**Route pages + layout (6 files): [R1]** + +- `dashboard/src/app/(workspace)/layout.tsx` — workspace shell (sidebar + routing) +- `dashboard/src/app/(workspace)/page.tsx` — workspace home **[F3: this is the root page `/` — must add a redirect after deletion]** +- `dashboard/src/app/(workspace)/c/[id]/page.tsx` — conversation detail +- `dashboard/src/app/(workspace)/compare/page.tsx` — side-by-side compare +- `dashboard/src/app/(workspace)/tts/page.tsx` — text-to-speech page +- `dashboard/src/app/(workspace)/whisper/page.tsx` — speech-to-text page + +**Workspace components (16 files):** + +- `ConversationView.tsx` — chat message display + streaming (13 KB) +- `Sidebar.tsx` — workspace nav (9 KB) +- `InputBar.tsx` — message input with attachments (9 KB) +- `AgentEditor.tsx` — create/edit custom agents (9 KB) +- `TaskEditor.tsx` — scheduled task CRUD (9 KB) +- `OrchestrationEditor.tsx` — chain/race/vote pipelines (9 KB) +- `OrchestrationRunner.tsx` — execute orchestrations (9 KB) +- `QuickActionEditor.tsx` — quick action CRUD (8 KB) +- `MessageBubble.tsx` — message rendering (6 KB) +- `CommandPalette.tsx` — Cmd+K action palette (6 KB) +- `ProjectSidebar.tsx` — project panel (5 KB) +- `TaskRunner.tsx` — execute scheduled tasks (4 KB) +- `ProjectSwitcher.tsx` — project switcher (3 KB) +- `ConversationList.tsx` — conversation list (3 KB) +- `MessageThread.tsx` — threaded messages (1.4 KB) +- `ContextBar.tsx` — context display (1.1 KB) + +**Lib files (workspace-specific):** + +- `db.ts` — IndexedDB schema + CRUD (14 KB, 494 lines) — conversations, messages, agents, quickActions, projects, scheduledTasks, taskRuns, modelRatings, orchestrations +- `agents.ts` — 6 built-in agent definitions (4 KB) +- `quick-actions.ts` — 30+ built-in quick actions (8 KB) +- `scheduled-tasks.ts` — task scheduler logic (2 KB) +- `cron.ts` — cron expression parser (1.5 KB) +- `migrate.ts` — v3→v4 IndexedDB migration (4 KB) +- `types.ts` — Conversation, Message, Agent, QuickAction, Project, ScheduledTask, Orchestration types (lines 78–221) + +**API routes (workspace-only — safe to delete):** + +- `api/ollama/title/route.ts` — auto-generate conversation title (only used by workspace `ConversationView.tsx`) + +**API routes INCORRECTLY listed as workspace-only — must KEEP [F1, F2]:** + +- ~~`api/ollama/chat/route.ts`~~ — **KEEP** — Mission Control calls this for model testing (line 719 of `page.tsx`) +- ~~`api/ollama/stream/route.ts`~~ — **KEEP** — Mission Control calls this for model comparison and benchmarks (lines 331, 538) +- ~~`api/ollama/logs/route.ts`~~ — **KEEP** — Mission Control has Ollama log viewer (line 297) +- ~~`api/tts/route.ts`~~ — **KEEP** — Mission Control has TTS engine status panel (line 179) +- ~~`api/whisper/route.ts`~~ — **KEEP** — Mission Control fetches Whisper status on load (line 165) +- ~~`api/whisper/transcribe/route.ts`~~ — **KEEP** — Mission Control has Whisper transcription test (line 313) + +**Tests (workspace-specific):** + +- `__tests__/agents.test.ts` +- `__tests__/cron.test.ts` + +### Local LLM Lab — Mission Control (`(mission-control)/`) + +Files to **KEEP** — these are the unique infrastructure value: + +- `mission-control/page.tsx` — system overview, model management, benchmarks (121 KB) +- `mission-control/components/` — Mission Control UI components + +**API routes to KEEP:** + +- `api/ollama/route.ts` — model list, pull, delete +- `api/ollama/pull/route.ts` — model pull with progress +- `api/ollama/chat/route.ts` — chat completion proxy **[F1: used by Mission Control model testing]** +- `api/ollama/stream/route.ts` — raw streaming proxy **[F1: used by Mission Control comparison/benchmarks]** +- `api/ollama/logs/route.ts` — Ollama server logs **[F1: used by Mission Control log viewer]** +- `api/tts/route.ts` — TTS engine status + synthesis **[F2: used by Mission Control TTS panel]** +- `api/whisper/route.ts` — Whisper status **[F2: used by Mission Control Whisper card]** +- `api/whisper/transcribe/route.ts` — Whisper transcription test **[F2: used by Mission Control]** +- `api/system/route.ts` — hardware info (chip, GPU, memory, disk) +- `api/system/memory/route.ts` — memory pressure stats +- `api/system/exec/route.ts` — optional exec endpoint +- `api/health/route.ts` — health check +- `api/extraction/route.ts` — extraction proxy + +**Lib files to KEEP:** + +- `llm-router.ts` — `@bytelyst/llm-router` re-export +- `ollama-config.ts` — OLLAMA_HOST env loading +- `product-config.ts` — product identity +- `router.ts` — model routing logic +- `format.ts` — byte/duration formatters +- `use-theme.ts` — dark/light toggle +- `use-keyboard-shortcuts.ts` — global shortcuts + +**Shared components to KEEP:** + +- `src/components/MarkdownResponse.tsx` — markdown renderer +- `src/components/ProgressBar.tsx` +- `src/components/RamBudgetBar.tsx` +- `src/components/Sparkline.tsx` +- `src/components/StatusDot.tsx` +- `src/components/Toast.tsx` + +**Tests to KEEP:** + +- `__tests__/format.test.ts` +- `__tests__/ollama-config.test.ts` +- `__tests__/product-config.test.ts` +- `__tests__/use-keyboard-shortcuts.test.ts` +- `__tests__/use-theme.test.ts` + +### Local LLM Lab — Non-Dashboard Assets (all KEEP) + +- `docs/` — 11 setup guides + hardware specs +- `tts/` — TTS scripts + samples +- `scripts/` — start-dashboard.sh + windows setup +- `experiments/` — oss-llm, open-claw, voicebox +- `chat-history/windsurf/` — Windsurf IDE archive + +### Local Memory GPT — Features LLM Lab Has But LocalMemGPT Doesn't + +These are **optional ports** — only if they prove valuable: + +| Feature | LLM Lab Implementation | Port Priority | +| ------------------------------------ | ------------------------------------ | ----------------- | +| **Agents** (custom personas) | 6 built-in + custom, IndexedDB | P2 — nice to have | +| **Quick Actions** (30+ templates) | Code review, explain, refactor, etc. | P2 — nice to have | +| **Orchestrations** (chain/race/vote) | Multi-model pipelines | P3 — advanced | +| **Projects** (conversation grouping) | Folder-like grouping | P1 — useful | +| **Scheduled Tasks** (cron) | Cron-based automated prompts | P3 — niche | +| **Model Ratings** (up/down) | Per-message thumbs up/down | P1 — useful | +| **STT input** (whisper) | whisper.cpp integration | P2 — voice input | +| **TTS output** (Orpheus) | Ollama-based speech synthesis | P3 — experimental | +| **Conversation branching** | parentId + branchIndex | P2 — nice to have | +| **Attachments** (image/file/audio) | Multi-modal input | P1 — useful | + +--- + +## Phases + +### Phase 1 — Remove Workspace from Local LLM Lab + +> **Effort:** ~2 hours +> **Risk:** Low — deletion only, no logic changes +> **Repo:** `learning_ai_local_llms` + +#### 1.1 Delete workspace route group + +Delete the entire `(workspace)/` directory: + +``` +dashboard/src/app/(workspace)/ # 22 items — layout, pages, 16 components +``` + +#### 1.2 Delete workspace-specific API routes + +Delete **only** the route that is workspace-only: + +``` +dashboard/src/app/api/ollama/title/ # Auto-title generation (workspace-only) +``` + +**[F1, F2] The following routes MUST be kept** — Mission Control uses them directly: + +- `api/ollama/chat/` — model testing prompt (page.tsx line 719) +- `api/ollama/stream/` — model comparison + benchmarks (lines 331, 538) +- `api/ollama/logs/` — Ollama log viewer (line 297) +- `api/tts/` — TTS engine status panel (line 179) +- `api/whisper/` — Whisper status card (line 165) +- `api/whisper/transcribe/` — transcription test button (line 313) + +#### 1.3 Clean up lib files + +Delete workspace-only lib files: + +``` +dashboard/src/app/lib/db.ts # IndexedDB (conversations, messages, agents, etc.) +dashboard/src/app/lib/agents.ts # Built-in agent definitions +dashboard/src/app/lib/quick-actions.ts # Built-in quick action definitions +dashboard/src/app/lib/scheduled-tasks.ts # Task scheduler +dashboard/src/app/lib/cron.ts # Cron parser +dashboard/src/app/lib/migrate.ts # v3→v4 migration +``` + +Remove workspace types from `types.ts` (lines 78–221: Conversation, Message, Agent, QuickAction, Project, ScheduledTask, Orchestration). Keep lines 1–77 (OllamaModel, RunningModel, OllamaData, WhisperModel, WhisperData, SystemData, Toast, PullProgress, StreamMetrics). **[F9, R8] Also keep `Attachment` (lines 119–126) and `ModelDefaults` (lines 163–169)** — both are imported by `router.ts` (line 1: `import type { Attachment, ModelDefaults } from './types'`) which is used by `api/ollama/chat/route.ts` (shared). + +#### 1.4 Delete workspace-specific tests + +``` +dashboard/src/app/lib/__tests__/agents.test.ts +dashboard/src/app/lib/__tests__/cron.test.ts +``` + +#### 1.5 Create root redirect page [F3] + +**[F3] CRITICAL:** The workspace route group `(workspace)/page.tsx` is the current root page (`/`). There is no separate `src/app/page.tsx`. After deleting the workspace, `GET /` returns 404. + +**Required:** Create `dashboard/src/app/page.tsx` that redirects to `/mission-control`: + +```tsx +import { redirect } from 'next/navigation'; +export default function Home() { + redirect('/mission-control'); +} +``` + +- Verify `layout.tsx` root has no workspace-specific imports (confirmed: it only imports fonts, design tokens, product-config, and Providers — no workspace references) +- Update any shared components that reference workspace routes + +#### 1.6 ~~Update globals.css~~ — NO ACTION NEEDED [F8] + +**[F8]** Verified: `globals.css` (319 lines) contains no workspace-specific tokens. All styles (card, sidebar, light theme, utility classes, skeleton shimmer) are shared by Mission Control. Skip this step. + +#### 1.6a Remove workspace-only npm dependencies [F7] + +Remove from `dashboard/package.json`: + +- `idb` — IndexedDB client, only used by `db.ts` (workspace) +- `cron-parser` — only used by `cron.ts` and `TaskEditor.tsx` / `TaskRunner.tsx` (workspace) +- `fuse.js` — only used by `CommandPalette.tsx` (workspace) + +#### 1.7 Verify + +```bash +cd dashboard && pnpm run typecheck && pnpm test && pnpm run build +``` + +**Commit:** `refactor(dashboard): remove chat workspace — LocalMemGPT is the chat surface` + +#### 1.8 Update documentation + +- Update `AGENTS.md` — remove workspace references, update repo layout, adjust test count +- Update `README.md` — remove chat workspace description, add note pointing to Local Memory GPT for chat +- Update `CLAUDE.md`, `.windsurfrules`, `.cursorrules` — align with new scope + +**Commit:** `docs: update agent docs after workspace removal` + +--- + +### Phase 2 — Add Cross-Link Between Repos + +> **Effort:** ~30 minutes +> **Risk:** None +> **Repos:** Both + +#### 2.1 Local LLM Lab → Local Memory GPT link + +Add a prominent link in Mission Control dashboard pointing to Local Memory GPT: + +- "Chat with your models →" card or banner +- Links to `http://localhost:3070` (LocalMemGPT web default port) +- Configurable via env var: `LOCALMEMGPT_URL` + +**Commit:** `feat(dashboard): add LocalMemGPT cross-link in Mission Control` + +#### 2.2 Local Memory GPT → Local LLM Lab link + +Add a link in Settings panel: + +- "Model Management →" pointing to `http://localhost:3000` (LLM Lab dashboard) +- Configurable via env var: `LOCALLLMLAB_URL` + +**Commit:** `feat(web): add LLM Lab cross-link in settings` + +--- + +### Phase 3 (Optional) — Port Valuable Features to Local Memory GPT + +> **Effort:** ~3–5 days total (pick and choose) +> **Risk:** Medium — new features in a working app +> **Repo:** `learning_ai_local_memory_gpt` + +Only pursue these if the features are missed after Phase 1. + +#### 3.1 Conversation Attachments (P1) + +LocalMemGPT currently has no attachment support. LLM Lab supports image/file/audio/url attachments. + +- Add `attachments` field to messages table (SQLite JSON column) +- Update chat SSE handler to pass images to Ollama vision models +- Update `MessageBubble.tsx` to render attachments +- Update `ChatView.tsx` input to support file upload + +**Effort:** ~1 day + +#### 3.2 Model Ratings (P1) + +LLM Lab has per-message thumbs up/down ratings with IndexedDB storage. + +- Add `rating` column to messages table +- Add `PATCH /api/messages/:id/rate` endpoint +- Update `MessageBubble.tsx` with rating buttons + +**Effort:** ~2 hours + +#### 3.3 Projects / Folders (P1) + +LLM Lab groups conversations into projects. LocalMemGPT has no grouping. + +- Add `folders` table to SQLite +- Add `folderId` column to conversations table +- Add folder CRUD endpoints +- Update Sidebar to show folder tree + +**Effort:** ~4 hours + +#### 3.4 Custom Agents / System Prompts (P2) + +LLM Lab has 6 built-in agents + custom agent editor. LocalMemGPT supports per-conversation system prompts but no reusable agent definitions. + +- Add `agents` table to SQLite +- Add agent CRUD endpoints +- Add agent picker in new conversation flow +- Port 6 built-in agent definitions + +**Effort:** ~4 hours + +#### 3.5 Quick Actions (P2) + +LLM Lab has 30+ built-in quick actions (code review, explain, summarize, etc.). + +- Add `quick_actions` table to SQLite +- Add quick action CRUD + execute endpoints +- Add Cmd+K command palette component +- Port built-in quick action definitions + +**Effort:** ~6 hours + +#### 3.6 Voice Input — Whisper STT (P2) + +LLM Lab has whisper.cpp integration for speech-to-text. + +- Add `POST /api/whisper/transcribe` endpoint (shell out to whisper binary) +- Add microphone button in ChatView input bar +- Detect whisper binary availability + +**Effort:** ~4 hours + +#### 3.7 Orchestrations — Multi-Model Pipelines (P3) + +LLM Lab supports chain/race/vote multi-model orchestrations. LocalMemGPT has compare (parallel) but not chain/vote. + +- Add `orchestrations` table +- Add orchestration CRUD + execute endpoints +- Add orchestration editor UI + +**Effort:** ~1 day + +#### 3.8 Scheduled Tasks (P3) + +LLM Lab has cron-based scheduled prompts. Very niche feature. + +- Add `scheduled_tasks` table +- Add task scheduler (setInterval-based in backend) +- Add task editor UI + +**Effort:** ~4 hours + +--- + +## File Inventory Summary + +### Phase 1 Deletions (Local LLM Lab) + +| Category | Files | ~Lines | +| --------------------- | ----------------------- | ---------------- | +| Workspace route group | 5 pages + 1 layout [R2] | ~700 | +| Workspace components | 16 `.tsx` files | ~5,500 | +| Workspace API routes | 1 route dir (`title/`) | ~50 | +| Workspace lib files | 6 `.ts` files | ~1,800 | +| Workspace types | partial `types.ts` | ~140 | +| Workspace tests | 2 test files | ~120 | +| Workspace npm deps | 3 packages removed | — | +| **Total** | **~30 files** | **~8,310 lines** | + +### Files Kept (Local LLM Lab) + +| Category | Files | ~Lines | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | +| Mission Control | 1 page + components | ~2,819 lines (page.tsx is 121 KB / 2,819 lines) [F10] | +| Mission Control API routes | 13 route dirs/files [R9] (route.ts + pull + chat + stream + logs + tts + whisper + whisper/transcribe + system + system/memory + system/exec + health + extraction) | ~1,200 | +| Shared lib files | 7 `.ts` files | ~600 | +| Shared components | 6 `.tsx` files | ~400 | +| Shared tests | 5 test files | ~500 | +| Non-dashboard assets | docs, tts, scripts, experiments | ~250 files | +| **Total** | **~275 files** | — | + +### Test Impact + +| Metric | Before | After | +| ---------------------- | ----------------------------------------------- | ------------------------------------------------------ | +| LLM Lab Vitest tests | ~80 (7 test files) | ~65-73 (−agents.test, −cron.test; 5 test files remain) | +| LLM Lab Playwright E2E | 7 specs | **Need updates in 5 specs** [F6] — see below | +| LocalMemGPT tests | 79 backend + 23 web + field-encrypt = ~104 [R3] | unchanged | + +**E2E spec details [F6]:** +| Spec | Action | +|------|--------| +| `chat.spec.ts` | **Delete** — tests workspace chat input/send at `/` | +| `health.spec.ts` | **Update** — remove `Conversation Routes` test that navigates to `/c/test-id` | +| `accessibility.spec.ts` | **Update** — remove `/compare`, `/tts`, `/whisper` from `routes` array (keep `/`, `/mission-control`) | +| `visual-regression.spec.ts` | **Update** — remove `workspace` and `compare` from ROUTES array (keep `mission-control`) | +| `navigation.spec.ts` | **Update** — test at `/` now redirects to `/mission-control` | +| `mission-control.spec.ts` | **Keep as-is** | +| `models.spec.ts` | **Update** — navigates to `/` which now redirects | + +--- + +## Environment Variables + +### New (Phase 2) + +| Variable | Repo | Default | Description | +| ----------------- | ------------------------------ | ----------------------- | ---------------------------------- | +| `LOCALMEMGPT_URL` | `learning_ai_local_llms` | `http://localhost:3070` | Link target for "Chat with models" | +| `LOCALLLMLAB_URL` | `learning_ai_local_memory_gpt` | `http://localhost:3000` | Link target for "Model Management" | + +--- + +## Risks & Mitigations + +| Risk | Likelihood | Mitigation | +| ---------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Users have workspace conversations they want to keep | Medium | Provide a one-time export script (Phase 1, pre-deletion) that dumps IndexedDB conversations to JSON importable by LocalMemGPT | +| Mission Control page.tsx imports trimmed types | Low | **[F12]** Verified: Mission Control imports `OllamaData`, `WhisperData`, `SystemData`, `Toast`, `PullProgress`, `StreamMetrics` — all in the KEEP section. `Attachment` type must also be kept since `router.ts` uses it | +| ~~TTS/Whisper routes are workspace-only~~ | ~~Low~~ | **[F2] RESOLVED:** Mission Control definitively uses both TTS and Whisper routes (46 references). All kept. | +| Phase 3 feature ports introduce bugs in stable LocalMemGPT | Medium | Each port gets its own commit + test coverage; skip ports that aren't missed | + +--- + +## Success Criteria + +- [ ] Local LLM Lab dashboard loads with Mission Control as the default page +- [ ] No workspace routes, components, or lib files remain +- [ ] `pnpm run typecheck && pnpm test && pnpm run build` passes in LLM Lab +- [ ] LLM Lab AGENTS.md accurately reflects the new scope +- [ ] Cross-links work in both directions +- [ ] Local Memory GPT is unchanged and all ~104 tests pass [R3] +- [ ] (Phase 4) `@bytelyst/ollama-client` published to Gitea registry, consumed by both repos +- [ ] (Phase 4) `@bytelyst/fastify-sse` extended with per-request helpers, LocalMemGPT migrated + +--- + +## Phase 4 — DRY Refactoring & Common Platform Extractions + +> **Note:** [R7] This phase was added as an addendum during the DRY audit (2026-03-29). It is independent of Phases 1-3 and can be executed before, after, or in parallel. +> +> **Effort:** ~3–5 days total +> **Risk:** Low-Medium — new shared packages, consumers migrate incrementally +> **Repo:** `learning_ai_common_plat` (new packages) + both local AI repos + ecosystem-wide + +Code audit identified **7 extraction candidates** — duplicated patterns across the two local AI repos and the broader ecosystem. + +### 4.1 `@bytelyst/ollama-client` — Ollama API Client (NEW PACKAGE) + +**Problem:** Both repos implement nearly identical Ollama API interaction code with duplicated NDJSON stream parsing. + +| Repo | File | Functions | ~Lines | +| ----------- | ---------------------------------------------- | ----------------------------------------------------------------------------- | ------ | +| LocalMemGPT | `backend/src/lib/ollama.ts` | `listOllamaModels()`, `checkOllamaHealth()`, `streamChat()`, `getEmbedding()` | 117 | +| LLM Lab | `dashboard/src/app/api/ollama/route.ts` | `fetchOllama()`, model list/pull/delete/show/load/unload | 128 | +| LLM Lab | `dashboard/src/app/api/ollama/stream/route.ts` | raw streaming proxy | 37 | +| LLM Lab | `dashboard/src/app/api/ollama/chat/route.ts` | chat proxy with llm-router | 109 | +| LLM Lab | `dashboard/src/app/lib/ollama-config.ts` | `OLLAMA_URL` env resolution + WSL2 gateway detection | 40 | + +**Shared NDJSON stream parsing pattern** (copy-pasted 5+ times across both repos): + +```ts +const reader = res.body.getReader(); +const decoder = new TextDecoder(); +let buffer = ''; +while (true) { + const { done, value } = await reader.read(); + if (done) break; + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split('\n'); + buffer = lines.pop() ?? ''; + for (const line of lines) { + if (!line.trim()) continue; + try { + yield JSON.parse(line); + } catch { + /* skip */ + } + } +} +``` + +**Proposed package:** `packages/ollama-client/` + +``` +@bytelyst/ollama-client +├── src/ +│ ├── config.ts # resolveOllamaUrl(env) — OLLAMA_URL/OLLAMA_HOST + WSL2 detection +│ ├── client.ts # OllamaClient class: tags, ps, show, pull, load, unload, delete, version +│ ├── stream.ts # streamChat(), streamGenerate() — AsyncGenerator +│ ├── embed.ts # getEmbedding() +│ ├── health.ts # checkHealth() with timeout +│ ├── ndjson.ts # parseNdjsonStream() — reusable NDJSON async generator +│ └── types.ts # OllamaModel, OllamaChatMessage, OllamaStreamChunk, etc. +└── package.json +``` + +**Consumers:** + +- `learning_ai_local_memory_gpt/backend` — replace `lib/ollama.ts` (117 lines deleted) +- `learning_ai_local_llms/dashboard` — replace `lib/ollama-config.ts` + 4 API route files simplified +- `@bytelyst/llm-router` — could consume `@bytelyst/ollama-client` for its Ollama provider + +**Effort:** ~1 day +**Priority:** P0 — eliminates the largest duplication + +--- + +### 4.2 Extend `@bytelyst/fastify-sse` — Per-Request SSE Utilities [R4] + +**Problem:** `@bytelyst/fastify-sse` provides `SSEHub` (broadcast to multiple clients) but NOT per-request SSE helpers. LocalMemGPT reinvented these as `sse-helpers.ts` (26 lines). + +| Existing | What it does | +| ---------------------------- | -------------------------------------------------------------------------------------- | +| `@bytelyst/fastify-sse` | `SSEHub` — multi-client broadcast pattern (hub/spoke) | +| LocalMemGPT `sse-helpers.ts` | `startSSE()`, `sendSSEData()`, `sendSSEEvent()`, `endSSE()` — single-request streaming | + +**Proposed:** Add per-request helpers to `@bytelyst/fastify-sse`: + +```ts +// New exports in @bytelyst/fastify-sse +export { startSSE, sendSSEData, sendSSEEvent, endSSE } from './per-request.js'; +``` + +**Consumers:** + +- `learning_ai_local_memory_gpt/backend` — replace `lib/sse-helpers.ts` with import from package +- `learning_ai_trails/backend` — already uses `@bytelyst/fastify-sse` hub, could use per-request too + +**Effort:** ~2 hours +**Priority:** P1 + +--- + +### 4.3 `@bytelyst/use-theme` — React Theme Toggle Hook (NEW PACKAGE) + +**Problem:** Near-identical `useTheme()` hook duplicated across **6 web apps** — only the storage key and class-application strategy differ. + +| Repo | File | Storage Key | Lines | +| ----------- | ------------------------------------ | ----------- | ----- | +| LocalMemGPT | `web/src/lib/use-theme.ts` | `lmg-theme` | 49 | +| LLM Lab | `dashboard/src/app/lib/use-theme.ts` | `llm-theme` | 48 | +| ChronoMind | `web/src/lib/use-theme.ts` | `cm-theme` | ~50 | +| FlowMonk | `web/src/lib/use-theme.ts` | `fm-theme` | ~50 | +| NomGap | `web/src/lib/use-theme.ts` | `ng-theme` | ~50 | +| ActionTrail | `web/src/lib/use-theme.ts` [R5] | `at-theme` | ~50 | + +**Proposed package:** `packages/use-theme/` + +```ts +export function useTheme(options?: { storageKey?: string; attribute?: 'class' | 'data-theme' }) { + // Configurable storage key (default: `${PRODUCT_ID}-theme`) + // Configurable DOM application (classList vs data-attribute) + // Returns { theme, setTheme, toggleTheme } +} +``` + +**Effort:** ~2 hours +**Priority:** P2 — saves ~300 total lines across 6 repos + +--- + +### 4.4 `@bytelyst/use-keyboard-shortcuts` — Keyboard Shortcuts Hook (NEW PACKAGE) + +**Problem:** Near-identical `useKeyboardShortcuts()` hook duplicated across **5+ web apps**, each with slight variations in handler names. + +| Repo | File | +| ----------- | ------------------------------------------------------------ | +| LocalMemGPT | `web/src/lib/use-keyboard-shortcuts.ts` (53 lines) | +| LLM Lab | `dashboard/src/app/lib/use-keyboard-shortcuts.ts` (57 lines) | +| ChronoMind | `web/src/lib/use-keyboard-shortcuts.ts` | +| ActionTrail | `web/src/lib/use-keyboard-shortcuts.ts` | +| NoteLett | `web/src/lib/use-keyboard-shortcuts.ts` | + +**Proposed package:** `packages/use-keyboard-shortcuts/` + +```ts +export function useKeyboardShortcuts(shortcuts: ShortcutDef[]) { + // Each ShortcutDef: { key, meta?, shift?, handler, allowInInput? } + // Data-driven instead of hardcoded if/else chains +} +``` + +**Effort:** ~3 hours +**Priority:** P2 — saves ~250 lines, improves consistency + +--- + +### 4.5 Ollama Model Types — Deduplicate into `@bytelyst/ollama-client` types + +**Problem:** `OllamaModel` interface is defined independently in both repos with slightly different shapes. + +| Repo | Definition | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| LocalMemGPT `ollama.ts` | `{ name, size, digest, modified_at, details?: { parameter_size, quantization_level, family } }` | +| LLM Lab `types.ts` | `{ name, model, modified_at, size, digest, details: { families, family, format, parameter_size, quantization_level } }` | + +**Resolution:** Canonical `OllamaModel` type in `@bytelyst/ollama-client/types.ts` — matches Ollama's actual API response. Both repos import from there. + +**Effort:** included in 4.1 +**Priority:** P0 (part of 4.1) + +--- + +### 4.6 LLM Lab `format.ts` Utilities — Promote Reusable Functions + +**Problem:** `format.ts` (96 lines) contains both LLM Lab-specific functions AND general-purpose utilities: + +| Function | Scope | Extraction Target | +| ------------------------- | ------------------------------------------------------ | --------------------------------------------------- | +| `formatBytes()` | **Reusable** — any repo needs byte formatting | `@bytelyst/ollama-client` or new `@bytelyst/format` | +| `estimateRam()` | LLM-infrastructure-specific | Keep in LLM Lab | +| `checkMemoryFit()` | LLM-infrastructure-specific | Keep in LLM Lab | +| `getModelBadges()` | LLM-infrastructure-specific | Keep in LLM Lab | +| `estimateTokens()` | **Reusable** — any LLM app needs token estimation | `@bytelyst/ollama-client` | +| `getModelContextWindow()` | **Reusable** — any LLM app needs context window lookup | `@bytelyst/ollama-client` | +| `formatUptime()` | **Reusable** — monitoring/ops dashboards | `@bytelyst/ollama-client` | + +**Effort:** ~1 hour (as part of 4.1) +**Priority:** P1 + +--- + +### 4.7 Client-Side SSE/NDJSON Stream Parser (Web) + +**Problem:** The client-side SSE parsing pattern is copy-pasted 3 times in LocalMemGPT's `web/src/lib/api.ts` (`streamChat`, `streamCompare`, plus a `parseSSEBody` in tests). LLM Lab has 3 more copies in `ConversationView.tsx`, `compare/page.tsx`, and `mission-control/page.tsx`. **[R6] Note:** After Phase 1, `ConversationView.tsx` and `compare/page.tsx` are deleted — LLM Lab reduces to 1 copy (Mission Control). Total post-Phase-1 copies: 4 (3 LocalMemGPT + 1 LLM Lab). + +**Proposed:** Export from `@bytelyst/ollama-client`: + +```ts +// Client-side SSE stream consumer +export function consumeSSEStream( + response: Response, + onData: (data: Record) => void, + onDone: () => void +): Promise; + +// Client-side NDJSON stream consumer +export function consumeNdjsonStream( + response: Response, + onChunk: (chunk: T) => void +): Promise; +``` + +**Effort:** ~2 hours (as part of 4.1) +**Priority:** P1 — eliminates 6 copy-pasted stream parsers + +--- + +### Phase 4 Summary + +| # | Package | Action | Lines Saved | Repos Affected | Priority | +| --- | ---------------------------------- | ---------- | ----------- | ----------------------- | -------- | +| 4.1 | `@bytelyst/ollama-client` | **NEW** | ~350 | 2 local AI + llm-router | P0 | +| 4.2 | `@bytelyst/fastify-sse` | **EXTEND** | ~26 | LocalMemGPT + future | P1 | +| 4.3 | `@bytelyst/use-theme` | **NEW** | ~300 | 6 web apps | P2 | +| 4.4 | `@bytelyst/use-keyboard-shortcuts` | **NEW** | ~250 | 5 web apps | P2 | +| 4.5 | (types in 4.1) | — | included | 2 local AI | P0 | +| 4.6 | (utils in 4.1) | — | ~40 | 2 local AI | P1 | +| 4.7 | (client parsers in 4.1) | — | ~180 | 2 local AI | P1 | + +**Total estimated savings:** ~1,150 lines of duplicated code across the ecosystem. + +**Recommended execution order:** + +1. **4.1** `@bytelyst/ollama-client` (biggest win, unblocks both repos) +2. **4.2** Extend `@bytelyst/fastify-sse` (small, quick) +3. **4.3 + 4.4** React hooks (lower priority, wider ecosystem impact — could batch with next DRY sweep) + +--- + +## Open Questions + +1. ~~**TTS/Whisper in Mission Control:**~~ **[F13] RESOLVED.** Mission Control uses `api/whisper` (status), `api/whisper/transcribe` (test), `api/tts` (engine status), `api/ollama/chat` (model testing), `api/ollama/stream` (benchmarks/compare), `api/ollama/logs` (log viewer). All 6 routes are kept. +2. **IndexedDB export:** Should we write a migration script that exports LLM Lab conversations into LocalMemGPT's import format? Only matters if the user has valuable conversations in LLM Lab. +3. **Phase 3 prioritization:** Which features (if any) from the optional port list are actually wanted? Recommend trying Phase 1+2 first, then deciding based on what's missed.