Files
adiuva/tasks/prd-neuraldesk.md
Roberto Musso f6cc8bb23a feat: US-001 — scaffold NeuralDesk Electron + React app
- electron-forge 7 + Vite plugin (vite-typescript template)
- React 19 + TypeScript 5 strict mode
- TanStack Router with file-based routing (4 routes: /, /timeline, /tasks, /projects)
- Tailwind CSS 3 + PostCSS with Figma design tokens (sidebar, primary, muted)
- Framer Motion, Lucide React, shadcn/ui utilities (cn, CVA, clsx, twMerge)
- AppShell layout: 240px sidebar with collapse toggle, active route highlighting
- Vite configs use .mts extension to avoid ESM/CJS conflict with electron-forge
- Full package build verified (linux x64)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 15:28:31 +01:00

26 KiB

PRD: NeuralDesk — MVP Implementation

Status: APPROVED / READY FOR DEV Version: 1.0 (MVP) Date: 2026-02-19 Stack: Electron · React · TypeScript · shadcn/ui · Tailwind · Drizzle ORM · SQLite · LanceDB · GitHub Copilot SDK Figma: Full File


Introduction

NeuralDesk is a local-first desktop workspace acting as a "Digital Executive Secretary." It centralizes notes, tasks, and project context into a local SQLite database and exposes a multi-agent AI layer (via GitHub Copilot SDK) that proactively surfaces insights and drafts actions. Data never leaves the machine, making it safe for enterprise environments.


Goals

  • Ship a working Electron desktop app with five sections: Home, Timeline, Tasks, Projects, Notes.
  • All data persisted locally in SQLite (zero cloud dependency for data storage).
  • Hierarchical Client → Sub-Client → Project structure fully navigable from a sidebar tree.
  • "Fluid Curtain" pull-down gesture that transitions any view into a full-screen AI chat scoped to the current context.
  • Multi-agent AI system (@Orchestrator, @ProjectAgent, @EmailAgent, @KnowledgeAgent) integrated via GitHub Copilot SDK.
  • Milestone completion = every section functional at the level described in User Stories below.

UI Summary (from Figma)

Shared Shell

  • Left sidebar: 240px, #fafafa background, border-right #e5e5e5.
    • Top: NeuralDesk logo/wordmark.
    • Nav items: Home (house icon), Timeline (chart-gantt icon), Tasks (clipboard-check icon), Projects (folder-kanban icon). Active item gets #f5f5f5 accent + no extra border.
    • Bottom: Collapse button (panel-left icon).
  • Right edge: Vertical rotated label "keep scrolling for AI / next section" + chevron-down. This is the visual affordance for the Fluid Curtain pull-down gesture.
  • Font: Geist (Regular 400, Medium 500, Semibold 600). Sizes: sm=14px, base=16px.
  • Colors: bg=#ffffff, foreground=#0a0a0a, muted=#737373, border=#e5e5e5, sidebar=#fafafa, sidebar-accent=#f5f5f5, primary=#171717, primary-fg=#fafafa.

HOME

  • Top-right corner: stat chip showing "N Task due" count.
  • Main area (centered, max-w ~1088px): AI greeting ✦ Hello, {name} (Heading 2, Geist Semibold 30px, -1px tracking).
  • Below: AI-generated daily brief paragraph with bold key phrases inline.
  • Chat input box: white, border #d4d4d4, shadow-lg, 109px tall, placeholder "Ask me anythings...", Send button (black, icon + label) bottom-right of the box.
  • Below chat: 4 suggestion chips (Item component) — icon badge + short prompt text — in a 4-column flex row.

TIMELINE

  • Main content area: placeholder background #fef2f2 (the Gantt chart is not yet designed in Figma; implementation is free to choose a library).
  • Same sidebar + right-edge Fluid Curtain affordance.

TASKS

  • Header row: 4 stat cards — "Total task", "To Do", "In Progress", "Completed" — each with an icon and count.
  • Below: search bar (full-width, placeholder "Search tasks or projects...") + "Order by" dropdown (right) + status filter tabs (All | To Do | In Progress | Completed).
  • Task list rows (flat, full-width):
    • Checkbox (left)
    • Title (bold, 14px) + description subtitle (gray, 14px)
    • Priority chip: HIGH (up-arrow, red-toned) | MEDIUM (right-arrow, gray) | LOW (down-arrow, green-toned)
    • Due date chip (calendar icon + "Due Mon DD")
    • Breadcrumb path (Client > Sub-Client > Project, chevron-separated)
    • Assignee (person icon + name string)
  • Completed tasks show row with green-tinted background.

