Skip to main content

Long-term memory MCP server for LLMs — hybrid search in a single SQLite file

Project description

rekal

Long-term memory for LLMs, as an MCP server.

Every conversation starts from scratch — your LLM forgets what you told it yesterday. rekal is a small MCP server that stores memories in a single SQLite file and retrieves them with hybrid search. Install it, point your MCP client at it, and your LLM starts remembering things between sessions.

pip install rekal

Why I built this

I got tired of repeating myself. "I prefer Ruff." "We deploy with tags." "The auth service lives in services/auth." Every new conversation, same explanations.

Existing memory tools either do keyword search (which misses anything phrased differently) or vector search (which misses exact terms). I wanted both, plus a bias toward recent memories so stale stuff sinks naturally. And I wanted it in a single file I could back up by copying.

How search works

rekal runs three searches and blends the results:

score = 0.4 · BM25(keyword match)
      + 0.4 · cosine(semantic similarity)
      + 0.2 · exp(-t/half_life)

So a memory about "deploying the auth service to staging" shows up whether you search for "deploy auth" or ask about "shipping the login system to pre-prod". Recent memories rank higher, but old ones still surface if they're relevant.

Embeddings run locally with fastembed — no API keys, no network calls.

Quick start

Add to your MCP client config (Claude Desktop, Cursor, Claude Code, etc.):

{
  "mcpServers": {
    "rekal": {
      "command": "rekal"
    }
  }
}

rekal creates ~/.rekal/memory.db on first run. That file is your entire memory — portable, backupable, yours.

Requires Python 3.14+.

What it looks like in practice

Your LLM picks up on things worth remembering and stores them:

User: "I prefer Ruff over Black for formatting"
LLM:  → memory_store("User prefers Ruff over Black", type="preference")

Weeks later, in a completely different conversation:

User: "Set up linting for my new project"
LLM:  → memory_search("formatting linting preferences")
      ← "User prefers Ruff over Black" (score: 0.92)

When knowledge changes, it doesn't just pile up — old versions stay linked:

LLM: → memory_supersede(old_id="mem_abc", new_content="API moved from v2 to v3")

And when things contradict each other, you can ask:

LLM: → memory_conflicts(project="backend")
     ← "use PostgreSQL for everything" contradicts "migrate analytics to ClickHouse"

Tools

rekal exposes 16 tools over MCP.

Core

Tool Description
memory_store Store a memory with type, project, tags, and conversation scope
memory_search Hybrid search — BM25 + vector + recency in one query
memory_update Update content, tags, or type (re-embeds automatically)
memory_delete Delete a memory by ID

Smart write

Tool Description
memory_supersede Replace a memory while preserving the old one as history
memory_link Link memories: supersedes, contradicts, related_to
memory_build_context Relevant memories + conflicts + timeline for a query, in one call

Introspection

Tool Description
memory_similar Find memories similar to a given one
memory_topics Topic summary grouped by type
memory_timeline Chronological view with optional date range filters
memory_related All links to and from a memory
memory_health Database stats — counts by type, project, date range
memory_conflicts Find memories that contradict each other

Conversations

Tool Description
conversation_start Start a conversation, optionally linked to a previous one
conversation_tree Get the full conversation DAG
conversation_threads List recent conversations with memory counts
conversation_stale Find inactive conversations

Memory types

Memories are tagged with a type so search can be scoped:

Type For Example
fact Things that are true "The API rate limit is 1000 req/min"
preference How the user likes things "Prefers dataclasses over hand-written __init__"
procedure Steps to do something "Deploy: git tag vX.Y.Z && git push --tags"
context What's going on right now "Currently rewriting the payment service"
episode Things that happened "Debugged the OOM — root cause was unbounded cache"

Architecture

Everything lives in one SQLite file:

rekal
  │
  SQLite ──┬── FTS5 index ──── keyword relevance (BM25)
           ├── sqlite-vec ──── semantic similarity (384d vectors)
           ├── recency ─────── exponential decay (30-day half-life)
           └── memory links ── supersedes / contradicts / related_to

Conversations form a DAG — follow-ups, branches, merges — so you can navigate interaction history the way you'd navigate a Git log.

Claude Code skills

rekal ships two optional Claude Code skills that improve how your LLM uses its memory:

Skill Trigger What it does
rekal-save Auto on session end, or /rekal-save Extracts durable knowledge from the conversation, deduplicates against existing memories, stores or supersedes
rekal-hygiene /rekal-hygiene (manual only) Finds conflicts, duplicates, stale data, and quality issues. Proposes fixes for your approval — never auto-deletes

Install the skills plugin

# In Claude Code:
/plugin marketplace add janbjorge/rekal
/plugin install rekal-skills@rekal

The skills require rekal to be configured as an MCP server (see Quick start above).

CLI

rekal serve    # Run as MCP server (default)
rekal health   # Database health report
rekal export   # Export all memories as JSON

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rekal-1.1.0.tar.gz (81.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rekal-1.1.0-py3-none-any.whl (19.3 kB view details)

Uploaded Python 3

File details

Details for the file rekal-1.1.0.tar.gz.

File metadata

  • Download URL: rekal-1.1.0.tar.gz
  • Upload date:
  • Size: 81.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rekal-1.1.0.tar.gz
Algorithm Hash digest
SHA256 b3b629e0c92be77a04ab20b53d25e488ce0f7b2794770917cd7ee480730feeee
MD5 643f87841d504abfb413f80027c22d41
BLAKE2b-256 9a761baa12f999ad958721e1f3fe382f5ae6b522e581b2e3070ce29f67e6d7de

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.1.0.tar.gz:

Publisher: release.yml on janbjorge/rekal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rekal-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: rekal-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rekal-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b50855bb3c351231ee68bc1ecd0638bbe1a3451303de6b41b64ec3ca742c45b1
MD5 2e2a921a7a60c834e0dc69b654b8748f
BLAKE2b-256 62114e26821be95bf70f6c5e016a6e9d95b60858e95656a93658de18c568fda7

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.1.0-py3-none-any.whl:

Publisher: release.yml on janbjorge/rekal

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page