Skip to main content
Glama

🐘 EleSync

CI PyPI Python versions License: MIT

A local memory vault that every AI can read and write to over MCP. One folder of markdown files on your machine. Claude, ChatGPT, Gemini, and any other MCP-aware client share it live β€” no service, no API key, no cloud.

pipx install "elesync[mcp]"
ele onboard

Install Β· Why local-first Β· Compared to other memory tools Β· Architecture Β· Privacy


The 60-second pitch

Every AI you talk to has its own siloed memory. Claude doesn't know what you told ChatGPT. ChatGPT doesn't know your Gemini context. You repeat yourself constantly.

EleSync turns that around: the vault is yours, on your disk, and every model is a client of it. It speaks the Model Context Protocol. Claude Desktop, Cursor, Windsurf, Continue, Zed, Cline, and Roo Code connect over stdio with one command. ChatGPT's Developer Mode connector needs a remote transport (Streamable HTTP) instead of stdio -- EleSync supports that too, tunneled or deployed. Tested live: ChatGPT reading and writing to the same vault Claude uses, over a tunnel, today.

The vault itself is just a directory of markdown files with YAML frontmatter, an SQLite FTS5 index, and (optionally) ONNX embeddings for semantic recall. No server. No daemon. No account. You can cat your memories. You can git push them. You can encrypt the whole vault and carry it on a USB stick.


Related MCP server: ai-memory

How it works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Claude    β”‚    β”‚   ChatGPT   β”‚    β”‚ MCP client  β”‚
β”‚   Desktop   β”‚    β”‚  (MCP)      β”‚    β”‚ (Cursor…)   β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚                  β”‚                  β”‚
       β”‚  MCP over stdio  β”‚ Streamable HTTP  β”‚  MCP over stdio
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                  β–Ό                  β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚    ele serve                 β”‚
          β”‚  (MCP server, ~600 LOC)      β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β–Ό
          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚   ~/EleSyncVault/            β”‚
          β”‚   β”œβ”€β”€ notes/ *.md   (truth)  β”‚
          β”‚   β”œβ”€β”€ index.sqlite  (FTS5)   β”‚
          β”‚   └── vectors/ *.npy (opt.)  β”‚
          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The markdown files are the source of truth. The SQLite index is a derived cache rebuilt from them on demand (ele sync). If the index is ever corrupt, delete it β€” ele rebuilds from the markdown.


Try it in under two minutes

pipx install "elesync[mcp]"
ele onboard           # interactive: pick a vault path, wire up Claude Desktop
ele remember "I'm a Rust developer; prefer concise code reviews without preamble"
ele recall "what languages do I use"
# > I'm a Rust developer; prefer concise code reviews without preamble  (claude Β· fact Β· 2026-06-25)

Restart Claude Desktop. Ask Claude: "What do you remember about me?" β€” it'll see what you just stored.

For the non-CLI flow (web UI, drag-and-drop import, no terminal):

ele web

…opens a local dashboard at 127.0.0.1:7477.


How it compares (mid-2026 landscape)

The "AI memory" space has split into two camps. Developer infrastructure for building agents (mem0, Letta, Zep, Graphiti, LangMem) is one thing. A memory vault you own, that the AIs you already use plug into, is a different thing. EleSync is the second.

EleSync

OpenMemory MCP

mem0

Letta

Zep / Graphiti

Storage

Plain markdown + SQLite

mem0 backend

Their DB

Their DB

Postgres + KG

What it stores

Your memories

Your memories

Memories for your agents

Tiered memory for agents

Temporal KG

Who it's for

You

You

Agent builders

Agent builders

Agent builders

Setup

pip install

mem0 install

SDK integration

SDK integration

Docker compose

Encryption at rest

XSalsa20-Poly1305 + argon2id

–

–

–

–

Portable USB vault

βœ“

–

–

–

–

Files inspectable in $EDITOR

βœ“

βœ—

βœ—

βœ—

βœ—

Temporal model ("what was true when")

βœ“ supersession history

–

–

–

βœ“ bi-temporal KG

Knowledge graph extraction

–

–

–

–

βœ“

Cross-AI provenance + conflict detection

βœ“

–

–

–

–

Hosted option

– (local-only)

βœ“

βœ“

βœ“

βœ“

Where EleSync is genuinely behind: no automatic entity/relationship extraction and no semantic decay β€” Zep/Graphiti's bi-temporal knowledge graph is richer than EleSync's linear supersession chains (a superseded fact is history you can replay with history; a validity window it is not). These are deliberate scope choices β€” files-on-disk is the constraint, and a knowledge graph in markdown stops looking like markdown fast.

Where it's genuinely ahead: you can grep your memory. You can git diff what changed last week. You can revoke your USB drive and your memory walks out the door with you, encrypted, readable on any machine with a Python install.


