| Week | Theme | Key Deliverables |
|---|---|---|
| 1 | Foundation | Auth (Clerk), DB (Neon/Drizzle), Billing (Stripe) |
| 2 | Agent Runtime | Prompt compiler, AI SDK v6 integration, 81 agents compiled |
| 3 | Chat UI | Skill dispatch, persona system, chat container |
| 4 | Google Drive | OAuth, workspace files, file explorer |
| 5 | Context Layer | BYOT keys, token metering, context save/recall |
| 6 | Sub-Agents | Spawn agent tool, skill execution, ROI tracking |
| 7 | Gateways | Meeting Mode, PLT orchestration, 11 gateways |
| 8 | Onboarding | 5-step flow, settings pages, error boundaries |
| 9 | Beta Ready | Search, P0 fixes, invite system, feedback |
| Metric | Count |
|---|---|
| AI Agents | 81 |
| Skills | 61 |
| Gateways | 11 |
| DB Tables | 10 |
| API Routes | 22 |
| Components | 30+ |
6 tasks, 25 files changed, 1,233 lines added
Problem: Every time streaming finished, ALL messages were POSTed as INSERT-only. After 3 saves of a 10-message conversation, DB had 30 rows.
Fix:
replaceMessages() — transactional DELETE + INSERTmessages/route.ts, messages.ts, chat-container.tsxProblem: Full message history passed to streamText(). Long conversations would exceed model context limits and fail.
Fix:
context-window.ts — Token estimator (chars/4) + truncation strategycontext-window.ts (new), runtime.tsPostgres FTS instead of Typesense — zero infrastructure, auto-updating.
tsvector columns on conversations (title) and context_entries (title + content)/api/search — conversations + agents + skills + contextGET /api/drive/status — lightweight health checkconnected / disconnected / not_configuredresolveWorkspace() now returns { fallback: boolean }Inline Rename: Replaced window.prompt() with inline :
hasMore, loadMoreConversations()?offset= and ?limit= paramsSchema: invite_codes + beta_feedback tables
Invite Flow:
POST /api/invite/validate — check code without redeemingPOST /api/invite/redeem — increment usage counterPOST /api/feedback stores to DB1. Seed an invite code:
INSERT INTO invite_codes (code, max_uses)
VALUES ('BETA2026', 50);Start dev server:
cd C:\dev\legionis && npm run dev
Open: http://localhost:4321
DB check (optional):
SELECT count(*) FROM messages
WHERE conversation_id = '';
-- Should equal actual message count
[agent:X] Truncated N -> M messagesGET /api/drive/status directly to verify JSON responseSELECT * FROM beta_feedback;| # | Area | What to Check | Pass Criteria |
|---|---|---|---|
| 1 | Messages | No duplicates after reload | Count matches actual |
| 2 | Context | 30+ turn conversation works | No errors, agent responds |
| 3 | Search | Cmd+K finds conversations | Results appear, grouped |
| 4 | Drive | Status badge in sidebar | Correct status shown |
| 5 | Rename | Inline edit on conversations | Enter saves, Esc cancels |
| 6 | Pagination | 50+ conversations load more | Button appears and works |
| 7 | Invite | New user needs code | Invalid rejected, valid accepted |
| 8 | Feedback | Submit feedback | Stored in DB |
Browser (Next.js App Router)
+-- Clerk Auth
+-- Zustand Stores (conversations, search)
+-- Chat Container (useChat + AI SDK)
+-- Command Palette (Cmd+K)
+-- Feedback Button
API Routes (Vercel Serverless)
+-- /api/chat (Agent Runtime + streamText)
+-- /api/search (Unified FTS)
+-- /api/conversations (CRUD + pagination + search)
+-- /api/drive/* (OAuth, files, status)
+-- /api/invite/* (validate, redeem)
+-- /api/feedback (CRUD)
+-- /api/webhooks/* (Clerk, Stripe)
Neon PostgreSQL
+-- 10 tables (users, workspaces, api_keys,
conversations, messages, context_entries,
file_references, usage_events, subscriptions,
invite_codes, beta_feedback)
+-- FTS indexes (tsvector + GIN)
Google Drive API v3
+-- Workspace files
+-- Agent deliverables
| File | Change |
|---|---|
messages/route.ts | Transactional replace |
chat-container.tsx | Dedup hash guard |
context-window.ts | NEW: Token estimation + truncation |
runtime.ts | Apply truncation before streamText |
conversations.ts | FTS search + pagination |
context-entries.ts | FTS search |
conversations/route.ts | ?q= search, ?offset/?limit |
search/route.ts | NEW: Unified search API |
command-palette.tsx | NEW: Cmd+K dialog |
sidebar.tsx | Search button, inline rename, load more, Drive badge |
drive/status/route.ts | NEW: Health check |
drive-status-badge.tsx | NEW: Sidebar status indicator |
resolve-workspace.ts | Returns fallback flag |
schema.ts | invite_codes + beta_feedback tables |
invite-codes.ts | NEW: Query functions |
beta-feedback.ts | NEW: Query functions |
invite/validate/route.ts | NEW: Code validation |
invite/redeem/route.ts | NEW: Code redemption |
feedback/route.ts | NEW: Feedback CRUD |
onboarding/page.tsx | Invite code step (6 steps total) |
feedback-button.tsx | NEW: Floating feedback UI |
dashboard/layout.tsx | Mount CommandPalette + FeedbackButton |
conversation-store.ts | hasMore + loadMore + PAGE_SIZE |
0001_fts_indexes.sql | NEW: FTS migration |