ctxvault
Live demo • Docs • Quick Start • Examples • Roadmap • Contributing
What is CtxVault?
Most agent frameworks treat memory as an afterthought: a shared vector store where isolation depends on configuration staying correct and everything, facts and procedures alike, gets embedded into the same undifferentiated index. The agent cannot tell what it knows from how it should act.
CtxVault is built around a different primitive. Memory is organized into vaults: self-contained, directory-backed units with explicit types, one for each kind of memory an agent has. Isolation is structural, the topology is defined explicitly (one vault per agent, a shared knowledge base, private skills for a specific role, or any combination), with access control that determines exactly which agents can reach which vault.
The result is a memory layer that behaves like real infrastructure: typed, composable, observable, persistent and entirely local.
Related MCP server: zipmem-mcp
Core Principles
Typed memory: semantic, procedural and episodic
Classical cognitive architectures, from ACT-R (Anderson et al., 2004) to CoALA (Sumers et al., 2024), separate an agent's long-term memory into distinct modules: what it knows, how it acts, and what happened. Most agent frameworks ignore the distinction and store everything in a single vector index. In CtxVault each kind of memory is a vault type:
Vault | Memory | What it holds | How the agent reads it |
Semantic | Semantic: what the agent knows | Documents (PDF, DOCX, MD, TXT), chunked and embedded into a local vector index | By meaning: a query returns the closest chunks, with their source |
Skill | Procedural: how the agent acts | Procedures in markdown, each with a name and a description | By name: the agent lists the skills and reads the one it needs |
Episodic | Episodic: when something was true | Statements with two timelines: when they hold in the world, and when the vault learned it | By entity, validity and source, as of today or any past instant |
All three types share the same primitives: public or restricted, local or global, composable in any topology. How each type works →
Structural isolation and access control
Isolation enforced through prompt logic or metadata schemas is fragile: it grows harder to reason about as systems scale, and fails silently when it breaks.
In CtxVault, each vault is an independent index. Agents have no shared retrieval path unless one is explicitly defined. Vaults can be declared restricted, with access granted to specific agents directly through the CLI. The boundary is part of the architecture, not a rule written in a config file that someone might later get wrong.
Found 3 vaults
> agent-a-vault [RESTRICTED]
path: ~/.ctxvault/vaults/agent-a-vault
agents: agent-a
> shared-vault [PUBLIC]
path: ~/.ctxvault/vaults/shared-vault
> agent-c-vault [RESTRICTED]
path: ~/.ctxvault/vaults/agent-c-vault
agents: agent-cPersistent memory across sessions
Agents lose all context when a session ends. CtxVault gives them a knowledge base that persists across conversations, queryable by meaning rather than exact match. Context written in one session is retrievable days later using semantically related language.
Observable and human-controllable
When agents write to memory autonomously, visibility into what they write is not a debugging feature: it is the foundation of a trustworthy system. Whatever an agent wrote, through any interface, you can look at it three ways, and add to it yourself.
On disk. Every vault is a plain directory on your machine, readable and editable with any tool. Drop a document into a semantic vault or a skill into a skill vault, index it, and the agent sees it next to what it wrote on its own.
.ctxvault/
├── config.json # the registry: every vault, its type, who can reach it
└── vaults/
├── product-sheets/ # semantic: your documents, and the chroma/ index
├── counter-procedures/ # skill: one markdown file per skill
└── store-facts/ # episodic: episodes.db, a SQLite fileFrom the CLI. The same vaults, queried directly, independent of what any agent is doing.
ctxvault docs my-vault # what the agent has written
ctxvault query my-vault "what decisions were made last week?"
ctxvault index my-vault # add your own documents
ctxvault episodes my-vault --all # an episodic vault's statementsIn the browser. ctxvault ui opens the memory viewer: a map of every vault, its type and the agents that can reach it, and a page per vault. Semantic documents show their chunks as the agent receives them, skills are rendered from their markdown, and an episodic vault has a time cursor that rewinds it to any past day. It is read-only and entirely local, and --export writes it to one self-contained HTML file. Try the live demo, no install needed: the bakery of example 07, three agents, six vaults, a year of facts.
Local-first
No cloud, no telemetry, no external services. Vaults are plain directories on your machine, the storage layer is entirely local. What you connect to that knowledge base is your choice.
Integration Modes
CtxVault exposes the same vault layer through four interfaces. Use whichever fits your context, or combine them freely.
Python client: In-process. Import Client, open a vault by name and call it directly, with no server to start: for scripts, tests, pipelines and agents that own their memory.
CLI: Human-facing. Monitor vaults, inspect agent-written content, add your own documents, query knowledge bases directly.
HTTP API: Programmatic integration. Connect LangChain, LangGraph, or any custom pipeline to vaults via REST. Full CRUD, semantic search, and agent write support.
MCP server: For autonomous agents. Give any MCP-compatible client direct vault access with no integration code required. The agent handles list_vaults, query, write_doc, and list_docs on its own, and on an episodic vault it records and corrects facts with write_episode, query_episodes, supersede_episode and invalidate_episode, counts repetitions with confirm_episode, holds contradictions open with dispute_episodes, and discovers what the vault is about with list_entities.
Whichever door wrote it, ctxvault ui shows it: the viewer reads the same vaults, so what an agent recorded over MCP is on the page next to what you indexed from the CLI.
CtxVault vs Alternatives
CtxVault | Chroma + your code | LangChain Memory | Mem0 | Graphiti (Zep) | |
Runs without cloud services | ✓ | ✓ | ✓ | self-hosted | self-hosted, plus a graph database |
MCP server | ✓ | you build it | ✗ | ✓ | ✓ |
Automatic fact extraction from conversations | ✗ (the agent decides what to write) | you build it | ✗ | ✓ | ✓ |
Distinct memory types (semantic, procedural, episodic) | ✓ | you build it | ✗ | ✗ | ✗ |
Bi-temporal facts (valid time and transaction time) | ✓ | you build it | ✗ | partial | ✓ |
Graph-structured memory (entities and relations) | ✗ (planned) | you build it | ✗ | ✓ | ✓ |
Per-agent access control | ✓ | you build it | ✗ | ✗ | ✗ |
Storage as plain files on disk | ✓ | ✓ | ✗ | ✗ | ✗ (graph database) |
Inspection UI | local | ✗ | ✗ | hosted | ✗ |
The ✗ in the CtxVault column are real: there is no graph layer and it does not extract facts for you. The ✓ are what it was built for: memory types, time, access control, and storage you can open as a folder.
Examples
Seven scenarios, each with full code and setup instructions.
# | Example | What it shows |
01 | Single vault, single agent. Semantic RAG over PDF, MD, TXT, DOCX with source attribution. ~100 lines. | |
02 | Two agents, two vaults. Each agent has no retrieval path to the other's vault: isolation enforced at the infrastructure layer, not through metadata filtering. ~200 lines. | |
03 | An agent that recalls context across sessions using semantic queries. "financial constraints" retrieves "cut cloud costs by 15%" written three days prior. | |
04 | Three agents, five vaults: private, shared between a subset, and public. A tiered support system where access boundaries reflect organizational boundaries. | |
05 | One agent, two vault types, semantic and skill, integrated via MCP. Retrieves knowledge for what to say and skills for how to say it. | |
06 | One account followed across six months. Facts are superseded instead of overwritten, so the briefing uses only what holds today while April is still reconstructable. | |
07 | Everything in one place: three agents, six vaults, all three memory types, access rules, a year of facts replayed with their dates. The capstone example, a small bakery, and the dataset behind the live demo. |
Installation
Requirements: Python 3.10+
pip install ctxvaultFrom source, with uv:
git clone https://github.com/Filippo-Venturini/ctxvault
cd ctxvault
uv sync # creates .venv and installs all dependencies
uv run ctxvault # run the CLIQuick Start
Five minutes from nothing to an agent that remembers. Run these from your project's root.
1. Create a vault. It is a folder, registered in .ctxvault/config.json next to you, like git init.
ctxvault init notes2. Give it something to know. Drop .md, .txt, .pdf or .docx files into .ctxvault/vaults/notes/ and index them.
ctxvault index notes3. Ask it. Retrieval is by meaning, so the words do not have to match.
ctxvault query notes "what did we decide about pricing?"4. Give it to your agent. The quickest way is MCP: add the server to your client's config (Claude Desktop, Cursor, any MCP client) and restart it. With uv installed nothing else is needed:
{
"mcpServers": {
"ctxvault": { "command": "uvx", "args": ["ctxvault", "mcp"] }
}
}Or uv tool install ctxvault once, and use { "command": "ctxvault-mcp" } instead.
The agent can now list your vaults, query them, and write what it learns back. From your own code instead, use the Python client in-process or the HTTP server.
5. See what it holds.
ctxvault uiNext: a skill vault for procedures (ctxvault init procedures --type skill), an episodic vault for facts that change (ctxvault init facts --type episodic), and restricted vaults so each agent reaches only its own.
Documentation
The full reference lives on the documentation site:
Quick start: from nothing to an agent that remembers.
Connect an agent from Python, over HTTP or through MCP: the three setups, each with its own configuration.
How it works: memory types, local and global vaults and access control.
Memory viewer: what
ctxvault uishows, snapshots, and who can open it.
Roadmap
CLI MVP
FastAPI server
Multi-vault support
Agent write API
MCP server support
Access control
Typed memory (semantic + procedural vaults)
Episodic memory (bi-temporal statements, supersession, time travel)
Graph-backed semantic memory
File watcher / auto-sync
Context pruning
Contributing
Contributions welcome! Please check the issues for open tasks.
Development setup:
git clone https://github.com/Filippo-Venturini/ctxvault
cd ctxvault
# With uv (recommended)
uv sync --extra dev
uv run pytest
# With pip
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytestCitation
If you use CtxVault in your research or project, please cite:
@software{ctxvault2026,
author = {Filippo Venturini},
title = {CtxVault: Local Semantic Knowledge Vault for AI Agents},
year = {2026},
url = {https://github.com/Filippo-Venturini/ctxvault}
}License
MIT License - see LICENSE for details.
Security
Acknowledgments
Built on Chroma for vector storage, Sentence Transformers for embeddings, FastAPI for the HTTP API, the MCP Python SDK for the MCP server and Typer for the CLI. The memory viewer is built with Preact and htm, and the documentation with Material for MkDocs. The examples use LangChain.
Available Tools
17 toolsconfirm_episodeA
Record that a statement already in the vault was asserted again. Use this when you hear something the vault already holds, instead of writing it a second time: the episode stays as it is and gains one attestation, so a fact heard once can be told from one heard many times.
Inputs: episode_id (required), vault_name (required), at, source. Returns: episode, vault_name
dispute_episodesA
Record that two open statements cannot both hold, when you cannot tell which one is wrong. Neither is closed: both keep coming back from queries, each flagged with the other in disputed_with, so you can ask instead of assert. The dispute ends by itself when one side is invalidated or superseded. If you do know which one is wrong, use supersede_episode or invalidate_episode instead.
Inputs: other_id (required), episode_id (required), vault_name (required), note. Returns: episode, vault_name
episode_historyA
Show every version of a statement, oldest first. Use this to explain why the vault believes something, or to see what an episode used to say before it was corrected.
Inputs: episode_id (required), vault_name (required). Returns: chain, episode_id, vault_name
invalidate_episodeA
Mark an episode as no longer true, without deleting it. Use this when something ends and nothing replaces it. If a corrected version exists instead, use supersede_episode so the two stay linked.
Inputs: episode_id (required), vault_name (required), reason, valid_to. Returns: episode, vault_name
list_docsA
List all indexed documents inside a specific vault. Use this to understand what knowledge is available before performing a search.
Inputs: vault_name (required). Returns: documents, vault_name
list_entitiesA
List the entities an episodic vault knows about, with how many episodes mention each one. This is the vault's vocabulary: use it to find out what subjects exist before querying for them, to spot the name a person or thing is recorded under, or to see what has gone quiet. Unlike query_episodes it enumerates rather than ranks, so nothing is left out. By default only entities named by statements that still hold are listed; pass include_closed to see everything the vault ever recorded.
Inputs: vault_name (required), valid_at, min_episodes, include_closed. Returns: total, entities, vault_name
list_skillsA
List all available skills inside a specific vault. Use this to understand what skills are available before trying to fetch one.
Inputs: vault_name (required). Returns: skills, vault_name
list_vaultsA
List all available vaults. Use this before querying or writing to discover which vaults exist and choose the right one.
Inputs: no named parameters. Returns: vaults
queryB
Search for relevant information in a CtxVault vault using semantic similarity. Use this when the user asks a question that might be answered by their personal knowledge base or documents. Returns the most relevant text chunks with their source files.
Inputs: query (required), vault_name (required). Returns: results
query_episodesA
Retrieve episodes from an episodic vault. By default only statements that still hold are returned. Filter by entity for 'everything about X', pass valid_at to ask what was true at a past moment, or known_at to ask what the vault had already learned by then. Query text is optional and ranks results; without it the newest come first.
Inputs: vault_name (required), limit, query, entities, +4 more. Returns: query, results, order_by, vault_name
read_skillA
Read one skill from a skill vault: its name, description and full instructions. Use this after list_skills, once you know which procedure fits the task, and follow the instructions it returns.
Inputs: skill_name (required), vault_name (required). Returns: skill
revise_episodeA
Restate an episode more precisely, when the world did not change but you can now say it better ('lives in Padova' -> 'lives in Padova, in the Arcella'). The revision opens where the original did and inherits its attestations and open disputes; the original stays in the history but is no longer what the vault states. Use supersede_episode instead when the world changed.
Inputs: content (required), episode_id (required), vault_name (required), source, +2 more. Returns: episode, vault_name
supersede_episodeA
Replace an episode with a corrected or updated version. The old statement is closed exactly where the new one begins and the two are linked, so the history of what changed stays readable. Entities and salience carry over from the old episode unless you pass new ones. Use this whenever new information contradicts something already recorded.
Inputs: content (required), episode_id (required), vault_name (required), source, +2 more. Returns: episode, vault_name
warmup_statusA
Check if the embedding model has finished initializing. Use this to verify warmup status before attempting queries or writes.
Inputs: no named parameters. Returns: ready, status, message
write_docB
Save new information or agent-generated content to a semantic vault for future retrieval. Use this only with semantic vaults, to persist important context, summaries, or notes that should be remembered across sessions. Supports .txt, .md, and .docx formats.
Inputs: content (required), file_path (required), vault_name (required), generated_by (required), +1 more. Returns: file_path
write_episodeA
Record something that happened or something the user stated, in an episodic vault. Use this for facts with a lifetime — situations, preferences, relationships, plans — rather than for documents. Give the entities it is about so it can be looked up later, and a salience between 0 and 1 for how much it matters.
Inputs: content (required), vault_name (required), source, entities, +4 more. Returns: episode, vault_name
write_skillB
Create and store a new skill in a skill vault. Use this to persist procedural knowledge, instructions, or how-to guides that agents can retrieve and execute later. The skill will be indexed by name and description for fast lookup. Use this only with skill vaults.
Inputs: skill_name (required), vault_name (required), description (required), instructions (required), +1 more. Returns: filename
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
Tools split cleanly into three domains (document vaults, skill vaults, episodic memory) and the descriptions cross-reference each other explicitly, e.g. invalidate_episode points to supersede_episode and revise_episode distinguishes 'world changed' from 'said better'. The only residual overlap is between query/query_episodes/list_docs, which is mitigated but not eliminated by the doc-vs-episode framing.
Fourteen of seventeen tools follow a clean verb_noun snake_case pattern (list_vaults, write_doc, read_skill, supersede_episode, list_entities). The outliers — query, episode_history, warmup_status — are readable but break the verb-first convention.
Seventeen tools is slightly heavy but justified by covering three distinct storage modes (documents, skills, temporal episodes) plus warmup and entity enumeration. No tool looks redundant enough to remove; episode lifecycle tools each handle a genuinely different case.
Episodic memory is exceptionally complete (write, query, confirm, invalidate, supersede, revise, dispute, history), but the document and skill surfaces are write/list/read only — no update, delete, or move for docs or skills, and no create_vault despite list_vaults implying vault management. These gaps will cause dead ends for maintenance workflows.
Maintenance
Related MCP Connectors
Long-term memory for AI agents: hybrid vector and full-text recall, rooms, time-travel.
Private, portable memory and reusable skills for AI agents.
Persistent long-term memory for AI agents: semantic search, knowledge graph, and task canvas.
Local-first long-term memory for AI agents, with byte-recomputable signed verification receipts.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal-first persistent memory for AI agents via MCP, enabling semantic search and memory sharing across agents with zero cloud cost and full privacy.10 npm1MIT
- AlicenseAqualityDmaintenancelocal-first long-term memory for MCP agents (no DB, no API keys)37 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to maintain and sync long-term memory and reusable skills across devices using local folder sync, with support for multiple agents and optional semantic recall.6 npm1MIT
- FlicenseNot gradedqualityBmaintenancePersistent memory for AI coding agents: local-first semantic search, dependency graphs, git history.1-