Install

Requires Python 3.10+.

Recommended β€” pipx installs the CLI and MCP server into their own isolated environment, so nothing collides with your other Python tools:

pipx install "elesync[mcp]"          # CLI + MCP server (recommended)

Or with pip:

pip install "elesync[mcp]"           # CLI + MCP server
pip install elesync                  # CLI only (the ele command; no MCP server)
pip install "elesync[semantic]"      # + ONNX embeddings (BAAI/bge-small-en, ~30MB download on first use)
pip install "elesync[encryption]"    # + at-rest encryption via libsodium
pip install "elesync[watch]"         # + auto-import from ~/Downloads
pip install "elesync[webauth]"       # + password auth for the web UI
pip install "elesync[dev]"           # everything above

The MCP server needs the mcp extra β€” plain pip install elesync gives you only the ele CLI. Extras stack, e.g. pipx install "elesync[mcp,semantic,encryption]".

Or grab a standalone executable from Releases β€” no Python required.

On Windows, scoop installs that same standalone executable (CLI and MCP server, no Python required) and keeps it updated:

scoop install https://raw.githubusercontent.com/darknodebros/EleSync/master/elesync.json

After install:

ele onboard          # interactive setup: vault path + MCP wiring for Claude Desktop
ele doctor           # verify everything is connected
ele doctor --fix     # repair fixable issues (e.g. stale/missing MCP wiring), then re-check

ele onboard writes the MCP server entry into claude_desktop_config.json (or the equivalent for other clients). It backs up the existing config first. Re-running is idempotent.


Use it with any MCP client

EleSync exposes itself as a standard MCP server, over either of the two transports the MCP spec defines: stdio (local clients) or Streamable HTTP (remote clients).

Local clients (stdio) -- Claude Desktop, Cursor, Windsurf, Continue, Zed, Cline, Roo Code

ele onboard writes the server entry into the client's own config file. It backs up the existing file first, preserves other servers, and re-running is idempotent:

ele onboard                        # Claude Desktop (the default)
ele onboard --target cursor        # ~/.cursor/mcp.json
ele onboard --target windsurf      # ~/.codeium/windsurf/mcp_config.json
ele onboard --target continue      # ~/.continue/config.json
ele onboard --target zed           # Zed settings.json (context_servers)
ele onboard --target cline         # VS Code settings.json (cline.mcpServers)
ele onboard --target roo-code      # VS Code settings.json (roo-cline.mcpServers)

--print-only shows the block without writing anything; --config-path overrides the auto-detected location.

For any client not listed, ele onboard --target generic --print-only prints a portable snippet:

{
  "mcpServers": {
    "elesync": {
      "command": "elesync",
      "args": [],
      "env": { "ELESYNC_DIR": "/Users/you/EleSyncVault" }
    }
  }
}

Remote clients (Streamable HTTP) -- ChatGPT Developer Mode, and anything else off-machine

ChatGPT's MCP connector (Developer Mode, shipped Sept 2025) requires a remote transport -- it can't launch a local stdio process the way Claude Desktop does. EleSync's server can switch transports with a flag -- but an off-machine MCP endpoint exposes remember and forget, so since v1.17.0 the server refuses to start one without authentication.

Three steps:

# 1. generate a Bearer token (stored in EleSync's config.json; printed once)
ele auth generate-token

# 2. start the server, naming the public hostname that will reach it
ele serve --transport http --port 8000 --allowed-host xxxx.ngrok-free.dev

# 3. put a tunnel or a TLS reverse proxy in front (quickest: ngrok)
ngrok http 8000

--allowed-host is required for any non-localhost hostname -- the server keeps DNS-rebinding protection on by default (CVE-2025-66416 in the underlying MCP SDK) and only widens the allow-list to hosts you explicitly name, rather than disabling the check. It is also how EleSync knows you are about to be public: any non-local --allowed-host (or a non-loopback --host) with no token configured makes ele serve exit with an error instead of starting an open vault. ele auth status and ele auth revoke manage the token; setting ELESYNC_TOKEN overrides the stored one for a single run.

Every request must then carry the standard header:

Authorization: Bearer <token>

Then in ChatGPT: Settings -> Connectors -> Advanced -> Developer Mode -> Add custom connector, server URL https://xxxx.ngrok-free.dev/mcp, and supply the token through the connector's authentication settings. If a client genuinely cannot send an Authorization header, ele serve ... --insecure starts anyway -- loudly, as a deliberate choice -- but treat that URL as world-readable and world-writable and keep the tunnel alive only while you're using it.

Verified working: recall and remember both round-trip correctly over a tunnel, including finding memories written earlier by Claude -- the actual point of EleSync.