PROJECTS

  • Left panel (tree): "Projects" heading + + new button + search input. Hierarchical tree: Client (folder, bold) → Sub-Client (folder) → Project (circle/file). Expand/collapse chevrons. Active project highlighted.
  • Right panel (project detail):
    • Breadcrumb (Client > Sub-Client) at top.
    • Project name as H1.
    • 3 stat cards: Notes count | Tasks Complete (x/y fraction) | Checkpoints (x/y fraction).
    • AI Project Summary card (sparkle icon + generated paragraph).
    • Project Timeline: inline Gantt — months across top (Feb 2026, Mar 2026 …), horizontal bar with dot markers for each checkpoint. Legend: To Do (dark) / Completed (green). "+ Add" button top-right.
    • Tasks (Kanban): 3 columns — To Do / In progress / Completed. Task cards: title, description, priority chip, due date, assignee. "+ Add" per column header.
    • Notes list: flat list of note entries + "+ Add" button.

NOTES

  • Milkdown editor (standalone route) for writing/editing a single note.
  • Markdown-native, full-screen editor style.

Data Schema

// clients — hierarchical (self-referencing parentId)
export const clients = sqliteTable('clients', {
  id: text('id').primaryKey(),          // UUID
  parentId: text('parent_id'),          // null = top-level client
  name: text('name').notNull(),
  industry: text('industry'),
  createdAt: integer('created_at').notNull(),
});

// projects — attached to a client/sub-client, or orphan
export const projects = sqliteTable('projects', {
  id: text('id').primaryKey(),
  clientId: text('client_id').references(() => clients.id), // nullable
  name: text('name').notNull(),
  status: text('status').default('active'),     // active | archived
  aiSummary: text('ai_summary'),               // AI-generated paragraph
  createdAt: integer('created_at').notNull(),
});

// tasks — belong to a project (or global/orphan if projectId null)
export const tasks = sqliteTable('tasks', {
  id: text('id').primaryKey(),
  projectId: text('project_id').references(() => projects.id), // nullable
  title: text('title').notNull(),
  description: text('description'),
  status: text('status').default('todo'),       // todo | in_progress | done
  priority: text('priority').default('medium'), // high | medium | low
  assignee: text('assignee'),                   // plain string name
  dueDate: integer('due_date'),                 // unix timestamp
  createdAt: integer('created_at').notNull(),
});

// checkpoints — milestones on the per-project timeline
export const checkpoints = sqliteTable('checkpoints', {
  id: text('id').primaryKey(),
  projectId: text('project_id').references(() => projects.id).notNull(),
  title: text('title').notNull(),
  date: integer('date').notNull(),              // unix timestamp
  isAiSuggested: integer('is_ai_suggested').default(0), // 0=manual, 1=AI
  isApproved: integer('is_approved').default(1),        // 0=pending AI approval
  createdAt: integer('created_at').notNull(),
});

// notes — markdown content attached to a project
export const notes = sqliteTable('notes', {
  id: text('id').primaryKey(),
  projectId: text('project_id').references(() => projects.id), // nullable
  title: text('title').notNull(),
  content: text('content').notNull(),           // raw Markdown
  createdAt: integer('created_at').notNull(),
  updatedAt: integer('updated_at').notNull(),
});

User Stories

PHASE 1 — Foundation


US-001: Electron + React scaffold

Description: As a developer, I need a working Electron app with React+TypeScript and a shared main/renderer process setup so that all other features have a platform to run on.

Acceptance Criteria:

  • electron-builder or electron-vite scaffold with hot-reload in dev.
  • Main process can open a BrowserWindow serving the React app.
  • TypeScript strict mode enabled, tsconfig.json configured.
  • package.json scripts: dev, build, preview.
  • App opens without errors on Linux, macOS, Windows.

US-002: SQLite database + Drizzle ORM setup

Description: As a developer, I need the SQLite database initialized with Drizzle ORM so that all CRUD operations use a typed, schema-driven interface.

