Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"scramb-memory-manager": {
"command": "uvx",
"args": [
"memory-manager"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 25, 2026memory-manager
Status: v0.2.0 — enterprise profile (F-01) released; target-size latency not yet met (see
"Enterprise"). Upgrading from v0.1: docs/guides/upgrade-0.2.md.
A self-hosted, production-grade long-term memory for Claude that claude.ai (web/mobile) and Claude Code share through one remote MCP server. Human-readable Markdown in Git is the source of truth; Postgres (pgvector + full text) is a derived, rebuildable search index. A small set of well-described tools plus built-in usage rules keeps the memory curated instead of cluttered.
Architecture
claude.ai ──(HTTPS + OAuth)──┐
Claude Code ──(HTTP/stdio)───┼──► MCP server ──► write queue ──► Git vault (Markdown, source of truth) ──► remote
│ │ │
│ └──► search ◄── indexer ◄───────┘ (after commit / webhook / poll)
│ │
│ Postgres (pgvector + tsvector)
└── embeddings: pluggable (Ollama/bge-m3 | OpenAI-compatible | none)
The diagram shows the default, single-writer Git storage backend. An enterprise deployment
runs the same server against the Postgres storage backend instead (source of truth with
append-only revisions, horizontal api/worker replicas, Entra login) — see "Enterprise" below
and ADR-0007.
See docs/PLAN.md for the full goal, scope and architecture, and
docs/TASKS.md for the current work backlog.
Features
- Storage backend: Git (default, Markdown as the source of truth) or Postgres with append-only revisions (enterprise, ADR-0007) — see "Enterprise" below.
- Vault: Markdown notes in Git as the source of truth, Postgres fully rebuildable from it.
- Writes carry
if_version; conflicts surface the current content instead of overwriting it. - Deletes are soft (archived to
_archive/, never hard-deleted). - Hybrid search: full-text +
pgvector, fused with RRF; embeddings are optional (Ollama, OpenAI-compatible, or none — full-text-only fallback). - MCP server over stdio (Claude Code) and Streamable HTTP (claude.ai and Claude Code), one
instance for both. Tools:
memory_search,memory_read,memory_files,memory_index,memory_write,memory_edit,memory_supersede,memory_archiveandmemory_promote(copy a note into a shared namespace); usage rules ship as server instructions plus thememory_guideprompt. - Embedded OAuth 2.1 authorization server with OIDC and password login, client ID metadata documents (CIMD), per-client and per-IP limits, and an audit log for every write.
- Static scoped bearer tokens as a lighter-weight alternative to OAuth.
- Write-rate and storage quotas, an optional operator blocklist for content categories, and audit export to a SIEM (stdout and/or OTLP).
- Vault import (Markdown, Claude, ChatGPT) and export for migration and backup, plus
migrate git-to-postgresinto the enterprise backend. - Container images signed (cosign) with an SBOM published alongside each release; the image bundles the Valkey client and the OTel SDK/exporter, both inert until configured.
- Deployment via Helm chart, Kustomize base, or a Flux example.
Quickstart
Brings up memory-manager, Postgres+pgvector and a local, throwaway vault remote - good enough to try the server without a real Git host or embedding provider yet.
podman compose up -d # or: docker compose up -d
No .env file is needed for this - every value the stack needs to boot is a plain literal in
compose.yaml. The first start builds the image and runs vault-init, a one-shot container that
creates a local bare "remote" (file:///data/remote.git, in the vault-remote volume) and seeds
it with a welcome note - point VAULT_REMOTE in compose.yaml at a real Git remote instead to
skip this (a real deployment is expected to adapt its own copy of the file). Wait for /readyz
to answer:
curl http://localhost:8080/readyz
Create a bearer token (printed once - store it) and point a client at the server:
podman compose exec memory-manager \
memory-manager token create me --scope memory:read --scope memory:write --namespace '*'
claude mcp add --transport http memory http://localhost:8080/mcp \
--header "Authorization: Bearer <token>"
Embeddings are optional (full-text search works without one, EMBEDDING_PROVIDER=none). For a
local embedding provider, copy .env.example to .env and set EMBEDDING_PROVIDER=ollama there
(picked up automatically if .env exists, ignored if it does not), then start the ollama
profile too:
cp .env.example .env # edit EMBEDDING_PROVIDER=ollama in it first
podman compose --profile ollama up -d
Tear the stack down again (including its volumes - the local vault remote and the Postgres index are both gone with it):
podman compose down -v
make up/make down do the same with Podman directly.
Connect
Remote setup for both clients (OAuth, verified 2026-10-07): docs/guides/remote-connect.md.
- Claude Code: see
docs/guides/claude-code.mdfor the stdio transport (claude mcp add) and the environment variables the server reads. - claude.ai: add memory-manager as a custom connector under Settings → Connectors → Add
custom connector, with the URL
https://memory.example.com/mcp(your own deployment's hostname, Streamable HTTP). OAuth login happens in the browser against the server's embedded authorization server; no token to copy and paste.
Deploy
- Kubernetes manifests (Kustomize base):
deploy/README.md - Helm chart:
charts/memory-manager/README.md - GitOps example with Flux:
deploy/flux/README.md - Exposing a self-hosted instance without a public ingress (Cloudflare Tunnel):
docs/guides/cloudflare-tunnel.md - Migrating an existing Git vault into the enterprise
postgresstorage backend:docs/guides/migrate-git-to-postgres.md - Running the enterprise profile end to end (Entra, Flux rollout, scaling, backups and
restore):
docs/guides/enterprise-operations.md - Cutting and verifying a release (image and chart signatures, SBOM):
docs/releasing.md
Enterprise
An organisation with Microsoft Entra ID can run memory-manager for about 2,000 employees on the
postgres storage backend (source of truth with append-only revisions, enterprise,
ADR-0007) instead of the default Git backend. On top of
everything above, this profile adds:
- Personal, group, project and org namespaces, enforced by Postgres row-level security as well as application code (ADR-0008).
- Sign-in through Microsoft Entra ID, with deprovisioned users cut off by a Graph delta sync (ADR-0006).
- An
/accountpage for self-service and administration, and a break-glass path for emergency access. - Provable erasure and retention (GDPR Art. 17) outside MCP, and write-rate/storage quotas per
user, namespace or token (
docs/guides/quotas.md). - Horizontal scaling: stateless
apireplicas plus aworker(memory-manager worker) that runs indexing and periodic jobs from a Postgres jobs outbox, sharing state through Postgres or Valkey (ADR-0009, ADR-0016). - Observability: traces from requests into worker jobs, metrics, dashboards and alerts.
Requirements: a Microsoft Entra ID tenant with a one-time tenant-admin consent step, Postgres
16+ with pgvector run via the CloudNativePG (CNPG) operator, and a Kubernetes cluster running
the Helm chart's enterprise profile (charts/memory-manager/values-enterprise.yaml).
Measured at target size: at the 1M-note / 5M-chunk target size the latency targets are not
yet met — after the fix in #296, p95 was 43–56 s for search, 16–37 s for read and 19–55 s for
write (targets: <300 ms / <100 ms / <200 ms), with 1.9–6.5 % failed requests. The measured cause
and the full numbers are in
docs/benchmarks/target-size.md; the follow-up is tracked in
#297. Enterprise scale at this size is not
yet proven.
Read on:
- Upgrading an existing v0.1 deployment to v0.2 and the enterprise profile:
docs/guides/upgrade-0.2.md - Upgrading an existing v0.2 deployment to v1.0:
docs/guides/upgrade-1.0.md - Running the enterprise profile end to end (Entra, Flux rollout, scaling, backups/restore):
docs/guides/enterprise-operations.md - What happens to a user's access and memory on role removal, offboarding and restore:
docs/guides/data-lifecycle.md - Entra app registration as an OpenTofu module:
deploy/entra/ - GitOps example with Flux:
deploy/flux/enterprise/README.md - Helm chart enterprise values:
charts/memory-manager/values-enterprise.yaml - Load-test report at target size:
docs/benchmarks/target-size.md - Threat model and pen-test checklist:
docs/security/threat-model.md,docs/security/pentest-checklist.md - Compliance pack (data flow, Art. 30 record, TOMs, deletion concept, roles, DPIA template,
transparency notice):
docs/compliance/
Security
- Policy, scope and how to report a vulnerability:
SECURITY.md - Review against the OWASP Top 10 for LLM Applications, threat model and findings:
docs/security-review.md - Exporting the audit log to a SIEM (stdout and/or OTLP,
AUDIT_EXPORT):docs/guides/audit-export.md - Rejecting writes by content category (
BLOCKLIST_FILE):docs/guides/blocklist.md
Roadmap
Next up is F-02 Client Integrations (planned):
compatibility profiles for further MCP clients, personal tokens and a per-profile conformance
suite. The current backlog is in docs/TASKS.md.
Comparison
A sourced comparison against mem0, Basic Memory and Graphiti/Zep lives in
docs/research/comparison.md. Compact excerpt:
| memory-manager | mem0 (OSS) | Basic Memory | Graphiti (OSS) / Zep (Cloud) | |
|---|---|---|---|---|
| License | AGPL-3.0-only | Apache-2.0 | AGPL-3.0 | Graphiti Apache-2.0 · Zep Cloud proprietary SaaS |
| Source of truth | Markdown files in a Git repo; Postgres is a derived index | Vector store rows (pgvector, Qdrant, …) | Markdown files on disk; SQLite/Postgres index | Graph DB (Neo4j/FalkorDB/Neptune); episodes as provenance |
| Human-editable | Yes (plain Markdown, Git history) | No (DB/dashboard only) | Yes (Markdown, Obsidian-compatible) | No (graph) |
| Search | FTS + pgvector, fused with RRF; FTS-only fallback | Semantic + BM25 + entity matching, fused | FTS + vector hybrid (FastEmbed default), optional reranker | Semantic + BM25 + graph traversal, with reranking |
| Write model | Explicit, curated tool writes with if_version | LLM extraction by default (infer=True), ADD-only | Explicit tool writes; optional expected_checksum | LLM extraction of entities/facts from episodes |
| LLM required | No (embeddings optional: Ollama/OpenAI-compatible/none) | Yes for default extraction | No (local FastEmbed embeddings) | Yes (structured-output LLM + embedder) |
| MCP | stdio + Streamable HTTP, one server for claude.ai and Claude Code | Hosted MCP only; self-hosted server has no MCP; OpenMemory sunset | stdio, streamable-http, SSE | Graphiti: experimental HTTP/stdio · Zep: hosted Context MCP |
| OAuth for claude.ai | Embedded OAuth 2.1 AS | Hosted platform only | Cloud only (WorkOS AuthKit) | Zep Cloud (OAuth 2.1 + PKCE); Graphiti MCP: none documented |
| Self-host footprint | 1 container + Postgres 16/pgvector + Git remote | FastAPI + Postgres/pgvector + dashboard + LLM key | uvx basic-memory (Python 3.12), SQLite | Graphiti: graph DB + LLM key · Zep BYOC: Enterprise plan only |
License
AGPL-3.0-only (see LICENSE). In plain words:
- Self-hosting an unmodified copy for yourself, your team or your company carries no extra obligations beyond the license itself.
- Offering a modified version of this server as a network service to others requires publishing the source of that modified version to its users (AGPL §13).
Contributing
See CONTRIBUTING.md for how to set up the project, the branch/commit/PR
rules and the DCO sign-off required on every commit.