For a permanent remote deployment (not just testing), put a real domain + TLS cert in front instead of a free ngrok tunnel. One note of scope honesty: the Bearer token is currently all-or-nothing -- one token unlocks every tool, including forget. Per-capability scoping (e.g. a read-only recall token for a less-trusted client) is on the roadmap.

Tools exposed via MCP

Tool

What it does

recall

Search the vault (BM25 + optional semantic)

remember

Write a new memory (optionally supersedes an older one)

forget

Delete a memory by ID

history

Show a memory's supersession chain β€” what a fact used to be, and when it changed

memory_status

Counts, sources, last-modified

list_scopes

Scope compartments this client can see, and how many memories each holds

find_conflicts

Cluster contradictions across sources

audit_log

Who read, wrote, or forgot what, and when (requires ELESYNC_AUDIT=1)


Importing existing memory from other AIs

The export landscape changed in 2026 β€” most providers retreated from file-based memory exports to "ask the assistant for your memories" workflows. EleSync handles both shapes.

Source

What works today

Adapter

ChatGPT conversation export (Settings β†’ Data Controls β†’ Export Data)

The ZIP contains conversations.json β€” full chat history. ele import parses it.

βœ“ verified

ChatGPT memory (the small set of explicit facts)

No file export exists in 2026. Use the in-app copy-paste prompt and save the output as text.

partial β€” see SETUP.md

Claude memory

Same copy-paste pattern as ChatGPT memory; no file export.

partial

Gemini

Via Google Takeout (export of conversation history, not memory).

βœ“ verified

Grok / DeepSeek / Perplexity / Copilot

Adapter built; export availability varies by region (Grok memory is EU-blocked).

experimental

ele import ~/Downloads/conversations.json --source chatgpt
ele import ~/Downloads/takeout-gemini.zip  --source gemini
ele watch ~/Downloads        # auto-detects and imports as exports arrive

The conversations.json from a full ChatGPT export can be multiple gigabytes. EleSync streams it; you don't need to unzip the full archive.


Architecture

No third-party services. The dependencies you need:

Layer

Dependency

Why

Core CLI + MCP

stdlib only

Zero required deps

Semantic recall

fastembed (ONNX)

BAAI/bge-small-en, runs on CPU

Encryption

pynacl

libsodium bindings, XSalsa20-Poly1305

Auto-import watch

watchdog

File system events

ele serve boots an MCP server over stdio. ele web boots a local HTTP server (127.0.0.1 only) that exposes a JSON REST API and an embedded HTML/CSS/JS dashboard. The web UI has zero external dependencies β€” no CDN, no analytics, no fonts loaded from third parties.

Provenance is first-class. Every memory carries source (claude, chatgpt, gemini, manual, …) and created_at. When two sources contradict each other, find_conflicts surfaces the cluster so you can decide which one is true.

Scoped sharing lets you give one MCP client a different view of the vault than another. Useful for keeping work memories away from a coding assistant, or hiding personal context from a client you don't fully trust.

# save memories into compartments
ele add "preferred language: Rust" --scopes coding

# wire a second, restricted connection alongside the full one
ele onboard --target cursor --scopes coding --name elesync-coding

A client wired with --scopes sees only those compartments; --write-scope sets where its new memories land. To write-lock a client entirely, set ELESYNC_SCOPES=readonly:coding (or just readonly) in its server entry's env β€” the MCP server then rejects remember and forget from that connection server-side.


Encryption + USB portable vault

