Recallbase / Blog / Architecture

How Recallbase works internally

No vector-database zoo, no graph server, no Redis: the entire memory layer runs on a single Postgres instance. Here is the architecture – from session hook to bi-temporal knowledge graph.

A constellation of connected points – the memory architecture

The loop: observe → distill → load

On session start, a hook (or the MCP server) loads a curated, hard-capped context: recent session summaries, confirmed knowledge, open items. On session end, the session gets documented. If it crashes, auto-dreaming kicks in overnight: the server-side transcript is distilled by an LLM – by morning, the memory is complete.

One Postgres instead of three systems

Sessions, the knowledge graph (nodes + edges), embeddings (pgvector) and full-text indexes live in the same database. That is not frugality – it is an architecture decision: one transaction boundary, one backup, one source of truth – and self-hosting stays realistic. The market is currently converging on exactly this pattern.

Search: hybrid rank fusion

Every search runs twice: full-text (German-stemmed plus exact fallback) and vector similarity. Both lists are fused into one ranking via Reciprocal Rank Fusion – if embeddings are unavailable, search silently degrades to pure full-text. Agents first get a compact hit index (IDs + one-liners) and fetch full texts on demand – keeping context small and the token bill low.

Bi-temporal knowledge

Insights are never deleted – they are invalidated: valid_from, invalidated_at, successor chaining. Contradiction detection retires outdated facts automatically – the agent never re-learns old mistakes, and “what was true back then?” stays queryable. Each insight also carries its event time (not just storage time) and an “ongoing?” flag.

Tenant isolation as database law

Row Level Security, fail-closed: without a set identity, every query returns zero rows – even with a bug in the application layer. Unauthenticated flows (signup, password reset) go through narrow SECURITY DEFINER functions. The app role cannot bypass RLS even if it wanted to.

One memory, many mouths

Claude Code talks via session hooks, Cursor/Codex/Gemini/OpenCode via the local MCP server, the Claude app on your phone via the remote MCP connector – all against the same API, all seeing the same state.

Curious? Try it free – 1 project, full loop.

Like the architecture?

Then try it – 2-minute setup, 1 project free.

Start for free