- Increase logo size (48x48 desktop, 56x56 mobile) for better visibility - Add logo as favicon - Add logo to mobile header - Move user menu to navigation bars (sidebar on desktop, bottom bar on mobile) - Fix desktop chat layout - container structure prevents voice controls cutoff - Fix mobile bottom bar - use icon-only ActionIcons instead of truncated text buttons - Hide Create Node/New Conversation buttons on mobile to save header space - Make fixed header and voice controls work properly with containers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
17 KiB
Ponderants App State Machine Architecture
Executive Summary
This document outlines the complete hierarchical state machine architecture for Ponderants, integrating the recently-completed Voice Mode with the full app experience: Conversation → Edit → Galaxy visualization.
Current Status: Voice Mode state machine is complete and tested (✅) Remaining Work: 3 major phases across ~15-20 implementation tasks
1. Current State (What We Have)
✅ Completed
-
Voice Mode State Machine (
lib/voice-machine.ts)- States: idle, checkingForGreeting, listening, userSpeaking, timingOut, submittingUser, waitingForAI, generatingTTS, playingTTS
- Fully tested with development controls
- Clean XState v5 implementation
-
Chat Interface (
app/chat/page.tsx)- Text input with AI responses
- Voice mode integration
- Initial greeting message
- User menu with logout
-
Authentication (OAuth with Bluesky/ATproto)
-
AI Integration (Vercel AI SDK with Gemini)
-
TTS (Deepgram API)
❌ Missing
- Node creation/extraction from conversation
- Node editing interface
- 3D galaxy visualization
- App-level state management
- Persistent navigation UI
- ATproto publishing
- Vector embeddings & linking
2. Hierarchical State Machine Architecture
Level 1: App Machine (Top Level)
┌─────────────────────────────────────────────────────────┐
│ APP MACHINE │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Convo │ ←──→ │ Edit │ ←──→ │ Galaxy │ │
│ │ │ │ │ │ │ │
│ └────┬────┘ └─────────┘ └─────────┘ │
│ │ │
│ └─── Manages: voiceMode / textMode │
└─────────────────────────────────────────────────────────┘
States:
convo: Active conversation (voice or text)edit: Editing a nodegalaxy: 3D visualization of node graph
Context:
{
currentNodeId: string | null;
pendingNodeDraft: NodeDraft | null;
nodes: Node[];
mode: 'mobile' | 'desktop';
}
Events:
EDIT_NODE(from conversation or save button)VIEW_GALAXY(from nav button)RETURN_TO_CONVO(from nav button)PUBLISH_NODE(from edit mode)CANCEL_EDIT
Level 2: Conversation Machine (Child of App.Convo)
┌─────────────────────────────────────────────────────────┐
│ CONVERSATION MACHINE │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Voice │ ←──────────────→ │ Text │ │
│ │ │ │ │ │
│ └────┬────┘ └─────────┘ │
│ │ │
│ └─── Embeds: voiceMachine (from lib/voice...) │
└─────────────────────────────────────────────────────────┘
States:
voice: Voice conversation mode (invokesvoiceMachine)text: Text-only conversation mode
Context:
{
messages: Message[];
suggestedNodes: NodeSuggestion[];
}
Events:
TOGGLE_VOICETOGGLE_TEXTSUGGEST_NODE(from AI)CREATE_NODE(user confirms suggestion)
Level 3: Voice Machine (Existing - Child of Conversation.Voice)
Already implemented in lib/voice-machine.ts. No changes needed.
3. Data Model
Node Schema
interface Node {
id: string; // ATproto record URI
title: string;
content: string; // Markdown
embedding: number[]; // gemini-embedding-001 (768 dims)
links: {
to: string; // Node ID
strength: number; // 0-1, from vector similarity
userApproved: boolean;
}[];
position3D: { x: number; y: number; z: number }; // UMAP coords
createdAt: Date;
updatedAt: Date;
published: boolean; // Published to ATproto PDS
}
interface NodeDraft {
title: string;
content: string;
conversationContext: Message[]; // Last N messages
}
interface NodeSuggestion {
draft: NodeDraft;
confidence: number; // AI's confidence in suggestion
}
4. UI Architecture
Responsive Navigation
Mobile (< 768px)
┌─────────────────────────────────────┐
│ App Content │
│ │
│ │
│ │
│ │
├─────────────────────────────────────┤
│ [Convo] [Edit] [Galaxy] │ ← Bottom Bar
└─────────────────────────────────────┘
Desktop (≥ 768px)
┌─────┬──────────────────────────────┐
│ │ │
│ C │ │
│ o │ App Content │
│ n │ │
│ v │ │
│ o │ │
│ │ │
│ E │ │
│ d │ │
│ i │ │
│ t │ │
│ │ │
│ G │ │
│ a │ │
│ l │ │
│ a │ │
│ x │ │
│ y │ │
├─────┴──────────────────────────────┤
│ User Menu │
└────────────────────────────────────┘
Component Structure
app/
├── layout.tsx (with AppShell from Mantine)
├── page.tsx (redirects to /chat)
└── chat/
└── page.tsx
components/
├── AppStateMachine.tsx (Provides app-level state context)
├── Navigation/
│ ├── MobileBottomBar.tsx
│ └── DesktopSidebar.tsx
├── Conversation/
│ ├── ConversationView.tsx (existing chat UI)
│ ├── VoiceControls.tsx (extracted from page)
│ ├── TextInput.tsx (extracted from page)
│ └── NodeSuggestionCard.tsx (NEW - shows AI suggestion)
├── Edit/
│ ├── NodeEditor.tsx (NEW - Mantine form with RTE)
│ └── LinkSuggestions.tsx (NEW - shows related nodes)
└── Galaxy/
├── GalaxyView.tsx (NEW - R3F canvas)
├── NodeMesh.tsx (NEW - 3D node representation)
└── ConnectionLines.tsx (NEW - edges between nodes)
lib/
├── app-machine.ts (NEW - top-level state machine)
├── conversation-machine.ts (NEW - voice/text toggle)
└── voice-machine.ts (EXISTING ✅)
hooks/
├── useAppMachine.ts (NEW)
├── useConversationMode.ts (NEW)
└── useVoiceMode.ts (EXISTING ✅)
5. Implementation Phases
Phase 1: App State Machine Foundation (Est: 2-3 hours)
Tasks:
- Create
lib/app-machine.tswith states: convo, edit, galaxy - Create
components/AppStateMachine.tsxprovider - Update
app/layout.tsxto wrap with provider - Create
hooks/useAppMachine.ts
Acceptance Criteria:
- Can transition between convo/edit/galaxy states
- State persists across page navigations
- Development panel shows current app state
Phase 2: Navigation UI (Est: 2-3 hours)
Tasks:
- Create
components/Navigation/MobileBottomBar.tsx- 3 buttons: Convo, Edit, Galaxy
- Highlights active mode
- Fixed position at bottom
- Create
components/Navigation/DesktopSidebar.tsx- Vertical layout
- Icons + labels
- Mantine NavLink components
- Update
app/layout.tsxwith responsive navigation - Add Mantine
AppShellfor layout management
Acceptance Criteria:
- Navigation shows on all pages
- Active state highlights correctly
- Clicking nav triggers state machine events
- Responsive (bottom bar mobile, sidebar desktop)
Phase 3: Node Creation Flow (Est: 4-5 hours)
Tasks:
- Update AI system prompt to suggest nodes
- Create
components/Conversation/NodeSuggestionCard.tsx- Shows AI-suggested node title/content
- "Save to Edit" and "Dismiss" buttons
- Update
conversation-machine.tsto handle:SUGGEST_NODEevent from AI responseCREATE_NODEevent from user action
- Implement node suggestion detection in AI response
- Wire up "Save to Edit" → transitions to Edit mode
Acceptance Criteria:
- AI can suggest creating a node during conversation
- Suggestion appears as card in chat
- Clicking "Save to Edit" transitions to edit mode with draft
- Draft includes conversation context
Phase 4: Node Editor (Est: 3-4 hours)
Tasks:
- Create
components/Edit/NodeEditor.tsx- Title input (Mantine TextInput)
- Content editor (Mantine RichTextEditor or Textarea with markdown preview)
- "Publish" and "Cancel" buttons
- "Continue Conversation" button
- Create
hooks/useNodeEditor.ts(Mantine form) - Implement publish flow:
- Generate embedding (gemini-embedding-001)
- Write to ATproto PDS
- Cache in SurrealDB
- Create
components/Edit/LinkSuggestions.tsx- Vector search for similar nodes
- User can approve/reject links
Acceptance Criteria:
- Can edit node title and content
- Markdown preview works
- "Publish" writes to ATproto + SurrealDB
- "Cancel" discards changes, returns to convo
- "Continue Conversation" saves draft, returns to convo
- Link suggestions appear based on embeddings
Phase 5: Galaxy Visualization (Est: 5-6 hours)
Tasks:
- Implement UMAP dimensionality reduction for nodes
- Create
components/Galaxy/GalaxyView.tsx- R3F Canvas with OrbitControls
- Dark space background
- Camera setup
- Create
components/Galaxy/NodeMesh.tsx- Sphere for each node
- Size based on node importance
- Color based on node age or category
- On hover: show tooltip with title
- On click: transition to Edit mode
- Create
components/Galaxy/ConnectionLines.tsx- Lines between linked nodes
- Opacity based on link strength
- Optimize rendering for 100+ nodes
Acceptance Criteria:
- Nodes render in 3D space
- Can orbit/zoom camera
- Clicking node opens it in Edit mode
- Links visible between related nodes
- Smooth performance with 100+ nodes
- Responsive (works on mobile)
Phase 6: Conversation Machine (Est: 2-3 hours)
Tasks:
- Create
lib/conversation-machine.ts- States: voice, text
- Invokes
voiceMachinein voice state
- Create
hooks/useConversationMode.ts - Refactor
app/chat/page.tsxto use conversation machine - Add voice/text toggle button
Acceptance Criteria:
- Can toggle between voice and text modes
- Voice mode properly invokes existing voiceMachine
- State transitions are clean
- Toggle button shows current mode
6. Remaining Work Breakdown
By Feature Area
| Feature | Tasks | Est. Hours | Priority |
|---|---|---|---|
| App State Machine | 4 | 2-3 | P0 (Foundation) |
| Navigation UI | 4 | 2-3 | P0 (Foundation) |
| Node Creation | 5 | 4-5 | P1 (Core Flow) |
| Node Editor | 4 | 3-4 | P1 (Core Flow) |
| Galaxy Viz | 5 | 5-6 | P1 (Core Flow) |
| Conversation Machine | 4 | 2-3 | P2 (Enhancement) |
| Testing | 6 | 3-4 | P0 (Ongoing) |
| ATproto Integration | 3 | 2-3 | P1 (Core Flow) |
| Vector Search | 2 | 2-3 | P1 (Core Flow) |
Total Estimation
- Core Features: 18-22 hours
- Testing & Polish: 3-4 hours
- Total: ~21-26 hours of focused development
By Priority
- P0 (Must Have): App machine, Navigation, Testing infrastructure
- P1 (Core Value): Node creation, Editor, Galaxy, ATproto, Vector search
- P2 (Enhancement): Conversation machine (voice/text toggle)
7. Technical Considerations
State Persistence
- Use
localStoragefor app state persistence - Restore state on page reload
- Clear state on logout
Performance
- Lazy load Galaxy view (code splitting)
- Virtualize node list in large graphs
- Debounce vector search queries
- Memoize UMAP calculations
Error Handling
- Graceful fallback if ATproto write fails
- Retry logic for network errors
- User-friendly error messages
- Rollback SurrealDB cache if PDS write fails
Accessibility
- Keyboard navigation for all UI
- ARIA labels for state machine controls
- Focus management on state transitions
- Screen reader announcements
8. Success Metrics
Must Pass Before Launch
- All magnitude tests pass
- Full user flow works: Convo → Node suggestion → Edit → Publish → Galaxy → View node
- No TypeScript errors
- Mobile and desktop layouts work
- Data writes to ATproto PDS successfully
- Vector search returns relevant results
Quality Bars
- State transitions are instant (< 100ms)
- Galaxy renders smoothly (60fps with 100 nodes)
- Voice mode integration doesn't break
- No console errors or warnings
9. Next Steps
Immediate (Start Here)
- Review this plan with user - Confirm priorities and scope
- Create app-machine.ts - Foundation for everything
- Build navigation UI - Visual feedback for state changes
- Implement node suggestion detection - Start extracting value from conversations
Short Term (This Week)
- Complete Phase 1 & 2 (App machine + Navigation)
- Begin Phase 3 (Node creation flow)
- Write magnitude tests for new flows
Medium Term (Next Week)
- Complete Phase 4 (Editor)
- Complete Phase 5 (Galaxy)
- Integration testing
10. Risk Assessment
Low Risk ✅
- App state machine (similar to voice machine)
- Navigation UI (standard Mantine components)
- Node editor (forms and RTE)
Medium Risk ⚠️
- ATproto publishing (OAuth flow works, but write API untested)
- Vector embeddings (API calls should work, but scale unknown)
- UMAP dimensionality reduction (library integration)
High Risk 🔴
- Galaxy performance on mobile (R3F can be heavy)
- Node suggestion detection from AI (prompt engineering needed)
- Link suggestion accuracy (depends on embedding quality)
Mitigation Strategies
- Galaxy: Start with simple spheres, add detail later. Implement LOD.
- Node Detection: Use structured output from Gemini if freeform fails
- Links: Allow manual link creation as fallback
Appendix A: File Tree (Post-Implementation)
app/
├── layout.tsx (AppShell + AppStateMachine provider)
├── page.tsx (redirect to /chat)
├── chat/page.tsx (Conversation view)
├── edit/page.tsx (Node editor view)
└── galaxy/page.tsx (3D visualization view)
components/
├── AppStateMachine.tsx
├── Navigation/
│ ├── MobileBottomBar.tsx
│ └── DesktopSidebar.tsx
├── Conversation/
│ ├── ConversationView.tsx
│ ├── VoiceControls.tsx
│ ├── TextInput.tsx
│ └── NodeSuggestionCard.tsx
├── Edit/
│ ├── NodeEditor.tsx
│ └── LinkSuggestions.tsx
└── Galaxy/
├── GalaxyView.tsx
├── NodeMesh.tsx
└── ConnectionLines.tsx
lib/
├── app-machine.ts (NEW)
├── conversation-machine.ts (NEW)
└── voice-machine.ts (EXISTING ✅)
hooks/
├── useAppMachine.ts (NEW)
├── useConversationMode.ts (NEW)
└── useVoiceMode.ts (EXISTING ✅)
api/
├── nodes/route.ts (CRUD for nodes)
├── embeddings/route.ts (Generate embeddings)
└── links/route.ts (Vector search for suggestions)