Skip to main content

Centralized memory system for AI development tools

Project description

mem-mesh

PyPI version CI Python 3.9+ License: MIT MCP Protocol

Persistent memory for AI coding tools — resumable session state, the decision context that never reaches git, and injection that is measured rather than assumed. Hybrid vector + FTS5 search over a single SQLite file, zero external services.

한국어 · Quick Start · MCP Setup · MCP Tools · Session & Pins · Architecture · Docker · Contributing


Why mem-mesh?

mem-mesh does not claim that searching your past sessions makes a model write better code — it treats that as a hypothesis it instruments and measures (Measured, not assumed). It earns its place on three things git, pull requests, and well-kept docs do not capture:

  • Session-to-session work statepin_add / pin_complete track the unit of work; session_resume restores where the last session stopped. "Where was I" answered directly.
  • Knowledge that never reaches git — the why of a decision, the approach that failed, the constraint learned during an incident. First-class categories with typed relations, so a superseded decision links to the one that replaced it.
  • Observability and retrospectiveweekly_review, the dashboard, and team relay show what your agents recorded, retrieved, and let go stale.
Differentiator What it means
Pin lifecycle Lightweight kanban inside every session: pin_addpin_completepin_promote. Restore in-progress work with session_resume.
Injection instrumentation Every auto-surfaced memory is tracked in injected_memories; a deterministic Stop-time heuristic judges whether it was used; weekly_review reports the hit rate. Utility is measured, not assumed.
Git-anchored staleness Code memories carry commit + file anchors; the client verifies freshness and reports it, so stale context is dropped from injection instead of misleading the agent.
Human-gated doc promotion doc_proposal drafts a promotion to version-controlled docs; a person approves; the client applies it. Memory is the staging area, git is the durable layer.
Hybrid search sqlite-vec vector embeddings + FTS5 full-text fused with Reciprocal Rank Fusion (RRF). Korean n-gram optimized out of the box.
NLI conflict detection 2-stage pipeline: vector similarity pre-filter → mDeBERTa NLI model catches contradictory memories before they're stored.
4-Tier Smart Expand session_resume(expand="smart") uses an importance × status matrix to load only what matters — ~60% token savings.
Zero external services Single SQLite file. pip install mem-mesh and you're running. No Postgres, no Redis, no cloud.
Dual MCP transport stdio (Cursor, Claude Desktop, Kiro) + Streamable HTTP/SSE (MCP spec 2025-03-26).
25+ client auto-detection Identifies the calling IDE/AI platform from MCP handshake or User-Agent.
Batch operations Pack multiple memory ops into one round-trip: 30–50% token savings.

Measured, not assumed

The "past-session search boosts coding" claim is instrumented rather than asserted. Every injected memory is recorded in injected_memories (one row per turn); a Stop-time heuristic with no LLM judges whether it was later referenced; weekly_review surfaces the injection hit rate. Offline, scripts/replay_injection_eval.py replays real captured prompts through the legacy and current injection formats and scores both with deterministic metrics plus an optional blind LLM judge. The premise is honest: if the current format shows no advantage, shrinking injection is a valid outcome. For pure code work in a repository whose commits, PRs, and docs are already well kept, the marginal value of retrieving past sessions is unproven — mem-mesh ships the tools to measure it, and the three capabilities above stand regardless of how that measurement resolves.


Features

  • Memory CRUDadd, search, context, update, delete
  • Hybrid search — sentence-transformers vectors + FTS5 RRF fusion, Korean n-gram support
  • Session & pins — short-lived work tracking with importance-based promotion to permanent memory
  • Injection instrumentationinjected_memories tracking + Stop-time usage heuristic + weekly_review injection stats; offline replay harness to validate injection value
  • Git-anchored lifespan — commit/file anchors with client-side staleness verification; stale memories excluded from injection
  • Human-gated promotiondoc_proposal promotes memory toward version-controlled docs (LLM drafts, human approves, client applies)
  • Auto-redaction — deterministic secret/PII masking on auto-captured content before it reaches long-term memory
  • Memory relationslink, unlink, get_links across 7 relation types
  • Conflict detection — mDeBERTa NLI prevents storing contradictory facts
  • Batch operations — 30–50% fewer tokens per multi-op workflow
  • Web dashboard — FastAPI REST API + real-time UI at localhost:8000

