Memory Vault
Memory serverOfficial Mihai Builds project
Created by MihaiBuilds
Published in MihaiBuilds/memory-vault. Publisher page
67 GitHub stars
What it is
A local-first AI memory system with hybrid search, MCP integration, and a knowledge graph.
AutoGineer overview, from the brain’s own files
Memory Vault provides a persistent storage layer for AI agents, solving the problem of context loss between sessions. It uses a single PostgreSQL database with pgvector to store memories, decisions, and project context. By combining hybrid semantic and keyword search with an automated knowledge graph, it allows agents to recall information accurately. It is designed to be platform-agnostic, exposing its capabilities through the Model Context Protocol (MCP) for integration with tools like Claude, as well as a REST API for custom applications. The system includes a web dashboard for managing memories and chatting with data using local LLMs.
How it works
Memory model: Hybrid
AutoGineer overview, from the brain’s own files
The system runs as a memory server using PostgreSQL and pgvector for storage. It processes data through a hybrid search engine that combines vector embeddings and keyword matching. An automated entity extraction process using spaCy builds a knowledge graph. The system exposes these capabilities via an MCP server for agent communication, a REST API for external integration, and a web-based dashboard for manual interaction and local LLM-powered chat.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 12 |
| docs | docs | 5 |
| scripts | scripts | 2 |
| src | source-code | 49 |
| tests | tests | 57 |
| web | folder | 28 |
The agent writes
- docker-compose.yml evidence: README.md
Requirements
Apps: Docker
Runtimes: Python >=3.11
Databases: PostgreSQL, Redis
API keys (by name): MV_TOKEN
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Google Antigravity, Kiro, OpenCode, Amp, Roo Code, Cline, JetBrains Junie, Devin (ex-Windsurf)
Set it up
- Not scanned by AutoGineerThe author’s README also describes installing it with Docker Compose. Read its install section: AutoGineer did not scan that path. https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md#can-i-run-multiple-memory-vault-instances
- Not scanned by AutoGineerThe author’s README also describes installing it with Docker Compose. Read its install section: AutoGineer did not scan that path. https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md#quick-start-docker
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md#quick-start-docker
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md#setup-with-pip--venv-fallback
- Not scanned by AutoGineerThe author’s README also describes installing it from a clone of its repository. Read its install section: AutoGineer did not scan that path. https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md#setup-with-uv-recommended
- Not scanned by AutoGineerThe author also offers a container image (ghcr.io/mihaibuilds/memory-vault-mcp:1.6.1). https://github.com/MihaiBuilds/memory-vault/tree/19d10c58319c63244f986ffa5bc6705f90e15d83
- Not scanned by AutoGineerIts dependencies are installed by the package manager when you run it and were not scanned by AutoGineer (12 declared). https://github.com/MihaiBuilds/memory-vault/tree/19d10c58319c63244f986ffa5bc6705f90e15d83
Created by MihaiBuilds. Published in MihaiBuilds/memory-vault. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Integrate with Claude Desktop or Claude Code via MCP
- Query memories through a local LLM chat interface
- Build custom AI tools using the REST API
- Manage and browse memories via the web dashboard
- Ingest documentation or notes via CLI
- “Recall everything about hybrid search.”
- The agent retrieves relevant memory chunks using the hybrid search engine and provides a grounded answer.
- “Remember that we chose Redis for the session cache.”
- The agent stores this decision as a new memory, which is then auto-classified and embedded for future retrieval.
Documentation by MihaiBuilds
Memory Vault
Image: Tests Image: License: MIT Image: Python 3.11+ Image: Latest Release Image: Docker Image Image: MCP Registry Image: Ruff
The memory database for AI applications. Self-hosted Postgres + pgvector with hybrid search, MCP-native, and a knowledge graph baked in.
Every conversation with Claude or ChatGPT starts from zero. No memory of what you built last week, what decisions you made last month, what problems you've already solved. You either re-explain everything from scratch, or paste in a wall of context and hope it fits in the window.
Memory Vault is the persistent layer underneath. It stores what you want your AI to remember — decisions, conversations, notes, project context — in a single Postgres database with hybrid semantic + keyword search. Claude can recall and store memories during any session via MCP, you can chat with your own memories through a local LLM, or you can build your own AI tool on top of the REST API.
Image: Memory Vault chat with sources
Chat with your vault using a local LLM. Every answer shows the exact memories it was grounded in — click any source to verify.
Status
v1.0 — released 2026-05-07. First stable release of Memory Vault. M1-M7 (hybrid search, Docker, MCP, REST API, dashboard, knowledge graph, local LLM chat) all shipped and stable.
See CHANGELOG.md for the full per-release history, or GitHub Releases for the platform-native view.
Semver from here forward — the public surface (REST API endpoints, MCP tool signatures, DB schema) is stable. Breaking changes only on a major version bump.
Quick Start (Docker)
git clone https://github.com/MihaiBuilds/memory-vault.git
cd memory-vault
docker compose up -dThat's it. PostgreSQL + pgvector + Memory Vault, running and ready. Migrations run automatically on first start.
# Check it's working
docker compose exec app memory-vault status
# Ingest a file
docker compose exec app memory-vault ingest /path/to/file.md --space default
# Search
docker compose exec app memory-vault search "your query here"Data persists in a Docker volume — docker compose down and up again, your memories are still there.
Open http://localhost:8000 in your browser to use the dashboard (Chat, Search, Browse, Graph, Ingest, Stats).
Windows users: clone into WSL2, not a Windows path, and read docs/windows.md if you hit a line-ending error.
No-Docker quick start
If you prefer running without Docker:
Prerequisites
Setup with uv (recommended)
# Clone
git clone https://github.com/MihaiBuilds/memory-vault.git
cd memory-vault
# Create virtual environment and install dependencies
uv sync
# Install the spaCy language model
uv run python -m spacy download en_core_web_sm
# Configure
cp .env.example .env
# Edit .env with your PostgreSQL credentials
# Run migrations
uv run memory-vault migrate
# Verify
uv run memory-vault statusSetup with pip + venv (fallback)
If you don't want to install uv, plain pip + venv works too:
# Clone
git clone https://github.com/MihaiBuilds/memory-vault.git
cd memory-vault
# Create virtual environment
python -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -e .
# Install the spaCy language model
python -m spacy download en_core_web_sm
# Configure
cp .env.example .env
# Edit .env with your PostgreSQL credentials
# Run migrations
memory-vault migrate
# Verify
memory-vault statusUsage
If you set up with uv, prefix commands with uv run (e.g. uv run memory-vault search ...). If you used pip + venv, activate the venv first (source .venv/bin/activate) and run commands directly:
# Ingest a file
memory-vault ingest notes.md --space default
# Search memories
memory-vault search "hybrid search architecture" --limit 5
# Check status
memory-vault statusFeatures
Hybrid search — semantic similarity + keyword matching combined, so you find the right memory even when you don't remember the exact words
MCP integration — four tools (
recall,remember,forget,memory_status) that Claude can use natively during any sessionLocal LLM chat — query your own memories through LM Studio without sending anything to the cloud, with sources shown for every answer
Knowledge graph — entities and relationships extracted automatically, connections between things emerge over time
Memory spaces — separate namespaces for different projects or domains
REST API — integrate AI memory into any application
One-command setup —
docker compose upand it's runningSelf-hosted — your data stays on your machine, always
Architecture
Image: Memory Vault architecture
Postgres + pgvector at the core. The same memory layer is reachable from MCP (Claude), the dashboard chat page, the REST API, and any app you build on top.
Three things are deliberate about this stack:
One database, not two. Vector embeddings, full-text indexes, and relational data all live in Postgres. No separate vector DB to keep in sync.
Frontend-agnostic. The dashboard is one consumer of the API, not the API itself. MCP, REST, CLI, and your own apps are equal first-class clients.
CPU-only by default. No GPU required. Embeddings (sentence-transformers) and entity extraction (spaCy) both run on a normal laptop.
Tech Stack
PostgreSQL 16 + pgvector — vector storage and hybrid search in one database
Python 3.11+ — async backend with psycopg 3
sentence-transformers —
all-MiniLM-L6-v2embeddings (384-d, runs on CPU)spaCy —
en_core_web_smfor entity extraction (CPU-only, no LLM calls)FastAPI — REST API with bearer auth, rate limiting, and OpenAPI docs
React 19 + Vite + TanStack Query — web dashboard, baked into the main Docker image
Cytoscape.js + cose-bilkent — force-directed knowledge graph rendering on the dashboard
Docker — one-command deployment with
docker compose upMCP — Claude integration via FastMCP (stdio transport)
MCP Integration (Claude Desktop & Claude Code)
Memory Vault exposes six tools via the Model Context Protocol so Claude can read and write memories during any conversation.
Tools
| Tool | Description |
|---|---|
recall | Search memories with hybrid search (vector + full-text + RRF) |
remember | Store a new memory — auto-classified and embedded |
forget | Soft-delete a memory by chunk ID |
purge_forgotten | Permanently delete memories forgotten more than N days ago |
move_memory | Move a memory to another space, rebuilding its graph entries |
memory_status | Database health, chunk counts, embedding model info |
Resources
| Resource | Description |
|---|---|
memory://spaces | List all memory spaces with chunk counts |
memory://stats | Current system statistics |
Setup — Claude Code
Make sure you've completed the No-Docker quick start above (uv sync or pip install, plus the spaCy model download) so the memory_vault package is installed.
Project scope — add to your project's .mcp.json:
{
"mcpServers": {
"memory-vault": {
"command": "/path/to/memory-vault/.venv/bin/python",
"args": ["-m", "memory_vault.mcp"],
"env": {
"DB_HOST": "localhost",
"DB_PORT": "5432",
"DB_NAME": "memory_vault",
"DB_USER": "memory_vault",
"DB_PASSWORD": "memory_vault"
}
}
}
}Global scope — to make memory-vault available in every Claude Code session, add the same server block to ~/.claude/.mcp.json, then add memory-vault to enabledMcpjsonServers in ~/.claude/settings.json:
{
"enabledMcpjsonServers": ["memory-vault"]
}Verify with claude mcp list — memory-vault should show connected.
Setup — Claude Desktop
Add the same server block to Claude Desktop's config (Settings → Developer → Edit Config), then restart Claude Desktop.
Docker Users
If you're running Memory Vault via Docker, use DB_HOST: "127.0.0.1" and make sure port 5432 is exposed in your docker-compose.yml:
{
"mcpServers": {
"memory-vault": {
"command": "/path/to/memory-vault/.venv/bin/python",
"args": ["-m", "memory_vault.mcp"],
"env": {
"DB_HOST": "127.0.0.1",
"DB_PORT": "5432",
"DB_NAME": "memory_vault",
"DB_USER": "memory_vault",
"DB_PASSWORD": "memory_vault"
}
}
}
}The MCP server runs on the host (not inside Docker) and connects to the PostgreSQL container over the exposed port.
Verify It Works
Once configured, Claude will have access to the memory tools. Try:
"Use memory_status to check the memory system."
"Remember that we chose Redis for the session cache."
"Recall everything about hybrid search."
Troubleshooting
ModuleNotFoundErroron startup — the virtual environment isn't installed; re-runuv sync(orpip install -e .) in the repo directory.OSError: [E050]on startup — the spaCy language model isn't installed; re-runpython -m spacy download en_core_web_sm.Server shows
failedin Claude Code — runclaude --debug mcpto see the server's error output.Tools not available in Claude Code despite server connecting — confirm
memory-vaultis listed inenabledMcpjsonServersin~/.claude/settings.json.Connection refused with Docker running — use
DB_HOST: "127.0.0.1"instead of"localhost".
Remote access over HTTP
Everything above runs MCP over stdio, which assumes the client and the server are on the same machine. If your client is somewhere else — Claude Desktop on another machine, an agent harness in a different container — Memory Vault can also serve MCP over HTTP using SSE.
It is off by default. A memory store is not something to start listening on a port without being asked:
MCP_HTTP_ENABLED=trueThe transport then mounts at /api/mcp on the same port as the REST API, so a
client connects to http://<host>:8000/api/mcp/sse.
Every request needs a token, created the same way as for the REST API:
memory-vault token create my-remote-clientClients differ in how they express a remote MCP server, but they all need the same three things — the SSE transport, the URL, and the token. In the shape most of them use:
{
"mcpServers": {
"memory-vault": {
"type": "sse",
"url": "http://192.168.1.50:8000/api/mcp/sse",
"headers": { "Authorization": "Bearer mv_your-token-here" }
}
}
}Say which hostnames are yours
Memory Vault answers only to hostnames you have declared, and refuses anything
else with HTTP 421. That check is what stops a page in a browser resolving
its own domain to 127.0.0.1 and reaching your memory store through your
machine.
The default covers a client on the same machine (localhost and 127.0.0.1,
on any port). Reaching it by any other name — a LAN address, a container name,
a hostname behind a reverse proxy — means saying so:
MCP_HTTP_ALLOWED_HOSTS=memory.internal:8000,192.168.1.50:8000The list replaces the default rather than adding to it, so include
localhost:* if you still want local clients. A host:* entry matches that
host on any port.
If a client gets 421 Misdirected Request, this is why: the name it used is
not on the list.
Security
API_AUTH_ENABLED=false does not open the MCP transport. That setting is a
local-development convenience for the REST API, and it deliberately stops
there — an unauthenticated REST API on your own laptop is a convenience, while
an unauthenticated memory store on a listening port is how instances end up
public. With the flag off, /api/spaces answers without a token and
/api/mcp/sse still answers 401.
Two things worth knowing before you expose the port:
Bind to somewhere sensible. Publishing the container port on
0.0.0.0reaches the whole network. Bind to a LAN address or keep it behind a reverse proxy or tunnel.There is no transport encryption. Tokens travel in a header, so put TLS in front of it — a reverse proxy or a tunnel — for anything crossing a network you do not control.
Tokens behave exactly as they do for the REST API: revoke one with
memory-vault token revoke <prefix> and it stops working on both surfaces at
once, because both check the same table.
stdio keeps working unchanged. This is an additional way in, not a replacement, and enabling it changes nothing for existing clients.
Local LLM Chat
Memory Vault includes a chat page that lets you talk to your own memories using a local LLM — no cloud, no OpenAI key, no telemetry. The dashboard runs hybrid search against your vault, builds a context block from the top hits, and streams the answer back from a model running on your machine.
Sources are shown with every answer. Every response includes the exact chunks the LLM used, with similarity scores and content previews. Click any source to verify the answer is grounded in your data, not invented. This is the differentiator vs. opaque chat-over-docs tools — you always know what the model saw.
Setup
Memory Vault uses LM Studio as the local LLM provider in v1.0.
Download and install LM Studio.
Load a non-thinking model — Qwen2.5 (7B+), Llama 3 (8B+), or similar. Avoid Qwen3, DeepSeek-R1, and o1-style reasoning models — they emit chain-of-thought into the answer and break the RAG flow.
Start the local server (LM Studio → Developer tab → Start Server). Default address:
http://localhost:1234.Open the Memory Vault dashboard → Chat page → ⚙️ Settings → confirm the Local LLM URL points at your LM Studio instance. The model is auto-detected.
That's it. Ask a question; the dashboard retrieves relevant chunks, sends them with your question to LM Studio, and streams the answer back.
How it works
Hybrid search retrieves the top chunks for your question (same engine as
/api/searchand MCPrecall)Top hits are packed into a 6,000-token context budget — oldest history dropped first, then lowest-similarity chunks
LM Studio generates an answer streamed token-by-token via Server-Sent Events
Sources arrive first in the stream, so the UI shows "based on N memories" before tokens start flowing
Why LM Studio first
LM Studio's native API supports reasoning="off", which is the only reliable way to suppress chain-of-thought from thinking models in a RAG flow. Memory Vault uses the native API by default and falls back to OpenAI-compat (/v1/chat/completions) with <think>...</think> stripping if the native API isn't available.
REST API
Every MCP tool is also exposed as an HTTP endpoint so you can integrate Memory Vault into any app, script, or language. The API is served by FastAPI at http://localhost:8000 when you run docker compose up.
Interactive docs: http://localhost:8000/docs
OpenAPI schema: http://localhost:8000/openapi.json
The auto-generated /docs page is the canonical API reference — it stays in sync with the code. The summary below is for orientation.
Authentication
All endpoints except /api/health require a bearer token. Create one via the CLI:
docker compose exec app memory-vault token create my-appThe plaintext token is shown once — copy it immediately. Then send it as a header:
curl -H "Authorization: Bearer mv_..." http://localhost:8000/api/spacesManage tokens:
memory-vault token list
memory-vault token revoke mv_abc1234To disable auth entirely (local dev only), set API_AUTH_ENABLED=false.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/health | Service + database health (no auth) |
GET | /api/spaces | List memory spaces with chunk counts |
POST | /api/search | Hybrid search (vector + full-text + RRF) |
GET | /api/search/quality | How well recent searches have been matching |
GET | /api/chunks | List chunks with pagination and filters |
GET | /api/chunks/{id} | Get a single chunk |
DELETE | /api/chunks/{id} | Soft-delete (forget) a chunk |
POST | /api/ingest/text | Ingest a text string as a chunk |
POST | /api/ingest/file | Upload a file through the ingestion pipeline |
POST | /api/chat | RAG chat over hybrid search (non-streaming) |
POST | /api/chat/stream | RAG chat with token-by-token SSE streaming |
Example — search
curl -X POST http://localhost:8000/api/search \
-H "Authorization: Bearer $MV_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "how does hybrid search work",
"spaces": ["default"],
"limit": 5
}'Example — search quality
curl http://localhost:8000/api/search/quality \
-H "Authorization: Bearer $MV_TOKEN"{
"queries": 42,
"window_hours": 24,
"avg_top_similarity": 0.51,
"weak_matches": 6,
"empty_results": 0,
"weak_threshold": 0.35
}Aggregated from searches that already ran — asking costs nothing and runs no
query of its own. It reports each search's best hit rather than the mean of
its top-K, because a search returns as many rows as you asked for whatever the
vault holds; averaging down the ranks measures your limit as much as the
quality of the match.
weak_matches is the number worth watching. A search that finds nothing
relevant still returns its closest guesses, so empty_results stays near zero
even when nothing is being answered well. A high weak count usually means the
answers were never stored, rather than that search is failing to find them.
The Stats page in the web UI shows the same figures.
Example — ingest text
curl -X POST http://localhost:8000/api/ingest/text \
-H "Authorization: Bearer $MV_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text": "Decided to use RRF for hybrid merging", "space": "default"}'Example — upload a file
curl -X POST http://localhost:8000/api/ingest/file \
-H "Authorization: Bearer $MV_TOKEN" \
-F "[email protected]" \
-F "space=default"Configuration
| Variable | Default | Description |
|---|---|---|
API_HOST | 0.0.0.0 | Bind address |
API_PORT | 8000 | Port |
API_AUTH_ENABLED | true | Set false to disable bearer auth (local dev only) |
API_CORS_ORIGINS | * | Comma-separated allowed origins, or * |
API_RATE_LIMIT_PER_MIN | 120 | Per-IP request limit per minute |
Dashboard
Memory Vault ships with a web UI baked into the same Docker image as the API — no separate deploy, no extra port. Open http://localhost:8000 in your browser after docker compose up.
Six pages:
Chat — talk to your vault with a local LLM, sources shown for every answer (default landing page)
Search — hybrid search with space filter, similarity scores, expandable hit content
Browse — paginated chunk list with space + sort filters, two-step inline delete
Graph — force-directed knowledge graph (Cytoscape.js), pan/zoom, click a node to see its mentions and related entities, filters for space / type / min-mentions / max-nodes
Ingest — paste text or upload files (one at a time in v1.0), per-file status, batch summary
Stats — system health, total chunks, spaces table with visual distribution, auto-refresh every 30s
Access
The dashboard uses the same bearer token as the API. Create one and paste it into the dashboard's token screen:
docker compose exec app memory-vault token create dashboardThe plaintext token is shown once — copy it immediately. Open http://localhost:8000, paste into the prompt, and the dashboard stores it in localStorage under memory-vault-token. You won't be asked again on that browser.
Rotating or revoking
# See which tokens exist
docker compose exec app memory-vault token list
# Revoke by prefix (shown in list output)
docker compose exec app memory-vault token revoke mv_abc1234
# Create a new one
docker compose exec app memory-vault token create dashboardAfter revoking, the dashboard will hit a 401 on its next request and auto-clear the stored token, forcing you to paste the new one.
Troubleshooting
Prompted for token every reload: your browser is blocking
localStorage(private mode, strict cookie settings). Use a normal window or allow storage forlocalhost.401 on every request: the token was revoked or
API_AUTH_ENABLEDchanged. Create a fresh token and paste it in.Dashboard shows but API calls fail with CORS: you're hitting the API on a different origin than the dashboard. The baked-in build avoids this — use
http://localhost:8000, not the dev server, unless you know what you're doing.Running the dev server:
cd web && npm install && npm run devserves the UI athttp://localhost:5173with API calls proxied to:8000. For development only.Windows-specific issues: see docs/windows.md.
Reporting a bug: run
docker compose exec app memory-vault diagnose(ormemory-vault diagnoseon the host for a fuller bundle includingdocker compose ps+ db logs). The command writes amemory-vault-diagnostic-YYYY-MM-DD-HHMMSS.zipcontaining app logs, status, OS info, and redacted env vars. Bearer tokens, passwords, andmv_tokens are auto-scrubbed — but please review the bundle before attaching it to a public GitHub issue.Quoting a request ID: every API response carries an
X-Request-IDheader (UUID hex). Include it in bug reports — it lets the maintainer grep the same request across the structured JSON logs.
How It Works
Hybrid Search
Memory Vault combines two search methods and merges the results:
Vector search — converts your query to an embedding, finds semantically similar chunks via HNSW index
Full-text search — keyword matching via PostgreSQL tsvector + GIN index
RRF merging — Reciprocal Rank Fusion combines both ranked lists so neither method dominates
This means you find the right memory whether you remember the exact words or just the concept.
Query Enrichment
Before searching, Memory Vault generates up to 3 query variations using the embedding model's WordPiece tokenizer to extract key technical terms. This improves recall without losing precision.
Ingestion Pipeline
Async queue-based pipeline with adapters for different input formats:
Markdown — splits by headings, preserves structure
Plain text — paragraph-based with smart merging
Claude JSON — parses Claude conversation exports
Knowledge Graph
Memory Vault extracts entities and relationships from every ingested chunk and stores them alongside your memories. Click the Graph page in the dashboard to see how the things you've stored connect to each other.
How extraction works:
spaCy NER — the small
en_core_web_smmodel (~15 MB, CPU-only) tagsPERSON,ORG, andPRODUCTentities, mapped to Person, Project, and Tool respectively.Concept extraction — multi-token noun phrases that appear at least twice within a chunk become Concept entities. No LLM, no API calls.
Co-occurrence relationships — any two entities found in the same chunk produce a
related_torelationship. Edge weight grows with co-occurrence count across chunks.Per-space deduplication — entities are deduplicated by
(lower(name), type, space), so the same entity stays one node within a space without merging across unrelated projects.
The whole pipeline runs synchronously on ingest, on the same CPU that runs the embeddings — no extra services, no external API costs.
These trade-offs are deliberate. spaCy + co-occurrence is fast, free, and gets you 80% of the way to a useful graph at 0% of the LLM cost. The honest gaps are documented in the Limitations section below.
Performance Tuning
Memory Vault ships with maintenance_work_mem = 1 GB as the default in the bundled docker-compose.yml. The stock PostgreSQL default is 64 MB, which makes HNSW index builds on pgvector painfully slow once your corpus grows past a few thousand chunks.
If you're running on a host with 16 GB of RAM or more, bumping this to 2 GB gives noticeably faster index rebuilds with no downside. Edit the command: block in docker-compose.yml:
db:
image: pgvector/pgvector:pg16
command:
- postgres
- -c
- maintenance_work_mem=2GBIf you're running on a small box (4 GB total RAM or less, e.g. a tiny VPS), you may want to drop this back down to 256 MB so the rest of the system has breathing room. Memory Vault still works at the stock 64 MB default — it's just slower on large index rebuilds.
Limitations
v1.0 limitations (honest)
English-only NER.
en_core_web_smis English-trained; non-English text gets little to no useful entity extraction. Hybrid search and chat work fine in any language — only the auto-extracted knowledge graph is English-limited.NER is context-dependent. spaCy decides PERSON vs. ORG based on the surrounding sentence. The same name can land as both Person and Project entities depending on syntactic role.
No fuzzy entity matching. "PostgreSQL" and "Postgres" are separate entities. No alias merging in v1.0.
No re-extraction on edit. If you forget a chunk and re-ingest a corrected version, the new entities are added; the old ones aren't cleaned up automatically.
Single-instance. No multi-user / multi-tenant. One vault per deployment. Team features are PRO.
LM Studio only for chat. No Ollama provider in v1.0.
PRO tier (planned)
Team features, advanced analytics, hosted tier. The free / open-source core stays free forever — open-core, not bait-and-switch.
FAQ
How is this different from claude-mem / cognee / Mem0?
Different layer of the stack. Filesystem-based tools (claude-mem, claudesidian, obsidian-second-brain) keep markdown notes on disk and use grep/read at retrieval time. They work great until your vault grows past a few thousand notes — then grep gets slow and semantic recall isn't there. Memory Vault is a database-backed memory layer (Postgres + pgvector + tsvector + RRF) designed to scale and to be built on top of. Frontend-agnostic. Use it through MCP, REST, the dashboard, or your own app — all equal first-class clients.
cognee and Mem0 are closer in stack but cloud-first or SDK-first. Memory Vault is self-hosted infrastructure-first.
Do I need a GPU?
No. Default embeddings (all-MiniLM-L6-v2, 384-d) and entity extraction (en_core_web_sm) both run on CPU. Local LLM chat uses LM Studio on whatever hardware you have — a modern 16 GB-RAM machine handles 7B-parameter models comfortably.
Is my data sent to the cloud?
No. Memory Vault is self-hosted end-to-end. Embeddings are local (sentence-transformers), entity extraction is local (spaCy), chat uses your local LM Studio instance. No telemetry, no API calls to OpenAI / Anthropic / anyone. Your data stays on your machine, period.
Can I use it without Claude?
Yes. The MCP integration is one of three interfaces. The REST API and dashboard work standalone. Use the chat page with any local LLM (LM Studio supports many open-weights models), or build your own AI tool on top of the API.
What languages does NER support?
English only in v1.0. The default spaCy model is English-trained — non-English text gets little to no useful entity extraction. No multilingual NER in v1.0. Hybrid search and chat work fine in any language; only the auto-extracted knowledge graph is English-limited.
How much disk and RAM does it need?
Roughly: 2 GB disk (Docker image + Postgres data + spaCy + embedding model), 1-2 GB RAM idle, 4 GB+ recommended for active use. The bundled config sets maintenance_work_mem=1GB for fast HNSW index builds — drop it to 256 MB on a small VPS.
Can I run multiple Memory Vault instances?
Yes. Each instance is a single docker compose up. Use separate compose project names (docker compose -p mv-personal up, docker compose -p mv-work up) to keep them isolated, or clone into separate directories.
What happens to my data on future updates?
Migrations are versioned and forward-only. docker compose pull && docker compose up -d runs new migrations on start. Schema changes will be additive within v1.x — no destructive migrations on a minor version bump. That's part of the v1.x semver promise.
Contributing
Memory Vault is MIT-licensed and PRs are welcome. See:
CONTRIBUTING.md — how to report bugs, suggest features, set up dev environment, coding conventions
CODE_OF_CONDUCT.md — Contributor Covenant v2.1
SECURITY.md — reporting vulnerabilities (email
[e-mail address on the upstream page](https://github.com/MihaiBuilds/memory-vault/blob/19d10c58319c63244f986ffa5bc6705f90e15d83/README.md), don't open public issues)docs/threat-model.md — what Memory Vault defends against, what it does not, and how to harden a deployment that goes beyond a single machine
Bug report template — includes
memory-vault diagnoseinstructionsFeature request template — frame the problem before suggesting a solution
Single-maintainer project. PRs are reviewed when I have time. Big features should be discussed in an issue first.
License
The core is MIT licensed — free forever. Everything that makes Memory Vault useful as a personal memory system (hybrid search, MCP integration, knowledge graph, dashboard, local LLM chat, Docker setup) will always be free and open source.
A PRO tier for teams and advanced features is planned.
Credits
@rivestack — Postgres + pgvector tuning tips that landed in v1.0 (
maintenance_work_mem=1GBfor fast HNSW builds). More of his suggestions are on the list.Beta testers — the people who cloned, broke, and reported things during M1-M7
The open source giants this is built on — PostgreSQL, pgvector, sentence-transformers, spaCy, FastAPI, FastMCP, React, Cytoscape.js
Acknowledgments
The GitHub contributor list credits everyone whose code is in the repo. This section acknowledges reporters and diagnosticians whose insight shaped shipped work but doesn't appear in commit authorship.
Leonard Janke (lcjanke2020), working with GPT-5.6-Sol through OpenAI Codex (@lcj-codex-coder) — 20+ issues reported across the v1.0.7–v1.0.10 window, spanning version-drift, MCP correctness, timezone handling, embedding-dimension validation, and knowledge-graph soft-delete semantics. Peer-tier diagnostics; every report came with a disposable-database reproduction.
@git-pharos — diagnostic bundle in #74 that exposed three underlying issues fixed in v1.0.7.
Rivestack — the per-query
ef_searchknob and warming the vector index at start-up, both shipped in v1.5.0. Operational pgvector experience: the kind of default that is fine in a demo and wrong at scale.
Security reports and correctness findings are always credited by handle, plus any format the reporter specified — including tooling attribution where requested.
Follow the Build
Website: mihaibuilds.com
Blog: mihaibuilds.com/blog
GitHub: @MihaiBuilds
X: @mihaibuilds
Watch the repo to follow along.
ARCHITECTURE.md
Memory Vault — Architecture Overview
This document describes the technical architecture of Memory Vault as it ships in v1.0. It covers the core components, the schema, how clients connect, and the design decisions behind the trade-offs.
For user-facing setup and feature docs, see the README. For contribution flow, see CONTRIBUTING.md. For the threat model and security posture, see SECURITY.md.
High-Level Architecture
┌─────────────────────────────────────────────────────────────┐
│ Clients │
│ │
│ Claude (MCP) Web Dashboard REST API CLI │
└────────┬──────────────┬───────────────┬──────────┬──────────┘
│ │ │ │
│ └───── HTTP ────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ FastAPI │ │
│ │ (REST + WebUI) │ │
│ └────────┬────────┘ │
│ │ │
┌────▼─────────┐ │ ┌────▼──────┐
│ MCP Server │ │ │ memory- │
│ (stdio) │ │ │ vault CLI │
└──────┬───────┘ │ └────┬──────┘
│ │ │
└───────────────────┼───────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────────▼──────┐ ┌───────▼────────┐ ┌─────▼─────────┐
│ Ingestion │ │ Hybrid Search │ │ Knowledge │
│ Pipeline │ │ Engine │ │ Graph │
│ - Markdown │ │ - Vector HNSW │ │ - spaCy NER │
│ - Plaintext │ │ - Full-text │ │ - Co-occur │
│ - Claude JSON │ │ - RRF merge │ │ - Cytoscape │
└─────────┬──────┘ └───────┬────────┘ └─────┬─────────┘
│ │ │
└────────────────┴────────────────┘
│
┌────────────▼────────────┐
│ PostgreSQL 16 │
│ + pgvector │
│ │
│ memory_spaces │
│ chunks │
│ api_tokens │
│ entities │
│ relationships │
│ entity_mentions │
│ query_log │
└─────────────────────────┘The same memory layer is reachable from four equal first-class clients: MCP (Claude Desktop / Claude Code), the REST API, the bundled web dashboard, and the memory-vault CLI. The dashboard is one consumer of the API — not the API itself.
Storage — PostgreSQL 16 + pgvector
Everything lives in a single Postgres database with the pgvector extension. Migrations are versioned and forward-only (src/memory_vault/migrations/001_initial_schema.sql, 002_api_tokens.sql, 003_knowledge_graph.sql) and run automatically on first start.
Tables
memory_spaces — namespaces for organizing memories.
idSERIAL primary keynameTEXT unique (lowercase, hyphens allowed; e.g.default,work,learning)description,created_at
chunks — the primary memory unit. One row per ingested chunk.
idUUID primary keyspace_idreferencesmemory_spacescontentTEXT — the raw textembeddingvector(384) —all-MiniLM-L6-v2embeddingcontent_tsvtsvector — auto-populated by trigger fromcontentsourceTEXT — origin (file path, URL, MCP tool that wrote it)speakerTEXT —'human','assistant', or nullmetadataJSONBimportanceFLOAT (default 0.5)chunk_indexINTEGER — position within a multi-chunk sourcecreated_at,updated_at
Indexes: HNSW on embedding (vector cosine), GIN on content_tsv (full-text), btree on space_id and created_at, GIN on metadata (jsonb_path_ops).
api_tokens — bearer-auth tokens for the REST API and dashboard.
idUUID primary keynameTEXT — friendly labeltoken_hashTEXT unique — SHA-256 hash of the plaintext token (never stored in clear)token_prefixTEXT — first 11 chars (mv_xxxxxxxx) for identification intoken listcreated_at,last_used_at,revoked_at
Tokens are 32 random bytes from secrets.token_urlsafe; lookup uses hmac.compare_digest for constant-time comparison.
entities — knowledge graph nodes (one per (lower(name), type, space_id) triple).
idUUID primary keynameTEXT,typeTEXT (person,project,tool,concept)space_idreferencesmemory_spaces— entities are deduplicated per space, not globallypropertiesJSONBcreated_at,updated_at
relationships — knowledge graph edges. One row per (source_entity, target_entity, type) derived from co-occurrence.
idUUID primary keysource_entity_id,target_entity_id— both referenceentitiestypeTEXT —related_toin v1.0strengthFLOAT — co-occurrence weight, increments with repeated co-occurrenceschunk_idreferenceschunks— provenance (which chunk produced this edge)supporting_chunksUUID[] — running list of all chunks that contributed
entity_mentions — one row per (entity, chunk, character offset). Lets the graph link back to exact spans in the source text.
id,entity_id,chunk_id,start_offset,end_offset,created_at
query_log — observability table for search latency and result counts. Used by the Stats dashboard.
Why one database, not two
Vector embeddings, full-text indexes, knowledge graph, tokens, and observability all live in the same Postgres. No separate vector DB to keep in sync, no second backup story, one connection string. HNSW indexes plus tuned maintenance_work_mem (1 GB default in the bundled docker-compose.yml) keep search fast at the scale a self-hosted personal-memory tool actually runs at.
Embeddings
Model: all-MiniLM-L6-v2 from sentence-transformers — 384 dimensions, runs on CPU, no GPU required, no API calls.
The model is downloaded on first ingest and cached under ~/.cache/huggingface. In Docker, this is part of the image build, so the running container has zero first-run download.
Index: pgvector HNSW with vector_cosine_ops. Default ef_search=40 — fine at thousands of chunks, starts to lose recall past tens of thousands.
Hybrid Search
The core differentiator. Pure vector search misses exact terms (model names, error codes, file paths); pure keyword search misses paraphrase. Memory Vault runs both and merges them with Reciprocal Rank Fusion.
Algorithm
score(d) = Σ_{r ∈ rankers} 1 / (k + rank_r(d))with k = 60 (Cormack et al. 2009 default). Higher score wins. Documents found by both rankers score higher than documents found by only one. RRF uses ranks, not raw scores — no normalization needed between the cosine-similarity-of-vectors world and the ts_rank-of-tsvector world.
Implementation
For each query:
Query enrichment — up to 3 query variations are generated using the embedding model's WordPiece tokenizer to extract key technical terms. Improves recall without losing precision.
Vector branch — embed the query, run HNSW similarity search, take top 50.
Keyword branch —
plainto_tsqueryagainstcontent_tsv, take top 50 byts_rank_cd.RRF merge —
UNION ALLboth ranked lists, sum1/(60+rank)per chunk, return top K (default K=20).
The same engine powers the REST /api/search, MCP recall, and the dashboard's Search and Chat pages — there's no second retrieval implementation.
Ingestion Pipeline
Async pipeline. Adapters convert different input formats into a list of RawChunk objects, then a single ingestion service handles dedup, embedding, and storage.
Adapters (v1.0)
Located in src/memory_vault/adapters/:
markdown.py— splits by headings, preserves structureplaintext.py— paragraph-based with smart mergingclaude.py— parses Claude conversation exports
Each adapter returns RawChunk(text, speaker, timestamp, chunk_index, metadata, content_hash). New adapters (PDF, web pages) are part of the PRO tier.
Pipeline stages
For every chunk produced by an adapter:
Parse → chunk — adapter-specific.
Dedup check —
content_hash(SHA-256) is compared against existing chunks in the target space. Duplicates are skipped, not re-embedded.Embed — sentence-transformers, batched (
EMBEDDING_BATCH_SIZE=32by default).Insert — single
INSERTper chunk;content_tsvis populated by a Postgres trigger automatically.Extract entities — spaCy NER + multi-token noun-phrase detection runs synchronously on the same CPU as the embedding step. Entities, relationships, and entity_mentions are written in the same transaction as the chunk.
If extraction fails for any reason, the chunk is still committed — extraction is best-effort, not a blocker for storage.
Knowledge Graph
Built without an LLM. Every chunk passes through spaCy at ingest time, and entities + relationships flow into the graph automatically.
Extraction
spaCy NER with
en_core_web_sm(~15 MB, CPU-only) tagsPERSON,ORG,PRODUCT, mapped to person, project, tool entity types respectively.Concept extraction — multi-token noun phrases that appear at least twice within a single chunk become concept entities.
Per-space dedup — entities are unique by
(lower(name), type, space_id). The same name in two different spaces is two different entities; the same name with two different types in the same space is also two entities.
Relationships
Co-occurrence — any two entities found in the same chunk produce a
related_toedge in the relationships table, withchunk_idrecording which chunk produced it.Strength — edge weight increments on every co-occurrence across chunks. Frequent co-occurrence → higher strength → larger edge in the visualization.
Visualization
/api/graph/entitiesand/api/graph/relationships— paginated raw access for any client./api/graph/visualize— bundled nodes + edges payload sized for the dashboard, with truncation rules (max 500 nodes by default, configurable per request).Dashboard Graph page — Cytoscape.js force-directed layout (
cose-bilkent), pan/zoom, click-through to entity detail (mentions across chunks, related entities).
Why no LLM
The default move in this space is to feed every chunk through an LLM and ask for entities and relationships. It works but couples graph quality to whichever model you happened to pick, and costs money on every ingest. spaCy + co-occurrence gets ~80% of the way for 0% of the LLM cost, with documented honest limits (English-only NER, context-dependent entity typing, no fuzzy matching).
REST API
FastAPI with bearer auth, rate limiting, and an auto-generated OpenAPI page at /docs. Served at http://localhost:8000 after docker compose up.
Endpoints (v1.0)
| Method | Path | Description |
|---|---|---|
GET | /api/health | Service + DB health (no auth) |
GET | /api/spaces | List memory spaces with chunk counts |
POST | /api/spaces | Create a new memory space |
GET | /api/chunks | List chunks with pagination + filters |
GET | /api/chunks/{id} | Get a single chunk |
DELETE | /api/chunks/{id} | Soft-delete a chunk |
POST | /api/search | Hybrid search |
POST | /api/ingest/text | Ingest a text string |
POST | /api/ingest/file | Upload a file through the ingestion pipeline |
POST | /api/chat | RAG chat (non-streaming) |
POST | /api/chat/stream | RAG chat with token-by-token SSE streaming |
GET | /api/graph/entities | List entities with filters |
GET | /api/graph/entities/{id} | Entity detail (mentions, related) |
GET | /api/graph/relationships | List edges with filters |
GET | /api/graph/visualize | Node + edge payload sized for visualization |
Authentication
All endpoints except /api/health require a bearer token. Tokens are created via the CLI (memory-vault token create <name>) and shown once in plaintext. Stored as SHA-256 hashes; lookup is constant-time.
To disable auth entirely (local dev only): API_AUTH_ENABLED=false.
Rate limiting
Simple per-IP request counter, default 120 req/min. Returns 429 Too Many Requests with Retry-After header when tripped. Configurable via API_RATE_LIMIT_PER_MIN.
Error handling
Global exception handler returns generic 500 with no traceback. psycopg.OperationalError returns generic 503. Full traces go to structured JSON logs only, correlated by an X-Request-ID header that's emitted on every response.
MCP Server
Memory Vault's MCP server exposes Memory Vault to Claude Desktop and Claude Code via the Model Context Protocol. Transport is stdio — no HTTP, no ports.
Tools
| Tool | Signature |
|---|---|
recall | (query: str, space: str = None, limit: int = 10) — hybrid search |
remember | (text: str, space: str = "default", source: str = None, speaker: str = None) — ingest a chunk |
forget | (chunk_id: str) — soft-delete |
memory_status | () — DB health, chunk count, spaces breakdown |
Resources
| Resource | Returns |
|---|---|
memory://spaces | List of spaces with chunk counts |
memory://stats | System statistics |
Config
For Claude Code, in your project's .mcp.json:
{
"mcpServers": {
"memory-vault": {
"command": "python",
"args": ["-m", "memory_vault.mcp"],
"env": {
"DB_HOST": "localhost",
"DB_PORT": "5432",
"DB_NAME": "memory_vault",
"DB_USER": "memory_vault",
"DB_PASSWORD": "memory_vault"
}
}
}
}Same JSON works in Claude Desktop's Settings → Developer → Edit Config.
The MCP server is not a wrapper around the REST API — both are first-class entry points into the same service code (search engine, ingestion pipeline, graph extraction).
See the README for setup details, including the Docker-host configuration variant.
Web Dashboard
React 19 + Vite + TanStack Query, built into a static bundle at image build time and served by FastAPI from src/memory_vault/api/static/. No separate process, no separate port, no npm start in production.
Pages (v1.0)
Chat (default landing page) — talk to the vault with a local LLM, sources panel shows the retrieved chunks for every answer
Search — hybrid search with space filter, similarity scores, expandable hit content
Browse — paginated chunk list, space + sort filters, two-step inline delete
Graph — Cytoscape force-directed knowledge graph, pan/zoom, type/min-mentions/max-nodes filters
Ingest — paste text or upload files (one at a time in v1.0), per-file status, batch summary
Stats — total chunks, spaces table with visual distribution, auto-refresh every 30s
Auth
Same bearer token as the REST API. The dashboard prompts on first load, stores the token in localStorage under memory-vault-token, and auto-clears on a 401 response.
Local LLM Chat
The dashboard's Chat page lets you talk to your own memories through a local LLM — no cloud, no API keys, no telemetry.
v1.0 supports LM Studio as the local LLM provider. Ollama and llama.cpp use the same OpenAI-compatible client architecture under the hood, but are not supported in v1.0.
Flow
User types a question on the Chat page.
The dashboard calls
POST /api/chat/streamwith the question + selected space + retrieval limit.The chat router runs hybrid search against the vault and packs the top hits into a context block sized for a 6,000-token budget (oldest history dropped first, then lowest-similarity chunks).
The router calls LM Studio's local API with
{system, context, user-question}.Sources are sent to the dashboard first in the SSE stream, so the UI can render "based on N memories" before tokens start flowing.
The LLM answer streams back token-by-token.
Why LM Studio first
LM Studio's native API supports reasoning="off", which is the only reliable way to suppress chain-of-thought from thinking-capable models in a RAG flow. Memory Vault uses the native API by default and falls back to OpenAI-compat (/v1/chat/completions) with <think>...</think> stripping if the native API isn't available.
CLI
A memory-vault command-line tool ships in the same Docker image as the API. Used for migrations, status checks, ingestion, search, token management, space management, and the diagnostic bundler.
memory-vault status # DB health, chunk count, spaces
memory-vault ingest path/to/file # one-shot ingest, with --space flag
memory-vault search "query" # CLI search with verbose output
memory-vault token create my-app # create a bearer token
memory-vault token list / revoke
memory-vault space create / list
memory-vault migrate # run pending migrations (idempotent)
memory-vault diagnose # produce a redacted diagnostic zip
memory-vault api # start the REST API (uvicorn)
memory-vault mcp # start the MCP server (stdio)The diagnostic bundler is the entry point for bug reports — see SECURITY.md and CONTRIBUTING.md.
Docker Setup
The bundled docker-compose.yml defines two services and runs everything with one command.
services:
db:
image: pgvector/pgvector:pg16
command:
- postgres
- -c
- maintenance_work_mem=1GB
volumes:
- pgdata:/var/lib/postgresql/data
app:
build: .
image: memory-vault-app:latest
ports: ["8000:8000"]
depends_on:
db: { condition: service_healthy }The image is multi-stage: stage 1 is a Node 20 builder that runs npm run build to produce the dashboard bundle; stage 2 is a Python 3.11 runtime that pip-installs the package, downloads the spaCy en_core_web_sm model, and copies the dashboard bundle into src/memory_vault/api/static/.
Released images are published to ghcr.io/mihaibuilds/memory-vault for both linux/amd64 and linux/arm64 (Apple Silicon, Raspberry Pi 4+, ARM VPSs). The release workflow (.github/workflows/release.yml) handles the multi-arch build on every v*.*.* tag.
First run: migrations apply automatically (memory-vault migrate is idempotent), the default memory space is created, the spaCy model is already in the image, and http://localhost:8000 serves the dashboard.
Design Decisions
Why PostgreSQL + pgvector instead of a dedicated vector database (Pinecone, Weaviate, Qdrant)? One database means one backup story, one connection string, one operational mental model. For a single-tenant self-hosted personal-memory tool, the marginal performance of a dedicated vector store doesn't outweigh the operational cost of running and syncing two systems. When that stops being true, the migration path to a hybrid setup is sane.
Why hybrid search instead of vector-only? Pure vector search is great at paraphrase and concept; bad at exact strings. Pure keyword search is the opposite. RRF gets both with no parameter tuning.
Why all-MiniLM-L6-v2 instead of a larger embedding model?
384 dimensions runs fast on CPU, fits in RAM on any modern laptop, and quality is good enough for personal memory. The goal is "anyone can run this," not maximum benchmark performance.
Why spaCy + co-occurrence for the knowledge graph instead of an LLM? LLM extraction couples graph quality to whichever model you happened to pick and bills you on every ingest. spaCy is fast, free, deterministic, and the limitations are documented honestly up front. Manual entity merging in the dashboard is not in v1.0.
Why MCP-first, not REST-first? Memory Vault was designed around the assumption that the primary user of this database is going to be Claude, not me. The REST API exposes the same operations for human-driven apps, but the MCP server isn't a wrapper around the REST API — both are direct paths into the same service code.
Why MIT-licensed core? Your AI memory should belong to you, not a cloud platform. The free tier is the full personal-memory product. The PRO tier adds operational and scale features that teams pay for — multi-user activation, dedup with importance decay, encrypted backups, conflict resolution, additional adapters.
What's in v1.0
Hybrid search, MCP, knowledge graph (no LLM), REST API, dashboard with Chat/Search/Browse/Graph/Ingest/Stats, local LLM chat (LM Studio), one-command Docker, multi-arch images, MIT-licensed.
For honest v1.0 limitations, see the Limitations section in the README.
171 files · 161 not served here
- .dockerignore (not served here)
- .env.example (not served here)
- .gitattributes (not served here)
- .github/FUNDING.yml (not served here)
- .github/ISSUE_TEMPLATE/bug_report.yml (not served here)
- .github/ISSUE_TEMPLATE/config.yml (not served here)
- .github/ISSUE_TEMPLATE/feature_request.yml (not served here)
- .github/dependabot.yml (not served here)
- .github/leak-patterns.txt (not served here)
- .github/pull_request_template.md (not served here)
- .github/workflows/codeql.yml (not served here)
- .github/workflows/leak-gate.yml (not served here)
- .github/workflows/lint.yml (not served here)
- .github/workflows/release.yml (not served here)
- .github/workflows/test.yml (not served here)
- .gitignore (not served here)
- ARCHITECTURE.md
- ATTRIBUTION.md
- CHANGELOG.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- Dockerfile (not served here)
- Dockerfile.mcp (not served here)
- LICENSE
- README.md
- SECURITY.md
- docker-compose.yml (not served here)
- docs/images/architecture.mmd (not served here)
- docs/images/architecture.png (not served here)
- docs/images/chat-with-sources.png (not served here)
- docs/threat-model.md (not served here)
- docs/windows.md
- mcp.json.example (not served here)
- pyproject.toml (not served here)
- scripts/security-pentest.sh (not served here)
- scripts/start.sh (not served here)
- server.json
- src/memory_vault/__init__.py (not served here)
- src/memory_vault/adapters/__init__.py (not served here)
- src/memory_vault/adapters/base.py (not served here)
- src/memory_vault/adapters/claude.py (not served here)
- src/memory_vault/adapters/markdown.py (not served here)
- src/memory_vault/adapters/plaintext.py (not served here)
- src/memory_vault/api/__init__.py (not served here)
- src/memory_vault/api/app.py (not served here)
- src/memory_vault/api/deps.py (not served here)
- src/memory_vault/api/middleware.py (not served here)
- src/memory_vault/api/routers/__init__.py (not served here)
- src/memory_vault/api/routers/chat.py (not served here)
- src/memory_vault/api/routers/chunks.py (not served here)
- src/memory_vault/api/routers/graph.py (not served here)
- src/memory_vault/api/routers/health.py (not served here)
- src/memory_vault/api/routers/ingest.py (not served here)
- src/memory_vault/api/routers/search.py (not served here)
- src/memory_vault/api/routers/spaces.py (not served here)
- src/memory_vault/api/schemas.py (not served here)
- src/memory_vault/api/server.py (not served here)
- src/memory_vault/cli.py (not served here)
- src/memory_vault/config.py (not served here)
- src/memory_vault/diagnose.py (not served here)
- src/memory_vault/extraction/__init__.py (not served here)
- src/memory_vault/extraction/graph_writer.py (not served here)
- src/memory_vault/extraction/spacy_extractor.py (not served here)
- src/memory_vault/logging_config.py (not served here)
- src/memory_vault/mcp/__init__.py (not served here)
- src/memory_vault/mcp/__main__.py (not served here)
- src/memory_vault/mcp/auth.py (not served here)
- src/memory_vault/mcp/http_transport.py (not served here)
- src/memory_vault/mcp/server.py (not served here)
- src/memory_vault/migrations/001_initial_schema.sql (not served here)
- src/memory_vault/migrations/002_api_tokens.sql (not served here)
- src/memory_vault/migrations/003_knowledge_graph.sql (not served here)
- src/memory_vault/migrations/004_chunk_content_hash_dedup.sql (not served here)
- src/memory_vault/migrations/005_chunk_ingest_identity.sql (not served here)
- src/memory_vault/migrations/006_scope_remember_dedup_index.sql (not served here)
- src/memory_vault/migrations/007_live_graph_views.sql (not served here)
- src/memory_vault/migrations/008_token_expiry.sql (not served here)
- src/memory_vault/migrations/009_least_privilege_roles.sql (not served here)
- src/memory_vault/models/__init__.py (not served here)
- src/memory_vault/models/db.py (not served here)
- src/memory_vault/services/__init__.py (not served here)
- src/memory_vault/services/embedding.py (not served here)
- src/memory_vault/services/graph.py (not served here)
- src/memory_vault/services/ingestion.py (not served here)
- src/memory_vault/services/search.py (not served here)
- src/memory_vault/services/spaces.py (not served here)
- tests/__init__.py (not served here)
- tests/conftest.py (not served here)
- tests/test_adapters.py (not served here)
- tests/test_api.py (not served here)
- tests/test_api_routers.py (not served here)
- tests/test_async_embed_yields_event_loop.py (not served here)
- tests/test_bad_input_matrix.py (not served here)
- tests/test_bulk_ingest.py (not served here)
- tests/test_chat_api.py (not served here)
- tests/test_chat_think_tag_boundary.py (not served here)
- tests/test_chunk_word_cap.py (not served here)
- tests/test_chunks_by_entity.py (not served here)
- tests/test_cli_exit_code.py (not served here)
- tests/test_container_hardening.py (not served here)
- tests/test_db_conninfo_encoding.py (not served here)
- tests/test_db_pool.py (not served here)
- tests/test_diagnose_redaction.py (not served here)
- tests/test_ef_search.py (not served here)
- tests/test_embedding_dimension_guard.py (not served here)
- tests/test_embedding_thread_safety.py (not served here)
- tests/test_ensure_space.py (not served here)
- tests/test_entity_merge.py (not served here)
- tests/test_entity_occurrences.py (not served here)
- tests/test_env_setting_parsing.py (not served here)
- tests/test_extraction.py (not served here)
- tests/test_graph_api.py (not served here)
- tests/test_graph_excludes_forgotten.py (not served here)
- tests/test_graph_type_multiselect.py (not served here)
- tests/test_ingest_atomicity.py (not served here)
- tests/test_least_privilege_roles.py (not served here)
- tests/test_live_graph_views.py (not served here)
- tests/test_logging_readonly_fallback.py (not served here)
- tests/test_mcp_http_mount.py (not served here)
- tests/test_mcp_remember_concurrent_dedup.py (not served here)
- tests/test_mcp_remember_extraction.py (not served here)
- tests/test_mcp_server_import.py (not served here)
- tests/test_mcp_token_verifier.py (not served here)
- tests/test_migration_003.py (not served here)
- tests/test_move_memory.py (not served here)
- tests/test_purge_forgotten.py (not served here)
- tests/test_query_logging.py (not served here)
- tests/test_ranking_dominance.py (not served here)
- tests/test_search.py (not served here)
- tests/test_search_quality.py (not served here)
- tests/test_since_timestamp_parsing.py (not served here)
- tests/test_space_create_race.py (not served here)
- tests/test_space_delete.py (not served here)
- tests/test_space_filter_security.py (not served here)
- tests/test_token_budget_cap.py (not served here)
- tests/test_token_expiry.py (not served here)
- tests/test_token_lookup.py (not served here)
- tests/test_unicode_and_large_content.py (not served here)
- tests/test_upload_source_name.py (not served here)
- tests/test_uuid_path_validation.py (not served here)
- tests/test_version_reporting.py (not served here)
- tests/test_warm_index.py (not served here)
- tests/test_windows_event_loop.py (not served here)
- web/.gitignore (not served here)
- web/README.md (not served here)
- web/eslint.config.js (not served here)
- web/index.html (not served here)
- web/package-lock.json (not served here)
- web/package.json (not served here)
- web/postcss.config.js (not served here)
- web/public/favicon.svg (not served here)
- web/public/icons.svg (not served here)
- web/src/App.tsx (not served here)
- web/src/api.ts (not served here)
- web/src/auth.ts (not served here)
- web/src/components/ErrorBanner.tsx (not served here)
- web/src/components/NetworkBanner.tsx (not served here)
- web/src/components/TokenGate.tsx (not served here)
- web/src/cytoscape-cose-bilkent.d.ts (not served here)
- web/src/index.css (not served here)
- web/src/main.tsx (not served here)
- web/src/pages/Browse.tsx (not served here)
- web/src/pages/Chat.tsx (not served here)
- web/src/pages/Graph.tsx (not served here)
- web/src/pages/Ingest.tsx (not served here)
- web/src/pages/Search.tsx (not served here)
- web/src/pages/Stats.tsx (not served here)
- web/tsconfig.app.json (not served here)
- web/tsconfig.json (not served here)
- web/tsconfig.node.json (not served here)
- web/vite.config.ts (not served here)
Advantages
- No separate vector database is required as vector embeddings, full-text indexes, and relational data all live in Postgres. evidence: README.md
- The system is frontend-agnostic, allowing MCP, REST, CLI, and custom apps to act as equal first-class clients. evidence: README.md
Limitations
- Thinking models like Qwen3 or DeepSeek-R1 can break the RAG flow by emitting chain-of-thought into the answer. evidence: README.md
- The system does not include transport encryption for the MCP HTTP server, requiring external TLS configuration. evidence: README.md
Security
Risk level: No risk found
This brain runs
MCP servers (3)
README.md(memory-vault):/path/to/memory-vault/.venv/bin/python -m memory_vault.mcpREADME.md(memory-vault):/path/to/memory-vault/.venv/bin/python -m memory_vault.mcpREADME.md(memory-vault):http://192.168.1.50:8000/api/mcp/sse· uses the network
Attribution and licence
- Created by
- MihaiBuilds
- Declared authors
- MihaiBuilds (declared in pyproject.toml)
- Publisher
- Mihai Builds (Official Mihai Builds project)
- Source
- MihaiBuilds/memory-vault · commit 19d10c5
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by MihaiBuilds or Mihai Builds.
Install from source
161 of its files are not served here, so there is no ZIP. MihaiBuilds/memory-vault at 19d10c5