Skip to main content

Erudition

Portable, typed, git-friendly memory for AI agents.

Claude Code's built-in memory is local-only and opaque. It lives inside Claude Code itself, isn't portable across machines, and isn't something you can casually read, diff, or edit by hand. Erudition is an MCP server that gives an agent read/write access to a memory store that's none of those things: a plain folder of markdown files, organized around a real taxonomy instead of a junk drawer, editable in whatever notes app you already use, and portable across every machine you own via git.

This README covers what Erudition does and how to install it. For the reasoning behind why it's built this way, and just as importantly, why it isn't built several other, more obvious ways, see WHY.md.

What it is

  • An MCP server. Works with Claude Code, Claude Desktop, or any other MCP-compatible client, exposing ten tools (see Tools below).
  • A markdown vault, not a database. Every memory is a .md file with YAML frontmatter, in a folder you fully control. No proprietary format, no service to run, no account to create. Obsidian is a good viewer/editor for it, but Erudition doesn't require Obsidian. Any plain-text editor works.
  • A taxonomy, not a junk drawer. Memories are typed (user / feedback / project / reference by default), so an agent (and you) can tell "a fact about how I like to work" apart from "a fact about this specific project" at a glance.

What it isn't

  • Not a hosted product. It runs locally, wherever your agent runs.
  • Not a "chat with your notes" RAG plugin. Erudition is about agent memory (what an agent should remember across sessions), not general document search.
  • Not a replacement for Claude Code (or Claude Code's own memory). It's a layer on top, and it's designed to stay small rather than grow into a competing agent runtime.

Quickstart

1. Install

pip install erudition-mcp

Or, for local development:

git clone https://github.com/Ralf090102/Erudition.git
cd Erudition
pip install -e .

Either way, this installs the erudition command (the PyPI distribution is named erudition-mcp; the import path and CLI command stay erudition).

2. Point it at a vault

Erudition needs to know which folder is your vault:

export ERUDITION_VAULT_PATH="/path/to/my-notes"

That's a complete, valid setup on its own. If you want the auto-commit toggle or a custom taxonomy, write an erudition.toml instead (or alongside). Copy erudition.example.toml and see the Configuration table below for every option.

3. Connect it to your MCP client

For Claude Code, add it to your MCP server config:

{
  "mcpServers": {
    "erudition": {
      "command": "erudition",
      "env": {
        "ERUDITION_VAULT_PATH": "/path/to/my-notes"
      }
    }
  }
}

Restart your client. You should see all ten tools below available.

Erudition keeps a small search index at {vault}/.erudition/. It's a rebuildable cache, not real content, so add .erudition/ to the vault's own .gitignore.

Tools

Tool What it does
read_note(path) Read a note's contents.
list_notes(folder="") List markdown notes in a folder, recursively (empty string lists the whole vault).
search_notes(query, folder="") Search note contents, backed by a rebuildable SQLite FTS5 index rather than a linear scan. This makes matching token-based, not raw substring: wid* matches "widgets," a bare idget doesn't the way a plain substring scan would. Supports FTS5 phrase ("exact phrase") and boolean (AND / OR / NOT) syntax. Falls back automatically to a plain linear scan if the local sqlite3 build lacks FTS5. Returns matching file paths and the lines that matched; if a query is still slow despite the index, the result includes a one-line note suggesting the staleness check itself might be worth revisiting.
write_note(path, content, overwrite=False, dry_run=False) Write a note; refuses to clobber an existing one unless overwrite=True. dry_run=True writes nothing and returns a preview (new content, or a diff against what's there) instead.
append_to_note(path, content, dry_run=False) Append to a note, creating it (and any parent folders) if it doesn't exist yet.
str_replace_in_note(path, old_string, new_string, dry_run=False) Replace one exact, uniquely-matching string within an existing note, in place — for a small correction to one part of a note without rewriting the rest. Refuses if old_string doesn't match exactly once (zero matches, or more than one), rather than guessing which occurrence you meant.
list_memory_types() List the vault's configured taxonomy: valid type values for save_memory, and what each is for.
save_memory(type, name, description, content, overwrite=False, dry_run=False) Save a typed memory (validated against the taxonomy), with standard frontmatter, indexed in MEMORY.md.
sync_memory() Mirror the vault's memory folder out to a configured local memory directory.
rebuild_search_index() Force a full rebuild of the search index from scratch. Rarely needed, since search_notes already self-heals from a cheap per-search staleness check; mostly a manual escape hatch for recovery or peace of mind after a large batch of external edits.

The taxonomy

Erudition's default memory types, and what each is for:

Type What goes here
user Who the person is: their role, goals, expertise. Lets an agent tailor how it explains things.
feedback Corrections and confirmed approaches, like "don't do X, we tried it and it broke Y" or "yes, that approach was right." Stops an agent from repeating a mistake or re-litigating a settled call.
project Ongoing context about why (decisions, deadlines, stakeholders) that isn't visible in the code or git history alone.
reference Pointers to where information actually lives, e.g. "bugs are tracked in Linear project X," not a copy of the bugs themselves.

This is a starting point, not a fixed schema. Define your own types under [taxonomy.*] in erudition.toml if your vault needs a different shape. See erudition.example.toml.

Saving and syncing memories

Beyond generic write_note, Erudition understands the taxonomy. save_memory validates the type you pass against the vault's configured types, writes the memory to Memory/{type}_{slug}.md with standard frontmatter, and keeps Memory/MEMORY.md as a lightweight index, one line per memory:

save_memory(
    type="feedback",
    name="Prefers terse commit messages",
    description="User wants one-line commit messages, no bullet lists.",
    content="Confirmed after three separate corrections. Applies to this repo only.",
)

If your agent also keeps its own local memory folder (Claude Code does), sync_memory() mirrors everything under the vault's memory folder out to it, so writing a memory once in the vault doesn't also require a manual second write elsewhere. Configure the destination via local_memory_dir (see Configuration below). sync_memory() errors clearly if it isn't set, rather than silently doing nothing.

Write safety: a permanent design choice, not a limitation

Erudition assumes one active writer at a time. Flat markdown files have no locking, so if a human and an agent (or two agent sessions) write to the same note within moments of each other, the later write silently wins. No merge, no conflict marker, no error.

This is deliberate, not an oversight. Closing that gap completely would mean row-level locking, which means becoming a database. That trades away the one thing that makes a markdown vault worth using over a SQLite-backed alternative: you can open, read, and edit every memory in any plain-text editor, no tooling required. Instead, Erudition offers durability without locking: an optional auto_commit setting that git-commits every write with a distinct, identifiable message (erudition: write <path>). It doesn't prevent a collision, but it means a collision is always recoverable via git log / git diff instead of silently gone.

If you run more than one agent session against the same vault at the same time, that's exactly the scenario this boundary is about. Treat "one writer at a time" as a real constraint, the same way you would with any file two processes might edit concurrently.

Separately from durability, write_note, append_to_note, and save_memory all accept dry_run=True: nothing gets written, and you get back a preview instead, either the full content for a brand-new note, or a unified diff against what's already there for an overwrite. Useful for checking what a change would actually do before committing to it, especially with overwrite=True.

Optional: Claude Code hook integration

This is Claude-Code-specific and entirely optional — it's a companion to the core MCP server above, not a change to it, and it doesn't do anything with other MCP clients. If you don't use Claude Code, skip this section.

Two problems this solves: remembering to read a "where we left off" note at the start of every session, and remembering to call sync_memory() after making changes. Claude Code has its own hook system (separate from MCP) for exactly this: SessionStart can inject context automatically when a session begins, and Stop runs after every turn.

Add this to your project's .claude/settings.json:

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "erudition hook session-start"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "erudition hook stop"
          }
        ]
      }
    ]
  }
}