Quick Start

Recommended: uvx (zero Python management)

One tool to install — uv — and mem-mesh handles the rest. No virtualenv, no pyenv tweaks, no sqlite-vec compile errors. Your MCP client spawns a cached, isolated mem-mesh on-demand.

# 1. Install uv (one-time, ~15 seconds)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. Run the onboarding wizard — writes MCP config for detected tools,
#    offers to install hooks, warms the uv cache.
uvx mem-mesh

That's it. Restart Cursor / Claude Desktop / Kiro and mem-mesh MCP tools are live.

uvx mem-mesh (bare) runs onboarding — no --from "mem-mesh[server]" needed, since the lightweight base package is all the wizard requires (it still writes config that runs the server via the [server] extra). uvx mem-mesh install is the explicit equivalent.

For agents / CI: uvx mem-mesh --json runs onboarding non-interactively and prints a single JSON result (per-step status + next_actions). Non-TTY invocations (pipes, agents) auto-run non-interactively even without --json. Onboarding writes the config single-source-of-truth — ~/.mem-mesh/api_url and ~/.mem-mesh/hook_token — which every tool's hooks read at runtime (reachable from GUI- and terminal-launched tools alike). The MEM_MESH_API_URL / MEM_MESH_HOOK_TOKEN env vars seed those files (and act as a per-session override; mem-mesh doctor flags any that shadow the files). The token must also stay exported for HTTP hooks / authenticated MCP, which read the shell env and have no file fallback. Example: MEM_MESH_API_URL=https://memory.example.com MEM_MESH_HOOK_TOKEN=… uvx mem-mesh --json.

Install or repair hooks directly through the same uvx entrypoint:

uvx mem-mesh hooks install --target codex
uvx mem-mesh hooks status

Want the web dashboard too? uvx --from "mem-mesh[server]" mem-mesh serve — open http://localhost:8000.

Alternative: pip install

If you prefer managing Python environments yourself:

pip install "mem-mesh[server]"
mem-mesh                    # onboarding wizard (or: mem-mesh install)
mem-mesh serve             # web server + SSE MCP at localhost:8000

Prerequisites (only if NOT using uvx)

mem-mesh loads the sqlite-vec extension at runtime, so Python's sqlite3 module must support loadable extensions.

  • uvx users — uv's managed Python builds already have extension loading enabled. Nothing to do.
  • Linuxpysqlite3-binary wheel installs automatically as a fallback.
  • macOS — system Python and Homebrew Python both work. Only pyenv's default build is broken.
  • Windows — system Python works; install pysqlite3-binary manually if needed.

macOS + pyenv users who hit Migration failed: no such module: vec0:

# Option A: rebuild Python against Homebrew sqlite3
brew install sqlite3
SQLITE_PREFIX="$(brew --prefix sqlite3)"
PYTHON_CONFIGURE_OPTS="--enable-loadable-sqlite-extensions" \
LDFLAGS="-L${SQLITE_PREFIX}/lib" \
CPPFLAGS="-I${SQLITE_PREFIX}/include" \
CFLAGS="-I${SQLITE_PREFIX}/include" \
  pyenv install 3.13 --force
pyenv rehash

# Option B (simplest): just use uvx — it bypasses system Python entirely

Linux distro Python, Docker images, and conda Python ship with extension loading enabled — no extra steps needed.


MCP Setup

mem-mesh install writes these entries for you automatically. The snippets below are what gets written, for reference.

uvx (recommended)

Zero Python-env management. The MCP client spawns a cached mem-mesh process per call; the first run downloads it, subsequent runs are instant.

{
  "mcpServers": {
    "mem-mesh": {
      "command": "uvx",
      "args": ["--from", "mem-mesh[server]", "mem-mesh-mcp-stdio"],
      "env": { "MEM_MESH_CLIENT": "cursor" }
    }
  }
}

Stdio (local Python)

Use your own Python install. Good if you need -e . dev installs.