Acceptance Criteria:

  • better-sqlite3 (or @electric-sql/pglite alternative) installed in main process.
  • Drizzle schema file defines all 5 tables (clients, projects, tasks, checkpoints, notes).
  • Migration runs on app start; DB file created at ~/.neuraldesk/data.db (or app.getPath('userData')).
  • Drizzle Studio accessible in dev mode (drizzle-kit studio).
  • TypeScript types inferred from schema (no manual type duplication).

US-003: App shell — sidebar navigation

Description: As a user, I want a persistent left sidebar so that I can navigate between all sections of the app.

Acceptance Criteria:

  • Sidebar renders at 240px with #fafafa background and right border.
  • Nav items: Home (house), Timeline (chart-gantt), Tasks (clipboard-check), Projects (folder-kanban). Each uses Lucide icon + label.
  • Active route highlights item with #f5f5f5 accent background.
  • Collapse button at bottom toggles sidebar to icon-only mode (64px).
  • Router renders correct view for each nav item (React Router or TanStack Router).
  • Verify in browser using dev-browser skill.

US-004: Client CRUD (hierarchical)

Description: As a user, I want to create, rename, and delete Clients and Sub-Clients so that I can mirror real-world corporate structures.

Acceptance Criteria:

  • "New Client" action creates a top-level client (parentId = null).
  • "New Sub-Client" action (available on a selected client) creates a child (parentId = selected client's id).
  • Client and Sub-Client names are editable via inline rename or modal.
  • Deleting a client warns if it has child clients or projects; cascade delete is opt-in.
  • Changes are immediately persisted to SQLite.
  • TypeScript types pass; no any.

US-005: Project CRUD

Description: As a user, I want to create projects attached to a client/sub-client or as standalone orphans so that I can track both client and internal work.

Acceptance Criteria:

  • "New Project" dialog asks for name and optionally a client (dropdown, searchable).
  • Projects with no client appear under an "Internal / No Client" group in the tree.
  • Project can be re-parented (moved to a different client) via edit dialog.
  • Project status toggled between active and archived.
  • Archived projects hidden by default; toggle to show.
  • Persisted to SQLite immediately.

US-006: Projects sidebar tree view

Description: As a user, I want to see all clients, sub-clients, and projects in a collapsible tree in the Projects section so that I can navigate the hierarchy at a glance.

Acceptance Criteria:

  • Tree renders: Client (folder icon) → Sub-Client (folder icon) → Project (circle icon).
  • Clients and sub-clients expand/collapse independently.
  • Search input filters tree in real-time (client name, sub-client name, project name).
  • Clicking a project loads the Project Detail panel on the right.
  • Active project is highlighted in the tree.
  • Verify in browser using dev-browser skill.

US-007: Task CRUD (global Tasks view)

Description: As a user, I want a global task list where I can create, filter, search, and update tasks so that I can manage all work across projects in one place.

Acceptance Criteria:

  • 4 stat cards at top: Total, To Do, In Progress, Completed — update reactively.
  • Search filters tasks by title or description, case-insensitive.
  • Status filter tabs (All | To Do | In Progress | Completed) filter list.
  • "Order by" dropdown supports: Due Date, Priority, Created Date.
  • Task rows show: checkbox, title, description, priority chip (HIGH/MEDIUM/LOW with color), due date chip, breadcrumb (Client > Sub-Client > Project), assignee.
  • Clicking checkbox toggles status: todo → done (skip in_progress for quick-complete).
  • Inline "New Task" button opens a creation modal with fields: title, description, priority, due date, project (optional), assignee (optional).
  • All changes persisted to SQLite.
  • Verify in browser using dev-browser skill.

US-008: Manual Timeline (global & per-project)

Description: As a user, I want to view and manually create timeline checkpoints on a Gantt-style view so that I have full control over milestone dates.

Acceptance Criteria:

  • Timeline view renders a horizontal time axis (months) with dot markers for each checkpoint.
  • Global Timeline shows checkpoints from all projects (color-coded by project or status).
  • Per-project timeline (in Project Detail) scoped to that project's checkpoints only.
  • "+ Add" button opens a dialog: title, date picker, project (in global view).
  • Checkpoint dots distinguish status: To Do (dark/filled) vs Completed (green).
  • "Today" marker line displayed on the timeline.
  • Clicking a checkpoint dot shows a popover with title, date, and delete action.
  • Persisted to SQLite.
  • Verify in browser using dev-browser skill.

US-009: Project Detail view

Description: As a user, I want a rich project detail panel that shows notes count, tasks summary, AI summary, timeline, Kanban, and notes list in one scrollable view.

Acceptance Criteria:

  • Breadcrumb (Client > Sub-Client) rendered at top.
  • Stat cards: Notes count | Tasks Complete (x/y) | Checkpoints (x/y).
  • AI Project Summary card shows sparkle icon + placeholder text ("AI summary will appear here") until agent generates it.
  • Inline Project Timeline (same Gantt component as US-008, scoped).
  • Kanban board: To Do / In Progress / Completed columns. Task cards show title, description, priority, due date, assignee. Drag between columns updates status.
  • Notes list: title + creation date for each note. Click opens Milkdown editor. "+ Add" creates new note.
  • Verify in browser using dev-browser skill.

US-010: Notes editor (Milkdown)

Description: As a user, I want a full-screen Markdown editor for each note so that I can write rich content without leaving the app.

Acceptance Criteria:

  • Milkdown editor renders in a dedicated route (/notes/:noteId).
  • Supports: headings, bold, italic, code blocks, bullet lists, ordered lists, blockquotes.
  • Auto-saves content to SQLite on change (debounced, 500ms).
  • Back navigation returns to the project detail view (or previous location).
  • Note title editable at the top (separate from Milkdown content).
  • Verify in browser using dev-browser skill.

PHASE 2 — The Fluid Curtain & Agents


US-011: Fluid Curtain — pull-down gesture + animation

Description: As a user, I want to pull down from the top of any view to slide the app off-screen and reveal the AI chat layer beneath.

Acceptance Criteria:

  • Scrolling up past the top of content (overscroll) OR pressing a keyboard shortcut (e.g., Cmd/Ctrl+K or ⌥↓) triggers the curtain.
  • App panel slides down using Framer Motion spring animation, exiting the bottom of the viewport.
  • AI Chat view is fully revealed below (full-screen, no sidebar obstruction).
  • Pulling the app back up (swipe/scroll from bottom or shortcut) re-covers the chat.
  • Animation is smooth (no jank). Spring config: stiffness 300, damping 30.
  • Right-edge "keep scrolling for AI" label and chevron are visible in every section as the affordance.
  • Verify in browser using dev-browser skill.

US-012: Context-scoped AI chat

Description: As a user, I want the AI chat (revealed by the curtain) to know the context I was in so that answers are scoped to the right project or global scope.

Acceptance Criteria:

  • When curtain is pulled from a Project Detail view, a context header displays "Chatting about: [Project Name]".
  • When pulled from Home, context is global (all data).
  • Context is passed as a system message to the GitHub Copilot SDK call (project notes, tasks, checkpoints as structured JSON).
  • Agent responses reference only documents within the scoped project.
  • Chat history is session-only (not persisted in MVP).

US-013: GitHub Copilot SDK integration + @Orchestrator

Description: As a developer, I need the GitHub Copilot SDK wired up with an Orchestrator agent that routes user messages to the correct specialist agent.

Acceptance Criteria:

  • SDK initialized in main process with enterprise credentials (from env/config).
  • @Orchestrator reads user intent and calls route_to_project, route_to_general, or route_to_email tool.
  • Routing result invokes the correct specialist agent and returns its response.
  • Streaming responses supported (tokens shown incrementally in chat UI).
  • Errors handled gracefully (SDK timeout, auth failure) with user-facing message.

US-014: @ProjectAgent with project tools

Description: As a user, I want the AI to answer project-specific questions and take actions (add task, suggest checkpoints) within the scoped project.

Acceptance Criteria:

  • read_project_notes tool fetches all notes for the project from SQLite.
  • add_task tool creates a task in the project (writes to SQLite) and confirms in chat.
  • suggest_checkpoints tool returns a list of proposed checkpoints (title + date) as interactive cards in chat (Approve / Reject each).
  • Approved checkpoints are inserted into checkpoints table with is_ai_suggested=1, is_approved=1.
  • get_summary tool generates a 2-3 sentence project summary and updates projects.ai_summary in SQLite.

PHASE 3 — Intelligence & RAG


US-015: LanceDB vector store setup + note embedding

Description: As a developer, I need notes and project content embedded into LanceDB so that semantic search is possible across all projects.

Acceptance Criteria:

  • LanceDB initialized in main process, storing vectors at ~/.neuraldesk/vectors/.
  • On note save (create or update), content is embedded via GitHub Copilot SDK embeddings endpoint and stored in LanceDB with {noteId, projectId, content} metadata.
  • Existing notes are indexed on first startup (migration script).
  • Embedding errors logged but do not block the save operation.

US-016: @KnowledgeAgent — semantic search across all projects

Description: As a user, I want to ask "what did we decide about X?" and get answers pulled from across all past project notes, not just the current one.

Acceptance Criteria:

  • vector_search_all tool accepts a query string, returns top-5 semantically similar note chunks from LanceDB.
  • Results include source note title and project name for attribution.
  • @Orchestrator routes knowledge queries to @KnowledgeAgent.
  • Response in chat includes inline citations ("From: Project A — Meeting Notes, Feb 12").

US-017: AI checkpoint suggestions from notes

Description: As a user, I want the AI to proactively analyze my meeting notes and suggest timeline checkpoints I may have missed.

Acceptance Criteria:

  • Triggered manually ("Suggest checkpoints" button in Project Detail timeline header) or by @ProjectAgent tool call.
  • @ProjectAgent reads all notes for the project, extracts date-anchored commitments, returns as suggested checkpoints.
  • Suggestions appear as dismissible cards in the Timeline UI with isAiSuggested=1, isApproved=0.
  • Approve → isApproved set to 1, checkpoint appears on timeline.
  • Reject → checkpoint deleted.
  • Verify in browser using dev-browser skill.

US-018: Home dashboard — AI daily brief

Description: As a user, I want the Home screen to greet me with an AI-generated daily brief summarizing my tasks and suggesting actions.

Acceptance Criteria:

  • On app open, @Orchestrator queries tasks due today/this week and recent project activity.
  • AI generates a personalized paragraph with key highlights (tasks due, suggested calls/emails).
  • Brief is displayed below the greeting with bold key phrases inline (as in Figma).
  • 4 suggestion chips below the chat box are pre-populated with context-relevant queries.
  • Chat box on Home is scoped globally (no project context).
  • Verify in browser using dev-browser skill.

Functional Requirements

  • FR-01: All data stored locally in SQLite at app.getPath('userData')/neuraldesk.db.
  • FR-02: App functions fully offline; AI features degrade gracefully when network is unavailable.
  • FR-03: Client tree supports unlimited nesting depth but UI only needs to display 3 levels (Client → Sub-Client → Project).
  • FR-04: Tasks table has a nullable projectId; global Tasks view shows all tasks regardless.
  • FR-05: The "Fluid Curtain" animation must not lose the underlying view state (app slides but remains mounted).
  • FR-06: GitHub Copilot SDK credentials are stored in OS keychain (not plaintext config).
  • FR-07: Milkdown auto-save uses a 500ms debounce; unsaved indicator shown if pending.
  • FR-08: All IDs are UUIDs (use crypto.randomUUID()).
  • FR-09: Drizzle migrations run automatically on startup; never destructive.
  • FR-10: Kanban drag-and-drop updates tasks.status and tasks.updatedAt immediately in SQLite.

Non-Goals (Out of Scope for MVP)

  • Email client / inbox integration (EmailAgent tools are stubs only).
  • Cloud sync or multi-device support.
  • Real assignee accounts (assignee is a plain name string, not a user entity).
  • Notifications or system tray alerts.
  • Dark mode.
  • Mobile or web version.
  • Export to PDF/CSV.
  • Notes version history.

Design Considerations

  • Font: Geist via @fontsource/geist or CDN. Apply globally via CSS variable.
  • Icons: Lucide React (house, chart-gantt, clipboard-check, folder-kanban, panel-left, send, sparkles, chevron-down).
  • Gantt: Custom SVG component. Month labels on X axis, <circle> dots for checkpoints, <line> baseline, <TodayMarker>. Use ResizeObserver for responsive width.
  • Kanban: @hello-pangea/dnd<DragDropContext> wrapping 3 <Droppable> columns, each task a <Draggable>.
  • Fluid Curtain: framer-motion useMotionValue + useSpring. Trigger: wheel event at scrollTop === 0 && deltaY < 0 OR Cmd/Ctrl+K. Right-edge "keep scrolling for AI" label is a visual hint only (not interactive).
  • shadcn/ui components to reuse: Button, Input, Badge, Card, Dialog, Separator, Tabs, Tooltip, DropdownMenu, Popover.

Technical Considerations

  • IPC: electron-trpc. Define a single appRouter in main process exposing all domains (tasks, projects, clients, checkpoints, notes, ai). Renderer uses trpc.[domain].[procedure].useQuery/useMutation(). Zod validates all inputs at the boundary.
  • GitHub Copilot SDK may require enterprise SSO token; provide a settings screen for token input (US not in MVP scope, but infrastructure must exist).
  • LanceDB Node.js binding (vectordb package) runs in main process only.
  • Milkdown v7+ with React adapter. Plugin list: commonmark, history, clipboard, math (optional).
  • Use electron-store or conf for lightweight app settings (user name for greeting, sidebar collapsed state, etc.).

Success Metrics

  • All 5 sections navigable and functional with real SQLite-persisted data.
  • Fluid Curtain animation runs at 60fps with no layout shift on return.
  • @ProjectAgent correctly scopes a context query (zero responses sourcing from another project).
  • Note embedding + LanceDB retrieval returns relevant results for a simple semantic query.
  • App cold-start < 3 seconds on a modern machine.

Open Questions

  1. Gantt library vs. custom SVG? Resolved: custom SVG component.
  2. GitHub Copilot SDK auth flow: Resolved: keytar (OS keychain). A minimal "Settings" screen for token input writes to keychain on save.
  3. IPC architecture: Resolved: electron-trpc with Zod validation. All DB/AI operations exposed as tRPC procedures in main process; renderer uses typed React Query hooks.
  4. Milkdown vs. simpler editor: Milkdown is powerful but has a learning curve. Is a simpler CodeMirror-based Markdown editor acceptable for MVP?
  5. "Fluid Curtain" on Linux: Overscroll behavior differs across OS/window managers. What's the fallback trigger (keyboard shortcut only)?

Implementation Roadmap

Phase 1 — Foundation (US-001 → US-010)

Step Story Key Decision Point
1.1 US-001: Electron+React scaffold electron-forge + Vite plugin (npm init electron-app@latest -- --template=vite-typescript)
1.2 US-002: SQLite + Drizzle setup Schema finalized; migrations strategy
1.3 US-003: App shell + sidebar TanStack Router (fully type-safe, $projectId params typed)
1.4 US-004 + US-005: Client & Project CRUD Data model confirmed
1.5 US-006: Projects tree view Radix Collapsible + recursive TreeNode (no extra dep, matches Figma)
1.6 US-007: Tasks global view
1.7 US-008: Manual Timeline / Gantt Custom SVG component (dot-on-axis, zero deps, matches Figma exactly)
1.8 US-009: Project Detail view @hello-pangea/dnd for Kanban drag-and-drop
1.9 US-010: Milkdown editor Plugin scope for MVP

Phase 2 — The Curtain & Agents (US-011 → US-014)

Step Story Key Decision Point
2.1 US-011: Fluid Curtain animation Wheel overscroll-up at scrollTop=0 + Cmd/Ctrl+K shortcut. Right-edge label is visual-only (not a button). Framer Motion spring (y to viewport height).
2.2 US-012: Context-scoped chat UI Chat bubble components, streaming UI
2.3 US-013: Copilot SDK + @Orchestrator keytar for OS keychain token storage (main process only, IPC to renderer).
2.4 US-014: @ProjectAgent tools Tool schema definition + SQLite write-back

Phase 3 — Intelligence & RAG (US-015 → US-018)

Step Story Key Decision Point
3.1 US-015: LanceDB setup + embedding GitHub Copilot SDK embeddings (text-embedding-3-small). Chunk notes by paragraph (~500 tokens).
3.2 US-016: @KnowledgeAgent search Vector search tuning, k=5 default
3.3 US-017: AI checkpoint suggestions Prompt engineering for date extraction
3.4 US-018: Home daily brief Orchestrator routing for daily summary