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. One SQLite file, no cloud, no API keys.

You tell your LLM you prefer Ruff, that deploys go through tags, that the auth service lives in services/auth. Next conversation, blank slate. You repeat yourself. Again. Forever.

rekal is an MCP server that gives LLMs persistent memory. It stores what matters and retrieves it later using hybrid search (BM25 keywords + vector similarity + recency decay). Embeddings run locally via fastembed. Nothing leaves your machine.

pip install rekal

or with uv:

uv tool install rekal

Requires Python 3.11+.

Setup

1. Install and add the MCP server

pip install rekal
# or
uv tool install rekal

Then add rekal to your MCP client:

claude mcp add rekal -- rekal

For other MCP clients, add to your config JSON:

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

On first run, rekal creates ~/.rekal/memory.db. That single file holds everything. Copy it to back up, drop it to start fresh.

2. (Optional) Claude Code skills

If you use Claude Code, rekal ships as a plugin with three skills for memory management. The plugin talks to the MCP server from step 1, so install that first.

/plugin marketplace add janbjorge/rekal
/plugin install rekal-skills@rekal
Skill Trigger What it does
rekal-init /rekal-init, or "bootstrap memory" Scans your codebase and bootstraps rekal with project knowledge
rekal-usage /rekal-usage, or "how do I use rekal" Tool reference, query patterns, and workflows — teaches agents how to use rekal effectively
rekal-save Auto on session end, or /rekal-save Reviews the conversation, deduplicates against existing memories, stores what's worth keeping
rekal-hygiene /rekal-hygiene Finds conflicts, duplicates, and stale data. Proposes fixes for your approval, never deletes on its own

How it works

Your LLM stores things worth remembering:

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

Weeks later, 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 facts change, old versions stay linked:

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

When things contradict each other:

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

Search

Three signals, blended into one score:

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

"deploy auth" and "shipping the login system to pre-prod" both find the same memory. Recent stuff ranks higher, but old memories still surface when relevant.

Tools

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 keeping 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

Type For Example
fact Things that are true "The API rate limit is 1000 req/min"
preference How you like things "Prefers dataclasses over hand-written __init__"
procedure Steps to do something "Deploy: git tag vX.Y.Z && git push --tags"
context Current state "Currently rewriting the payment service"
episode Things that happened "Debugged the OOM, root cause was unbounded cache"

Architecture

One SQLite file, four components:

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), navigable like a git log.

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.5.0.tar.gz (145.6 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.5.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for rekal-1.5.0.tar.gz
Algorithm Hash digest
SHA256 387f2b8381a201a03684c8b334131c371e930a01e8aad872d88f298c2359baa8
MD5 86740d2d36ac3cc09d84f2bc913aff6b
BLAKE2b-256 e7219974a654c0a591b00451217002b24c6d4d604d0d9afe9f3602ac94db6d31

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.5.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.5.0-py3-none-any.whl.

File metadata

  • Download URL: rekal-1.5.0-py3-none-any.whl
  • Upload date:
  • Size: 20.0 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.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c89ecfb566af54e8e09a439fccd6f7110263d21bf9970d319fffc3a440024498
MD5 bb6ce5d2a721514a9768955ff8fb8612
BLAKE2b-256 30ec9fdda43e89db95c192f2e61586c2efd2944540b140ad62a8fe45f702da78

See more details on using hashes here.

Provenance

The following attestation bundles were made for rekal-1.5.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