Cortex
Enables AI coding agents to maintain a private, local-first persistent memory by automatically saving, searching, and retrieving structured project memories through MCP, with hybrid keyword and embedding search, feedback-driven ranking, and no cloud dependency.
README
<p align="center"> <img src="docs/assets/og.png" alt="Cortex — memoria para tus agentes IA" width="640"> </p>
<h1 align="center">Cortex</h1>
<p align="center"> <b>Local-first persistent memory for AI coding agents.</b><br> MCP server + HTTP API · SQLite on your disk · hybrid search (FTS5 + local embeddings) · no cloud required. </p>
<p align="center"> <a href="#quickstart-2-minutes">Quickstart</a> · <a href="#plug-it-into-your-agent">Clients</a> · <a href="#mcp-tools">Tools</a> · <a href="docs/self-hosting.md">Self-hosting</a> · <a href="docs/http-api.md">HTTP API</a> </p>
The problem
Your coding agent solves a nasty bug on Tuesday. On Wednesday it opens a fresh context window and has no idea that bug ever existed. You paste the same explanation again.
Cortex gives the agent a memory it writes to and reads from by itself, through MCP:
structured memories (bug_fix, decision, discovery, pattern, preference, ...),
scoped per project, ranked by relevance, decayed over time, and re-surfaced when the same
symptom shows up again.
Everything lives in a single SQLite file on your machine (~/.memoria/memoria.db).
No account, no API key, no telemetry.
What's in the box
- 20 MCP tools — save / search / context / recall / hint / feedback / sessions / reflections / forget (full list).
- Hybrid retrieval — SQLite FTS5 keyword search fused with vector KNN via Reciprocal Rank Fusion. Embeddings are optional and run locally (
@xenova/transformers, 384-dim MiniLM, ~22 MB, CPU). - Outcome-aware trust — the agent reports back whether a surfaced memory helped, was stale or misled it (
memoria_feedback); trust scores re-rank future results. - Proactive hints —
memoria_hinttakes the upcoming tool call / prompt / file path and returns up to 3 short hints to inject before acting. - Reflections — a CPU-only clustering pass groups related memories; your agent's LLM synthesizes the meta-lesson (Cortex never calls an LLM itself).
- Decay & forget — relevance decays,
memoria_forgetpreviews (dry-run by default) and soft-deletes the floor. - Privacy by default — API keys, PATs, JWTs, SSH keys and
<private>...</private>blocks are stripped before anything is written to disk. - Ops-ready — structured JSON logs, Prometheus metrics at
/api/metrics, quotas, optional bearer auth, multi-tenant workspaces.
Quickstart (2 minutes)
Requirements: Node >= 20 (verified on 22 and 26), git. better-sqlite3 compiles or
downloads a prebuilt binary on install — no other system dependency.
git clone https://github.com/gonzalonicolasr/cortexmem.git
cd cortexmem
npm install
npm test # optional: 216 tests, ~1s
Or install it without cloning — you get a cortexmem command on your PATH:
npm install -g github:gonzalonicolasr/cortexmem
cortexmem --version
Smoke test it as a plain CLI:
node bin/memoria.mjs save "Fix hydration bug" \
--type bug_fix --what "moved the fetch out of useEffect" \
--project demo --learned "SSR/CSR mismatch, not a race condition"
node bin/memoria.mjs search hydration --project demo
node bin/memoria.mjs stats
That's it — the database was created at ~/.memoria/memoria.db on first write.
Plug it into your agent
Cortex speaks MCP over stdio. If you installed globally, the command is cortexmem mcp;
from a clone, use node with the absolute path to bin/memoria.mjs.
<details open> <summary><b>Claude Code</b></summary>
claude mcp add cortex -- node /absolute/path/to/cortexmem/bin/memoria.mjs mcp
claude mcp list | grep cortex # → ✓ Connected
</details>
<details> <summary><b>Codex CLI</b> (<code>~/.codex/config.toml</code>)</summary>
[mcp_servers.cortex]
command = "node"
args = ["/absolute/path/to/cortexmem/bin/memoria.mjs", "mcp"]
</details>
<details> <summary><b>Cursor / Windsurf / any client with a JSON MCP config</b></summary>
{
"mcpServers": {
"cortex": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/cortexmem/bin/memoria.mjs", "mcp"]
}
}
}
</details>
<details> <summary><b>pi</b> (needs an MCP extension — pi has no built-in MCP)</summary>
Install an MCP extension for pi and point it at the same command/args pair as the JSON
example above. For the HTTP transport, see docs/self-hosting.md.
</details>
Restart the client after editing its config — Codex and Claude Code do not re-read it hot.
Teach the agent to actually use it
Tools alone are not enough: the agent has to know when to write. Copy
CLAUDE.md (the memory protocol) into your agent's instruction file
(CLAUDE.md, AGENTS.md, .cursorrules, pi's AGENTS.md, ...). It's ~40 lines and tells
the agent to save automatically after bug fixes, decisions, discoveries and config changes,
and to call memoria_context at session start.
CLI
memoria mcp Start the MCP server (stdio)
memoria serve [port] Start the HTTP API (default 7437, loopback-only)
memoria save <title> [flags] Save a memory
memoria search <query> Full-text search
memoria context [project] Print the project context block
memoria recent [flags] Recent memories
memoria stats Counts by type / project
memoria projects List projects
memoria decay Apply relevance decay
Flags: --project --type --limit --what --why --where --learned --topic.
Server mode
Want one memory shared by every machine / agent in your homelab? Run the HTTP API and front it with a reverse proxy:
MEMORIA_HOST=127.0.0.1 MEMORIA_AUTH_TOKEN=$(openssl rand -hex 24) \
node bin/memoria.mjs serve 7437
curl -s localhost:7437/api/health
Endpoint reference: docs/http-api.md.
systemd unit, bearer auth, embeddings backfill, reflection cron and backups:
docs/self-hosting.md.
⚠️ The HTTP server trusts the
X-Workspace-Idheader (multi-tenant design: an upstream proxy validates the user and injects it). Never bind it to a public interface withoutMEMORIA_AUTH_TOKEN+ a proxy in front.
Semantic search (optional)
npm install @xenova/transformers # already an optionalDependency
export MEMORIA_SEMANTIC_SEARCH=1
node bin/backfill-embeddings.mjs # embed existing memories
The model downloads once (~22 MB) and runs on CPU. With the flag on, memoria_search and
memoria_recall become hybrid (FTS5 + KNN fused with RRF); with it off, everything still
works as pure keyword search. Non-English memories: set
MEMORIA_EMBEDDING_MODEL=Xenova/paraphrase-multilingual-MiniLM-L12-v2 before the
backfill (same 384 dims) — see semantic search.
Environment variables
| Variable | Default | What it does |
|---|---|---|
MEMORIA_DATA_DIR |
~/.memoria |
Directory holding memoria.db |
MEMORIA_DB_PATH |
— | Explicit DB file (wins over DATA_DIR; :memory: supported) |
MEMORIA_PROJECT |
auto-detected from cwd | Override project detection |
MEMORIA_WORKSPACE_ID |
1 |
Workspace used by CLI/stdio |
MEMORIA_PORT / MEMORIA_HOST |
7437 / 127.0.0.1 |
HTTP bind |
MEMORIA_AUTH_TOKEN |
— | If set, HTTP requires Authorization: Bearer <token> (except /api/health) |
MEMORIA_SEMANTIC_SEARCH |
off | 1 enables embeddings + hybrid search |
MEMORIA_EMBEDDING_MODEL |
Xenova/all-MiniLM-L6-v2 |
Any 384-dim feature-extraction model |
MEMORIA_EMBEDDING_CACHE_DIR |
transformers default | Where model files are cached |
MEMORIA_REDACT_ON_READ |
off | 1 also redacts on the way out, not just on write |
MEMORIA_UNLIMITED_WORKSPACES |
— | CSV of workspace ids exempt from quotas — set it to 1 for personal self-hosting |
Quotas
Defaults are sized for the multi-tenant hosted deployment: 1 000 active memories, 10 MB of logical text, 50 projects, 5 active sessions, 32 KB per memory. For a personal local install, lift them:
export MEMORIA_UNLIMITED_WORKSPACES=1 # workspace 1 = the CLI/stdio default
MCP tools
| Tool | Use it for |
|---|---|
memoria_save |
Persist a structured memory (title, type, what, why, where_at, learned, topic_key) |
memoria_search |
Hybrid/keyword search |
memoria_context |
Project context block; can open a session in the same call |
memoria_recall |
"Have I seen this error before?" — symptom → past fixes |
memoria_hint |
Proactive pre-tool-call hints (≤3, short) |
memoria_feedback |
Report helped / stale / misleading → adjusts trust |
memoria_reflections_pending · _complete · _dismiss |
Meta-lesson synthesis loop |
memoria_forget |
Hygiene: decay preview + soft-delete floor |
memoria_session_start · _end |
Session lifecycle with structured summary |
memoria_update · _delete · _timeline · _recent |
Memory maintenance & browsing |
memoria_stats · _projects · _project_describe |
Introspection & project metadata |
memoria_save_prompt |
Store what the user asked, verbatim |
Tool names keep the memoria_ prefix (the project's original name) for backwards
compatibility with existing installs.
Data, privacy, backups
- One SQLite file (WAL mode). Back it up with
sqlite3 ~/.memoria/memoria.db ".backup out.db". - Secrets are stripped before the row is written: AWS keys, GitHub/GitLab PATs,
OpenAI/Anthropic/Slack/Google/Stripe/Cloudflare keys, JWTs, SSH private keys, and anything
you wrap in
<private>...</private>. It's a safety net, not a licence to paste secrets. - Nothing leaves your machine unless you run the HTTP server and expose it.
Development
npm test # vitest, 216 tests
npm run test:watch
Multilingual embedding tests are gated behind MEMORIA_TEST_MULTILINGUAL=1 so the normal
suite never downloads a model. Changelog: CHANGELOG.md.
Hosted (optional)
If you'd rather not run anything, the same engine is hosted at
cortexmem.com: sign up, copy the cc_... API key from the panel,
and point your client at the HTTP endpoint instead of the local command:
claude mcp add cortex https://cortexmem.com/api/cortex/mcp \
--transport http --header "Authorization: Bearer cc_YOUR_KEY"
# ~/.codex/config.toml
[mcp_servers.cortex]
url = "https://cortexmem.com/api/cortex/mcp"
[mcp_servers.cortex.http_headers]
Authorization = "Bearer cc_YOUR_KEY"
Self-hosting stays fully featured — the hosted tier adds the web panel and the brain graph, not the memory itself.
License
MIT © Gonzalo Rocca — see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.