{
  "mcpServers": {
    "mem-mesh": {
      "command": "python",
      "args": ["-m", "app.mcp_stdio"],
      "cwd": "/absolute/path/to/mem-mesh",
      "env": { "MCP_LOG_LEVEL": "INFO" }
    }
  }
}

HTTP (streamable, shared running server)

For web clients or when multiple tools share one process. Requires mem-mesh serve running. Use "type": "http"type: "sse" is legacy and hangs after a server restart.

{
  "mcpServers": {
    "mem-mesh": {
      "url": "http://localhost:8000/mcp/sse",
      "type": "http"
    }
  }
}

Config file locations by tool:

Tool Config file
Cursor .cursor/mcp.json
Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json
Kiro ~/.kiro/settings/mcp.json

Mode comparison

uvx Stdio HTTP
Prereq uv only Python env with mem-mesh[server] Running mem-mesh serve
First call ~15s (cache warm) Instant Instant
Server to manage None None Yes
Dashboard Optional (uvx … serve) Optional Included
Hooks support Requires separate server Yes (local mode) Yes (api mode)

MCP Tools (15)

Tool Description Key parameters
add Store a memory content, project_id, category, tags
search Hybrid vector + FTS5 search query, project_id, category, limit, recency_weight, response_format
context Retrieve memories surrounding a given memory memory_id, depth, project_id
update Edit a memory memory_id, content, category, tags
delete Remove a memory memory_id
stats Usage statistics project_id, start_date, end_date
link Create a typed relation between memories source_id, target_id, relation_type
unlink Remove a relation source_id, target_id
get_links Query relations memory_id, relation_type, direction
pin_add Add a short-lived work-tracking pin content, project_id, importance, tags
pin_complete Mark a pin done; optionally promote to permanent memory pin_id, promote, category
pin_promote Promote an already-completed pin to permanent memory pin_id, category
session_resume Restore context from the previous session project_id, expand, limit
session_end Close a session with a summary project_id, summary, auto_complete_pins
batch_operations Execute multiple ops in one call operations (array of add/search/pin_add/pin_complete)

search response formats: minimal | compact | standard | full


Search

