clawdbot-workspace/MEMORY-SYSTEM-ARCHITECTURE.md

27 KiB

Memory System Architecture Diagram

Visual representation of how the Clawdbot memory system works.


High-Level Flow

┌─────────────────────────────────────────────────────────────┐
│                    USER / AGENT CHAT                        │
│  "What did we decide about the API key strategy?"          │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              AGENT REASONING LAYER                          │
│  "This is about prior decisions → must search memory"      │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                  memory_search(query)                       │
│  → Converts query to embedding vector                       │
│  → Searches SQLite vector store                             │
│  → Returns: snippets + file paths + line numbers            │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│           SEARCH RESULTS (snippets only)                    │
│  memory/2026-02-04.md (lines 42-58)                        │
│  "Decided to use manual API key signup batch..."           │
│  Score: 0.87                                                │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              memory_get(path, from, lines)                  │
│  → Reads full context from markdown file                   │
│  → Returns: complete text from specified line range        │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│                   AGENT RESPONSE                            │
│  "On Feb 4, we decided manual signup batch (~30 min)       │
│   because CAPTCHA bypass violates ToS..."                  │
└─────────────────────────────────────────────────────────────┘

Storage Architecture

┌────────────────────────────────────────────────────────────────┐
│                    WORKSPACE DIRECTORY                         │
│              ~/.clawdbot/workspace/                            │
└────────────────────────┬───────────────────────────────────────┘
                         │
        ┌────────────────┴────────────────┐
        │                                 │
        ▼                                 ▼
┌──────────────────┐           ┌──────────────────────┐
│  MARKDOWN FILES  │           │  CONFIG FILES        │
│  (Source Truth)  │           │  (Identity/Rules)    │
├──────────────────┤           ├──────────────────────┤
│ memory/          │           │ AGENTS.md            │
│ ├─ 2026-02-09.md │           │ SOUL.md              │
│ ├─ 2026-02-08.md │           │ USER.md              │
│ ├─ research.md   │           │ HEARTBEAT.md         │
│ └─ TEMPLATE.md   │           │ TOOLS.md             │
└────────┬─────────┘           └──────────────────────┘
         │
         │ (watched by file watcher, 1.5s debounce)
         │
         ▼
┌─────────────────────────────────────────────────────────┐
│              INDEXING PIPELINE                          │
│  1. Detect file changes (watcher)                       │
│  2. Chunk markdown (~400 tokens, 80 overlap)            │
│  3. Generate embeddings (OpenAI/Gemini/local)           │
│  4. Store in SQLite                                     │
└────────────────────┬────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────┐
│           SQLITE DATABASE (Search Engine)               │
│        ~/.clawdbot/memory/main.sqlite                   │
├─────────────────────────────────────────────────────────┤
│  Tables:                                                │
│  ┌─────────────────────────────────────────────┐       │
│  │ files                                       │       │
│  │  - path, hash, mtime, size                 │       │
│  └─────────────────────────────────────────────┘       │
│  ┌─────────────────────────────────────────────┐       │
│  │ chunks                                      │       │
│  │  - id, file_id, text, start_line, end_line │       │
│  └─────────────────────────────────────────────┘       │
│  ┌─────────────────────────────────────────────┐       │
│  │ chunks_vec (vector table)                   │       │
│  │  - chunk_id, embedding (float32[1536])     │       │
│  │  - Accelerated by sqlite-vec extension     │       │
│  └─────────────────────────────────────────────┘       │
│  ┌─────────────────────────────────────────────┐       │
│  │ chunks_fts (full-text search)               │       │
│  │  - FTS5 index for BM25 keyword search      │       │
│  └─────────────────────────────────────────────┘       │
│  ┌─────────────────────────────────────────────┐       │
│  │ embedding_cache                             │       │
│  │  - text_hash, embedding (dedup)            │       │
│  └─────────────────────────────────────────────┘       │
└─────────────────────────────────────────────────────────┘

Hybrid Search Flow (Vector + BM25)

       memory_search("API key strategy")
                  │
                  ▼
       ┌──────────────────────┐
       │  Query Embedding     │
       │  (via OpenAI API)    │
       └──────────┬───────────┘
                  │
        ┌─────────┴─────────┐
        │                   │
        ▼                   ▼
┌──────────────┐   ┌──────────────────┐
│ Vector Search│   │ BM25 Keyword     │
│ (semantic)   │   │ Search (exact)   │
├──────────────┤   ├──────────────────┤
│ Top 20 by    │   │ Top 20 by FTS5   │
│ cosine sim   │   │ BM25 rank        │
└──────┬───────┘   └────────┬─────────┘
       │                    │
       └──────────┬─────────┘
                  │
                  ▼
       ┌──────────────────────┐
       │  Merge & Rank        │
       │  (weighted score)    │
       │  70% vector          │
       │  30% keyword         │
       └──────────┬───────────┘
                  │
                  ▼
       ┌──────────────────────┐
       │  Top 5 Results       │
       │  (with snippets)     │
       └──────────────────────┘

Embedding Providers

┌──────────────────────────────────────────────────────┐
│              EMBEDDING PROVIDER OPTIONS              │
└──────────────────────────────────────────────────────┘

Option 1: OpenAI (Recommended for Production)
┌────────────────────────────────────────────┐
│ Provider: openai                           │
│ Model: text-embedding-3-small              │
│ Size: 1536 dimensions                      │
│ Cost: $0.02 / 1M tokens (Batch: $0.01)    │
│ Speed: Fast (Batch API parallel)           │
│ Setup: API key only                        │
└────────────────────────────────────────────┘

Option 2: Gemini
┌────────────────────────────────────────────┐
│ Provider: gemini                           │
│ Model: text-embedding-004                  │
│ Size: 768 dimensions                       │
│ Cost: Free tier available                  │
│ Speed: Fast                                │
│ Setup: API key only                        │
└────────────────────────────────────────────┘

Option 3: Local (Offline)
┌────────────────────────────────────────────┐
│ Provider: local                            │
│ Model: embeddinggemma-300M-Q8_0.gguf       │
│ Size: ~600 MB download                     │
│ Cost: Free (compute only)                  │
│ Speed: Slower (CPU/GPU dependent)          │
│ Setup: Auto-download, rebuild required     │
└────────────────────────────────────────────┘

Write Flow (Agent → Disk)

┌──────────────────────────────────────────────────────┐
│  AGENT DECISION: "Need to remember this"            │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│              write / edit / append                   │
│  target: memory/2026-02-09.md                       │
│  content: "## Decisions Made\n- Chose X..."         │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│           MARKDOWN FILE UPDATED                      │
│  memory/2026-02-09.md (on disk)                     │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼ (file watcher triggers)
┌──────────────────────────────────────────────────────┐
│         INDEXING PIPELINE (Automatic)                │
│  1. Detects change                                   │
│  2. Re-chunks file                                   │
│  3. Generates embeddings (cached if unchanged)       │
│  4. Updates SQLite                                   │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│      SEARCH INDEX UPDATED (background)               │
│  New decision is now searchable                      │
└──────────────────────────────────────────────────────┘

Pre-Compaction Memory Flush

┌──────────────────────────────────────────────────────┐
│         SESSION TOKEN COUNT MONITOR                  │
│  Threshold: contextWindow - reserveFloor - 4000     │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼ (threshold crossed)
┌──────────────────────────────────────────────────────┐
│            MEMORY FLUSH TRIGGER                      │
│  Silent agentic turn (user doesn't see)             │
│  System: "Session nearing compaction. Store now."   │
│  User: "Write lasting notes; reply NO_REPLY"        │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│          AGENT REVIEWS CONTEXT                       │
│  Scans recent messages for:                         │
│  - Decisions made                                    │
│  - Preferences stated                                │
│  - Important facts                                   │
│  - TODOs assigned                                    │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│         WRITES TO MEMORY (if needed)                 │
│  write("memory/2026-02-09.md", ...)                 │
│  → Durable memory stored                            │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│              REPLIES "NO_REPLY"                      │
│  (User never sees this turn)                        │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│          COMPACTION PROCEEDS SAFELY                  │
│  Old context removed, but memory is on disk         │
└──────────────────────────────────────────────────────┘

Git Backup Flow

┌──────────────────────────────────────────────────────┐
│              END OF DAY / SESSION                    │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│         MANUAL OR CRON TRIGGER                       │
│  git add -A && git commit -m "..." && git push      │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│            ALL MARKDOWN FILES STAGED                 │
│  memory/*.md, AGENTS.md, USER.md, etc.              │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│         COMMITTED TO LOCAL GIT REPO                  │
│  SHA: abc123... "Daily backup: 2026-02-09"          │
└──────────────────────┬───────────────────────────────┘
                       │
                       ▼
┌──────────────────────────────────────────────────────┐
│         PUSHED TO REMOTE (GitHub/GitLab)             │
│  Entire memory history is now backed up              │
│  Recoverable even if local disk fails                │
└──────────────────────────────────────────────────────┘

Data Flow Summary

HUMAN INPUT
    ↓
AGENT CHAT
    ↓
DECISION/FACT IDENTIFIED
    ↓
WRITE TO MARKDOWN ← (source of truth)
    ↓
FILE WATCHER DETECTS CHANGE
    ↓
INDEXING PIPELINE
    ├→ Chunk text
    ├→ Generate embeddings
    └→ Store in SQLite ← (search engine)
    ↓
SEARCHABLE VIA memory_search
    ↓
AGENT CAN RECALL IN FUTURE SESSIONS
    ↓
GIT BACKUP (end of day)
    ↓
SAFE IN REMOTE REPO

Performance Characteristics

┌───────────────────────────────────────────────────────┐
│              OPERATION TIMINGS                        │
├───────────────────────────────────────────────────────┤
│ memory_search query:     <100ms                      │
│ memory_get read:         <10ms                       │
│ Index rebuild (35 files): ~2 seconds                 │
│ File watcher debounce:   1.5 seconds                 │
│ Embedding generation:    ~50ms per chunk (OpenAI)    │
│ SQLite vector search:    <50ms (with sqlite-vec)     │
│ BM25 search:             <20ms (FTS5)                │
└───────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────┐
│              STORAGE FOOTPRINT                        │
├───────────────────────────────────────────────────────┤
│ 35 markdown files:       ~500 KB                     │
│ SQLite database:         ~15 MB                      │
│ Vector embeddings:       ~12 MB (in SQLite)          │
│ Metadata + indexes:      ~3 MB                       │
└───────────────────────────────────────────────────────┘

┌───────────────────────────────────────────────────────┐
│              COST (OpenAI Batch API)                  │
├───────────────────────────────────────────────────────┤
│ Initial index (35 files): ~$0.10                     │
│ Daily updates (~3 files): ~$0.01                     │
│ Monthly cost:            ~$0.50                      │
└───────────────────────────────────────────────────────┘

Scaling Considerations

┌─────────────────────────────────────────────────────┐
│         FILES        │    CHUNKS   │   SEARCH TIME  │
├─────────────────────────────────────────────────────┤
│  < 50 files         │   < 200     │   < 100ms      │
│  50-200 files       │   200-1000  │   < 200ms      │
│  200-500 files      │   1000-2500 │   < 500ms      │
│  500-1000 files     │   2500-5000 │   < 1 second   │
│  1000+ files        │   5000+     │   Consider:    │
│                     │             │   - Partitioning│
│                     │             │   - Archiving  │
│                     │             │   - Multi-index│
└─────────────────────────────────────────────────────┘

Recommendation: Archive old logs after 3-6 months
- Move to `memory/archive/YYYY/` 
- Keep recent 90 days active
- Full archive remains searchable if needed

Failure Modes & Recovery

┌─────────────────────────────────────────────────────────┐
│             FAILURE SCENARIO          │   RECOVERY      │
├─────────────────────────────────────────────────────────┤
│ SQLite index corrupted               │ Rebuild from MD │
│ Markdown files deleted               │ Restore from git│
│ Embedding API down                   │ Fallback/local  │
│ Disk full                            │ Archive old logs│
│ Config error                         │ Revert git      │
│ Clawdbot crash mid-write             │ Git diff check  │
└─────────────────────────────────────────────────────────┘

Recovery command:
rm ~/.clawdbot/memory/main.sqlite && clawdbot memory index

Principle: Markdown files are source of truth — 
SQLite is always regenerable.

END OF ARCHITECTURE DIAGRAM

ᕕ( ᐛ )ᕗ