erudition hook session-start reads the note at session_start_note (defaults to Memory/CURRENT.md; see Configuration) and injects its contents as session context. erudition hook stop calls sync_memory(). Both are best-effort: a missing note or an unconfigured sync_memory is a silent no-op, never an error that could block a session or a turn.

Configuration

Setting Env var erudition.toml key Default
Vault path ERUDITION_VAULT_PATH vault_path (required, one or the other)
Auto-commit on write ERUDITION_AUTO_COMMIT auto_commit false
Memory taxonomy [taxonomy.*] the four types above
Memory folder ERUDITION_MEMORY_FOLDER memory_folder Memory
Local memory mirror (for sync_memory) ERUDITION_LOCAL_MEMORY_DIR local_memory_dir unset
Session-start note (for the optional hook) ERUDITION_SESSION_START_NOTE session_start_note Memory/CURRENT.md
Config file location ERUDITION_CONFIG ./erudition.toml if present

An env var always wins over the config file for the setting it covers. Full example with every option: erudition.example.toml.

Development

pip install -e ".[dev]"
pytest

Status

Early stage. Config-driven vault path, generalized taxonomy, the write-safety toggle (including dry-run previews), the taxonomy-aware memory tools (save_memory, sync_memory, list_memory_types, append_to_note, str_replace_in_note), a rebuildable FTS5 search index, and a real, repo-tracked test suite are all done. Live on PyPI as erudition-mcp since 2026-08-10. Expect breaking changes before a 1.0 release.

License

MIT. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

erudition_mcp-0.2.0.tar.gz (35.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

erudition_mcp-0.2.0-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file erudition_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: erudition_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 35.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for erudition_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 76a65ef4b05dcf0dd167ef9a610528c100cad5e4f3c2f44d99fe0f49c73852f7
MD5 73e75b84d49b575d6396e41c67ebb4e5
BLAKE2b-256 0fb809f639a89662eebbb48b6be929dc65cc2847c613c9f54caa22a7e6d3a8b3

See more details on using hashes here.

File details

Details for the file erudition_mcp-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: erudition_mcp-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 24.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.5

File hashes

Hashes for erudition_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0c3eccbce4c38a20eb7378d3a7684beb670ae815d086579d5e5e677c2dad5951
MD5 7cf09e41c08ba35b7732ea61dbee0113
BLAKE2b-256 27db9d97ba88a1ff31f503e610dc4a7002e969aadd8e92ce19558c78e6060b68

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page