mem-mesh runs two retrieval engines in parallel and merges results with Reciprocal Rank Fusion:

  • Vectordragonkue/snowflake-arctic-embed-l-v2.0-ko (1024-dim, Korean retrieval SOTA, MTEB-ko #1) by default; KURE, E5 and MiniLM models supported
  • FTS5 — SQLite full-text search with n-gram tokenization for CJK languages
  • RRF fusion — balances semantic similarity and keyword precision
  • Quality filters — noise removal, intent analysis, vector pre-filter overfetch to improve recall

Session & Pins

Session lifecycle

session_resume(project_id, expand="smart")  →  work  →  session_end(project_id, summary)
  • session_resume restores incomplete pins and context from the previous session. Stale pins are auto-closed. expand="smart" applies an importance × status matrix that cuts token usage by ~60%.
  • session_end records a summary and closes the session. If the session terminates abnormally, the next session_resume automatically recovers open pins.

Pin lifecycle

Pins are the unit of work inside a session. Track code changes, implementations, and configuration work as pins — not in permanent memory.

pin_add(content, project_id)  →  do the work  →  pin_complete(pin_id, promote=True)
                                                   # promote=True completes and promotes in one call

Status flow: open (planned, not started) → in_progress (active; default on pin_add) → completed

Multi-step work can pre-register later steps as open pins, then activate them one at a time.

Auto-stale cleanup (triggered on session_resume):

  • in_progress pins older than 7 days → auto-completed
  • open pins older than 30 days → auto-completed

When to pin: only when files change. Questions, explanations, and read-only lookups do not need pins. Multi-step tasks get one pin per step.

Importance levels:

Level Use for
5 Architecture decisions, core design changes
3–4 Feature implementations, significant fixes
1–2 Minor edits, typo fixes
omit Auto-inferred from content

Promote: pin_complete(pin_id, promote=True) completes and promotes to permanent memory in one call. To promote after the fact: pin_promote(pin_id).

Client detection: In HTTP mode, the calling client is identified from the MCP initialize handshake or User-Agent header (25+ IDE/AI platforms supported). In stdio mode, set MEM_MESH_CLIENT in the environment.

AI agent checklist

1. Session start   → session_resume(project_id, expand="smart")
2. Past context    → search() before coding if referencing previous decisions
3. Track work      → pin_add → pin_complete (promote=True to merge into memory)
4. Permanent store → decision / bug / incident / idea / code_snippet only
5. Session end     → session_end(project_id, summary, auto_complete_pins=True)
6. Never store     → API keys / tokens / passwords / PII

Principle: Hooks are read-only signals. All pin creation, completion, and promotion decisions are made by the LLM with full context.


Memory Relations

Seven relation types: related | parent | child | supersedes | references | depends_on | similar

get_links direction: outgoing | incoming | both


Configuration

Variable Description Default
MEM_MESH_DATABASE_PATH SQLite database path XDG per-user path (see app/core/config.py _default_db_path)
MEM_MESH_EMBEDDING_MODEL Embedding model name dragonkue/snowflake-arctic-embed-l-v2.0-ko
MEM_MESH_EMBEDDING_DIM Vector dimensions 1024
MEM_MESH_SERVER_PORT Web server port 8000
MEM_MESH_SEARCH_THRESHOLD Minimum similarity score 0.5
MEM_MESH_USE_UNIFIED_SEARCH Enable hybrid search true
MEM_MESH_ENABLE_KOREAN_OPTIMIZATION Korean n-gram FTS true
MEM_MESH_LOG_LEVEL Server log level INFO
MEM_MESH_LOG_FILE Log output file (none)

See .env.example for the full list.

Pointing hooks at a remote mem-mesh server

Bash hooks (Stop, SessionStart, SubagentStop, …) resolve the API URL in this order:

  1. MEM_MESH_API_URL environment variable
  2. API_URL environment variable
  3. ~/.mem-mesh/api_url — single-line file with the server URL
  4. The URL baked into the hook at install time
  5. http://localhost:8000

Use the config file when you want one installed hook bundle to talk to a remote server (e.g. https://mem.example.com) without editing settings.json and without relying on env-var inheritance — Claude Code does not export settings.json.env retroactively to already-running sessions, so an env var added mid-session won't reach hooks until you restart.

mkdir -p ~/.mem-mesh
echo 'https://mem.example.com' > ~/.mem-mesh/api_url
mem-mesh doctor   # confirms the resolved URL and its source

Per machine — the file is not synced. Delete it (or set MEM_MESH_API_URL) to fall back to the baked default.


Web Dashboard

  • Dashboard: http://localhost:8000
  • API docs (Swagger): http://localhost:8000/docs
  • Health check: http://localhost:8000/health

Architecture

flowchart LR
    subgraph Clients
        Cursor[Cursor]
        Claude[Claude Desktop]
        Kiro[Kiro]
        Web[Web Client]
    end

    subgraph Transport
        Stdio[Stdio MCP]
        SSE[SSE / Streamable HTTP]
    end

    subgraph Core
        MCP[mcp_common]
        Storage[Storage Service]
    end

    subgraph Data
        SQLite[(SQLite + sqlite-vec + FTS5)]
    end

    Cursor --> Stdio
    Claude --> Stdio
    Kiro --> Stdio
    Web --> SSE
    Stdio --> MCP
    SSE --> MCP
    MCP --> Storage
    Storage --> SQLite

Directory structure

mem-mesh/
├── app/
│   ├── core/              # DB, embeddings, services, schemas
│   ├── mcp_common/        # Shared MCP tools, dispatcher, batch
│   ├── mcp_stdio/         # FastMCP stdio server
│   ├── mcp_stdio_pure/    # Pure MCP stdio server
│   └── web/               # FastAPI (dashboard, SSE MCP, OAuth, WebSocket)
├── static/                # Frontend (Vanilla JS, Web Components)
├── tests/                 # pytest
├── scripts/               # Migration and benchmark scripts
├── docs/rules/            # AI agent rule modules
├── data/                  # memories.db
└── logs/

Docker

# Build and start
make quickstart
# or step by step:
make docker-build && make docker-up

# Open http://localhost:8000

First-run setup (dashboard auth)

When the server starts with no dashboard auth configured, anyone who can reach the port can read/write/delete all memories. To let you close this from the browser (no shell-only config), mem-mesh mints a one-time setup token on first boot and prints it to the server console:

============================================================
  FIRST-RUN SETUP  —  dashboard auth is NOT configured
============================================================
  Open : /setup
  Token: <one-time-token>
  (one-time — consumed the moment you finish setup)
============================================================

Open shows the bare path /setup by default — open it on whatever host:port you bound the server to. Set MEM_MESH_PUBLIC_URL to have the banner print a full URL (e.g. https://your-host/setup).

The token is also written next to the DB (/app/data/setup_token), so it survives a mid-onboarding restart. Retrieve it any time:

docker exec mem-mesh-prod cat /app/data/setup_token
# or scan the logs
docker compose logs mem-mesh | grep -A1 "Token:"

Open /setup, enter the token plus an admin username (default admin) and password (≥ 8 chars). On submit mem-mesh saves the credential, enables Basic Auth, consumes the token (single-use), and logs you straight into the dashboard. On a fresh server the first page load auto-redirects to /setup.

Once auth is configured the token is deleted on every startup, so a leftover token can never reconfigure an already-secured server.

Reset the token (lost it, and auth is not configured yet) — delete the file and restart; ensure_setup_token() is idempotent, so a plain restart keeps the same value:

docker exec mem-mesh-prod rm -f /app/data/setup_token
docker restart mem-mesh-prod
docker logs mem-mesh-prod 2>&1 | grep -A1 "Token:"

Development

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
python -m pytest tests/ -v

# Format and lint
black app/ tests/
ruff check app/ tests/

# Check embedding migration status
python scripts/migrate_embeddings.py --check-only

Documentation

  • CLAUDE.md — AI tool checklist (MUST/SHOULD/MAY rules, security policy)
  • AGENTS.md — Project context, Golden Rules, Context Map, session management details

AI agent rules

File Purpose
DEFAULT_PROMPT.md Standalone behavior rules for projects without installed hooks
modules/ Optional Rule Manager modules: core, search, memory-log, pins, relations, batch, security

Generated hook rules share the installed hook prompt version:

mem-mesh hooks rules --project-id <project-id> --format plain
mem-mesh hooks rules --project-id <project-id> --format claude

Architecture docs


Contributing

  1. Open an issue or pull request
  2. Follow black and ruff formatting
  3. Add tests for any new behavior

See CONTRIBUTING.md for details and CHANGELOG.md for release history.


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

mem_mesh-1.26.1.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

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

mem_mesh-1.26.1-py3-none-any.whl (1.1 MB view details)

Uploaded Python 3

File details

Details for the file mem_mesh-1.26.1.tar.gz.

File metadata

  • Download URL: mem_mesh-1.26.1.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mem_mesh-1.26.1.tar.gz
Algorithm Hash digest
SHA256 7d107da26b36a6189c0fe4dac3280d4b7cf90ab0bb50d7d0034dabecfcf47cf8
MD5 e3ae74821c1590c528e5ad73eb0cee6e
BLAKE2b-256 0c40ef7e1c008693cf1659824392d0446661d22da327c64522c128692c6ea1b4

See more details on using hashes here.

Provenance

The following attestation bundles were made for mem_mesh-1.26.1.tar.gz:

Publisher: release.yml on x-mesh/mem-mesh

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

File details

Details for the file mem_mesh-1.26.1-py3-none-any.whl.

File metadata

  • Download URL: mem_mesh-1.26.1-py3-none-any.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mem_mesh-1.26.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12c2b8704f25c12bf755a9696ade6017dda106bac05c90692614cee1eebb0722
MD5 c946ccdc8ea78c23409c9514673933ae
BLAKE2b-256 f9b620d7921e123c41c40cd4b1cabd1411ce2535fcba51b45f26e0b42640441d

See more details on using hashes here.

Provenance

The following attestation bundles were made for mem_mesh-1.26.1-py3-none-any.whl:

Publisher: release.yml on x-mesh/mem-mesh

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