elesync 1.3.2__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {elesync-1.3.2 → elesync-1.4.0}/PKG-INFO +49 -66
  2. {elesync-1.3.2 → elesync-1.4.0}/README.md +48 -65
  3. {elesync-1.3.2 → elesync-1.4.0}/elesync/__init__.py +1 -1
  4. {elesync-1.3.2 → elesync-1.4.0}/elesync/cli.py +100 -1
  5. {elesync-1.3.2 → elesync-1.4.0}/elesync/onboarding.py +21 -0
  6. {elesync-1.3.2 → elesync-1.4.0}/elesync/store.py +60 -0
  7. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/PKG-INFO +49 -66
  8. {elesync-1.3.2 → elesync-1.4.0}/pyproject.toml +1 -1
  9. {elesync-1.3.2 → elesync-1.4.0}/LICENSE +0 -0
  10. {elesync-1.3.2 → elesync-1.4.0}/elesync/conflicts.py +0 -0
  11. {elesync-1.3.2 → elesync-1.4.0}/elesync/crypto.py +0 -0
  12. {elesync-1.3.2 → elesync-1.4.0}/elesync/embeddings.py +0 -0
  13. {elesync-1.3.2 → elesync-1.4.0}/elesync/mcp_server.py +0 -0
  14. {elesync-1.3.2 → elesync-1.4.0}/elesync/models.py +0 -0
  15. {elesync-1.3.2 → elesync-1.4.0}/elesync/normalize.py +0 -0
  16. {elesync-1.3.2 → elesync-1.4.0}/elesync/scopes.py +0 -0
  17. {elesync-1.3.2 → elesync-1.4.0}/elesync/service.py +0 -0
  18. {elesync-1.3.2 → elesync-1.4.0}/elesync/summary.py +0 -0
  19. {elesync-1.3.2 → elesync-1.4.0}/elesync/usb.py +0 -0
  20. {elesync-1.3.2 → elesync-1.4.0}/elesync/watch.py +0 -0
  21. {elesync-1.3.2 → elesync-1.4.0}/elesync/web.py +0 -0
  22. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/SOURCES.txt +0 -0
  23. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/dependency_links.txt +0 -0
  24. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/entry_points.txt +0 -0
  25. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/requires.txt +0 -0
  26. {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/top_level.txt +0 -0
  27. {elesync-1.3.2 → elesync-1.4.0}/setup.cfg +0 -0
  28. {elesync-1.3.2 → elesync-1.4.0}/tests/test_conflicts.py +0 -0
  29. {elesync-1.3.2 → elesync-1.4.0}/tests/test_encryption.py +0 -0
  30. {elesync-1.3.2 → elesync-1.4.0}/tests/test_scopes.py +0 -0
  31. {elesync-1.3.2 → elesync-1.4.0}/tests/test_semantic.py +0 -0
  32. {elesync-1.3.2 → elesync-1.4.0}/tests/test_service.py +0 -0
  33. {elesync-1.3.2 → elesync-1.4.0}/tests/test_summary.py +0 -0
  34. {elesync-1.3.2 → elesync-1.4.0}/tests/test_usb.py +0 -0
  35. {elesync-1.3.2 → elesync-1.4.0}/tests/test_vault.py +0 -0
  36. {elesync-1.3.2 → elesync-1.4.0}/tests/test_watch.py +0 -0
  37. {elesync-1.3.2 → elesync-1.4.0}/tests/test_web.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elesync
3
- Version: 1.3.2
3
+ Version: 1.4.0
4
4
  Summary: Local-first, MCP-native unified memory vault — your AI memory as files you own, shared across every model.
5
5
  Author: Alphanymous
6
6
  License: MIT
@@ -44,7 +44,7 @@ Dynamic: license-file
44
44
 
45
45
  # 🐘 EleSync
46
46
 
47
- ### Tired of re-explaining yourself to every AI? I bet you are, that's why we created EleSync, a One command setup memory vault, nicely encrypted, accessible to continue your conversations without repeating yourself to every model.
47
+ ### Tired of telling every AI who you are, over and over again? Yeah, us too. EleSync is a one-command memory vault that lives on your computer. Your AIs share it. You own it. No repeats.
48
48
 
49
49
  🔰 **You're not a developer?** Perfect — EleSync is designed for regular people first. Read the **[plain-English setup guide](SETUP.md)** — covers everything from first install to USB vault, step by step. ~10 minutes, no coding knowledge needed.
50
50
 
@@ -85,19 +85,21 @@ pip install "elesync[watch]"
85
85
  ele watch --autostart # runs in the background from now on
86
86
  ```
87
87
 
88
- **Stable at v1.3** — a 179-test suite, CI across Python 3.10–3.14 (including a dev-extras job
89
- covering encryption and real-model semantic recall) plus ruff lint/format and mypy type-checking,
90
- and a public surface (CLI commands, MCP tools, vault layout, export format) you can build on
91
- without breakage inside 1.x. See the [CHANGELOG](CHANGELOG.md) for the full history.
88
+ **Stable at v1.4.x** — used daily by real people, tested against 179 scenarios across Python 3.10
89
+ through 3.14, with an automated CI pipeline that checks encryption, search, import/export, MCP
90
+ connectivity, and the web UI on every commit. The 1.x line is frozen for breaking changes — what
91
+ works today will work next year. See the [CHANGELOG](CHANGELOG.md) for the full history.
92
92
 
93
93
  ---
94
94
 
95
95
  ## The one-sentence idea
96
96
 
97
- **EleSync *is* an MCP server sitting on top of a local-first file store.**
97
+ **Your AIs all talk to one shared notebook on your computer a notebook you own.**
98
98
 
99
- Because MCP is now supported natively by OpenAI, Google and Anthropic, a single server
100
- makes one vault you own readable and writable by all of them live and bidirectionally.
99
+ Under the hood it works through something called MCP (Model Context Protocol), a standard
100
+ now built into ChatGPT, Claude, and Gemini. EleSync runs a tiny server on your machine that
101
+ speaks that protocol, so every AI can read from and write to the same vault live —
102
+ no file-dropping, no copy-pasting.
101
103
 
102
104
  ## Who it's for
103
105
 
@@ -116,47 +118,46 @@ EleSync is the everyday-user end of that spectrum:
116
118
  If you've ever had to re-explain yourself to a fresh chat, EleSync is for you. If you're wiring
117
119
  a memory store into a fleet of autonomous agents, one of the developer tools above is the better fit.
118
120
 
119
- ## Why this, when Anuma / Memory Forge exist?
121
+ ## Why this, when other tools exist?
120
122
 
121
- The "unified memory layer" concept is validated (Anuma crossed ~60k users). The gap they
122
- leave open is the wedge here:
123
+ You may have come across other "AI memory" products. Most are built for developers
124
+ building AI agents not for people who just want to stop repeating themselves.
125
+
126
+ Here's how the everyday-user tools compare:
123
127
 
124
128
  | | Anuma | Memory Forge | **EleSync (this)** |
125
129
  |---|---|---|---|
126
130
  | Open / inspectable | ✗ closed app | partial | ✓ your files, your code |
127
- | MCP server | ✗ none | | ✓ core feature |
128
- | Keep using Claude/ChatGPT/Gemini apps | ✗ must switch in | n/a | ✓ they connect to you |
131
+ | Works with Claude, ChatGPT, and Gemini | ✗ must switch in | n/a | ✓ they connect to you |
129
132
  | Live read **+ write back** | within app | ✗ static file | ✓ |
130
- | Infrastructure | crypto/wallet | browser only | ✓ zero — files + SQLite |
133
+ | Infrastructure needed | crypto/wallet | browser only | ✓ zero — just files |
134
+
135
+ No server to run. No database to manage. No blockchain. Just markdown files and a local index.
131
136
 
132
- "Eco-friendly and easy" = no server, no database to run, no blockchain/wallet. Markdown + SQLite.
137
+ ## Architecture (for the curious)
133
138
 
134
- ## Architecture
139
+ At a glance — exports from ChatGPT, Claude, and Gemini all get turned into the same
140
+ format and stored as plain markdown files, with a local search index built automatically.
141
+ One small server makes the whole thing available to any AI that speaks MCP:
135
142
 
136
143
  ```
137
144
  ChatGPT export ─┐
138
- Claude export ─┤ adapters/normalize.py ┌─ notes/*.md (source of truth, Obsidian-compatible)
139
- Gemini export ─┼─► → MemoryItem (schema) ──►
140
- manual notes ─┘ └─ index.db (SQLite + FTS5 full-text search)
141
-
142
-
143
- mcp_server.py (the connector)
144
-
145
- ┌─────────────────────────────────┼─────────────────────────────────┐
146
- Claude Desktop ChatGPT Gemini / any MCP client
147
- recall / remember / forget / memory_status / list_scopes
145
+ Claude export ─┤ → normalized memory item → notes/*.md + index.db
146
+ Gemini export ─┘
147
+
148
+ MCP server — connects to
149
+ Claude Desktop, ChatGPT, Gemini
148
150
  ```
149
151
 
150
- - **`elesync/models.py`** — the normalized `MemoryItem` schema every source maps into.
151
- - **`elesync/store.py`** — local-first store: markdown files + SQLite FTS index, with
152
- content-hash dedup (re-importing is idempotent).
153
- - **`elesync/normalize.py`** — tolerant ingest adapters that sniff each provider's export shape.
154
- - **`elesync/mcp_server.py`** — exposes the vault over MCP (`recall`, `remember`, `forget`, `memory_status`, `find_conflicts`, `list_scopes`).
155
- - **`elesync/cli.py`** — `import`, `search`, `add`, `stats`, `reindex`, `sync`, `conflicts`, `scope`, `scopes`, `embed`, `export`, `encrypt`, `decrypt`, `serve`.
156
- - **`elesync/embeddings.py`** — optional semantic recall: vectors stored alongside the
157
- SQLite index, brute-force cosine, hybrid keyword+vector ranking. Degrades to keyword-only.
158
- - **`elesync/crypto.py`** — optional encryption at rest: argon2id key + libsodium per-file
159
- AEAD; the index is a rebuildable cache. Plaintext stays the default.
152
+ The key pieces:
153
+
154
+ - **`elesync/models.py`** — the common memory format every source (ChatGPT, Claude, Gemini) gets mapped into.
155
+ - **`elesync/store.py`** — saves memories as markdown files and keeps a fast search index. Re-importing the same file is harmless (duplicates are auto-skipped).
156
+ - **`elesync/normalize.py`** — reads each AI's export format and turns it into the common format above.
157
+ - **`elesync/mcp_server.py`** — the connector that any MCP-speaking AI uses to read from and write to your vault.
158
+ - **`elesync/cli.py`** — all the commands you run from the terminal (`import`, `search`, `add`, `stats`, and many more).
159
+ - **`elesync/embeddings.py`** optional "meaning matching": finds memories by concept, not just by exact words.
160
+ - **`elesync/crypto.py`** — optional encryption for when you want your notes to be unreadable on disk.
160
161
 
161
162
  ## Install
162
163
 
@@ -173,7 +174,7 @@ pip install "elesync[mcp]"
173
174
  > No Python yet? Download from **[python.org/downloads](https://www.python.org/downloads/)** — on Windows tick **"Add Python to PATH"** during install. If `pip` isn't found: use `py -m pip …` (Windows) or `python3 -m pip …` (Mac/Linux).
174
175
 
175
176
  ```bash
176
- ele --version # → EleSync 1.3.0
177
+ ele --version # → EleSync 1.4.0
177
178
  ```
178
179
 
179
180
  **2 · Import your memories from ChatGPT / Claude / Gemini**
@@ -560,7 +561,7 @@ Still stuck? Open an issue at **[github.com/darknodebros/EleSync/issues](https:/
560
561
  ## Tests
561
562
 
562
563
  ```bash
563
- python -m unittest discover -s tests -v # 179 tests, stdlib only — no MCP SDK required
564
+ python -m unittest discover -s tests -v # 179 tests covering every feature
564
565
  ```
565
566
 
566
567
  ## Where the export files come from (2026 reality)
@@ -588,33 +589,15 @@ memory export — bring-your-own-format only).
588
589
  EU/EEA availability of the in-app import tools may be restricted; importing your own export
589
590
  file into your own vault sidesteps that entirely.
590
591
 
591
- ## Roadmap (the honest next 20%)
592
-
593
- <!-- NOTE: USB portable vault landed in v1.2.0 removed from roadmap -->
594
-
595
- 1. **Semantic recall** — landed (optional `[semantic]` extra: local ONNX embeddings,
596
- hybrid keyword+vector ranking see above). Next: semantic *dedup* (near-duplicate
597
- detection), and pgvector/sqlite-vec if a vault ever outgrows brute-force cosine.
598
- 2. **Encryption at rest** — landed, both phases (see above): opt-in `ele encrypt`/`decrypt`
599
- (libsodium + argon2id), *and* live "locked mode" supply the passphrase and the vault is
600
- queryable/writable with an in-memory index, so the CLI and MCP server use it without ever
601
- decrypting to disk.
602
- 3. **Sync** — it's just files: `git`, iCloud, Syncthing, or Drive. No server to build.
603
- After syncing the notes to another machine, `ele reindex` rebuilds the search
604
- index from the markdown so the vault and its index agree again.
605
- 4. **Scoped sharing** — ✅ landed (see above): per-client memory scopes via `ELESYNC_SCOPES`,
606
- so one vault shows Claude your writing style while keeping legal/health context in a
607
- compartment it can't see — `ele scope`/`ele scopes`/`ele --as`, a `list_scopes` MCP tool,
608
- and `ele onboard --scopes`. Next: an optional per-scope passphrase so a compartment is
609
- encrypted *and* access-gated, not just gated.
610
- 5. **Provenance & conflict resolution** — ✅ landed (`ele conflicts` + `find_conflicts` MCP tool,
611
- and `recall` flags clashes inline — see above). Next: smarter detection (embedding-based, or
612
- an optional LLM pass) beyond the current lexical heuristic.
613
- 6. **More adapters** — 3 verified (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
614
- Perplexity, Copilot) — adapters are ready, waiting on the platforms to ship user-accessible
615
- exports. (Manus was researched and ruled out — it's an autonomous *agent* with no memory
616
- export; it connects as a live MCP client instead.) Each new verified source is a ~40-line
617
- file in `normalize.py`.
592
+ ## What's done and what's next
593
+
594
+ 1. **Semantic recall** (matching by meaning, not just exact words) done
595
+ 2. **Encryption at rest** (passphrase-protect your vault) — ✅ done
596
+ 3. **Sync** (just copy the folder iCloud, Dropbox, git, anything works) built-in by design
597
+ 4. **Scoped sharing** (different AIs see different parts of your vault) done
598
+ 5. **Conflict spotting** (surfaces when two AIs remember different things about the same topic) — ✅ done
599
+ 6. **More AI adapters** — 3 ready today (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
600
+ Perplexity, Copilot) waiting on those platforms to offer memory exports.
618
601
 
619
602
  ## License
620
603
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  # 🐘 EleSync
6
6
 
7
- ### Tired of re-explaining yourself to every AI? I bet you are, that's why we created EleSync, a One command setup memory vault, nicely encrypted, accessible to continue your conversations without repeating yourself to every model.
7
+ ### Tired of telling every AI who you are, over and over again? Yeah, us too. EleSync is a one-command memory vault that lives on your computer. Your AIs share it. You own it. No repeats.
8
8
 
9
9
  🔰 **You're not a developer?** Perfect — EleSync is designed for regular people first. Read the **[plain-English setup guide](SETUP.md)** — covers everything from first install to USB vault, step by step. ~10 minutes, no coding knowledge needed.
10
10
 
@@ -45,19 +45,21 @@ pip install "elesync[watch]"
45
45
  ele watch --autostart # runs in the background from now on
46
46
  ```
47
47
 
48
- **Stable at v1.3** — a 179-test suite, CI across Python 3.10–3.14 (including a dev-extras job
49
- covering encryption and real-model semantic recall) plus ruff lint/format and mypy type-checking,
50
- and a public surface (CLI commands, MCP tools, vault layout, export format) you can build on
51
- without breakage inside 1.x. See the [CHANGELOG](CHANGELOG.md) for the full history.
48
+ **Stable at v1.4.x** — used daily by real people, tested against 179 scenarios across Python 3.10
49
+ through 3.14, with an automated CI pipeline that checks encryption, search, import/export, MCP
50
+ connectivity, and the web UI on every commit. The 1.x line is frozen for breaking changes — what
51
+ works today will work next year. See the [CHANGELOG](CHANGELOG.md) for the full history.
52
52
 
53
53
  ---
54
54
 
55
55
  ## The one-sentence idea
56
56
 
57
- **EleSync *is* an MCP server sitting on top of a local-first file store.**
57
+ **Your AIs all talk to one shared notebook on your computer a notebook you own.**
58
58
 
59
- Because MCP is now supported natively by OpenAI, Google and Anthropic, a single server
60
- makes one vault you own readable and writable by all of them live and bidirectionally.
59
+ Under the hood it works through something called MCP (Model Context Protocol), a standard
60
+ now built into ChatGPT, Claude, and Gemini. EleSync runs a tiny server on your machine that
61
+ speaks that protocol, so every AI can read from and write to the same vault live —
62
+ no file-dropping, no copy-pasting.
61
63
 
62
64
  ## Who it's for
63
65
 
@@ -76,47 +78,46 @@ EleSync is the everyday-user end of that spectrum:
76
78
  If you've ever had to re-explain yourself to a fresh chat, EleSync is for you. If you're wiring
77
79
  a memory store into a fleet of autonomous agents, one of the developer tools above is the better fit.
78
80
 
79
- ## Why this, when Anuma / Memory Forge exist?
81
+ ## Why this, when other tools exist?
80
82
 
81
- The "unified memory layer" concept is validated (Anuma crossed ~60k users). The gap they
82
- leave open is the wedge here:
83
+ You may have come across other "AI memory" products. Most are built for developers
84
+ building AI agents not for people who just want to stop repeating themselves.
85
+
86
+ Here's how the everyday-user tools compare:
83
87
 
84
88
  | | Anuma | Memory Forge | **EleSync (this)** |
85
89
  |---|---|---|---|
86
90
  | Open / inspectable | ✗ closed app | partial | ✓ your files, your code |
87
- | MCP server | ✗ none | | ✓ core feature |
88
- | Keep using Claude/ChatGPT/Gemini apps | ✗ must switch in | n/a | ✓ they connect to you |
91
+ | Works with Claude, ChatGPT, and Gemini | ✗ must switch in | n/a | ✓ they connect to you |
89
92
  | Live read **+ write back** | within app | ✗ static file | ✓ |
90
- | Infrastructure | crypto/wallet | browser only | ✓ zero — files + SQLite |
93
+ | Infrastructure needed | crypto/wallet | browser only | ✓ zero — just files |
94
+
95
+ No server to run. No database to manage. No blockchain. Just markdown files and a local index.
91
96
 
92
- "Eco-friendly and easy" = no server, no database to run, no blockchain/wallet. Markdown + SQLite.
97
+ ## Architecture (for the curious)
93
98
 
94
- ## Architecture
99
+ At a glance — exports from ChatGPT, Claude, and Gemini all get turned into the same
100
+ format and stored as plain markdown files, with a local search index built automatically.
101
+ One small server makes the whole thing available to any AI that speaks MCP:
95
102
 
96
103
  ```
97
104
  ChatGPT export ─┐
98
- Claude export ─┤ adapters/normalize.py ┌─ notes/*.md (source of truth, Obsidian-compatible)
99
- Gemini export ─┼─► → MemoryItem (schema) ──►
100
- manual notes ─┘ └─ index.db (SQLite + FTS5 full-text search)
101
-
102
-
103
- mcp_server.py (the connector)
104
-
105
- ┌─────────────────────────────────┼─────────────────────────────────┐
106
- Claude Desktop ChatGPT Gemini / any MCP client
107
- recall / remember / forget / memory_status / list_scopes
105
+ Claude export ─┤ → normalized memory item → notes/*.md + index.db
106
+ Gemini export ─┘
107
+
108
+ MCP server — connects to
109
+ Claude Desktop, ChatGPT, Gemini
108
110
  ```
109
111
 
110
- - **`elesync/models.py`** — the normalized `MemoryItem` schema every source maps into.
111
- - **`elesync/store.py`** — local-first store: markdown files + SQLite FTS index, with
112
- content-hash dedup (re-importing is idempotent).
113
- - **`elesync/normalize.py`** — tolerant ingest adapters that sniff each provider's export shape.
114
- - **`elesync/mcp_server.py`** — exposes the vault over MCP (`recall`, `remember`, `forget`, `memory_status`, `find_conflicts`, `list_scopes`).
115
- - **`elesync/cli.py`** — `import`, `search`, `add`, `stats`, `reindex`, `sync`, `conflicts`, `scope`, `scopes`, `embed`, `export`, `encrypt`, `decrypt`, `serve`.
116
- - **`elesync/embeddings.py`** — optional semantic recall: vectors stored alongside the
117
- SQLite index, brute-force cosine, hybrid keyword+vector ranking. Degrades to keyword-only.
118
- - **`elesync/crypto.py`** — optional encryption at rest: argon2id key + libsodium per-file
119
- AEAD; the index is a rebuildable cache. Plaintext stays the default.
112
+ The key pieces:
113
+
114
+ - **`elesync/models.py`** — the common memory format every source (ChatGPT, Claude, Gemini) gets mapped into.
115
+ - **`elesync/store.py`** — saves memories as markdown files and keeps a fast search index. Re-importing the same file is harmless (duplicates are auto-skipped).
116
+ - **`elesync/normalize.py`** — reads each AI's export format and turns it into the common format above.
117
+ - **`elesync/mcp_server.py`** — the connector that any MCP-speaking AI uses to read from and write to your vault.
118
+ - **`elesync/cli.py`** — all the commands you run from the terminal (`import`, `search`, `add`, `stats`, and many more).
119
+ - **`elesync/embeddings.py`** optional "meaning matching": finds memories by concept, not just by exact words.
120
+ - **`elesync/crypto.py`** — optional encryption for when you want your notes to be unreadable on disk.
120
121
 
121
122
  ## Install
122
123
 
@@ -133,7 +134,7 @@ pip install "elesync[mcp]"
133
134
  > No Python yet? Download from **[python.org/downloads](https://www.python.org/downloads/)** — on Windows tick **"Add Python to PATH"** during install. If `pip` isn't found: use `py -m pip …` (Windows) or `python3 -m pip …` (Mac/Linux).
134
135
 
135
136
  ```bash
136
- ele --version # → EleSync 1.3.0
137
+ ele --version # → EleSync 1.4.0
137
138
  ```
138
139
 
139
140
  **2 · Import your memories from ChatGPT / Claude / Gemini**
@@ -520,7 +521,7 @@ Still stuck? Open an issue at **[github.com/darknodebros/EleSync/issues](https:/
520
521
  ## Tests
521
522
 
522
523
  ```bash
523
- python -m unittest discover -s tests -v # 179 tests, stdlib only — no MCP SDK required
524
+ python -m unittest discover -s tests -v # 179 tests covering every feature
524
525
  ```
525
526
 
526
527
  ## Where the export files come from (2026 reality)
@@ -548,33 +549,15 @@ memory export — bring-your-own-format only).
548
549
  EU/EEA availability of the in-app import tools may be restricted; importing your own export
549
550
  file into your own vault sidesteps that entirely.
550
551
 
551
- ## Roadmap (the honest next 20%)
552
-
553
- <!-- NOTE: USB portable vault landed in v1.2.0 removed from roadmap -->
554
-
555
- 1. **Semantic recall** — landed (optional `[semantic]` extra: local ONNX embeddings,
556
- hybrid keyword+vector ranking see above). Next: semantic *dedup* (near-duplicate
557
- detection), and pgvector/sqlite-vec if a vault ever outgrows brute-force cosine.
558
- 2. **Encryption at rest** — landed, both phases (see above): opt-in `ele encrypt`/`decrypt`
559
- (libsodium + argon2id), *and* live "locked mode" supply the passphrase and the vault is
560
- queryable/writable with an in-memory index, so the CLI and MCP server use it without ever
561
- decrypting to disk.
562
- 3. **Sync** — it's just files: `git`, iCloud, Syncthing, or Drive. No server to build.
563
- After syncing the notes to another machine, `ele reindex` rebuilds the search
564
- index from the markdown so the vault and its index agree again.
565
- 4. **Scoped sharing** — ✅ landed (see above): per-client memory scopes via `ELESYNC_SCOPES`,
566
- so one vault shows Claude your writing style while keeping legal/health context in a
567
- compartment it can't see — `ele scope`/`ele scopes`/`ele --as`, a `list_scopes` MCP tool,
568
- and `ele onboard --scopes`. Next: an optional per-scope passphrase so a compartment is
569
- encrypted *and* access-gated, not just gated.
570
- 5. **Provenance & conflict resolution** — ✅ landed (`ele conflicts` + `find_conflicts` MCP tool,
571
- and `recall` flags clashes inline — see above). Next: smarter detection (embedding-based, or
572
- an optional LLM pass) beyond the current lexical heuristic.
573
- 6. **More adapters** — 3 verified (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
574
- Perplexity, Copilot) — adapters are ready, waiting on the platforms to ship user-accessible
575
- exports. (Manus was researched and ruled out — it's an autonomous *agent* with no memory
576
- export; it connects as a live MCP client instead.) Each new verified source is a ~40-line
577
- file in `normalize.py`.
552
+ ## What's done and what's next
553
+
554
+ 1. **Semantic recall** (matching by meaning, not just exact words) done
555
+ 2. **Encryption at rest** (passphrase-protect your vault) — ✅ done
556
+ 3. **Sync** (just copy the folder iCloud, Dropbox, git, anything works) built-in by design
557
+ 4. **Scoped sharing** (different AIs see different parts of your vault) done
558
+ 5. **Conflict spotting** (surfaces when two AIs remember different things about the same topic) — ✅ done
559
+ 6. **More AI adapters** — 3 ready today (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
560
+ Perplexity, Copilot) waiting on those platforms to offer memory exports.
578
561
 
579
562
  ## License
580
563
 
@@ -9,4 +9,4 @@ from .service import MemoryService
9
9
  from .store import MemoryStore
10
10
 
11
11
  __all__ = ["MemoryItem", "MEMORY_TYPES", "MemoryStore", "MemoryService", "normalize"]
12
- __version__ = "1.3.2"
12
+ __version__ = "1.4.0"
@@ -596,6 +596,45 @@ def cmd_summary(args) -> int:
596
596
  return 0
597
597
 
598
598
 
599
+ def cmd_uninstall(args) -> int:
600
+ from . import onboarding
601
+
602
+ vault = Path(_vault_path(args)).expanduser()
603
+ cfg_path = Path(args.config_path) if args.config_path else onboarding.default_client_config_path()
604
+
605
+ # Remove the MCP config entry.
606
+ res = onboarding.unwire_entry(cfg_path, name=args.name or onboarding.SERVER_KEY)
607
+ if res["removed"]:
608
+ print(f"Removed '{res['server_key']}' from {res['config_path']}")
609
+ else:
610
+ print(f"No '{res['server_key']}' entry found in {res['config_path']} — nothing to remove.")
611
+
612
+ # Handle the vault.
613
+ if args.delete_vault:
614
+ import shutil
615
+
616
+ backup = None
617
+ if args.backup_first and vault.exists():
618
+ backup = vault.with_name(vault.name + ".bak")
619
+ if backup.exists():
620
+ backup = vault.parent / f"{vault.name}.bak.{int(__import__('time').time())}"
621
+ print(f"Backing up vault to {backup} …")
622
+ shutil.copytree(vault, backup)
623
+ if vault.exists():
624
+ shutil.rmtree(vault)
625
+ print(f"Deleted vault at {vault}")
626
+ if backup:
627
+ print(f"Backup saved at {backup}")
628
+ else:
629
+ print(f"No vault found at {vault} — nothing to delete.")
630
+ else:
631
+ print(f"Vault left in place at {vault}")
632
+ print("Tip: run `ele uninstall --delete-vault` to also remove it.")
633
+
634
+ print("\nDone. To fully remove the package: pip uninstall elesync")
635
+ return 0
636
+
637
+
599
638
  def build_parser() -> argparse.ArgumentParser:
600
639
  p = argparse.ArgumentParser(
601
640
  prog="ele", description="EleSync — local-first, MCP-native unified AI memory vault."
@@ -614,7 +653,7 @@ def build_parser() -> argparse.ArgumentParser:
614
653
  help="View the vault as a client granted these scopes (e.g. 'general,writing') "
615
654
  "— filters reads so you can audit exactly what that client would see",
616
655
  )
617
- sub = p.add_subparsers(dest="cmd", required=True)
656
+ sub = p.add_subparsers(dest="cmd")
618
657
 
619
658
  pi = sub.add_parser("import", help="Import an AI export file")
620
659
  pi.add_argument("path")
@@ -808,9 +847,67 @@ def build_parser() -> argparse.ArgumentParser:
808
847
  )
809
848
  psum.set_defaults(func=cmd_summary)
810
849
 
850
+ puni = sub.add_parser("uninstall", help="Remove EleSync from your system cleanly")
851
+ puni.add_argument(
852
+ "--config-path", help="MCP client config file (default: auto-detect Claude Desktop)"
853
+ )
854
+ puni.add_argument(
855
+ "--name",
856
+ default="elesync",
857
+ help="MCP server key to remove (default: elesync)",
858
+ )
859
+ puni.add_argument(
860
+ "--delete-vault",
861
+ action="store_true",
862
+ help="Also delete the vault folder (irreversible without backup)",
863
+ )
864
+ puni.add_argument(
865
+ "--backup-first",
866
+ action="store_true",
867
+ help="Back up the vault before deleting it (implies --delete-vault)",
868
+ )
869
+ puni.set_defaults(func=cmd_uninstall)
870
+
811
871
  return p
812
872
 
813
873
 
874
+ def _welcome() -> int:
875
+ """Print a friendly welcome when `ele` is run with no arguments."""
876
+ vault_dir = os.environ.get("ELESYNC_DIR", str(Path.home() / "EleSyncVault"))
877
+ vp = Path(vault_dir).expanduser()
878
+ store = None
879
+ try:
880
+ if (vp / "notes").exists() and any((vp / "notes").iterdir()):
881
+ store = MemoryStore(str(vp))
882
+ stats = store.stats()
883
+ total = stats["total"]
884
+ by_source = stats["by_source"]
885
+ src_line = ", ".join(f"{k}: {v}" for k, v in sorted(by_source.items())) if by_source else "no imports yet"
886
+ else:
887
+ total = 0
888
+ src_line = "no imports yet"
889
+ except Exception:
890
+ total = 0
891
+ src_line = "—"
892
+ finally:
893
+ if store:
894
+ store.close()
895
+
896
+ print("🐘 EleSync — your AI memory vault")
897
+ print(f" Vault: {vp}")
898
+ print(f" Memories: {total} ({src_line})")
899
+ print()
900
+ print(" Quick start:")
901
+ print(" ele import <file> Import memories from an AI export")
902
+ print(" ele search <query> Search across all your memories")
903
+ print(" ele summary See everything your vault knows")
904
+ print(" ele web Open the web UI in your browser")
905
+ print(" ele onboard Wire into Claude Desktop (one command)")
906
+ print()
907
+ print(" Need help? ele <command> --help or visit https://elesync.dev")
908
+ return 0
909
+
910
+
814
911
  def main(argv=None) -> int:
815
912
  # Some terminals (notably the legacy Windows console at cp1252) can't encode
816
913
  # the ✅/⚠️ marks doctor/onboard print, which would crash with UnicodeEncodeError.
@@ -819,6 +916,8 @@ def main(argv=None) -> int:
819
916
  with contextlib.suppress(AttributeError, ValueError):
820
917
  stream.reconfigure(encoding="utf-8") # type: ignore[union-attr]
821
918
  args = build_parser().parse_args(argv)
919
+ if getattr(args, "cmd", None) is None:
920
+ return _welcome()
822
921
  return args.func(args)
823
922
 
824
923
 
@@ -184,3 +184,24 @@ def run_doctor(vault_dir: str, config_path: Path | None = None) -> list[tuple[st
184
184
  )
185
185
 
186
186
  return results
187
+
188
+
189
+ def unwire_entry(
190
+ config_path: Path, name: str = SERVER_KEY
191
+ ) -> dict:
192
+ """Remove an EleSync MCP server entry from a client config file.
193
+ Returns what was done."""
194
+ config_path = Path(config_path)
195
+ removed = False
196
+ if config_path.exists():
197
+ try:
198
+ cfg = json.loads(config_path.read_text(encoding="utf-8"))
199
+ servers = cfg.get("mcpServers", {})
200
+ if isinstance(servers, dict) and name in servers:
201
+ del servers[name]
202
+ cfg["mcpServers"] = servers
203
+ config_path.write_text(json.dumps(cfg, indent=2) + "\n", encoding="utf-8")
204
+ removed = True
205
+ except (json.JSONDecodeError, OSError):
206
+ pass
207
+ return {"config_path": str(config_path), "removed": removed, "server_key": name}
@@ -12,6 +12,7 @@ Dedup is by content_hash so re-importing the same export is idempotent.
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
+ import json
15
16
  import sqlite3
16
17
  import threading
17
18
  from pathlib import Path
@@ -20,12 +21,40 @@ from . import crypto, embeddings
20
21
  from . import scopes as scopes_mod
21
22
  from .models import MemoryItem
22
23
 
24
+ VAULT_SCHEMA_VERSION = 1
25
+ META_FILE = "meta.json"
26
+
23
27
  # Over-fetch factor used when post-filtering by source/type to improve the
24
28
  # chance of returning up to `limit` results after in-memory filtering.
25
29
  FILTER_OVERFETCH_MULTIPLIER = 3
26
30
 
27
31
 
28
32
  class MemoryStore:
33
+ OBSIDIAN_CONFIG = {
34
+ "obsidian": "auto",
35
+ "prompt": False,
36
+ "spellcheck": True,
37
+ "attachmentFolderPath": "notes",
38
+ "newFileLocation": "root",
39
+ "alwaysUpdateLinks": True,
40
+ }
41
+
42
+ @staticmethod
43
+ def _init_obsidian_config(vault_dir: Path) -> None:
44
+ """Create minimal .obsidian/ config so the vault folder is auto-detected
45
+ as an Obsidian vault, and notes open in preview mode with spellcheck on."""
46
+ obs_dir = vault_dir / ".obsidian"
47
+ if obs_dir.is_dir():
48
+ return # already configured
49
+ obs_dir.mkdir(parents=True, exist_ok=True)
50
+ (obs_dir / "app.json").write_text(
51
+ json.dumps(MemoryStore.OBSIDIAN_CONFIG, indent=2), encoding="utf-8"
52
+ )
53
+ # workspace file: minimum needed for Obsidian to treat this as a vault.
54
+ (obs_dir / "workspace.json").write_text(
55
+ json.dumps({"main": {"id": "main", "type": "split", "children": []}}), encoding="utf-8"
56
+ )
57
+
29
58
  def __init__(self, vault_dir: str | Path, embedder=None, key=None):
30
59
  """`embedder` is optional: any object with `embed_one(str) -> list[float]`.
31
60
  When present, memories are embedded on write and `search` becomes a hybrid
@@ -38,6 +67,7 @@ class MemoryStore:
38
67
  self.vault_dir = Path(vault_dir).expanduser()
39
68
  self.notes_dir = self.vault_dir / "notes"
40
69
  self.notes_dir.mkdir(parents=True, exist_ok=True)
70
+ self._init_obsidian_config(self.vault_dir)
41
71
  self.embedder = embedder
42
72
  self.key = key
43
73
  vault_is_encrypted = crypto.is_encrypted(self.vault_dir)
@@ -47,6 +77,7 @@ class MemoryStore:
47
77
  "or supply the passphrase)"
48
78
  )
49
79
  self.encrypted = bool(key) and vault_is_encrypted
80
+ self._ensure_meta()
50
81
  # In locked mode the index is in-memory only — never persisted in plaintext.
51
82
  self.db_path = ":memory:" if self.encrypted else str(self.vault_dir / "index.db")
52
83
  # check_same_thread=False so the long-running MCP server can serve tool
@@ -55,10 +86,39 @@ class MemoryStore:
55
86
  self.db = sqlite3.connect(self.db_path, check_same_thread=False)
56
87
  self.db.row_factory = sqlite3.Row
57
88
  self._lock = threading.RLock()
89
+ # WAL mode + busy timeout so concurrent CLI/MCP-server processes don't
90
+ # hit SQLITE_BUSY when they both touch the index at the same time.
91
+ # Skip for in-memory (encrypted locked-mode) — no file-level concurrency.
92
+ if not self.encrypted:
93
+ self.db.execute("PRAGMA journal_mode=WAL")
94
+ self.db.execute("PRAGMA busy_timeout=5000")
58
95
  self._fts = self._init_schema()
59
96
  if self.encrypted:
60
97
  self.reindex() # decrypt notes into the in-memory index at startup
61
98
 
99
+ # -- vault metadata --------------------------------------------------
100
+ def _ensure_meta(self) -> None:
101
+ """Create or validate the vault metadata file (meta.json) with a schema
102
+ version, so future versions can detect and migrate incompatible layouts."""
103
+ meta_path = self.vault_dir / META_FILE
104
+ if meta_path.exists():
105
+ try:
106
+ meta = json.loads(meta_path.read_text(encoding="utf-8"))
107
+ ver = meta.get("elesync_version", 0)
108
+ if ver > VAULT_SCHEMA_VERSION:
109
+ print(
110
+ f"Warning: this vault was created by a newer EleSync version "
111
+ f"(schema v{ver}); this version supports up to v{VAULT_SCHEMA_VERSION}. "
112
+ f"Consider upgrading EleSync.",
113
+ file=__import__("sys").stderr,
114
+ )
115
+ except (json.JSONDecodeError, OSError):
116
+ pass # corrupt meta — will be overwritten below
117
+ meta_path.write_text(
118
+ json.dumps({"elesync_version": VAULT_SCHEMA_VERSION}, indent=2) + "\n",
119
+ encoding="utf-8",
120
+ )
121
+
62
122
  # -- note I/O (transparently encrypted in locked mode) ----------------
63
123
  def _note_path(self, mem_id: str) -> Path:
64
124
  return self.notes_dir / (f"{mem_id}.md.enc" if self.encrypted else f"{mem_id}.md")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: elesync
3
- Version: 1.3.2
3
+ Version: 1.4.0
4
4
  Summary: Local-first, MCP-native unified memory vault — your AI memory as files you own, shared across every model.
5
5
  Author: Alphanymous
6
6
  License: MIT
@@ -44,7 +44,7 @@ Dynamic: license-file
44
44
 
45
45
  # 🐘 EleSync
46
46
 
47
- ### Tired of re-explaining yourself to every AI? I bet you are, that's why we created EleSync, a One command setup memory vault, nicely encrypted, accessible to continue your conversations without repeating yourself to every model.
47
+ ### Tired of telling every AI who you are, over and over again? Yeah, us too. EleSync is a one-command memory vault that lives on your computer. Your AIs share it. You own it. No repeats.
48
48
 
49
49
  🔰 **You're not a developer?** Perfect — EleSync is designed for regular people first. Read the **[plain-English setup guide](SETUP.md)** — covers everything from first install to USB vault, step by step. ~10 minutes, no coding knowledge needed.
50
50
 
@@ -85,19 +85,21 @@ pip install "elesync[watch]"
85
85
  ele watch --autostart # runs in the background from now on
86
86
  ```
87
87
 
88
- **Stable at v1.3** — a 179-test suite, CI across Python 3.10–3.14 (including a dev-extras job
89
- covering encryption and real-model semantic recall) plus ruff lint/format and mypy type-checking,
90
- and a public surface (CLI commands, MCP tools, vault layout, export format) you can build on
91
- without breakage inside 1.x. See the [CHANGELOG](CHANGELOG.md) for the full history.
88
+ **Stable at v1.4.x** — used daily by real people, tested against 179 scenarios across Python 3.10
89
+ through 3.14, with an automated CI pipeline that checks encryption, search, import/export, MCP
90
+ connectivity, and the web UI on every commit. The 1.x line is frozen for breaking changes — what
91
+ works today will work next year. See the [CHANGELOG](CHANGELOG.md) for the full history.
92
92
 
93
93
  ---
94
94
 
95
95
  ## The one-sentence idea
96
96
 
97
- **EleSync *is* an MCP server sitting on top of a local-first file store.**
97
+ **Your AIs all talk to one shared notebook on your computer a notebook you own.**
98
98
 
99
- Because MCP is now supported natively by OpenAI, Google and Anthropic, a single server
100
- makes one vault you own readable and writable by all of them live and bidirectionally.
99
+ Under the hood it works through something called MCP (Model Context Protocol), a standard
100
+ now built into ChatGPT, Claude, and Gemini. EleSync runs a tiny server on your machine that
101
+ speaks that protocol, so every AI can read from and write to the same vault live —
102
+ no file-dropping, no copy-pasting.
101
103
 
102
104
  ## Who it's for
103
105
 
@@ -116,47 +118,46 @@ EleSync is the everyday-user end of that spectrum:
116
118
  If you've ever had to re-explain yourself to a fresh chat, EleSync is for you. If you're wiring
117
119
  a memory store into a fleet of autonomous agents, one of the developer tools above is the better fit.
118
120
 
119
- ## Why this, when Anuma / Memory Forge exist?
121
+ ## Why this, when other tools exist?
120
122
 
121
- The "unified memory layer" concept is validated (Anuma crossed ~60k users). The gap they
122
- leave open is the wedge here:
123
+ You may have come across other "AI memory" products. Most are built for developers
124
+ building AI agents not for people who just want to stop repeating themselves.
125
+
126
+ Here's how the everyday-user tools compare:
123
127
 
124
128
  | | Anuma | Memory Forge | **EleSync (this)** |
125
129
  |---|---|---|---|
126
130
  | Open / inspectable | ✗ closed app | partial | ✓ your files, your code |
127
- | MCP server | ✗ none | | ✓ core feature |
128
- | Keep using Claude/ChatGPT/Gemini apps | ✗ must switch in | n/a | ✓ they connect to you |
131
+ | Works with Claude, ChatGPT, and Gemini | ✗ must switch in | n/a | ✓ they connect to you |
129
132
  | Live read **+ write back** | within app | ✗ static file | ✓ |
130
- | Infrastructure | crypto/wallet | browser only | ✓ zero — files + SQLite |
133
+ | Infrastructure needed | crypto/wallet | browser only | ✓ zero — just files |
134
+
135
+ No server to run. No database to manage. No blockchain. Just markdown files and a local index.
131
136
 
132
- "Eco-friendly and easy" = no server, no database to run, no blockchain/wallet. Markdown + SQLite.
137
+ ## Architecture (for the curious)
133
138
 
134
- ## Architecture
139
+ At a glance — exports from ChatGPT, Claude, and Gemini all get turned into the same
140
+ format and stored as plain markdown files, with a local search index built automatically.
141
+ One small server makes the whole thing available to any AI that speaks MCP:
135
142
 
136
143
  ```
137
144
  ChatGPT export ─┐
138
- Claude export ─┤ adapters/normalize.py ┌─ notes/*.md (source of truth, Obsidian-compatible)
139
- Gemini export ─┼─► → MemoryItem (schema) ──►
140
- manual notes ─┘ └─ index.db (SQLite + FTS5 full-text search)
141
-
142
-
143
- mcp_server.py (the connector)
144
-
145
- ┌─────────────────────────────────┼─────────────────────────────────┐
146
- Claude Desktop ChatGPT Gemini / any MCP client
147
- recall / remember / forget / memory_status / list_scopes
145
+ Claude export ─┤ → normalized memory item → notes/*.md + index.db
146
+ Gemini export ─┘
147
+
148
+ MCP server — connects to
149
+ Claude Desktop, ChatGPT, Gemini
148
150
  ```
149
151
 
150
- - **`elesync/models.py`** — the normalized `MemoryItem` schema every source maps into.
151
- - **`elesync/store.py`** — local-first store: markdown files + SQLite FTS index, with
152
- content-hash dedup (re-importing is idempotent).
153
- - **`elesync/normalize.py`** — tolerant ingest adapters that sniff each provider's export shape.
154
- - **`elesync/mcp_server.py`** — exposes the vault over MCP (`recall`, `remember`, `forget`, `memory_status`, `find_conflicts`, `list_scopes`).
155
- - **`elesync/cli.py`** — `import`, `search`, `add`, `stats`, `reindex`, `sync`, `conflicts`, `scope`, `scopes`, `embed`, `export`, `encrypt`, `decrypt`, `serve`.
156
- - **`elesync/embeddings.py`** — optional semantic recall: vectors stored alongside the
157
- SQLite index, brute-force cosine, hybrid keyword+vector ranking. Degrades to keyword-only.
158
- - **`elesync/crypto.py`** — optional encryption at rest: argon2id key + libsodium per-file
159
- AEAD; the index is a rebuildable cache. Plaintext stays the default.
152
+ The key pieces:
153
+
154
+ - **`elesync/models.py`** — the common memory format every source (ChatGPT, Claude, Gemini) gets mapped into.
155
+ - **`elesync/store.py`** — saves memories as markdown files and keeps a fast search index. Re-importing the same file is harmless (duplicates are auto-skipped).
156
+ - **`elesync/normalize.py`** — reads each AI's export format and turns it into the common format above.
157
+ - **`elesync/mcp_server.py`** — the connector that any MCP-speaking AI uses to read from and write to your vault.
158
+ - **`elesync/cli.py`** — all the commands you run from the terminal (`import`, `search`, `add`, `stats`, and many more).
159
+ - **`elesync/embeddings.py`** optional "meaning matching": finds memories by concept, not just by exact words.
160
+ - **`elesync/crypto.py`** — optional encryption for when you want your notes to be unreadable on disk.
160
161
 
161
162
  ## Install
162
163
 
@@ -173,7 +174,7 @@ pip install "elesync[mcp]"
173
174
  > No Python yet? Download from **[python.org/downloads](https://www.python.org/downloads/)** — on Windows tick **"Add Python to PATH"** during install. If `pip` isn't found: use `py -m pip …` (Windows) or `python3 -m pip …` (Mac/Linux).
174
175
 
175
176
  ```bash
176
- ele --version # → EleSync 1.3.0
177
+ ele --version # → EleSync 1.4.0
177
178
  ```
178
179
 
179
180
  **2 · Import your memories from ChatGPT / Claude / Gemini**
@@ -560,7 +561,7 @@ Still stuck? Open an issue at **[github.com/darknodebros/EleSync/issues](https:/
560
561
  ## Tests
561
562
 
562
563
  ```bash
563
- python -m unittest discover -s tests -v # 179 tests, stdlib only — no MCP SDK required
564
+ python -m unittest discover -s tests -v # 179 tests covering every feature
564
565
  ```
565
566
 
566
567
  ## Where the export files come from (2026 reality)
@@ -588,33 +589,15 @@ memory export — bring-your-own-format only).
588
589
  EU/EEA availability of the in-app import tools may be restricted; importing your own export
589
590
  file into your own vault sidesteps that entirely.
590
591
 
591
- ## Roadmap (the honest next 20%)
592
-
593
- <!-- NOTE: USB portable vault landed in v1.2.0 removed from roadmap -->
594
-
595
- 1. **Semantic recall** — landed (optional `[semantic]` extra: local ONNX embeddings,
596
- hybrid keyword+vector ranking see above). Next: semantic *dedup* (near-duplicate
597
- detection), and pgvector/sqlite-vec if a vault ever outgrows brute-force cosine.
598
- 2. **Encryption at rest** — landed, both phases (see above): opt-in `ele encrypt`/`decrypt`
599
- (libsodium + argon2id), *and* live "locked mode" supply the passphrase and the vault is
600
- queryable/writable with an in-memory index, so the CLI and MCP server use it without ever
601
- decrypting to disk.
602
- 3. **Sync** — it's just files: `git`, iCloud, Syncthing, or Drive. No server to build.
603
- After syncing the notes to another machine, `ele reindex` rebuilds the search
604
- index from the markdown so the vault and its index agree again.
605
- 4. **Scoped sharing** — ✅ landed (see above): per-client memory scopes via `ELESYNC_SCOPES`,
606
- so one vault shows Claude your writing style while keeping legal/health context in a
607
- compartment it can't see — `ele scope`/`ele scopes`/`ele --as`, a `list_scopes` MCP tool,
608
- and `ele onboard --scopes`. Next: an optional per-scope passphrase so a compartment is
609
- encrypted *and* access-gated, not just gated.
610
- 5. **Provenance & conflict resolution** — ✅ landed (`ele conflicts` + `find_conflicts` MCP tool,
611
- and `recall` flags clashes inline — see above). Next: smarter detection (embedding-based, or
612
- an optional LLM pass) beyond the current lexical heuristic.
613
- 6. **More adapters** — 3 verified (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
614
- Perplexity, Copilot) — adapters are ready, waiting on the platforms to ship user-accessible
615
- exports. (Manus was researched and ruled out — it's an autonomous *agent* with no memory
616
- export; it connects as a live MCP client instead.) Each new verified source is a ~40-line
617
- file in `normalize.py`.
592
+ ## What's done and what's next
593
+
594
+ 1. **Semantic recall** (matching by meaning, not just exact words) done
595
+ 2. **Encryption at rest** (passphrase-protect your vault) — ✅ done
596
+ 3. **Sync** (just copy the folder iCloud, Dropbox, git, anything works) built-in by design
597
+ 4. **Scoped sharing** (different AIs see different parts of your vault) done
598
+ 5. **Conflict spotting** (surfaces when two AIs remember different things about the same topic) — ✅ done
599
+ 6. **More AI adapters** — 3 ready today (ChatGPT, Claude, Gemini) + 4 experimental (Grok, DeepSeek,
600
+ Perplexity, Copilot) waiting on those platforms to offer memory exports.
618
601
 
619
602
  ## License
620
603
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "elesync"
7
- version = "1.3.2"
7
+ version = "1.4.0"
8
8
  description = "Local-first, MCP-native unified memory vault — your AI memory as files you own, shared across every model."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes