Tabby’s memory system is what makes it truly intelligent. Instead of starting from scratch every conversation, it remembers your preferences, coding style, past interactions, and context to provide increasingly personalized assistance.The memory layer is powered by Mem0 with a hybrid storage architecture:
Supabase stores vector embeddings of memories for semantic search.Database Schema:
CREATE TABLE memories ( id UUID PRIMARY KEY, user_id TEXT NOT NULL, memory TEXT NOT NULL, hash TEXT UNIQUE, metadata JSONB, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), embedding VECTOR(1536) -- OpenAI ada-002 dimensions);-- HNSW index for fast vector searchCREATE INDEX ON memories USING hnsw (embedding vector_cosine_ops);
Vector Search:
-- Find similar memories using cosine similarityCREATE FUNCTION match_memories( query_embedding VECTOR(1536), match_threshold FLOAT, match_count INT, filter_user_id TEXT)RETURNS TABLE ( id UUID, memory TEXT, similarity FLOAT)AS $$ SELECT id, memory, 1 - (embedding <=> query_embedding) AS similarity FROM memories WHERE user_id = filter_user_id AND 1 - (embedding <=> query_embedding) > match_threshold ORDER BY similarity DESC LIMIT match_count;$$ LANGUAGE SQL;
Why HNSW Index?
HNSW (Hierarchical Navigable Small World) is a graph-based algorithm for approximate nearest neighbor search. It’s much faster than brute-force vector search with minimal accuracy loss.
Speed: Sub-millisecond queries even with 100k+ memories
Accuracy: 95%+ recall compared to exact search
Scalability: Handles millions of vectors efficiently
class MemoryClassifier: CLASSIFICATION_PROMPT = """Classify the following memory into ONE type: - SHORT_TERM: Temporary states, current activities ("currently working on...") - LONG_TERM: Permanent preferences, identity ("I prefer...", "My name is...") - EPISODIC: Past events with time ("yesterday", "last week") - SEMANTIC: General knowledge ("Python uses...", "Capital of...") - PROCEDURAL: How-to instructions ("To do X, first...") Memory: {content} """ def classify(self, content: str) -> str: response = openai.chat.completions.create( model="gpt-4.1-nano-2025-04-14", messages=[{ "role": "user", "content": self.CLASSIFICATION_PROMPT.format(content=content) }], max_tokens=20, temperature=0 ) return response.choices[0].message.content.strip().upper()
Automatic Classification:
@app.post("/memory/add")async def add_memory(request: AddMemoryRequest): metadata = request.metadata or {} # Auto-classify if enabled if request.auto_classify and "memory_type" not in metadata: content = " ".join([m.content for m in request.messages]) memory_type = classifier.classify(content) metadata["memory_type"] = memory_type result = memory.add( messages=[{"role": m.role, "content": m.content} for m in request.messages], user_id=request.user_id, metadata=metadata ) return {"success": True, "result": result, "classified_type": metadata.get("memory_type")}
# If you add:"User prefers dark mode"# Then later add:"I like dark themes"# Mem0 will UPDATE the existing memory instead of creating a duplicate:"User prefers dark mode and dark themes"
This is done via content hashing and semantic similarity checks.
const history = await fetch(`${MEMORY_API_URL}/memory/history/mem_abc123`) .then(r => r.json());// Shows:// v1: "User prefers TypeScript"// v2: "User prefers TypeScript and Python"// v3: "User is an expert in TypeScript and Python"
Vector embeddings are being generated (check Supabase)
HNSW index is created on embedding column
Debug:
-- Check if memories existSELECT * FROM memories WHERE user_id = 'your_user_id';-- Check if embeddings are presentSELECT id, memory, embedding IS NOT NULL as has_embeddingFROM memories;
Neo4j not showing relationships
Check:
Neo4j credentials in .env are correct
Neo4j instance is running and accessible
Graph store is enabled in Mem0 config
Test connection:
from neo4j import GraphDatabasedriver = GraphDatabase.driver( uri=neo4j_url, auth=(neo4j_username, neo4j_password))with driver.session() as session: result = session.run("MATCH (n) RETURN count(n)") print(result.single()[0]) # Should print node count