MemoDocumentation
EN

Frontend Design

Memo's user interface is a Flutter desktop application (with a mobile companion) following the "Greige" (pewter study) design language — warm neutrals, bronze accents, clear contrast, no harsh whites.

Technology Stack

Layer Technology
Framework Flutter 3.10+ (Dart)
State Management Riverpod (AsyncNotifierProvider)
HTTP Client Dio (request + SSE streaming)
Routing GoRouter (declarative, path-based)
Icons Phosphor Icons (Bold weight, MIT licensed)
SVG flutter_svg (provider logos)
Markdown Custom markdown renderer with code highlighting

Design Language: "Greige"

The color palette uses warm, muted neutrals:

Token Purpose Value
--surface Primary background Warm dark grey
--surface-2 Secondary surface (cards, panels) Slightly lighter
--ink Primary text Off-white
--ink-dim Secondary text Muted warm grey
--ink-faint Tertiary text, labels Faded grey
--line Borders, dividers Subtle grey
--bronze-bright Active / accent Warm bronze/gold
--bronze-deep Accent borders Deep bronze
--bronze-pale Accent backgrounds Pale bronze wash

Typography uses var(--body) (sans-serif, 0.88rem base) and var(--mono) (monospace, 0.84rem) font stacks.

State Management: Riverpod

// Example: Chat provider
final chatProvider = AsyncNotifierProvider<ChatNotifier, ChatState>(
  ChatNotifier.new,
);

class ChatNotifier extends AsyncNotifier<ChatState> {
  Future<void> sendMessage(String text) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      final client = ref.read(apiClientProvider);
      final stream = await client.postChatStream(text);
      // Process SSE events, update state incrementally
      return updatedState;
    });
  }
}

Key providers:

Provider Purpose
chatProvider Active conversation state, message list, streaming
memoryProvider Memory search, analytics, import/export
providerListProvider External provider configurations
modelListProvider Downloaded and available models
agentProvider Agent execution state, permission dialogs
orchestraProvider Orchestra config, role assignments
whatsappProvider Connection state, messages, contacts
calendarProvider Events, reminders, settings
moodProvider Mood score, engine toggle
skillListProvider Installed and active skills
settingsProvider General app settings

API Client: MemoApiClient

// frontend/lib/core/api_client.dart
class MemoApiClient {
  final Dio _dio;
  static const baseUrl = 'http://localhost:8090';

  // Chat
  Future<Stream<SSEEvent>> postChatStream(ChatRequest req);
  Future<ChatResponse> postChat(ChatRequest req);
  Future<void> stopChat();

  // Memory
  Future<List<Memory>> searchMemory(String query, {int topK = 5});
  Future<void> rememberMemory(String text);
  Future<int> forgetMemory(String pattern);
  Future<MemoryAnalytics> getMemoryAnalytics();

  // Providers
  Future<List<ProviderConfig>> getProviders();
  Future<void> saveProvider(ProviderConfig config);
  Future<void> deleteProvider(String name);

  // ... ~90 method signatures mirroring backend endpoints
}

Dio is configured with a singleton Provider<MemoApiClient> pattern. SSE streams are parsed with dio.request() using responseType: ResponseType.stream.

Main Screens

Screen Path Purpose
Chat / Main chat interface with message list, input, engine strip
Agent /agent Agent mode chat with tool-calling UI
Model Store /store Two-panel model discovery and download
WhatsApp /whatsapp WhatsApp chat list and messaging
Calendar /calendar Monthly grid, event list, add/edit
Settings /settings 12-tab configuration panel

Settings Tabs (12)

Each tab is a focused widget under frontend/lib/widgets/settings/tabs/:

Tab File Content
General general_tab.dart Name, language, theme, memory toggle, web search mode
System Prompt system_prompt_tab.dart Identity prompt editor with preset selector
Incognito Prompt incognito_prompt_tab.dart Separate prompt for incognito mode
Memory memory_tab.dart RAG config, debug search, analytics, import/export
API Providers provider_tab.dart Provider list, add/edit with per-model context window
Orchestra orchestra_tab.dart Role config, chief model, quick-setup button
Agent Permissions agent_permissions_tab.dart Tool permission policies (6-level)
Skills skills_tab.dart Skill list, install, activate, remove
GPU Config gpu_config_tab.dart llama.cpp settings, GPU layers, VRAM
Backup backup_tab.dart Cloud sync setup, export, restore, wipe
Remote Access remote_access_tab.dart ngrok, Tailscale, LAN binding
About about_tab.dart Version, license, credits, update check

The settings tab sidebar shows Phosphor Bold icons alongside labels. The active tab's icon lights up in accent color; inactive tabs use textDim.

Provider & Orchestra Config Dialogs

Provider Dialog

  • Provider type selector (OpenAI, Claude, Gemini, Grok, Groq, OpenRouter, Ollama)
  • API key field (masked, encrypted storage)
  • Model ID and context window (tokens)
  • Enabled/disabled toggle with priority ordering
  • Test connection button

Orchestra Dialog

  • Visual explainer: "Chief plans → Specialists run in parallel → Synthesis"
  • Quick setup: assign one model to the chief and all enabled roles at once
  • Collapsible role cards (icon, name, assigned model, on/off toggle)
  • System prompt tucked under "Advanced" expandable
  • Enabled-role count in header, unassigned role warning icons

Engine Strip

A persistent footer bar showing:

┌─────────────────────────────────────────────┐
│ 🟢 llama-3.1-8b-instruct  │  ◼ stop all    │
│ 🟢 nomic-embed-text-v1.5   │  🤖 OpenAI     │
└─────────────────────────────────────────────┘
  • Green dot = running, orange = starting, red = stopped, grey = no model
  • Shows both the chat model and embedding model
  • Active external provider shown with company logo + name
  • "◼ stop all" button kills all active LLM processes
  • Mood score gauge visible when mood engine is active

Key Design Patterns

  1. Mounted checks: Always if (!mounted) return; before setState in async callbacks
  2. Provider invalidation: ref.invalidate(provider) after mutations to trigger UI rebuilds
  3. Error handling: AsyncValue.guard() wraps all async operations
  4. Feature cards: Launchpad welcome screen with explanatory cards
  5. Empty states: Explanatory text when a feature has no data
  6. Tooltips: Descriptive hints on mode badges (Incognito, Agent, WhatsApp)

Responsive Layout

Breakpoint Behavior
> 1200px Full sidebar (280px) + content + optional right panel
860–1200px Collapsible sidebar with toggle button
< 860px Mobile layout — sidebar as overlay, full-width content

The mobile companion app shares the same codebase and adapts the layout for smaller screens.