> ## Documentation Index
> Fetch the complete documentation index at: https://docs.memvid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Frame Architecture

> Why Memvid uses a a unique frame architecture for AI memory.

One of Memvid's core innovations is the **Smart Frame**, a storage primitive inspired by how video files encode information. Just as videos are composed of sequential frames that can be played, randomly seeked, or edited, without rewriting the entire file, Memvid represents AI data as an append-only sequence of semantic frames. Each frame captures meaning at a point in time, enabling efficient retrieval, temporal navigation, and incremental growth without destructive updates.

***

## The Early Insight

Memvid was born from a real internal problem.

While our team was building agentic systems for the healthcare industry, we ran into a foundational challenge: memory. We were responsible for building AI agents that could screen applicants and adapt to the unique, high-stakes requirements of healthcare staffing, reasoning over long histories of candidates, roles, facility requirements, and constantly changing constraints. The dataset wasn't just large, it was mission-critical and evolving fast.

### The Problem We Faced

For an AI agent to be useful in real-world staffing workflows, it needed to reliably remember people, conversations, decisions, and constraints over long periods of time. When someone asked:

* “What roles has this candidate applied for in the past six months?”
* “Have they worked night shifts before?”
* “What requirements did this facility specify last week?”

The answer had to be exact. Not a summary. Not a best guess. Not a hallucination.

That requirement exposed hard limits in existing AI memory systems. No matter which approach we tried, we ran into the same failures:

| Approach                          | Problem                                                                                                                              |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Feed everything to the LLM**    | Large language models have strict context limits. Real-world histories quickly exceeded those limits, making full recall impossible. |
| **Fine-tune/pretrain a model**    | Slow, expensive, and brittle. Data changed constantly, and retraining for every update simply didn’t scale.                          |
| **Traditional RAG with VectorDB** | Vector search retrieves *similar* information, not *exact* information. Critical details were lost to semantic approximation.        |
| **Chunking strategies**           | Chunking fractured context. Ordering, dependencies, and timelines were easily broken, often in subtle, dangerous ways.               |

On top of that, the data itself was extremely sensitive. We needed memory that could run fully on-prem, work offline, remain portable across devices, and avoid centralized infrastructure entirely. Traditional RAG pipelines weren’t just complex and expensive, they were security liabilities.

None of the existing approaches met the bar.

### **What We Actually Needed**

We needed a system that could:

* Store unbounded, growing histories
* Recall exact information, not semantic guesses
* Support real-time writes as new data arrived
* Run fully offline and on-prem
* Be portable and self-contained
* Minimize attack surface and infrastructure complexity

So we stepped back and asked a different question.

### **The Video Insight**

> ***What existing technology already handles massive, sequential data with random access, efficient compression, and decades of battle-tested reliability?***

The answer was video.

A two-hour film contains millions of frames, yet you can jump to any moment instantly. The file is self-contained: no database, no server, no external dependencies. Corrupted frames don’t invalidate the entire file. And decades of optimization have made video codecs extraordinarily efficient.

Real-world AI memory has the same shape.

Information accumulates over time. Events are sequential. You need to jump to specific moments while preserving the full historical timeline. Memory must be incrementally writable, crash-safe, and portable across machines.

**Video codecs have spent 40+ years solving exactly these problems:**

* **Sequential data with random access**: jump to any frame instantly
* **Efficient compression**: 100x compression ratios via redundancy exploitation
* **Self-contained files**: No external dependencies or infrastructure required
* **Crash recovery**: Corrupted frames are localized, not catastrophic
* **Streaming support**: Start processing data before the full file loads

## From Video to Memory

So we tried something unconventional: Storing embeddings inside frames.

Each interaction becomes a frame. Each applicant update, requirement change, or decision is a frame. String them together, index them properly, and you get operational memory that an AI system can query with exact, deterministic recall.

That insight evolved into **Memvid**.

We shipped it in production. It worked. And we quickly realized this wasn’t just a healthcare problem, every serious AI application faces the same challenge. So we open-sourced the solution.

***

## Why Smart Frames as Storage Units?

Traditional systems treat documents as isolated objects. Memvid treats information as frames in a continuous, evolving knowledge stream.

That difference changes everything.

### The Problem with Document-Centric Storage

```mermaid theme={null}
graph LR
    subgraph Traditional["Traditional Approach"]
        direction LR
        D1[Doc 1]
        D2[Doc 2]
        D3[Doc 3]
        D4[Doc 4]
    end

    D1 -.-> P1[No temporal order]
    D2 -.-> P2[Scattered metadata]
    D3 -.-> P3[No relationships]
    D4 -.-> P4[Sync complexity]

    style D1 fill:#666,color:#fff
    style D2 fill:#666,color:#fff
    style D3 fill:#666,color:#fff
    style D4 fill:#666,color:#fff
    style P1 fill:#c44,color:#fff
    style P2 fill:#c44,color:#fff
    style P3 fill:#c44,color:#fff
    style P4 fill:#c44,color:#fff
```

When documents are stored as separate objects:

* **No inherent ordering**: When was doc 3 added relative to doc 1?
* **No context continuity**: What was the state of knowledge at time T?
* **Fragmented storage**: Metadata, vectors, and content in different places
* **Sync complexity**: Keeping everything consistent is error-prone

### The Frame Solution

```mermaid theme={null}
graph LR
    subgraph Timeline["Knowledge Timeline"]
        F1[Frame 1<br/>t=0] --> F2[Frame 2<br/>t=1]
        F2 --> F3[Frame 3<br/>t=2]
        F3 --> F4[Frame 4<br/>t=3]
        F4 --> F5[Frame N<br/>t=N]
    end

    style F1 fill:#FF9900,color:#000
    style F2 fill:#FF9900,color:#000
    style F3 fill:#FF9900,color:#000
    style F4 fill:#FF9900,color:#000
    style F5 fill:#FF9900,color:#000
```

Frames provide:

| Benefit                     | How Frames Deliver It                          |
| --------------------------- | ---------------------------------------------- |
| **Temporal ordering**       | Every frame has a position in the sequence     |
| **Point-in-time queries**   | "What did we know at frame 100?"               |
| **Atomic units**            | Each frame is self-contained with all metadata |
| **Efficient deltas**        | Similar consecutive frames compress well       |
| **Single-file portability** | Everything serializes to one `.mv2` file       |

***

## How It Works:

Here's exactly how Memvid processes and stores your content. No black boxes.

### Step 1: Frame Creation

When you call `put()`, Memvid creates a frame structure:

<AccordionGroup>
  <Accordion title="Header" defaultOpen icon="file-code">
    * **Frame ID:** `42`
    * **Timestamp:** `1704067200`
    * **URI:** `mv2://docs/meeting-notes`
    * **Checksum:** `sha256:a1b2c3...`
  </Accordion>

  <Accordion title="Metadata" defaultOpen icon="tags">
    * **Title:** "Q4 Meeting Notes"
    * **Labels:** `["meeting", "q4"]`
    * **Track:** "notes"
    * **Custom:** `{ author: "alice" }`
  </Accordion>

  <Accordion title="Payload" defaultOpen icon="file-zipper">
    zstd-compressed content bytes
  </Accordion>

  <Accordion title="Embeddings (optional)" defaultOpen icon="vector-square">
    384-dim vector, quantized to int8 - only if semantic search is needed
  </Accordion>
</AccordionGroup>

### Step 2: Index Updates

After frame creation, multiple indexes are updated atomically:

```mermaid theme={null}
graph LR
    subgraph LexIdx["Lexical Index (BM25)"]
        L1["'meeting' → 42"]
        L2["'notes' → 42"]
        L3["'Q4' → 42"]
    end

    subgraph VecIdx["Vector Index (HNSW)"]
        V1["[0.1, 0.3, ...] → 42"]
    end

    subgraph TimeIdx["Time Index (B-Tree)"]
        T1["1704067200 → 42"]
    end

    Frame42((Frame 42)) --> LexIdx
    Frame42 --> VecIdx
    Frame42 --> TimeIdx

    style Frame42 fill:#FF9900,color:#000
    style LexIdx fill:#2a2a2a,stroke:#4a9eff
    style VecIdx fill:#2a2a2a,stroke:#9b59b6
    style TimeIdx fill:#2a2a2a,stroke:#2ecc71
```

### Step 3: WAL Commit

Before returning success, the frame is committed to the Write-Ahead Log:

```mermaid theme={null}
graph LR
    subgraph WAL["Write-Ahead Log"]
        direction LR
        E41[Entry 41<br/>Frame 41 ✓]
        E42[Entry 42<br/>Frame 42 ✓]
        E43[Entry 43<br/>pending...]
    end

    E41 --> E42 --> E43

    style E41 fill:#2ecc71,color:#000
    style E42 fill:#FF9900,color:#000
    style E43 fill:#666,color:#fff
```

If the process crashes mid-write, the WAL ensures:

* Committed frames are recovered on next open
* Incomplete frames are discarded cleanly
* No corruption propagates to existing data

### Step 4: Segment Compaction

Periodically, frames are grouped into segments for storage efficiency:

```mermaid theme={null}
graph TB
    subgraph MV2[".mv2 FILE"]
        subgraph Segments
            direction LR
            S0["Segment 0<br/>Frames 0-99"]
            S1["Segment 1<br/>Frames 100-199"]
            S2["Segment 2<br/>Frames 200-299"]
        end
        subgraph Indexes
            direction LR
            TOC["TOC"]
            LEX["Lexical"]
            VEC["Vector"]
            TIME["Time"]
            WAL["WAL"]
        end
    end

    Segments --> Indexes

    style S0 fill:#FF9900,color:#000
    style S1 fill:#FF9900,color:#000
    style S2 fill:#FF9900,color:#000
    style MV2 stroke:#FF9900,stroke-width:2px
```

***

## Traditional VectorDB: How They Store Context

To understand why frames matter, let's see how traditional vector databases handle the same data:

### The Traditional VectorDB Architecture

```mermaid theme={null}
graph TB
    subgraph Client["Your Application"]
        Doc[Document]
    end

    subgraph VectorDB["Traditional VectorDB"]
        Chunker[Text Chunker]
        Embedder[Embedding API]
        VecStore[Vector Store]
        MetaStore[Metadata Store]
        DocStore[Document Store]
    end

    subgraph External["External Dependencies"]
        API[OpenAI/Cohere API]
        PG[(PostgreSQL)]
        S3[(S3/Blob Storage)]
    end

    Doc --> Chunker
    Chunker --> Embedder
    Embedder --> API
    API --> VecStore
    VecStore --> MetaStore
    MetaStore --> PG
    Doc --> DocStore
    DocStore --> S3
```

### Problems with This Approach

| Issue                     | Traditional VectorDB                                           | Memvid Frames                            |
| ------------------------- | -------------------------------------------------------------- | ---------------------------------------- |
| **Storage fragmentation** | Vectors in one place, metadata in another, raw docs in a third | Everything in one frame, one file        |
| **Temporal amnesia**      | No concept of "when" something was added                       | Every frame has a timestamp and position |
| **Point-in-time queries** | Impossible or requires complex versioning                      | Built-in: `as_of_frame=100`              |
| **Consistency**           | Distributed transactions across systems                        | Single-file atomic writes                |
| **Portability**           | Export/import across multiple systems                          | Copy one `.mv2` file                     |
| **Offline operation**     | Requires API access for embeddings                             | Local embeddings, fully offline          |
| **Crash recovery**        | Hope your 3 systems are all consistent                         | WAL ensures atomic recovery              |

### What Traditional VectorDBs Actually Store

When you insert a document into Pinecone, Weaviate, or ChromaDB:

```python theme={null}
# Traditional VectorDB
vectordb.insert(
    id="doc-123",
    vector=[0.1, 0.2, ...],  # 1536 floats
    metadata={"title": "Meeting Notes"}
)
# Where's the original document?
# When was it added?
# What was the knowledge state before this?
# 🤷
```

The vector is stored. Maybe some metadata. But:

* **Original content?** Often discarded or stored separately
* **Temporal context?** Not tracked
* **Relationship to other docs?** Only through vector similarity
* **History?** Non-existent

### What Memvid Frames Store

```python theme={null}
# Memvid
mem.put(
    title="Meeting Notes",
    label="meeting",
    metadata={},
    text="Full document content here..."
)
# Stored atomically:
# ✓ Full original content (compressed)
# ✓ All metadata
# ✓ Timestamp + frame position
# ✓ Relationship to previous frames
# ✓ Crash-safe commit
# ✓ Embedding vector (optional - add when you need semantic search)
```

***

## Performance Benefits of Frame Architecture

The frame architecture isn't just conceptually cleaner. It's faster.

### Why Frames Are Fast

#### 1. Locality of Reference

Traditional systems scatter data across storage layers. Frames keep related data together:

<CardGroup cols={2}>
  <Card title="Traditional: 3 Round Trips" icon="network-wired">
    1. Query vector index (network)
    2. Fetch metadata (different server)
    3. Retrieve document (blob storage)
  </Card>

  <Card title="Memvid: 1 Seek" icon="bolt">
    1. Seek to frame offset in .mv2 file (all data co-located)
  </Card>
</CardGroup>

#### 2. Segment-Based Caching

Frames group into segments that cache efficiently:

```mermaid theme={null}
graph LR
    Q["Query: Q4 meetings?"] --> T["Time Index"]
    T --> S3["Segment 3"]
    S3 --> M["Load to Memory"]
    M --> C["Cache Hit!"]

    style Q fill:#4a9eff,color:#000
    style S3 fill:#FF9900,color:#000
    style C fill:#2ecc71,color:#000
```

<Steps>
  <Step title="Time Index Lookup">
    Time index identifies Segment 3 contains Q4 frames
  </Step>

  <Step title="Single Read">
    Load Segment 3 into memory (one I/O operation)
  </Step>

  <Step title="Cache Ready">
    All Q4 frames now cached, subsequent queries are instant
  </Step>
</Steps>

#### 3. Compression Efficiency

Similar frames compress dramatically when stored together:

| Content Type  | Raw Size | Frame-Compressed | Savings |
| ------------- | -------- | ---------------- | ------- |
| Chat history  | 10 MB    | 0.8 MB           | 92%     |
| Documentation | 50 MB    | 4.2 MB           | 91%     |
| Mixed content | 100 MB   | 12 MB            | 88%     |

This happens because:

* Sequential frames often share vocabulary (Zstd dictionary)
* Embeddings quantize to int8 (75% vector size reduction)
* Metadata schemas are consistent within segments

#### 4. Index Co-location

All indexes live in the same file, enabling compound queries without joins:

```sql theme={null}
-- Conceptual query (not actual syntax)
SELECT frames
WHERE text MATCH 'budget'           -- Lexical index
  AND vector SIMILAR TO query_vec   -- Vector index
  AND timestamp > '2024-01-01'      -- Time index

-- All indexes in one file = one I/O operation
```

### Benchmark: Frame vs Traditional

Real-world comparison on 1M document corpus:

| Operation           | Pinecone | ChromaDB | Memvid           |
| ------------------- | -------- | -------- | ---------------- |
| Insert 1K docs      | 2.3s     | 4.1s     | 0.8s             |
| Hybrid search       | N/A      | N/A      | 8ms              |
| Point-in-time query | N/A      | N/A      | 9ms              |
| Export all data     | 45min    | 12min    | 0.1s (copy file) |
| Cold start          | 3.2s     | 1.8s     | 0.05s            |
| Storage size        | 2.1 GB   | 1.8 GB   | 0.4 GB           |

<Info>
  **Why so fast?** Memvid doesn't need network calls, distributed coordination, or multi-system consistency. It's just reading from a well-organized file.
</Info>

***

## Frame Lifecycle

### Creation

When you add content, Memvid:

1. Generates a unique frame ID
2. Extracts and indexes text content
3. Computes embeddings (if enabled)
4. Records timestamp in the time index
5. Appends to the WAL for crash safety
6. Assigns a URI (`mv2://track/title`)

### Retrieval

When you search or view:

1. Query hits the appropriate index (lexical, vector, or time)
2. Frame metadata is loaded from the TOC
3. Payload is decompressed and returned
4. Access is logged for analytics

### Deletion

"Deleted" frames aren't physically removed. They're **tombstoned**:

```python theme={null}
# Mark frame as deleted
mem.delete(frame_id=42)

# Frame still exists but won't appear in searches
# Use vacuum to physically reclaim space
```

```bash theme={null}
memvid doctor knowledge.mv2 --vacuum
```

***

## Frame IDs vs URIs

Every frame has two identifiers:

| Identifier   | Format  | Example             | Use Case            |
| ------------ | ------- | ------------------- | ------------------- |
| **Frame ID** | Integer | `124`               | Internal reference  |
| **URI**      | String  | `mv2://docs/api.md` | Human-readable path |

```python theme={null}
# Access by frame ID
frame = mem.frame(124)

# Access by URI
frame = mem.frame('mv2://docs/api.md')
```

***

## Best Practices

### Frame Sizing

* **Small frames** (under 4KB): Great for chat messages, notes
* **Medium frames** (4KB - 1MB): Documents, articles
* **Large frames** (over 1MB): PDFs, images, audio

### Batch Ingestion

Use `put_many()` for bulk ingestion (100-200x faster):

```python theme={null}
docs = [
    {'text': 'Content 1', 'title': 'Doc 1', 'label': 'docs'},
    {'text': 'Content 2', 'title': 'Doc 2', 'label': 'docs'},
    # ... thousands more
]

mem.put_many(docs)
```

### Tombstone Management

Periodically vacuum to reclaim space:

```bash theme={null}
# Check how much space can be reclaimed
memvid stats knowledge.mv2

# Reclaim deleted frame space
memvid doctor knowledge.mv2 --vacuum
```

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Memory Architecture" icon="database" href="/concepts/memory-architecture">
    See how frames fit into the file structure
  </Card>

  <Card title="Time Index" icon="clock" href="/file-format/time-index-track">
    Learn about temporal ordering
  </Card>
</CardGroup>
