Self-hosted semantic memory layer for AI tools. MCP-native, privacy-first, hybrid search.
Project description
A self-hosted semantic memory layer that gives any AI tool persistent, searchable recall.
What is Engram?
Engram is a personal knowledge base that stores your notes, conversations, documents, and web pages as vector embeddings — then lets any MCP-compatible AI assistant (Claude, Cursor, Windsurf, etc.) search and recall them by meaning, not just keywords. Everything lives in a PostgreSQL database you control, runs locally or in the cloud, and costs near-zero to self-host.
Features
- Hybrid Search — Combines vector similarity (pgvector HNSW) with PostgreSQL full-text BM25, fused via Reciprocal Rank Fusion
- MCP Server — Any MCP-compatible client can store, search, and manage memories over HTTP
- REST API — Full CRUD + search, with OpenAPI docs at
/api/docs/ - Multi-format Ingestion — Ingest PDFs, DOCX, TXT, Markdown, URLs, and Obsidian vaults
- Auto-Enrichment — Optional LLM-powered tagging, entity extraction, and memory decay
- React Dashboard — Browse, search, and visualize your memory graph
- Privacy-First — Runs 100% locally with Ollama; no data leaves your machine
- Pluggable Embeddings — Ollama (default, free), OpenRouter, or bring your own provider
Architecture
┌──────────────────────────────┐
│ AI Clients │
│ (Claude, Cursor, Windsurf) │
└─────────────┬────────────────┘
│ MCP / REST
▼
┌──────────────────────────────────────┐
│ MCP Server (FastMCP :8080) │
│ REST API (Django DRF :8000) │
│ Dashboard (React + Vite :5173) │
└─────────────┬────────────────────────┘
│
┌──────────┴──────────┐
│ Application Layer │
│ Embedder ─→ Ollama │
│ Auto-Tagger │
│ Entity Extractor │
│ Memory Decay │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ PostgreSQL 16 │
│ + pgvector (768d) │
│ + Full-text search │
│ + HNSW index │
└──────────────────────┘
Quick Start
Prerequisites: Python 3.12+, PostgreSQL 16 with pgvector, Ollama (or Docker)
# Install from PyPI
pip install engram-semantic
# Or clone for development
git clone https://github.com/jblacketter/engram.git && cd engram
# 2. Start database + Ollama via Docker
docker compose up -d
# 3. Pull the embedding model
ollama pull nomic-embed-text
# 4. Install Python dependencies
pip install -e ".[dev]"
# 5. Copy environment config
cp .env.example .env
# 6. Run migrations and start the server
python manage.py migrate
python manage.py runserver
The API is now live at http://localhost:8000/api/ and docs at http://localhost:8000/api/docs/.
Start the MCP server (separate terminal):
python -m mcp_server
Start the frontend (separate terminal):
cd frontend && npm install && npm run dev
Dashboard at http://localhost:5173.
Connecting AI Clients
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"engram": {
"url": "http://localhost:8080/mcp"
}
}
}
Claude Code
claude mcp add engram http://localhost:8080/mcp
Cursor / Windsurf
Add to your MCP settings:
{
"mcpServers": {
"engram": {
"url": "http://localhost:8080/mcp"
}
}
}
See docs/connecting-clients.md for authenticated setups and advanced config.
API Reference
REST Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/health/ |
Health check |
GET |
/api/memories/ |
List memories (paginated) |
POST |
/api/memories/ |
Create a memory |
GET |
/api/memories/<id>/ |
Get memory by UUID |
PATCH |
/api/memories/<id>/ |
Update memory |
DELETE |
/api/memories/<id>/ |
Delete memory |
POST |
/api/search/ |
Hybrid semantic + keyword search |
GET |
/api/stats/ |
Memory statistics |
GET |
/api/tags/ |
List all tags |
POST |
/api/ingest/file/ |
Ingest a file (PDF, DOCX, TXT, etc.) |
POST |
/api/ingest/url/ |
Scrape and ingest a URL |
POST |
/api/ingest/batch/ |
Batch ingest files and URLs |
Auth: Authorization: Bearer <REST_API_KEY> (disabled when env var is empty).
MCP Tools
| Tool | Description |
|---|---|
store_memory |
Store a new memory with optional tags and importance |
get_memory |
Retrieve a memory by UUID |
update_memory |
Update content, tags, or importance |
delete_memory |
Delete a memory |
search_brain |
Hybrid search with configurable semantic/keyword weight |
find_related |
Find semantically similar memories |
list_recent_memories |
List recent memories, optionally filtered by source |
store_from_url |
Fetch and ingest a URL |
ingest_file |
Ingest a base64-encoded file |
get_stats |
System statistics |
Project Structure
engram/
├── api/ # REST API (DRF views, serializers, auth)
├── core/ # Data models, services (memory CRUD, search)
├── embeddings/ # Embedding providers (Ollama, OpenRouter)
├── intelligence/ # Auto-tagger, entity extraction, decay, reports
├── ingestion/ # File, URL, batch, and Obsidian importers
├── mcp_server/ # FastMCP server with tool definitions
├── engram/ # Django project settings and URL config
├── frontend/ # React + TypeScript + Tailwind SPA
├── docker/ # Entrypoint scripts, pgvector init SQL
├── nginx/ # Reverse proxy config (production)
├── docs/ # Extended documentation
├── tests/ # Test suite
├── Dockerfile # Django production image
├── Dockerfile.mcp # MCP server image
├── docker-compose.yml # Dev: PostgreSQL + Ollama
└── pyproject.toml # Python package config
Configuration
Key environment variables (see .env.example for the full list):
| Variable | Default | Description |
|---|---|---|
DJANGO_SECRET_KEY |
— | Django secret key |
DJANGO_SETTINGS_MODULE |
engram.settings.development |
Settings module |
POSTGRES_DB |
engram |
Database name |
POSTGRES_HOST |
localhost |
Database host |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama API URL |
OLLAMA_EMBED_MODEL |
nomic-embed-text |
Embedding model |
OLLAMA_CHAT_MODEL |
llama3.2:3b |
Chat model for enrichment |
OPENROUTER_API_KEY |
— | Fallback embedding provider |
MCP_API_KEY |
— | MCP auth token (empty = open) |
REST_API_KEY |
— | REST auth token (empty = open) |
AUTO_ENRICH_ON_CREATE |
false |
Auto-tag and extract entities |
Production Deployment
docker compose -f docker-compose.prod.yml up -d
This starts PostgreSQL, Ollama (with GPU support), Django (gunicorn), the MCP server, and nginx with TLS. See docs/setup-docker.md for full production setup and docs/setup-supabase.md for cloud-hosted PostgreSQL.
Tech Stack
Backend: Django 5.1 • Django REST Framework • FastMCP 2.0 • PostgreSQL 16 + pgvector • Ollama Frontend: React 18 • TypeScript • Vite • Tailwind CSS • D3 • Recharts Infra: Docker • nginx • gunicorn • uvicorn
Documentation
| Guide | Description |
|---|---|
| Connecting Clients | Claude Desktop, Claude Code, Cursor setup |
| Embedding Providers | Ollama, OpenRouter, OpenAI, Cohere comparison |
| Docker Setup | Local and production Docker guide |
| Supabase Setup | Cloud PostgreSQL with Supabase |
| Schema | Database schema deep dive |
| Workflows | Daily capture and search patterns |
| Extending | Adding providers, tools, and importers |
| Windows LAN Deploy | Deploy on a Windows server for home LAN access |
| Troubleshooting | Common issues and fixes |
| Roadmap | Feature roadmap |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file engram_semantic-1.0.0.tar.gz.
File metadata
- Download URL: engram_semantic-1.0.0.tar.gz
- Upload date:
- Size: 59.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a71aa21c6e5420e0ccf8e4569d774f43ab8b3bcbdff76c73764d655611e08ff1
|
|
| MD5 |
7532e257ec5b2f254af673269c131f65
|
|
| BLAKE2b-256 |
195904e44e13f01926e3def8aeee8c27756539628a611dc2225675c5db120a7d
|
Provenance
The following attestation bundles were made for engram_semantic-1.0.0.tar.gz:
Publisher:
publish.yml on jblacketter/engram
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
engram_semantic-1.0.0.tar.gz -
Subject digest:
a71aa21c6e5420e0ccf8e4569d774f43ab8b3bcbdff76c73764d655611e08ff1 - Sigstore transparency entry: 1236492377
- Sigstore integration time:
-
Permalink:
jblacketter/engram@2222e728c7cbc045e7337f7565c0776b6e915fad -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jblacketter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2222e728c7cbc045e7337f7565c0776b6e915fad -
Trigger Event:
release
-
Statement type:
File details
Details for the file engram_semantic-1.0.0-py3-none-any.whl.
File metadata
- Download URL: engram_semantic-1.0.0-py3-none-any.whl
- Upload date:
- Size: 49.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
add9a0635b993b6d8c2353c230c82237e67376844a536ad0658ce10f8dd8f981
|
|
| MD5 |
f35c935c1f632d66761b10bbfd1c8fa7
|
|
| BLAKE2b-256 |
7f4474cc1f6b56814416bec9fd327b0c1c7066b20bae9540c6534035fcd16a9a
|
Provenance
The following attestation bundles were made for engram_semantic-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on jblacketter/engram
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
engram_semantic-1.0.0-py3-none-any.whl -
Subject digest:
add9a0635b993b6d8c2353c230c82237e67376844a536ad0658ce10f8dd8f981 - Sigstore transparency entry: 1236492378
- Sigstore integration time:
-
Permalink:
jblacketter/engram@2222e728c7cbc045e7337f7565c0776b6e915fad -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/jblacketter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2222e728c7cbc045e7337f7565c0776b6e915fad -
Trigger Event:
release
-
Statement type: