Skip to main content

Overview

Omi uses a dual-collection architecture for storing user data:

Conversations

Primary storage for recorded interactions - transcripts, audio, structured summaries

Memories

Secondary storage for extracted facts/learnings FROM conversations
This separation allows for efficient retrieval of both full conversation context and quick access to key facts about the user.

On-device summaries in desktop reads

The app conversation response may carry a display-only client_processing projection. Binding it does not modify canonical structured or create authoritative tasks or memories. The macOS ServerConversation adapter selects the projection once for every display consumer: only schema v1 is understood, and a response containing transcript segments must match the projection’s transcript_sha256 using encoding v5, including speaker identity and attribution. A list response omitting the transcript relies on the server’s transactional binding and invalidation when the transcript changes; it cannot independently prove freshness. An enriched canonical overview, sections, events, or non-default category wins over a retained projection, including after an upgrade and cloud reprocessing. processing_state is not a cloud-origin discriminator: it can be absent with a projection, or remain local_pending after late binding. Title-only/default-field cloud results are indistinguishable from the deterministic minimum in this wire contract, so that ambiguous shape follows the projection-first rule. Canonical action items win exact-description collisions, preserving both completed and reopened state; unmatched projected items are display-only additions with no canonical task identity. Selected provenance remains available as ServerConversation.localSummary and is cached in transcription_sessions.localSummaryJson. The producer’s clientProcessingJson retry bytes are separate. Revision-aware sync replaces the selected summary atomically; older or unversioned snapshots cannot fill fields across projection/canonical sources. A cached transcript whose hash differs from the selected projection is left unloaded until detail refresh. Run the desktop regressions from the repository root:
These hermetic tests exercise decode, reconciliation, and production SQLite storage. Named-bundle end-to-end acceptance remains a separate check.

Architecture Diagram

Firestore Structure


Part 1: Storing Conversations

Processing Flow

API Request

The app sends a POST request to /v1/conversations with transcript data

Processing

process_conversation() in utils/conversations/process_conversation.py handles the logic

Structure Extraction

LLM extracts title, overview, action items, and events from the transcript

Storage

upsert_conversation() in database/conversations.py saves to Firestore

Vector Embedding

Conversation is embedded and stored in Pinecone for semantic search

Conversation Model Fields

Structured Information

The structured field contains LLM-extracted information:

Transcript Segments

Each segment in transcript_segments includes:

Action Items

Action items are stored both inline (in structured.action_items) and in a standalone collection:

Events

Calendar events extracted from conversations:

Part 2: Extracting & Storing Memories

Memories are facts about the user extracted from conversations. They represent learnings, preferences, habits, and other personal information.

Memory Extraction Process

During process_conversation(), the system:

Analyze Transcript

Reviews the conversation transcript for personal information

Extract Facts

Identifies facts worth remembering about the user (~15 words max)

Store with Link

Saves to memories collection with a link back to the source conversation

Memory Model Fields

Memory Categories

Interesting

Notable facts about the user: hobbies, opinions, stories

System

Preferences and patterns: work habits, sleep schedule

Manual

User-created memories: explicitly added facts
Legacy categories (core, hobbies, lifestyle, interests, habits, work, skills, learnings, other) are automatically mapped to the new primary categories for backward compatibility.

Memory Extraction Rules

The system follows these guidelines when extracting memories:
  • Maximum ~15 words per memory
  • Must pass the “shareability test” - would this be worth telling someone?
  • Maximum 2 interesting + 2 system memories per conversation
  • No duplicate or near-duplicate facts
  • Skip mundane details (eating, sleeping, commuting)

Part 3: Data Protection & Encryption

Both conversations and memories support encryption for sensitive data.

Standard Protection Level

No encryption, stored as plaintext. This is the default for most users.
  • Fastest read/write performance
  • Data visible in Firestore console
  • Suitable for general use

Implementation


Part 4: Vector Embeddings

Conversations are also stored as vector embeddings in Pinecone for semantic search.

What Gets Embedded

Vector Creation

Vectors are created in a background thread after conversation processing:
The save_structured_vector() function:
  1. Generates embedding from conversation.structured (title + overview + action_items + events)
  2. Extracts metadata via LLM (people, topics, entities, dates)
  3. Upserts to Pinecone with metadata filters
Vectors are created ONCE during initial processing. Reprocessed conversations do NOT update their vectors.

Key Code Locations


API Endpoints

Conversations

Memories


Chat System Architecture

How conversations are retrieved for chat using LangGraph

Real-time Transcription

WebSocket-based real-time speech-to-text

Backend Deep Dive

General backend architecture overview

Backend Setup

Environment setup and configuration

Manual speaker attribution during concurrent writes

Manual speaker decisions live in a protected sparse receipt alongside the transcript. Live STT merging and both processing-result writers read that receipt in their commit transaction. Live merging preserves every manually covered speech span, including speaker-wide defaults, explicit clears, and training opt-outs. The committed transcript and deleted-ID delta are returned together for client delivery. Translation and inference-only writers patch current IDs without owning the segment set. Privacy-level migration re-encodes the transcript and receipt together. Changing attribution does not automatically regenerate a summary; refresh remains an explicit user action. Enrollment remains best-effort.