All six steps verified against the tree: - memory_chunks/memory_embeddings tables present in schema - src/memory-pg.ts writes chunks and embeddings - RRF query lives at docs/internal/sql/search-memories.sql Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3.2 KiB
PostgreSQL Hybrid Memory
This document defines the next schema step for Clawdie memory on PostgreSQL.
Decision
Use hybrid retrieval:
- structured relational memory in
memories - keyword and full-text retrieval over chunks
- semantic retrieval with
pgvector
Do not replace relational memory with vectors. Add vectors as a second retrieval path and merge results.
Why
- structured fields still matter for topics, decisions, participants, and filters
- exact keyword search is still useful for names, commands, and rare strings
- vector similarity improves semantic recall
- hybrid ranking is more robust than either keyword-only or vector-only search
Recommended schema layers
-
memories- canonical memory object
- session summary, metadata, timestamps, importance, topics
-
memory_chunks- chunked text derived from each memory
- one memory can have multiple chunks
- full-text search lives here
-
memory_embeddings- one embedding row per chunk
- stores vector, provider, model, and version metadata
Retrieval flow
- apply metadata filters first
- run full-text search over
memory_chunks - run vector similarity search over
memory_embeddings - merge results with reciprocal rank fusion (RRF)
- return top chunks and their parent memories
Versioning rules
Store enough metadata to re-embed later:
embedding_providerembedding_modelchunking_versioncontent_hashcreated_at
This lets Clawdie migrate from one embedding model to another without losing track of what was stored.
Dimension choice
Older drafts used vector(1536) as a placeholder baseline. Current repo
migrations and defaults use vector(1024) for bge-m3.
If the model changes, create a new migration or a new embedding table/version.
First milestone
- ✅ commit the base relational schema
- ✅ add chunk and embedding tables
- ✅ populate chunks (
src/memory-pg.tswrites intomemory_chunks) - ✅ generate embeddings outside PostgreSQL (OpenRouter or local llama-server)
- ✅ store embeddings in
memory_embeddings - ✅ test one hybrid query with RRF (
docs/internal/sql/search-memories.sql)
Current recommendation
- root/shared installs use
system_brainfor the memory database and role - additive tenants derive memory DB names from
dbSlug(tenantId):<slug>_brain
- use PostgreSQL 18 with
pgcrypto,uuid-ossp, andvector - start with hybrid retrieval, not vector-only retrieval
- embedding model default:
BAAI/bge-m3 - embedding transport default:
- OpenRouter when
OPENROUTER_API_KEYis configured - otherwise local
http://localhost:8080/v1
- OpenRouter when
- embeddings can be disabled entirely by setting
EMBED_BASE_URL=''
Dimension choice (resolved)
Using vector(1024) — bge-m3 outputs 1024 dimensions natively.
Configured via EMBED_BASE_URL, EMBED_MODEL, and EMBED_DIMENSIONS in
.env. Current defaults in src/config.ts are:
EMBED_MODEL=BAAI/bge-m3EMBED_DIMENSIONS=1024
OpenRouter is the default remote fallback when a local embedding endpoint is not configured.