EleSync can encrypt the entire vault at rest. The encryption is real cryptography (libsodium's secretbox: XSalsa20-Poly1305 with Poly1305 MAC, keys derived via argon2id), not a base64 wrapper.

ele encrypt              # one-time: convert an existing vault to encrypted form
                         # passphrase is hashed with argon2id, never stored
ele serve                # prompts for passphrase, unlocks in memory only

The same vault format runs on a USB drive with a launcher script. Plug into any machine with Python, run RUN_ME.py, unlock with the passphrase, and Claude / ChatGPT on that machine talk to it:

ele usb install /Volumes/MY_DRIVE     # creates encrypted vault + launcher + README
ele usb attach   /Volumes/MY_DRIVE    # wires Claude Desktop on this machine
ele usb detach   /Volumes/MY_DRIVE    # cleanly unwires before unplug
ele usb status   /Volumes/MY_DRIVE    # what's on the drive?

Web UI

ele web launches a local dashboard for non-CLI users:

EleSync web UI dashboard

Browse, search, edit, import drag-and-drop, switch between vaults (including USB), add/delete memories. The UI is one HTML file with embedded JS β€” no build step, no framework, no external dependencies.

Dark mode toggle (persists in localStorage). Keyboard shortcuts: / to search, N for new memory, ? for help, Esc to close panels, Ctrl+K for command palette. CSV export in addition to JSON. Mobile-responsive down to 375px with touch-friendly targets.

Self-hosted mode: ele web --host 0.0.0.0 binds to all interfaces for multi-device family/team use. A security warning is shown if you expose to the network without authentication.

By default there's no login β€” it binds to 127.0.0.1 only, so it's as private as anything else running on your machine. If you want a login anyway (shared machine, or you're the cautious type), add a user and it turns on automatically:

ele web adduser alice              # prompts for a password, hashed with bcrypt
ele web adduser bob --role viewer  # read-only account β€” can browse/search, can't add/edit/delete
ele web listusers
ele web removeuser bob             # remove the last user and login turns back off

Passwords are bcrypt-hashed, session tokens are stored as SHA-256 hashes (never plaintext) in <vault>/.web_auth/, and viewer accounts are enforced server-side, not just hidden in the UI β€” a viewer session gets a real 403 on any write attempt, not just a greyed-out button. This is a local-first tool, not a hardened multi-tenant server: for anything exposed past 127.0.0.1, put a real reverse proxy with TLS in front of it.


Sync across devices

Because the vault is just files, you sync it however you sync files:

  • git β€” git init your vault, push to GitHub/GitLab/Forgejo

  • Syncthing β€” peer-to-peer, no cloud

  • iCloud / Dropbox / Drive β€” works fine, just point your vault at the synced folder

  • Encrypted USB β€” see above

  • Portable snapshot β€” ele backup writes a single compressed .eleb archive (including supersession history); ele restore rebuilds losslessly on any machine, into a fresh vault or an existing one:

# machine A β€” snapshot
ele backup                # timestamped .eleb in <vault>/backups
ele backup --encrypt      # passphrase-protected (needs the [encryption] extra)
ele backup list           # what's there: date, size, memories, checksum state
ele backup list --verify  # re-hash each one and flag anything that changed

# machine B β€” restore (idempotent; safe to re-run)
ele restore ~/EleSyncVault/backups/elesync-backup-20260717-205632.eleb

Backups are tracked in a manifest (elesync-backups.json) beside them, recording each archive's timestamp, size, format version, encryption state, and SHA-256. Set a retention count to stop them piling up β€” old backups are pruned only after a new one has been written and recorded, so you are never left without a good copy:

ELESYNC_BACKUP_KEEP=7 ele backup     # or "backup": {"keep": 7} in config.json
ELESYNC_BACKUP_DIR=/mnt/usb/elesync ele backup   # or "backup": {"dir": "..."}

Retention only ever manages that directory. ele backup /some/path.eleb is recorded so list can see it, but nothing you name explicitly is ever deleted.

# device A
cd ~/EleSyncVault && git add . && git commit -m "memories" && git push

# device B, after pulling
ele sync            # rebuilds the SQLite index from markdown

The SQLite index is gitignored by default. Only the markdown is the source of truth.


Privacy

  • Zero telemetry. EleSync never connects to the internet unless you tell it to (ele import of a URL, semantic model download on first use).

  • Zero accounts. There is no signup. There is no server.

  • Zero ads, zero tracking, zero data collection. Not "we don't do that yet". There is no business model that depends on your data.

  • The vault is yours. Delete it and EleSync forgets everything.

The semantic-recall extra downloads the BAAI/bge-small-en model from HuggingFace on first use (~30MB). After that, it runs entirely locally on CPU. You can skip the download by not installing [semantic].


Status

EleSync is at 1.17.0 (562 tests, ~10,500 LOC). The 1.x line will not break compatibility β€” vault format, MCP tool names, and CLI commands are stable until a 2.0.

Roadmap

What's planned or in design β€” contributions welcome on any of these:

  • Knowledge graph (design phase) β€” lightweight entity/relation tagging where the calling AI supplies structured tags at remember() time. No local NLP model, no API calls. Design discussion β†’

  • Auto-supersession for untagged updates β€” the write-path gate deliberately requires a shared tag today, because a false positive tombstones a live memory. Direction C (shipped 1.13.0) surfaces the untagged/ambiguous cases via ele conflicts for a manual accept step; the open question is whether untagged updates should also auto-supersede on save, and how to keep the false-positive rate low without adding heavyweight dependencies. Predicate-anchored heuristic vs. optional semantic backend β€” no decision yet.

  • Performance at scale β€” profiling and optimization for vaults with 10K+ memories.

See CONTRIBUTING.md for how to get started. First-time contributors: look for issues tagged good first issue.


License

MIT. See LICENSE.


A
license - permissive license
-
quality - not tested
B
maintenance

Maintenance

–Maintainers
–Response time
0dRelease cycle
47Releases (12mo)
Commit activity
Issues opened vs closed

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/darknodebros/EleSync'

If you have feedback or need assistance with the MCP directory API, please join our Discord server