- Created prd.json with detailed user stories, acceptance criteria, and implementation notes for the Adiuva project. - Updated progress.txt to reflect recent implementations of routers for checkpoints and notes, along with learnings for future iterations. - Modified ralph.sh to change the default tool from "amp" to "claude" for improved compatibility.
26 KiB
PRD: Adiuva — 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
Adiuva 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,
#fafafabackground, border-right#e5e5e5.- Top: Adiuva logo/wordmark.
- Nav items: Home (house icon), Timeline (chart-gantt icon), Tasks (clipboard-check icon), Projects (folder-kanban icon). Active item gets
#f5f5f5accent + 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 (
Itemcomponent) — 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-builderorelectron-vitescaffold with hot-reload in dev.- Main process can open a
BrowserWindowserving the React app. - TypeScript strict mode enabled,
tsconfig.jsonconfigured. package.jsonscripts: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/pglitealternative) 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
~/.adiuva/data.db(orapp.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
#fafafabackground 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
#f5f5f5accent 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
activeandarchived. - 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+Kor⌥↓) 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).
@Orchestratorreads user intent and callsroute_to_project,route_to_general, orroute_to_emailtool.- 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_notestool fetches all notes for the project from SQLite.add_tasktool creates a task in the project (writes to SQLite) and confirms in chat.suggest_checkpointstool returns a list of proposed checkpoints (title + date) as interactive cards in chat (Approve / Reject each).- Approved checkpoints are inserted into
checkpointstable withis_ai_suggested=1, is_approved=1. get_summarytool generates a 2-3 sentence project summary and updatesprojects.ai_summaryin 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
~/.adiuva/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_alltool 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 →
isApprovedset 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')/adiuva.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.statusandtasks.updatedAtimmediately 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/geistor 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>. UseResizeObserverfor responsive width. - Kanban: ✅
@hello-pangea/dnd—<DragDropContext>wrapping 3<Droppable>columns, each task a<Draggable>. - Fluid Curtain: ✅
framer-motionuseMotionValue+useSpring. Trigger:wheelevent atscrollTop === 0 && deltaY < 0ORCmd/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 singleappRouterin main process exposing all domains (tasks,projects,clients,checkpoints,notes,ai). Renderer usestrpc.[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 (
vectordbpackage) runs in main process only. - Milkdown v7+ with React adapter. Plugin list:
commonmark,history,clipboard,math(optional). - Use
electron-storeorconffor 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
Gantt library vs. custom SVG?✅ Resolved: custom SVG component.GitHub Copilot SDK auth flow:✅ Resolved:keytar(OS keychain). A minimal "Settings" screen for token input writes to keychain on save.IPC architecture:✅ Resolved:electron-trpcwith Zod validation. All DB/AI operations exposed as tRPC procedures in main process; renderer uses typed React Query hooks.- Milkdown vs. simpler editor: Milkdown is powerful but has a learning curve. Is a simpler
CodeMirror-based Markdown editor acceptable for MVP? - "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 |