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.
- {elesync-1.3.2 → elesync-1.4.0}/PKG-INFO +49 -66
- {elesync-1.3.2 → elesync-1.4.0}/README.md +48 -65
- {elesync-1.3.2 → elesync-1.4.0}/elesync/__init__.py +1 -1
- {elesync-1.3.2 → elesync-1.4.0}/elesync/cli.py +100 -1
- {elesync-1.3.2 → elesync-1.4.0}/elesync/onboarding.py +21 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/store.py +60 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/PKG-INFO +49 -66
- {elesync-1.3.2 → elesync-1.4.0}/pyproject.toml +1 -1
- {elesync-1.3.2 → elesync-1.4.0}/LICENSE +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/conflicts.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/crypto.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/embeddings.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/mcp_server.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/models.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/normalize.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/scopes.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/service.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/summary.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/usb.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/watch.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync/web.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/SOURCES.txt +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/dependency_links.txt +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/entry_points.txt +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/requires.txt +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/elesync.egg-info/top_level.txt +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/setup.cfg +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_conflicts.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_encryption.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_scopes.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_semantic.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_service.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_summary.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_usb.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_vault.py +0 -0
- {elesync-1.3.2 → elesync-1.4.0}/tests/test_watch.py +0 -0
- {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
|
+
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
|
|
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.
|
|
89
|
-
|
|
90
|
-
and
|
|
91
|
-
|
|
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
|
-
**
|
|
97
|
+
**Your AIs all talk to one shared notebook on your computer — a notebook you own.**
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
121
|
+
## Why this, when other tools exist?
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
|
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
|
|
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
|
-
|
|
137
|
+
## Architecture (for the curious)
|
|
133
138
|
|
|
134
|
-
|
|
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 ─┤
|
|
139
|
-
Gemini export
|
|
140
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- **`elesync/
|
|
154
|
-
- **`elesync/
|
|
155
|
-
- **`elesync/
|
|
156
|
-
- **`elesync/
|
|
157
|
-
|
|
158
|
-
- **`elesync/crypto.py`** — optional encryption
|
|
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.
|
|
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
|
|
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
|
-
##
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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
|
|
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.
|
|
49
|
-
|
|
50
|
-
and
|
|
51
|
-
|
|
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
|
-
**
|
|
57
|
+
**Your AIs all talk to one shared notebook on your computer — a notebook you own.**
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
81
|
+
## Why this, when other tools exist?
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
|
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
|
|
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
|
-
|
|
97
|
+
## Architecture (for the curious)
|
|
93
98
|
|
|
94
|
-
|
|
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 ─┤
|
|
99
|
-
Gemini export
|
|
100
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
- **`elesync/
|
|
114
|
-
- **`elesync/
|
|
115
|
-
- **`elesync/
|
|
116
|
-
- **`elesync/
|
|
117
|
-
|
|
118
|
-
- **`elesync/crypto.py`** — optional encryption
|
|
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.
|
|
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
|
|
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
|
-
##
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
|
|
@@ -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"
|
|
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
|
+
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
|
|
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.
|
|
89
|
-
|
|
90
|
-
and
|
|
91
|
-
|
|
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
|
-
**
|
|
97
|
+
**Your AIs all talk to one shared notebook on your computer — a notebook you own.**
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
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
|
|
121
|
+
## Why this, when other tools exist?
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
|
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
|
|
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
|
-
|
|
137
|
+
## Architecture (for the curious)
|
|
133
138
|
|
|
134
|
-
|
|
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 ─┤
|
|
139
|
-
Gemini export
|
|
140
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
- **`elesync/
|
|
154
|
-
- **`elesync/
|
|
155
|
-
- **`elesync/
|
|
156
|
-
- **`elesync/
|
|
157
|
-
|
|
158
|
-
- **`elesync/crypto.py`** — optional encryption
|
|
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.
|
|
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
|
|
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
|
-
##
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|