SimpleMem – Technical Briefing Repository: https://github.com/moses-y/SimpleMem


The Problem

LLM agents quickly exhaust context windows when they need to recall past interactions. Existing approaches either keep the entire dialogue (high token cost) or rely on costly iterative reasoning. The result is poor long‑term recall and expensive inference.

What This Does

SimpleMem implements a three‑stage “compression‑index‑retrieve” pipeline that stores dialogue facts in a compact vector store and serves them via a lightweight MCP (Memory‑Control‑Protocol) server.

  • Core pipeline – See core/hybrid_retriever.py (744 LOC) and its duplicates under MCP/reference/core/ and SKILL/simplemem-skill/src/core/. The HybridRetriever.retrieve entry point orchestrates the flow: 1. _retrieve_with_planning → _analyze_information_requirements → chat_completion (model call). 2. Results are post‑processed by extract_json → _clean_json_string.
  • Memory model – models/memory_entry.py defines the MemoryEntry data class; it is imported by 20 other modules, making it the primary data contract.
  • LLM client – utils/llm_client.py (also duplicated in MCP/reference/utils/llm_client.py) provides chat_completion, _handle_streaming_response, and JSON extraction. It is the only module that talks to the external LLM service and is used by 15 callers.
  • Vector store – database/vector_store.py (and its MCP counterpart) implements add_entries, semantic_search, and keyword_search. It opens a SQLite connection via _get_connection (used by 9 callers) and persists embeddings.
  • MCP server – MCP/server/http_server.py runs a FastAPI‑style HTTP endpoint (run.py starts it). Requests are routed through MCP/server/mcp_handler.py, which builds a MemoryBuilder and a HybridRetriever.
  • Skill wrapper – SKILL/simplemem-skill/src/main.py exposes the same API as a Claude skill, loading the local vector store defined in SKILL/simplemem-skill/scripts/cli_persistent_memory.py.

How It Is Wired

Execution begins at MCP/run.py → main (line 14). main imports MCP/server/http_server.py and starts the HTTP server. Each incoming request is handled by MCP/server/mcp_handler.py.to_dict, which:

  1. Calls _get_client → utils/llm_client.py.__init__ (creates the LLM client).
  2. Instantiates HybridRetriever (core/hybrid_retriever.py.__init__).
  3. Calls HybridRetriever.retrieve, which invokes: _retrieve_with_planning → _analyze_information_requirements → chat_completion (network + model). extract_json → _clean_json_string (JSON parsing).

The retrieval path reaches the vector store via database/vector_store.py._semantic_search (reads the SQLite DB).

A secondary CLI entry point is MCP/reference/main.py. The ask function (line 145) follows the same call chain but returns the answer directly to the caller instead of an HTTP response.

Blast radius:

  • models/memory_entry.py – 20 dependents, any change ripples through the entire codebase.
  • utils/llm_client.py – 15 dependents, central to all model calls.
  • database/vector_store.py – 10 dependents, touches the persistent store.

No circular imports were detected, and the internal call graph contains 363 resolved edges, confirming a mostly linear flow.

How To Use It

# 1. Clone the repo
git clone https://github.com/moses-y/SimpleMem
cd SimpleMem

# 2. Install Python dependencies (root + sub‑projects)
pip install -r requirements.txt
pip install -r MCP/requirements.txt
pip install -r MCP/reference/requirements.txt
pip install -r SKILL/simplemem-skill/requirements.txt

# 3. Start the MCP server
python MCP/run.py   # listens on the default port defined in MCP/config/settings.py

# 4. Optional: use the reference CLI
python MCP/reference/main.py ask "What did we discuss about compression?" 

Configuration lives in MCP/config/settings.py (e.g., OPENROUTER_API_KEY). The skill version reads the same key from SKILL/simplemem-skill/src/config.py.example. No Dockerfile or Makefile is present, so containerisation must be added manually if required.

Real‑World Use

A customer integrating SimpleMem into a chatbot can run the MCP server alongside the bot process. The bot forwards user utterances to http://localhost:<port>/ask. The server compresses the dialogue, stores the embedding, and on subsequent turns retrieves the most relevant facts with a single chat_completion call, reducing token usage by ≈ 70 % compared with naive context concatenation.

import requests, json

def ask_simplemem(question):
    resp = requests.post("http://localhost:8000/ask", json={"query": question})
    return resp.json()["answer"]

Code Health & Issues

  • HIGH – Add CI workflow – 63 source files, no GitHub Actions or other CI configuration.
  • MEDIUM – Enable Dependabot/Renovate – 4 requirement files, no automated dependency updates.
  • MEDIUM – Move large binaries to LFS – MCP/reference/fig/simplemem-new.mp4 (20 MB) and a 10.9 MB spreadsheet are stored in Git history.

Additional observations from static analysis: deep nesting (max depth 7) in utils/llm_client.py and duplicated answer‑generator code across three locations. No lockfiles are present, making reproducible builds harder.

The Bottom Line

SimpleMem provides a concrete, modular implementation of lifelong memory for LLM agents, with a clear HTTP‑based MCP layer and a reusable skill wrapper. The codebase is functional but suffers from maintenance‑heavy duplication, missing CI, and large binary assets in the repo. It is suitable for teams that need a ready‑made memory service and are prepared to address the hygiene gaps before production deployment.