Rlm Infinite Memory For Claude Code
EncrEor/rlm-claude · 39 stars · Python · MIT
MCP server Recursive Language Models for Claude Code - Infinite memory solution inspired by MIT CSAIL paper
Install
The repo has no one-line install. Follow its README.
Files
RLM - Infinite Memory for Claude Code
Your Claude Code sessions forget everything after
/compact. RLM fixes that.
The Problem
Claude Code has a context window limit. When it fills up:
/compactwipes your conversation history- Previous decisions, insights, and context are lost
- You repeat yourself. Claude makes the same mistakes. Productivity drops.
The Solution
RLM is an MCP server that gives Claude Code persistent memory across sessions:
You: "Remember that the client prefers 500ml bottles"
→ Saved. Forever. Across all sessions.
You: "What did we decide about the API architecture?"
→ Claude searches its memory and finds the answer.
3 lines to install. 14 tools. Zero configuration.
Quick Install
Requirements: Python 3.10+ (download), Claude Code CLI
Via PyPI (recommended)
pip install mcp-rlm-server[all]
The hooks and templates ship inside the package. Since a pip install gives you no repo checkout, ask the package where they landed:
python -m mcp_server --hooks-dir # e.g. .../site-packages/mcp_server/hooks python -m mcp_server --templates-dir
Point your ~/.claude/settings.json hook commands at that path (see
Hook Configuration), or copy them to ~/.claude/rlm/hooks/.
Via uv (fast, no global pollution)
uv tool install mcp-rlm-server[all] --python 3.12
Via Git (full install with hooks)
git clone https://github.com/EncrEor/rlm-claude.git cd rlm-claude ./install.sh
Via Docker
docker build -t rlm-server . # Or pull from registry (when published): # docker pull ghcr.io/encreor/rlm-claude
Then configure Claude Code to use the Docker container (see Docker setup below).
Restart Claude Code. Done.
Upgrading from v0.9.0 or earlier
v0.9.1 moved the source code from mcp_server/ to src/mcp_server/ (PyPA best practice). A compatibility symlink is included so existing installations keep working, but we recommend re-running the installer:
cd rlm-claude git pull ./install.sh # reconfigures the MCP server path
Your data (~/.claude/rlm/) is untouched. Only the server path is updated.
How It Works
┌─────────────────────────┐
│ Claude Code CLI │
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ RLM MCP Server │
│ (14 tools) │
└────────────┬────────────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌─────────▼────────┐ ┌──────▼──────┐ ┌──────────▼─────────┐
│ Insights │ │ Chunks │ │ Retention │
│ (key decisions, │ │ (full conv │ │ (auto-archive, │
│ facts, prefs) │ │ history) │ │ restore, purge) │
└──────────────────┘ └─────────────┘ └────────────────────┘
Nothing Lost Silently
Chunking is a deliberate act: RLM never writes a chunk on its own. What it does is make sure an unsaved session cannot go unnoticed:
- Before
/compact: a manual/compactis blocked when nothing was chunked in the last 15 minutes. Chunk, re-run it, it passes. Auto-compact is never blocked (that would strand a full session), only warned. - After a session: a hook traces what each session touched (file paths and allow-listed program names, never command lines). At the next start, a session that changed things and ended without a chunk is listed with its transcript, so it can still be recovered. Crashes and closed terminals are covered too: it is the missing chunk that is detected, not a clean exit.
Two Memory Systems
| System | What it stores | How to use |
|---|---|---|
| Insights | Key decisions, facts, preferences | rlm_remember() / rlm_recall() |
| Chunks | Full conversation segments | rlm_chunk() / rlm_peek() / rlm_grep() |
Features
Memory & Insights
rlm_remember- Save decisions, facts, preferences with categories and importance levelsrlm_recall- Search insights by keyword (multi-word tokenized), category, or importance- Without a query, results rank by importance first, then recency — a settled
criticalrule outranks today'smediumnote - Truncated results say so: the reply reports how many matched, so a capped recall can't pass for a complete one
- Without a query, results rank by importance first, then recency — a settled
rlm_forget- Remove an insightrlm_status- System overview (insight count, chunk stats, access metrics)
Conversation History
rlm_chunk- Save conversation segments with typed categorization (snapshot,session,debug;insightredirects torlm_remember)rlm_peek- Read a chunk (full or partial by line range)rlm_grep- Regex search across all chunks (+ fuzzy matching for typo tolerance)rlm_search- Hybrid search: BM25 + semantic cosine similarity (FR/EN, accent-normalized, chunks + insights)rlm_list_chunks- List all chunks with metadata
Multi-Project Organization
rlm_sessions- Browse sessions by project or domainrlm_domains- List available domains for categorization- Auto-detection of project from git or working directory
- Cross-project filtering on all search tools
Smart Retention
rlm_retention_preview- Preview what would be archived (dry-run)rlm_retention_run- Archive old unused chunks, purge ancient onesrlm_restore- Bring back archived chunks- 3-zone lifecycle: Active → Archive (.gz) → Purge
- Immunity system: critical tags, frequent access, and keywords protect chunks
- Archiving is a demotion, not a deletion: archived chunks leave the active index, but
rlm_searchstill matches them by summary and tags and returns them underarchived_matches—rlm_peek(chunk_id)restores one in full - Every retrieval counts as an access (peek, grep and search alike), so a chunk your searches keep surfacing reaches immunity instead of being archived as idle
Safety Nets & Memory Routing (Hooks)
- PreCompact hook: blocks a manual
/compactwith no chunk in the last 15 minutes; warns (never blocks) on auto-compact. It never creates a chunk itself - PostToolUse hook (rlm_chunk): records when the last chunk happened (read by the PreCompact hook) and ties the chunk to its session (
session_idandtranscript_pathin the index) - PostToolUse hook (Edit/Write/Bash) — session trace: appends to
~/.claude/rlm/sessions/<session_id>.jsonlthe paths a session edits and the basenames of allow-listed programs it runs. Never a command line: it can carry passwords - SessionStart hook — unsaved sessions: lists past sessions that changed things and ended with neither a chunk nor an acknowledgement, with their transcript path. Acknowledge one with
python3 ~/.claude/rlm/hooks/session_orphans.py --ack <session_id> "reason" - PostToolUse hook (Write/Edit): Detects writes to Claude Code's auto-memory and nudges toward RLM for decisions, insights, and session logs
- User-driven philosophy: you decide when to chunk, the system saves before loss
Semantic Search (optional)
- Hybrid BM25 + cosine - Combines keyword matching with vector similarity for better relevance
- Auto-embedding - New chunks are automatically embedded at creation time
- Two providers - Model2Vec (fast, 256d) or FastEmbed (accurate, 384d)
- Graceful degradation - Falls back to pure BM25 when semantic deps are not installed
Provider comparison (benchmark on 108 chunks)
| Model2Vec (default) | FastEmbed | |
|---|---|---|
| Model | potion-multilingual-128M |
paraphrase-multilingual-MiniLM-L12-v2 |
| Dimensions | 256 | 384 |
| Embed 108 chunks | 0.06s | 1.30s |
| Search latency | 0.1ms/query | 1.5ms/query |
| Memory | 0.1 MB | 0.3 MB |
| Disk (model) | ~35 MB | ~230 MB |
| Semantic quality | Good (keyword-biased) | Better (true semantic) |
| Speed | 21x faster | Baseline |
Top-5 result overlap between providers: ~1.6/5 (different results in 7/8 queries). FastEmbed captures more semantic meaning while Model2Vec leans toward keyword similarity. The hybrid BM25 + cosine fusion compensates for both weaknesses.
Recommendation: Start with Model2Vec (default). Switch to FastEmbed only if you need better semantic accuracy and can afford the slower startup.
# Model2Vec (default) — fast, ~35 MB pip install mcp-rlm-server[semantic] # FastEmbed — more accurate, ~230 MB, slower pip install mcp-rlm-server[semantic-fastembed] export RLM_EMBEDDING_PROVIDER=fastembed # Compare both providers on your data python3 scripts/benchmark_providers.py # Backfill existing chunks (run once after install) python3 scripts/backfill_embeddings.py
Checking embedding coverage
Embedding is best-effort: a chunk is always written, even when the provider is unavailable. That chunk is then invisible to semantic search until it gets a vector, so the gap is reported rather than left to be discovered later.
rlm_status warns whenever coverage is incomplete, names the reason when the
provider failed to load, and echoes the most recent entries of rlm.log (an
append-only log in your context directory). To heal a gap:
# Dry-run first: lists chunks that would be embedded python3 scripts/reconcile_stores.py # Re-embed everything missing, with timestamped backups python3 scripts/reconcile_stores.py --apply
Both honour RLM_CONTEXT_DIR. Use the same RLM_EMBEDDING_PROVIDER as your
server — the script refuses to mix vector dimensions.
Sub-Agent Skills
/rlm-analyze- Analyze a single chunk with an isolated sub-agent/rlm-parallel- Analyze multiple chunks in parallel (Map-Reduce pattern from MIT RLM paper)
Comparison
| Feature | Raw Context | Letta/MemGPT | claude-mem | RLM |
|---|---|---|---|---|
| Persistent memory | No | Yes | Yes | Yes |
| Works with Claude Code | N/A | No (own runtime) | Plugin (hooks + worker) | Native MCP + hooks |
| What gets saved | Nothing | Agent-managed | Every tool call, compressed by an LLM | What you chunk; unsaved sessions are flagged |
| Background LLM calls | No | Yes | Yes (per observation) | None |
| Guard before compact | No | N/A | N/A (captures continuously) | Yes (manual /compact blocked without a chunk) |
| Search (regex + BM25 + semantic) | No | Basic | Full-text + optional vector | Yes |
| Fuzzy search (typo-tolerant) | No | No | — | Yes |
| Multi-project support | No | No | Yes | Yes |
| Smart retention (archive/purge) | No | Basic | — | Yes |
| Sub-agent analysis | No | No | — | Yes |
| Zero config install | N/A | Complex | One command | 3 lines |
| FR/EN/JA support | N/A | EN only | Multi-language modes | 3 languages |
| Cost | Free | Self-hosted | LLM usage or hosted plan | Free |
— = not assessed. The claude-mem column reflects its documentation as of October 2026.
claude-mem and RLM make opposite bets. claude-mem records everything automatically and spends model calls to compress it; RLM stores only what you decide to keep, at no model cost, and makes sure a session you forgot to save is pointed out to you instead of silently lost.
Usage Examples
Session startup (recommended)
# Load universal rules (apply regardless of topic). # Pass a limit above your critical count — the default is 10, and a recall # that returns 10 of 34 rules looks exactly like a complete one. rlm_recall(importance="critical", limit=50) # Load context for current topic rlm_recall(query="deployment") # Check memory status rlm_status()
Save and recall insights
# Save a universal rule (loaded every session)
rlm_remember("Always deploy LOCAL → VPS, never direct",
category="decision", importance="critical",
tags="deploy,workflow")
# Save a topic-specific insight
rlm_remember("WeasyPrint requires inline CSS for PDF rendering",
category="finding", importance="high",
tags="weasyprint,pdf")
# Find insights later
rlm_recall(query="source of truth")
rlm_recall(category="decision")
rlm_recall(importance="critical", limit=50) # all universal rules (mind the default limit of 10)
Importance levels
| Level | When to use | Loaded |
|---|---|---|
critical |
Universal rules (apply regardless of topic) | Every session |
high |
Topic-specific rules | When working on that topic |
medium |
Useful info, not blocking | On explicit search |
Test: "Does this rule apply even when working on a completely different topic?" If yes → critical.
Manage conversation history
# Save important discussion (typed)
rlm_chunk("Discussion about API redesign... [long content]",
summary="API v2 architecture decisions",
tags="api,architecture",
chunk_type="session") # or "snapshot", "debug"
# Search across all history
rlm_search("API architecture decisions") # BM25 ranked
rlm_grep("authentication", fuzzy=True) # Typo-tolerant
# Read a specific chunk
rlm_peek("2026-01-18_MyProject_001")
Multi-project organization
# Filter by project
rlm_search("deployment issues", project="MyApp")
rlm_grep("database", project="MyApp", domain="infra")
# Browse sessions
rlm_sessions(project="MyApp")
Project Structure
rlm-claude/
├── src/mcp_server/
│ ├── server.py # MCP server (14 tools)
│ └── tools/
│ ├── memory.py # Insights (remember/recall/forget)
│ ├── navigation.py # Chunks (chunk/peek/grep/list)
│ ├── search.py # BM25 search engine
│ ├── tokenizer_fr.py # FR/EN tokenization
│ ├── sessions.py # Multi-session management
│ ├── retention.py # Archive/restore/purge lifecycle
│ ├── embeddings.py # Embedding providers (Model2Vec, FastEmbed)
│ ├── vecstore.py # Vector store (.npz) for semantic search
│ ├── diagnostics.py # Warning log (rlm.log) — degraded ops stay visible
│ └── fileutil.py # Safe I/O (atomic writes, path validation, locking)
│
├── hooks/ # Claude Code hooks
│ ├── i18n.py # Translations (EN/FR/JA) for hook messages
│ ├── pre_compact_chunk.py # Guard before /compact (PreCompact hook)
│ ├── memory_write_redirect.py # Redirect auto-memory writes to RLM (PostToolUse hook)
│ ├── reset_chunk_counter.py # Last-chunk time + chunk ↔ session link (PostToolUse hook)
│ ├── session_trace.py # What a session touches, metadata only (PostToolUse hook)
│ ├── session_orphans.py # Unsaved past sessions at startup, --ack (SessionStart hook)
│ └── session_common.py # Shared paths, config and lock-safe index update
│
├── templates/
│ ├── hooks_settings.json # Hook config template
│ ├── CLAUDE_RLM_SNIPPET.md # CLAUDE.md instructions
│ └── skills/ # Sub-agent skills
│
├── context/ # Storage (created at install, git-ignored)
│ ├── session_memory.json # Insights
│ ├── index.json # Chunk index
│ ├── chunks/ # Conversation history
│ ├── archive/ # Compressed archives (.gz)
│ ├── embeddings.npz # Semantic vectors (Phase 8)
│ └── sessions.json # Session index
│
├── install.sh # One-command installer
└── README.md
Configuration
Hook Configuration
The installer automatically configures hooks in ~/.claude/settings.json:
{
"hooks": {
"PreCompact": [
{
"matcher": "manual",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/pre_compact_chunk.py" }]
},
{
"matcher": "auto",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/pre_compact_chunk.py" }]
}
],
"PostToolUse": [
{
"matcher": "mcp__rlm-server__rlm_chunk",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/reset_chunk_counter.py" }]
},
{
"matcher": "Write",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/memory_write_redirect.py" }]
},
{
"matcher": "Edit",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/memory_write_redirect.py" }]
},
{
"matcher": "Edit|Write|MultiEdit|NotebookEdit|Bash",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/session_trace.py" }]
}
],
"SessionStart": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "python3 ~/.claude/rlm/hooks/session_orphans.py" }]
}]
}
}
The same block lives in templates/hooks_settings.json, which the installer reads.
Session Trace
Optional ~/.claude/rlm/session_trace.json (every key optional):
{
"notable_commands": ["ssh", "scp", "rsync", "psql", "kubectl", "terraform", "ansible-playbook", "deploy.sh"],
"min_edits": 5,
"idle_hours": 2,
"retention_days": 30,
"max_listed": 5
}
notable_commands: programs whose basename is recorded when a session runs them (arguments never are). One notable run is enough for a session to count.min_edits: a session with more Edit/Write than this counts.idle_hours: a session idle for less than this is presumed still running (parallel sessions are left alone).retention_days: traces older than this are deleted. Keep it aligned with Claude Code'scleanupPeriodDays(30 by default): past it the transcript is gone and the session cannot be recovered anyway.
Language
Hook messages default to English. Set RLM_LANG=fr for French or RLM_LANG=ja for Japanese:
# Option 1: Set globally in your shell profile (~/.zshrc, ~/.bashrc) export RLM_LANG=fr # or ja # Option 2: Set per-hook in ~/.claude/settings.json # Replace the command with: "command": "RLM_LANG=fr python3 ~/.claude/rlm/hooks/pre_compact_chunk.py"
Supported languages: en (default), fr, ja.
Storage Directory
RLM stores data in ~/.claude/rlm/context/ by default. Override with RLM_CONTEXT_DIR:
export RLM_CONTEXT_DIR=/path/to/custom/storage
This is particularly useful for Docker deployments (see below).
Custom Domains
Organize chunks by topic with custom domains:
{
"domains": {
"my_project": {
"description": "Domains for my project",
"list": ["feature", "bugfix", "infra", "docs"]
}
}
}
Edit context/domains.json after installation.
Manual Installation
Via pip
pip install -e ".[all]" claude mcp add rlm-server -- python3 -m mcp_server
Via uv
uv tool install mcp-rlm-server[all] --python 3.12 claude mcp add rlm-server -- ~/.local/bin/mcp-rlm-server
Hook Setup (required for pip and uv installs)
The ./install.sh script handles this automatically. For manual installs:
# Get hook scripts from the repo git clone https://github.com/EncrEor/rlm-claude.git /tmp/rlm-setup # Install hooks and i18n mkdir -p ~/.claude/rlm/hooks cp /tmp/rlm-setup/hooks/*.py ~/.claude/rlm/hooks/ chmod +x ~/.claude/rlm/hooks/*.py # Install skills (optional) mkdir -p ~/.claude/skills/rlm-analyze ~/.claude/skills/rlm-parallel cp /tmp/rlm-setup/templates/skills/rlm-analyze/skill.md ~/.claude/skills/rlm-analyze/ cp /tmp/rlm-setup/templates/skills/rlm-parallel/skill.md ~/.claude/skills/rlm-parallel/ # Cleanup rm -rf /tmp/rlm-setup
Then configure hooks in ~/.claude/settings.json (see Hook Configuration above).
Docker Setup
Build the image:
git clone https://github.com/EncrEor/rlm-claude.git cd rlm-claude docker build -t rlm-server .
Configure Claude Code MCP to use Docker:
claude mcp add rlm-server -- docker run -i --rm -v ~/.claude/rlm/context:/data rlm-server
Or manually in ~/.claude/settings.json:
{
"mcpServers": {
"rlm-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "~/.claude/rlm/context:/data", "rlm-server"]
}
}
}
The Docker image uses RLM_CONTEXT_DIR=/data internally, and the volume mount maps it to your local storage.
Uninstall
./uninstall.sh # Interactive (choose to keep or delete data) ./uninstall.sh --keep-data # Remove RLM config, keep your chunks/insights ./uninstall.sh --all # Remove everything ./uninstall.sh --dry-run # Preview what would be removed
Security
RLM includes built-in protections for safe operation:
- Path traversal prevention - Chunk IDs are validated against a strict allowlist (
[a-zA-Z0-9_.-&]), and resolved paths are verified to stay within the storage directory - Atomic writes - All JSON and chunk files are written using write-to-temp-then-rename, preventing corruption from interrupted writes or crashes
- File locking - Concurrent read-modify-write operations on shared indexes use
fcntl.flockexclusive locks - Content size limits - Chunks are limited to 2 MB, and gzip decompression (archive restore) is capped at 10 MB to prevent resource exhaustion
- SHA-256 hashing - Content deduplication uses SHA-256 (not MD5)
All I/O safety primitives are centralized in mcp_server/tools/fileutil.py.
Troubleshooting
"MCP server not found"
claude mcp list # Check servers claude mcp remove rlm-server # Remove if exists claude mcp add rlm-server -- python3 -m mcp_server
"Hooks not working"
cat ~/.claude/settings.json | grep -A 10 "PreCompact" # Verify hooks config ls ~/.claude/rlm/hooks/ # Check installed hooks
Roadmap
- Phase 1: Memory tools (remember/recall/forget/status)
- Phase 2: Navigation tools (chunk/peek/grep/list)
- Phase 3: Auto-chunking + sub-agent skills
- Phase 4: Production (auto-summary, dedup, access tracking)
- Phase 5: Advanced (BM25 search, fuzzy grep, multi-sessions, retention)
- Phase 6: Production-ready (tests, CI/CD, PyPI)
- Phase 7: MAGMA-inspired (temporal filtering, entity extraction)
- Phase 8: Hybrid semantic search (BM25 + cosine, Model2Vec)
- Phase 9: Typed chunking —
chunk_typeparameter (snapshot/session/debug/insight redirect) - Phase 10: Auto-memory/RLM cohabitation — Write/Edit hook redirects auto-memory to RLM + Japanese i18n
- Phase 11: Safety nets — PreCompact guard v2, recall ranked by importance with truncation reported, session trace + unsaved-session report
Inspired By
Research Papers
- RLM Paper (MIT CSAIL) - Zhang et al., Dec 2025 - "Recursive Language Models" — foundational architecture (chunk/peek/grep, sub-agent analysis)
- MAGMA (arXiv:2601.03236) - Jan 2026 - "Memory-Augmented Generation with Memory Agents" — temporal filtering, entity extraction (Phase 7)
Libraries & Tools
- Model2Vec - Static word embeddings for fast semantic search (Phase 8)
- BM25S - Fast BM25 implementation in pure Python (Phase 5)
- FastEmbed - ONNX-based embeddings, optional provider (Phase 8)
- Letta/MemGPT - AI agent memory framework — early inspiration
Standards & Platform
- MCP Specification - Model Context Protocol
- Claude Code Hooks - PreCompact / PostToolUse hooks
Contributing
Translations
The repository is maintained in English. User-facing files can be translated to your language:
| File | Purpose | Translations welcome |
|---|---|---|
README.md |
Main documentation | README.xx.md (e.g., README.fr.md, README.ja.md) |
templates/CLAUDE_RLM_SNIPPET.md |
CLAUDE.md instructions | CLAUDE_RLM_SNIPPET.xx.md |
Code, comments, and commit messages stay in English.
Authors
- Ahmed MAKNI (@EncrEor)
- Claude Opus 4.6 (joint R&D)
License
MIT License - see LICENSE
Facts
- Kind
- MCP server
- Group
- Uncategorized
- Stars
- 39
- License
- MIT
- Language
- Python
- Last push
- 2026-10-07
- Forks
- 10
- Topics
- ai-tools, claude, claude-code, context-management, infinite-memory, llm-memory, mcp, mcp-server, model-context-protocol
- 1REAio.github.morluto/reaReverse engineer anything from your terminal or agent with one CLI and MCP server.125.3k
- 2com.browser-use/browser-usecom.browser-use/browser-useControl a real Chrome browser to complete any task: fill forms, extract data, book flights.117.7k
- 3World Monitorapp.worldmonitor/mcpLive markets, conflicts, country risk, chokepoints, energy, and China decision signals. 93 tools.88.3k
- 4Scrapling MCP Serverd4vinci/scrapling🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scraplingdev86.9k
- 5Everythingmodelcontextprotocol/serversThis MCP server attempts to exercise all the features of the MCP protocol. It is not intended to be a useful server, but rather a test server for builders of MCP clients. It implements prompts, tools, resources, sampling, and more to showcase MCP capabilities.85.8k
- 6Fetchmodelcontextprotocol/serversA Model Context Protocol server that provides web content fetching capabilities. This server enables LLMs to retrieve and process content from web pages, converting HTML to markdown for easier consumption.85.8k