Memo UI — Feature Inventory
1. NAVIGATION (app_shell.dart)
- AppShell → NavRail (64px) + IndexedStack
- NavRail (v5.0): Logo, Chats, Models, Calendar, Mail, Routines, Developer, Swarm (beta-gated, hidden unless Settings → Beta Features is on and the platform supports it — not macOS), Settings (dialog). The old Agent and WhatsApp tabs are gone: agent chats live in the one chat list (marked with a robot) and WhatsApp/Telegram pairing lives in Settings and the setup wizard's Channels step
- Active tab: filled icon, accent color
- SetupWizardOverlay (first launch; see §5.9)
- LlamaInstallerOverlay (download progress)
- VersionBanner (update notification)
- Theme: light/dark toggle (System, Light, Dark)
2. CHAT SCREEN (chat_screen.dart)
- Width: 260px
- Search bar (filter by title)
- "New Chat" button
- Chat list: title, preview, timestamp, delete on hover
- Active chat highlight
- A small spinner on every chat that is generating a reply right now (and a "just finished" mark right after) — background tasks, WhatsApp/Telegram replies, other browser tabs and Claude Code/Codex sessions included (v4.6.0,
GET /api/chats/streaming)
- Empty state: "No chats yet"
2.2 Top Bar (_ChatTopBar)
- Title + badges (incognito, agent, agent project)
- Badge styles: icon + label, colored bg 12% alpha
- Action buttons: Undo (agent), WhatsApp toggle, Export (markdown)
- Model picker (
widgets/model_picker.dart, v4.6.0): a panel, not a popup menu. Height capped to the room below the button, scrolls inside, search box once there are more than seven rows, foldable vendor sections, model-family logos, readable names from prettyModelName ("Gemini 3.7 Flash" + a "High" tag; the raw id is what is stored and sent). Subscriptions models carry a remaining-allowance badge (quota_badge.dart) and time to refill; the picker re-reads quota 2.5 s after opening and every 50 s. chat_input.dart's own switcher still lists raw ids
2.3 Messages Area
- WelcomeView (empty state): Logo, tagline, feature cards, quick actions
- ChatMessageList: scrollable, auto-scroll, RepaintBoundary per bubble
- Context ring (
widgets/context_ring.dart, in the engine strip at the foot of the chat, v4.6.0): an 18 px ring filled to the share of the model's window in use — accent, amber within 15 points of the auto-compact threshold, red at/over it; tooltip "Context window: N% full". Tapping it opens a popover anchored above it (ContextReportView): used / window and provider · model, a segmented bar, one row per part (messages, summarized earlier conversation, system prompt, memory, skills, tool definitions, new message) with tokens and % of the window, free space, the auto-compact buffer, a note when a summary replaces N messages, whether the figure is the provider's real count or a ~ estimate, and — for a Subscriptions model — "Usage limits": session (5h) / weekly (7d) / "N-hour/N-day limit" / "This model" meters with "% left", a bar and "Resets in …". Re-read when a turn starts or ends and whenever the popover opens (contextReportProvider, GET /api/context); renders nothing if the backend cannot answer
- Live progress line (
stream_progress.dart, v4.6.0): while a turn runs, the current phase and a one-second elapsed timer ("The model is thinking · 0:45"); orange "no word from the server" after 30 s of silence. The backend's 10-second heartbeat chunks keep the idle timeout from firing during a quiet thinking phase
- Usage-limit card (
quota_notice_card.dart, v4.6.0): shown when a turn failed because the allowance ran out — countdown to the refill, an "automatically continue when it resets" checkbox (default on, device preference memo_quota_auto_continue) and "Continue now"; at the refill time continue is typed into the chat. A quota_low marker shows a one-off low-allowance warning. In memory only, one card per chat
2.4 Message Bubbles (chat_message_list.dart)
User bubble:
- Right-aligned, accentMuted bg (6% gold)
- Image preview (if hasImage): Image.file, 480px max, rounded
- Markdown content (MarkdownBody)
- Timestamp (always visible)
Assistant bubble:
- Left-aligned, avatar (M logo)
- bgPanel bg, borderSoft border
- Thinking toggle (collapsible section)
- Agent event cards (streaming tool calls)
- Markdown content
- Timestamp + copy button (on hover)
Streaming bubble:
- Real-time content from streamingContentProvider
- Thinking from streamingThinkingProvider
Typing indicator:
Image picker:
- Button → FilePicker (image type) → sets _pickedImagePath
- Preview row: 60x60 thumbnail, filename, close button
- Does NOT send immediately — user types prompt + sends manually
File picker:
- Button → FilePicker (any type) → sets _pickedFilePath
- Same preview + send pattern
Text field:
- Multiline, max 160px height
- "/" (at the start of a message or after a space, anywhere in the text) opens the slash menu: every installed skill plus /remember, /forget, /model, /orchestra
- Filtered list, arrow navigation, Enter selects
Send/Stop button:
- Gold accent (idle) → red (sending) via AnimatedContainer
- Stop icon when sending, Send icon when idle
Send logic:
- If image/file picked → sendFile(text, path) (streaming or non-streaming)
- If text only → sendMessage(text)
- WhatsApp mode → _sendWhatsApp(text)
3. MODEL STORE SCREEN (model_store_screen.dart)
Current tabs:
- Discover, Local Models, Downloading (horizontal tab bar)
3.1 Discover Tab
- Search bar (HuggingFace search)
- Filter chips: All, Vision, Text, Embedding, Tool
- Model cards grid (2 columns)
- Card: name, author, tags, downloads, likes, download button
- Loading: skeleton cards
- Empty: "No models found"
- Error: retry button
3.2 Local Models Tab
- Search + sort bar
- Local model cards:
- Filename + repo ID
- Tags: Vision (backend mmproj_path), Embedding, Think, Tool, Text
- File size (GB/MB format)
- Delete button
- Actions: Start (play icon), Config (gear), Show in Dir (folder)
- Status: running/stopped/loading/error
- Models filtered: mmproj/multimodal files hidden
- Model config dialog: ctx_size, port, gpu_layers, start/stop
3.3 Downloading Tab
- Active download: progress bar, speed, ETA, cancel
- Empty: "No active downloads"
4. AGENT CHATS (no separate screen since v5.0 — an agent chat is a chat with a project folder)
- Agent mode toggle
- New Agent Chat: picks project folder
- Agent chat list
- Agent messages: tool execution cards with status
- Permission requests: dialog (allow/deny/always)
- Undo button for edits
- Code Mode sub-mode chip (bottom engine strip,
engine_strip.dart): shows the active sub-mode (Plan/Auto/Build); cycle with Ctrl+Tab anywhere in the app, or tap the chip
- Plan approval: when a Plan sub-mode turn finishes, Memo asks in plain chat whether to proceed to Build or Auto (skipped — chains straight to Build — if the global auto-permission toggle is already on)
4.1 TASK DETAIL SCREEN (task_detail_screen.dart)
- Self-Driving task list detail view: live phase/progress, plan-approval card (
_PlanApprovalSection) for planner-mode lists, escalation banner
- Live activity: tool calls, sub-agent turns (
[coder]/[analyzer]/[reviewer]/[test-runner]), "model is generating" indicator during long silent LLM calls
- Pause/resume/cancel/skip controls for a running task list
- Connection status: connected/disconnected/connecting
- QR code display for pairing
- Contact list with avatars
- Message history + search
- WhatsApp-style input
5.1 CALENDAR SCREEN (calendar_screen.dart)
- Month view + event list, add/edit events
5.2 ROUTINES SCREEN (routines_screen.dart)
- List of scheduled Routines (schedule + prompt or agent config)
- Plain-language description → parsed into a routine config
- Desktop; mobile shows real pre-scheduled local notifications
5.3 DEVELOPER SCREEN (developer_screen.dart)
- Developer API Gateway, both wire formats: Anthropic-compatible (for Claude Code) and OpenAI-compatible (
GET /v1/models, POST /v1/chat/completions) — Base URL, model list (type/model-id), token, live request log
- API key requirement now enforced for any non-loopback caller on both endpoints (v4.5.0); optional memory integration
- Settings › Subscriptions: sign in with an Antigravity, Claude or Codex account; every model the account offers appears in the chat's top-right model selector,
/model and the local /v1 gateway (subs/<model>), no separate API key
- Opens next to the chat; shows the live screenshot of the isolated Chromium session Memo drives (
browser_* tools), repainted after every page-changing step
- Works both ways, with Agent Mode off too: an address bar (no
https:// needed), a click on the screenshot clicks the same spot on the page (mapped through the PNG's real pixel size), a keyboard row to type into the focused field, scroll
- Resizable by dragging; full width on narrow (phone-width) screens
- Frames arrive as
browser_frame SSE chunks and are never part of the chat history; the session endpoints are /api/browser/session/*
5.4 SWARM SCREEN (swarm_screen.dart) — BETA
- Host: create room, room code, add/reorder/remove joined workers, set each worker's compute share
- Join: enter a room code to lend compute without downloading the model
- Gated behind Settings → Beta Features; not shown on macOS
- A small icon next to the chat input box (not a separate screen/tab)
- Native audio-to-audio conversation via Google Live or OpenAI Realtime, delegate (into an existing chat) or standalone modes; falls back to local whisper.cpp transcription + Piper TTS when no native engine is configured
- One-directional barge-in; mid-session memory refresh (not just once at session start)
- Clear failure messages when a real voice engine can't start (no engine selected / incomplete config / background chat session failing to open) instead of a silent self-echo
- No echo cancellation yet (known limitation)
5.6 MASCOT WINDOW (mascot_window.dart / memo_mascot.dart) — new in v4.5.0
- A separate, always-on-top, frameless window (same process,
desktop_multi_window) showing an animated character reflecting Memo's live activity — not a screen inside AppShell
- Enabled/disabled and skin-selected from Settings → General, with a live preview of each skin
- Poses driven by
/api/mascot/activity: thinking, writing, running a specific tool, a distinct "Completed!" moment, idle flourishes (blink/breathe/occasional wave)
- Speaks in time during Live Mode (mouth animation + "Speaking…" bubble) — no "listening" pose, since neither voice engine currently reports one
- Click/drag zone shaped to the character's silhouette, not its bounding box; forced onto XWayland on Linux so always-on-top actually works under Wayland
5.7 MAIL SCREEN (mail_screen.dart) — new in v5.0
- Off until an account is connected. Connect dialogs (
mail_connect_dialogs.dart, shared with the setup wizard): Gmail and Outlook one-click OAuth, or any IMAP/SMTP account with auto-discovered settings
- Inbox with the account switcher, message view (
mail_body.dart keeps the mail's layout and decodes Turkish charsets), attachments, search, compose and Save draft; an outgoing secret match shows a localized reason and keeps the composer open
- Replies: prepared replies to review, edit and send yourself (
mail_reply_draft.dart); the reason behind each autonomous outcome is shown in the Digital Twin dialog's reply activity
- Mail security dialog (
mail_security_dialog.dart): dry-run the inbound shield and the outbound scan on pasted text; sends and stores nothing
- A shortcut to the Digital Twin dialog
5.8 DIGITAL TWIN DIALOG AND BRIEFING PANEL (twin_dialog.dart, autonomy_panel.dart, briefing_panel.dart, briefing_content_editor.dart) — new in v5.0
- Tabs: Contacts (link a person's mail address and WhatsApp number, per-person policy, merge, timeline across channels), Preferences (working hours, time zone, project inspection), Read-only tools (availability, a registered project's git state), Autonomy (engine, channels, undo window, reply activity with a specific reason per outcome, follow-up radar and promises, the audit log)
- Briefing panel inside Autonomy: morning and pre-meeting switches with their times (the morning time is any half hour), the cards (a card shows the model's summary and the owner's custom items), and the content editor — the same widget the setup wizard uses: built-in sections, up to five custom items, channels (Telegram, WhatsApp, mail — a channel that is not set up cannot be newly switched on), the sending mail account, and the separate briefing model
- Reached from Mail → Digital Twin and from Settings → Mail & Autonomy
- Required steps carry a
*; "Next" stays off until a required step is done; the side list scrolls and every row opens that step; compact windows use one column
- Steps: language and appearance · model connection
* · embedding model · persona · mail · mail reply model * (only with a mail account) · decision model · memory and learning · voice and images · channels · daily briefing · privacy and backup · summary and check
- Progress is a pure function of real app state (
setup_progress.dart), so it resumes where you left off; it can be re-run from Settings → General. See SETUP_WIZARD.md
5.10 NEW-CHAT START SCREEN (new_chat_landing.dart) — new in v5.0
- A Chat | Agent switch chosen before the first message, a centred composer with the model picker, and starter suggestions; the composer drops to the bottom after sending
- A blank chat is listed first and New Chat reopens it; agent chats get a title from your first words
- Agent chats show the model and reasoning-effort pickers, the Code Mode switch, the Tasks button and, with the Beta on, the browser panel; sub-agents appear as cards you can open and steer, finished ones move to a history list
6. SETTINGS DIALOG (settings_dialog.dart)
- Reorganized (v3.3.4) into a searchable, grouped rail with a search box up top, replacing the old flat row of ~20 tabs
- Left panel: grouped tab rail
- Right panel: content area
- Includes (non-exhaustive): General (incl. Minimal Mode, per-sub-feature overrides, mascot toggle + skin picker), Providers, CLI Connections (Claude Code/Codex install check), Llama, Memory, Cloud Sync, Identity, Orchestra, Agent Permissions, Code Sub-Mode Prompts (edit the Plan/Auto/Build system prompts), Skills, Learning (Proactive), Live Mode (engine + voice config), Stats (Usage), Beta Features, Remote Access, Accounts (self-hosted multi-user), Backup/Restore, Report Bug, About
- Tabs (original set, still present in some form):
General
- Theme selector (System/Light/Dark)
- Language selector (Türkçe/English)
- Streaming toggle
- Beta features toggle
- Incognito mode toggle
- Desktop mascot toggle + skin picker (live preview), v4.5.0
Providers
- Provider cards: name, active status
- Configure, Test, Delete buttons
- Add Provider button — providers with a genuine free tier carry a green badge and sit in their own group ("Have a free model"); OpenRouter, Kilo Code, OpenCode Zen and Cline offer a Pick a free model button that selects a working $0 model in one click (v4.6.0). Cline is new in v4.6.0
- Active provider indicator
Llama
- Binary path + Browse
- Models directory + Browse
- GPU Layers (slider)
- Engine mode (CPU/NVIDIA/AMD dropdown)
- Context size (text field)
- Temperature (slider)
Memory
Five sections switched with a pill bar, each pill carrying a live count (v4.6.0):
- Settings — memory enabled toggle, Top K results, min similarity, memory files list + delete
- Known Facts — every pinned fact, editable in place; checkboxes plus a select-all / deselect-all bar for bulk delete
- Conversation History — the ordinary (non-pinned) memories, paginated, same selection tools
- Analytics — usage analytics
- Debug — debug search
- Every delete asks for confirmation and reports how many records it removed
Subscriptions (subscriptions_tab.dart, v4.6.0)
- One sign-in per vendor — Antigravity, Claude, Codex; the browser opens (Memo opens it itself), the account's email is shown, sign out any time
- The account's live model list grouped by vendor, with a remaining-allowance badge and time to refill; re-read every 50 s while the tab is open. The list stays empty for ~30 s after a sign-in, so the tab keeps re-reading until models arrive
- A note about third-party-client risk is shown on the page
Skills (skills_tab.dart)
- Lists, installs and removes skills. A skill is switched on by calling it from a chat (
/name, "…using the X skill", "…using the necessary skills"), for that chat only
Usage Stats (stats_tab.dart)
- KPI cards, 30-day chart, per-model breakdown, and the Prompt Cache panel (v4.6.0): read from cache / written to cache / full-price input, hit ratio, "N cached" badges per model and category; "not reported" when the provider sends no cache figure
Cloud Sync
- Google Drive auth status
- Sync enabled toggle
- Auto-sync interval
- Sync Now / Pull Now / Disconnect buttons
Identity
- Name field
- Style selector
- System prompt textarea
- Reset to Default button
Orchestra
- Enable toggle
- Role configuration list
- Add Role button
Agent
- Agent enabled toggle
- Sandbox config
- Permission history list
- Clear permissions button
About
- Version string
- Check for Updates button
- Build info
7. MODEL CONFIG DIALOG (model_config_dialog.dart)
- Title: model filename
- Context size field
- Port field
- GPU layers field
- Status indicator + Start/Stop button
- Loading state while starting
8. OTHER COMPONENTS
- Trigger: "/" at the start of the text or after whitespace — mid-sentence too, so a skill can be called from inside a message. A path, a URL or a second slash never opens it
- Rows: every installed skill (inserted as its
/name form, e.g. /pair-programming; a skill this chat already called is marked), then the commands that do something real: /remember, /forget, /model, /orchestra. From the middle of a sentence only skills are offered
- Picking a skill only calls it: it is switched on for this chat and the turn says "Using skill: X"; there is no on/off switch anywhere. Picking replaces just the typed
/word; the rest of the text and the cursor stay
- In a CLI-provider chat, shows that CLI's own real commands instead (first word only)
8.1.1 @ File-Mention
- Trigger: "@" in text field
- Filtered popup, search by filename, references a file without typing the full path — useful for pointing agent mode at something specific
8.2 Agent Permission Dialog
- Icon + title
- Command preview (code block)
- File path display
- Allow, Deny, Allow Once, Always Allow buttons
8.3 Setup Wizard
- Full-screen overlay
- Steps: Welcome → Model → Provider → Done
- Next/Back/Skip navigation
- Progress indicator
8.4 Llama Installer
- Full-screen overlay
- Download progress bar
- Status text
- Cancel button
8.5 Version Banner
- Top of screen (dismissible)
- "New version available" message
- Download link
9. GLOBAL UI BEHAVIORS
States (all components):
- Loading: spinner / skeleton
- Empty: illustration + message + action
- Error: red text + retry
- Streaming: real-time token update
- Disabled: 30% opacity
Interactions:
- Right-click/long-press → context menu (edit, delete, copy)
- Hover → bgHover bg, reveal actions
- Scroll → thin custom scrollbar
- Errors → floating snackbar (dark bg, white text)
- RepaintBoundary per message bubble
- const constructors everywhere
- No AnimationController per bubble
10. DATA MODELS
ChatMessage
- role, content, thinking, imagePath, filePath, timestamp, agentEvents
- hasImage, hasFile, hasThinking getters
LocalModel
- repoId, filename, size, path, isEmbedding, isVision
- sizeFormatted getter (GB/MB/KB)
- Vision: determined by mmproj_path != null from backend
StreamChunk (SSE)
- content, thinking, done, error, finishReason, stats
DownloadProgress
- active, repoId, filename, totalBytes, downloaded, percent, speed
11. API ENDPOINTS (Flutter → Go backend)
Chat
- POST /api/send/stream (SSE streaming text)
- POST /api/send_file/stream (SSE streaming file/image upload)
- POST /api/send (non-streaming text)
- POST /api/send_file (non-streaming file)
- GET /api/messages
- POST /api/messages/update
- POST /api/messages/delete
Sessions
- GET /api/chats
- POST /api/chats/new
- POST /api/chats/switch
- POST /api/chats/delete
- POST /api/chats/rename
- GET /api/chats/active
- GET /api/chat/export
- GET /api/chat/title
Models
- GET /api/models/local
- DELETE /api/models/local
- POST /api/models/import
- POST /api/models/start
- POST /api/models/stop
- GET /api/models/status
- POST /api/models/embedding/start
- POST /api/models/embedding/stop
- GET /api/models/embedding/status
- GET /api/models/search
- GET /api/models/files
- POST /api/models/download
- GET /api/models/download/progress
- POST /api/models/download/cancel
Providers
- GET /api/providers
- POST /api/providers/update
- DELETE /api/providers/delete
- POST /api/providers/test
- POST /api/providers/activate
Identity
- GET /api/system-prompt
- POST /api/system-prompt
- POST /api/system-prompt/reset
- GET /api/incognito-prompt
- POST /api/incognito-prompt
Memory
- POST /api/memory/clear
- GET /api/memory/files
- DELETE /api/memory/files
- GET /api/memory/settings
- POST /api/memory/settings
- GET /api/memory/enabled
- POST /api/memory/enabled
Agent
- GET /api/agent/enabled
- POST /api/agent/enabled
- GET /api/agent/permissions
- POST /api/agent/permission
- DELETE /api/agent/permission
- POST /api/agent/permissions/clear
- POST /api/agent/undo
- POST /api/agent/chat
Sync
- GET /api/sync/auth
- POST /api/sync/auth
- GET /api/sync/account
- GET /api/sync/settings
- POST /api/sync/settings
- POST /api/sync/trigger
- POST /api/sync/pull
- POST /api/sync/disconnect
WhatsApp
- POST /api/whatsapp/start
- POST /api/whatsapp/stop
- GET /api/whatsapp/status
- POST /api/whatsapp/send
- GET /api/whatsapp/search
- GET /api/whatsapp/chats
- GET /api/whatsapp/messages
- GET /api/whatsapp/stats
- POST /api/whatsapp/chat/stream (SSE)
System
- GET /api/version
- GET /api/version/check
- GET /api/status
- GET /api/incognito
- POST /api/incognito
- GET /api/gpu
- GET /api/image
- POST /api/transcribe
- GET /api/models/llama/check
- POST /api/models/llama/install
- POST /api/models/llama/skip
- GET /api/models/config
- PUT /api/models/config
- POST /api/export
- POST /api/import
- POST /api/wipe
- GET /api/events
- GET /api/orchestra
- POST /api/orchestra
- GET /api/remote-access
- POST /api/remote-access
Source document