mnemox 0.2.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.
- mnemox-0.2.0/LICENSE +21 -0
- mnemox-0.2.0/PKG-INFO +329 -0
- mnemox-0.2.0/README.md +308 -0
- mnemox-0.2.0/ember/__init__.py +3 -0
- mnemox-0.2.0/ember/__main__.py +129 -0
- mnemox-0.2.0/ember/capture/__init__.py +6 -0
- mnemox-0.2.0/ember/capture/drain.py +341 -0
- mnemox-0.2.0/ember/capture/secrets.py +137 -0
- mnemox-0.2.0/ember/cli.py +309 -0
- mnemox-0.2.0/ember/config.py +180 -0
- mnemox-0.2.0/ember/crypto/__init__.py +35 -0
- mnemox-0.2.0/ember/crypto/_blind.py +70 -0
- mnemox-0.2.0/ember/crypto/_cipher.py +122 -0
- mnemox-0.2.0/ember/crypto/_kdf.py +58 -0
- mnemox-0.2.0/ember/crypto/errors.py +13 -0
- mnemox-0.2.0/ember/db/__init__.py +25 -0
- mnemox-0.2.0/ember/db/migrate.py +32 -0
- mnemox-0.2.0/ember/db/migrations/__init__.py +1 -0
- mnemox-0.2.0/ember/db/migrations/_migration_0001.py +51 -0
- mnemox-0.2.0/ember/db/migrations/_migration_0002.py +192 -0
- mnemox-0.2.0/ember/embeddings/__init__.py +8 -0
- mnemox-0.2.0/ember/embeddings/engine.py +201 -0
- mnemox-0.2.0/ember/embeddings/tokenizer.py +89 -0
- mnemox-0.2.0/ember/extraction/__init__.py +5 -0
- mnemox-0.2.0/ember/extraction/local.py +81 -0
- mnemox-0.2.0/ember/invalidation/__init__.py +15 -0
- mnemox-0.2.0/ember/invalidation/cosine.py +140 -0
- mnemox-0.2.0/ember/keystore/__init__.py +27 -0
- mnemox-0.2.0/ember/keystore/_backend.py +256 -0
- mnemox-0.2.0/ember/keystore/_salt.py +40 -0
- mnemox-0.2.0/ember/keystore/errors.py +9 -0
- mnemox-0.2.0/ember/mcp/__init__.py +5 -0
- mnemox-0.2.0/ember/mcp/tools.py +510 -0
- mnemox-0.2.0/ember/mirror/__init__.py +5 -0
- mnemox-0.2.0/ember/mirror/render.py +143 -0
- mnemox-0.2.0/ember/models/__init__.py +1 -0
- mnemox-0.2.0/ember/models/cache.py +40 -0
- mnemox-0.2.0/ember/models/loader.py +54 -0
- mnemox-0.2.0/ember/modes/__init__.py +19 -0
- mnemox-0.2.0/ember/modes/scope.py +243 -0
- mnemox-0.2.0/ember/oplog/__init__.py +19 -0
- mnemox-0.2.0/ember/oplog/backfill.py +98 -0
- mnemox-0.2.0/ember/oplog/codec.py +87 -0
- mnemox-0.2.0/ember/oplog/entry.py +35 -0
- mnemox-0.2.0/ember/oplog/producer.py +192 -0
- mnemox-0.2.0/ember/ranking/__init__.py +7 -0
- mnemox-0.2.0/ember/ranking/cosine.py +12 -0
- mnemox-0.2.0/ember/ranking/fusion.py +78 -0
- mnemox-0.2.0/ember/ranking/result.py +18 -0
- mnemox-0.2.0/ember/retrieval/__init__.py +5 -0
- mnemox-0.2.0/ember/retrieval/_search.py +143 -0
- mnemox-0.2.0/ember/retrieval/bm25.py +88 -0
- mnemox-0.2.0/ember/retrieval/tiers.py +101 -0
- mnemox-0.2.0/ember/schema/__init__.py +1 -0
- mnemox-0.2.0/ember/server.py +156 -0
- mnemox-0.2.0/ember/storage/__init__.py +31 -0
- mnemox-0.2.0/ember/storage/paths.py +33 -0
- mnemox-0.2.0/ember/storage/store.py +210 -0
- mnemox-0.2.0/ember/sync/__init__.py +32 -0
- mnemox-0.2.0/ember/sync/_aad.py +23 -0
- mnemox-0.2.0/ember/sync/client.py +382 -0
- mnemox-0.2.0/ember/sync/cursor.py +76 -0
- mnemox-0.2.0/ember/sync/errors.py +22 -0
- mnemox-0.2.0/ember/sync/merge.py +197 -0
- mnemox-0.2.0/ember/sync/oplog_store.py +169 -0
- mnemox-0.2.0/ember/sync/pull.py +53 -0
- mnemox-0.2.0/ember/sync/push.py +42 -0
- mnemox-0.2.0/ember/sync/transport.py +65 -0
- mnemox-0.2.0/ember/vec/__init__.py +19 -0
- mnemox-0.2.0/ember/vec/_build.py +151 -0
- mnemox-0.2.0/ember/vec/_gate.py +66 -0
- mnemox-0.2.0/ember/vec/_meta.py +67 -0
- mnemox-0.2.0/ember/vec/_query.py +86 -0
- mnemox-0.2.0/ember/vec/index.py +98 -0
- mnemox-0.2.0/ember/write/__init__.py +6 -0
- mnemox-0.2.0/ember/write/flush.py +197 -0
- mnemox-0.2.0/ember/write/pipeline.py +104 -0
- mnemox-0.2.0/mnemox.egg-info/PKG-INFO +329 -0
- mnemox-0.2.0/mnemox.egg-info/SOURCES.txt +84 -0
- mnemox-0.2.0/mnemox.egg-info/dependency_links.txt +1 -0
- mnemox-0.2.0/mnemox.egg-info/entry_points.txt +2 -0
- mnemox-0.2.0/mnemox.egg-info/requires.txt +10 -0
- mnemox-0.2.0/mnemox.egg-info/top_level.txt +1 -0
- mnemox-0.2.0/pyproject.toml +37 -0
- mnemox-0.2.0/setup.cfg +4 -0
- mnemox-0.2.0/tests/test_config.py +150 -0
mnemox-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Sandler
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mnemox-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mnemox
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: mnemox local-first agent memory system with MCP server. Atom-based context for AI agents.
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/ajadi/mnemox
|
|
7
|
+
Keywords: mcp,memory,llm,claude,ai-agent
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: mcp<2,>=1.10
|
|
12
|
+
Requires-Dist: onnxruntime~=1.20
|
|
13
|
+
Requires-Dist: tokenizers~=0.21
|
|
14
|
+
Requires-Dist: numpy~=2.1
|
|
15
|
+
Requires-Dist: argon2-cffi<24,>=23.1
|
|
16
|
+
Requires-Dist: cryptography<46,>=42
|
|
17
|
+
Requires-Dist: keyring<26,>=24
|
|
18
|
+
Provides-Extra: vec
|
|
19
|
+
Requires-Dist: sqlite-vec>=0.1.6; extra == "vec"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
<div align="center">
|
|
23
|
+
|
|
24
|
+
<img src="assets/logo.svg" alt="Ember" width="420">
|
|
25
|
+
|
|
26
|
+
### Your Claude Code sessions never forget again.
|
|
27
|
+
|
|
28
|
+
Local-first memory via MCP — one SQLite file, on-device embeddings,<br>
|
|
29
|
+
encrypted cross-machine sync. No cloud. No Docker.
|
|
30
|
+
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
[](https://www.python.org/)
|
|
33
|
+
[](https://modelcontextprotocol.io/)
|
|
34
|
+
[](#status)
|
|
35
|
+
|
|
36
|
+
<img src="assets/demo.svg" alt="Ember recalls a past decision in a fresh Claude Code session" width="760">
|
|
37
|
+
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## The problem
|
|
43
|
+
|
|
44
|
+
- **Claude forgets between sessions.** Every `/clear` or new window throws away the context you built — decisions, trade-offs, gotchas — and you re-explain them from scratch.
|
|
45
|
+
- **Cloud memory pulls your context off-machine and costs money.** mem0 & co. ship your project history to someone else's servers and meter it.
|
|
46
|
+
- **Self-hosted memory means heavy infra.** Qdrant + Neo4j + Docker is a lot of moving parts just to remember what you decided yesterday.
|
|
47
|
+
|
|
48
|
+
**Ember solves it with one SQLite file on your machine.**
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Why Ember
|
|
53
|
+
|
|
54
|
+
| | **Ember 🔥** | mem0 (cloud) | OpenMemory | Self-hosted stack |
|
|
55
|
+
|---------------------------------------|:------------:|:------------:|:----------:|:-----------------:|
|
|
56
|
+
| Runs fully local (no cloud) | ✅ | ❌ | ⚠️ partial | ✅ |
|
|
57
|
+
| No heavy infra (no Docker/Qdrant/Neo4j) | ✅ | ✅ | ❌ | ❌ |
|
|
58
|
+
| Single-file store (SQLite) | ✅ | ❌ | ❌ | ❌ |
|
|
59
|
+
| MCP-native | ✅ | ⚠️ | ⚠️ | ⚠️ |
|
|
60
|
+
| Zero-knowledge E2E sync | ✅ | ❌ | ❌ | ❌ |
|
|
61
|
+
|
|
62
|
+
Ember is the only one that is **local, single-file, MCP-native, zero-infra, and privately synced** at the same time.
|
|
63
|
+
|
|
64
|
+
> ¹ mem0 "no heavy infra" = managed SaaS — you run nothing, but your context goes to their cloud.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
Already using Claude Code? Just tell it: *"set up Ember for me"* — it can run the installer and wire up your `.mcp.json`.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 60-second quickstart
|
|
73
|
+
|
|
74
|
+
**1. Install** (creates a dedicated venv at `~/.ember/venv` and fetches the embedding model):
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
git clone https://github.com/ajadi/ember && cd ember
|
|
78
|
+
./install.sh
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**2. Connect to Claude.** Add one entry to your project's `.mcp.json`
|
|
82
|
+
(replace `<your-project-root>` with the absolute path to your project):
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"ember": {
|
|
88
|
+
"command": "~/.ember/venv/bin/python",
|
|
89
|
+
"args": ["-m", "ember", "serve"],
|
|
90
|
+
"env": {
|
|
91
|
+
"EMBER_MODE": "project",
|
|
92
|
+
"EMBER_PROJECT_ROOT": "<your-project-root>"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**3. Verify.** Restart Claude Code and ask it to write and recall a memory — the
|
|
100
|
+
`ember_write`, `ember_search`, and `ember_list` tools appear in the MCP tool list.
|
|
101
|
+
|
|
102
|
+
> `ember init` prints the exact `.mcp.json` snippet for your platform, including
|
|
103
|
+
> the absolute Python path. See [Reference](#reference) for details.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## How it works
|
|
108
|
+
|
|
109
|
+
```mermaid
|
|
110
|
+
flowchart LR
|
|
111
|
+
A["atoms<br/>(decisions, notes,<br/>questions, retros)"] --> B["SQLite<br/>(one file)"]
|
|
112
|
+
B --> C["MCP server<br/>(python -m ember serve)"]
|
|
113
|
+
C --> D["Claude Code"]
|
|
114
|
+
D -- "ember_write / ember_search" --> C
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Claude writes **atoms** (decisions, observations, questions, retrospectives) into a
|
|
118
|
+
single local SQLite file. On recall, Ember ranks them with multi-tier retrieval
|
|
119
|
+
(FTS5 BM25 + on-device cosine fusion) and serves them straight back over MCP.
|
|
120
|
+
|
|
121
|
+
- **All local.** Memory lives in one SQLite file on your machine — nothing leaves it.
|
|
122
|
+
- **On-device embeddings.** EmbeddingGemma-300m runs locally via ONNX; no embedding API calls.
|
|
123
|
+
- **Private by design.** Cross-machine sync is end-to-end encrypted — the relay sees only ciphertext. Your memories never leave your control in plaintext.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Status
|
|
128
|
+
|
|
129
|
+
**✅ Works today (Phase 1–3)**
|
|
130
|
+
- Local-first MCP memory server (`python -m ember serve`) with 7 tools: write, search, get, list, invalidate, flush, stats
|
|
131
|
+
- On-device EmbeddingGemma-300m embeddings (ONNX, no network)
|
|
132
|
+
- Single-file SQLite store, `project` and `global` modes
|
|
133
|
+
- Multi-tier retrieval R0–R3 (exact, cosine, FTS5 BM25, fusion)
|
|
134
|
+
- Auto-invalidation of superseded memories by cosine similarity
|
|
135
|
+
- Transparent `sqlite-vec` auto-upgrade for large stores (graceful fallback to pure-Python cosine)
|
|
136
|
+
- Universal native-hook capture loop with durable spool + `ember drain`
|
|
137
|
+
- CLI: `init` / `serve` / `mirror` / `drain` / `backfill`
|
|
138
|
+
- Capture memory from Forge workflows (optional adapter)
|
|
139
|
+
- **Encrypted, zero-knowledge cross-machine sync** via a self-hostable hub — your memories never leave your control in plaintext (real-world multi-machine-over-network validation in progress)
|
|
140
|
+
- Oplog backfill — retroactively sync memories written before sync was enabled (`ember backfill`)
|
|
141
|
+
|
|
142
|
+
**📋 Planned**
|
|
143
|
+
- Hosted zero-knowledge sync hub (managed option)
|
|
144
|
+
|
|
145
|
+
> Actively developed — **star to follow.**
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Reference
|
|
150
|
+
|
|
151
|
+
<details>
|
|
152
|
+
<summary><strong>CLI commands</strong></summary>
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
ember [--version]
|
|
156
|
+
init [--mode {project,global,server}] # initialise store + write config.json
|
|
157
|
+
serve # start the MCP server over stdio
|
|
158
|
+
mirror --project-id <id> [--output-dir memory] [--db-path PATH]
|
|
159
|
+
drain [--queue-path PATH] [--db-path PATH] [--project-id ID]
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- **`init`** — creates the store and writes `config.json`. Idempotent: re-running preserves `project_id` and `created`, refreshes `ember_version` / `last_init`. Prints the exact `.mcp.json` snippet for your platform. `--mode server` initialises a server-mode store and config (`client_id` + `hub_url`) for hub sync; set `EMBER_HUB_TOKEN` in the environment.
|
|
163
|
+
- **`serve`** — starts the Ember MCP server over stdio (register this in `.mcp.json`).
|
|
164
|
+
- **`mirror`** — renders stored atoms to Markdown under `memory/` (or `--output-dir`).
|
|
165
|
+
- **`drain`** — drains the capture queue into the store (used by the capture loop).
|
|
166
|
+
|
|
167
|
+
| Mode | DB location | config.json |
|
|
168
|
+
|------|-------------|-------------|
|
|
169
|
+
| `project` (default) | `<project-root>/.ember/ember.db` | `<project-root>/.ember/config.json` |
|
|
170
|
+
| `global` | `~/.ember/global.db` | `~/.ember/config.json` |
|
|
171
|
+
| `server` | `<project-root>/.ember/ember.db` | `<project-root>/.ember/config.json` (server: client_id + hub_url) |
|
|
172
|
+
|
|
173
|
+
</details>
|
|
174
|
+
|
|
175
|
+
<details>
|
|
176
|
+
<summary><strong>Environment variables</strong></summary>
|
|
177
|
+
|
|
178
|
+
| Variable | Description | Default |
|
|
179
|
+
|----------|-------------|---------|
|
|
180
|
+
| `EMBER_MODE` | `project` or `global` | `project` |
|
|
181
|
+
| `EMBER_PROJECT_ROOT` | Root directory for project-mode DB | `cwd` |
|
|
182
|
+
| `EMBER_DB_PATH` | Explicit DB path (overrides mode routing) | — |
|
|
183
|
+
| `EMBER_MODEL_DIR` | Override for ONNX model cache directory | `~/.ember/models/embeddinggemma-300m/` |
|
|
184
|
+
| `EMBER_INVALIDATION_THRESHOLD` | Cosine threshold for auto-invalidation (0–1] | `0.92` |
|
|
185
|
+
| `ANTHROPIC_API_KEY` | Enables optional `ember_flush` enrichment via Claude Haiku; absent ⇒ enrichment skipped | — |
|
|
186
|
+
|
|
187
|
+
</details>
|
|
188
|
+
|
|
189
|
+
<details>
|
|
190
|
+
<summary><strong>Global mode .mcp.json</strong></summary>
|
|
191
|
+
|
|
192
|
+
One shared DB for all projects:
|
|
193
|
+
|
|
194
|
+
```json
|
|
195
|
+
{
|
|
196
|
+
"mcpServers": {
|
|
197
|
+
"ember": {
|
|
198
|
+
"command": "~/.ember/venv/bin/python",
|
|
199
|
+
"args": ["-m", "ember", "serve"],
|
|
200
|
+
"env": { "EMBER_MODE": "global" }
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
</details>
|
|
207
|
+
|
|
208
|
+
<details>
|
|
209
|
+
<summary><strong>Model cache</strong></summary>
|
|
210
|
+
|
|
211
|
+
EmbeddingGemma-300m ONNX weights are stored at
|
|
212
|
+
`~/.ember/models/embeddinggemma-300m/` (overridable via `EMBER_MODEL_DIR`).
|
|
213
|
+
`install.sh` fetches them on first run and skips the download afterwards.
|
|
214
|
+
|
|
215
|
+
**One-time setup (gated model):** EmbeddingGemma-300m requires a Hugging Face
|
|
216
|
+
account and license acceptance before the first download:
|
|
217
|
+
|
|
218
|
+
1. Accept the license at <https://huggingface.co/google/embeddinggemma-300m>
|
|
219
|
+
2. Run `huggingface-cli login` (token from <https://huggingface.co/settings/tokens>)
|
|
220
|
+
3. Re-run the installer (or fetch manually below).
|
|
221
|
+
|
|
222
|
+
To fetch manually:
|
|
223
|
+
|
|
224
|
+
```sh
|
|
225
|
+
huggingface-cli download google/embeddinggemma-300m \
|
|
226
|
+
--local-dir ~/.ember/models/embeddinggemma-300m
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
</details>
|
|
230
|
+
|
|
231
|
+
<details>
|
|
232
|
+
<summary><strong>MCP tools</strong></summary>
|
|
233
|
+
|
|
234
|
+
| Tool | Purpose |
|
|
235
|
+
|------|---------|
|
|
236
|
+
| `ember_write` | Write a memory record (atom). |
|
|
237
|
+
| `ember_search` | Multi-tier retrieval (BM25 + cosine fusion); tier `R0`–`R3`. |
|
|
238
|
+
| `ember_get` | Fetch a single record by ID (project-scoped). |
|
|
239
|
+
| `ember_list` | List records for a project, newest first. |
|
|
240
|
+
| `ember_invalidate` | Soft-delete (invalidate) a record. |
|
|
241
|
+
| `ember_flush` | Optional Haiku enrichment pass (requires `ANTHROPIC_API_KEY`; skipped otherwise). |
|
|
242
|
+
| `ember_stats` | Record counts and last-flush timestamp. |
|
|
243
|
+
|
|
244
|
+
</details>
|
|
245
|
+
|
|
246
|
+
<details>
|
|
247
|
+
<summary><strong>Optional dependencies</strong></summary>
|
|
248
|
+
|
|
249
|
+
Vector-search acceleration (transparent; activates automatically for large stores):
|
|
250
|
+
|
|
251
|
+
```sh
|
|
252
|
+
pip install "ember[vec]"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Without `sqlite-vec`, Ember stays on pure-Python cosine — no configuration needed.
|
|
256
|
+
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
<details>
|
|
260
|
+
<summary><strong>Platform support</strong></summary>
|
|
261
|
+
|
|
262
|
+
| Platform | Status |
|
|
263
|
+
|----------|--------|
|
|
264
|
+
| macOS (Apple Silicon / Intel) | Supported |
|
|
265
|
+
| Linux (x86-64, arm64) | Supported |
|
|
266
|
+
| Windows | Best-effort |
|
|
267
|
+
|
|
268
|
+
See [Windows setup (best-effort)](#windows-setup-best-effort) below.
|
|
269
|
+
|
|
270
|
+
</details>
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Windows setup (best-effort)
|
|
275
|
+
|
|
276
|
+
> Windows support is best-effort. The native installer (`install.ps1`) covers the common case; edge cases (antivirus, execution-policy restrictions, PATH quirks) may need manual adjustment.
|
|
277
|
+
|
|
278
|
+
**Prerequisites**
|
|
279
|
+
|
|
280
|
+
- Python 3.10+ — download from [python.org](https://www.python.org/) or run:
|
|
281
|
+
```
|
|
282
|
+
winget install Python.Python.3.12
|
|
283
|
+
```
|
|
284
|
+
Ensure Python is on your `PATH` (the installer wizard has an "Add Python to PATH" checkbox).
|
|
285
|
+
|
|
286
|
+
**Recommended shell**
|
|
287
|
+
|
|
288
|
+
- **PowerShell** — use `install.ps1` (native Windows, no git-bash required):
|
|
289
|
+
```powershell
|
|
290
|
+
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned # once, if needed
|
|
291
|
+
.\install.ps1
|
|
292
|
+
```
|
|
293
|
+
- **git-bash** — alternatively run the POSIX `install.sh` inside git-bash.
|
|
294
|
+
|
|
295
|
+
**After install — `.mcp.json` command path**
|
|
296
|
+
|
|
297
|
+
On Windows the Python executable is `Scripts\python.exe`, not `bin/python`:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"mcpServers": {
|
|
302
|
+
"ember": {
|
|
303
|
+
"command": "%USERPROFILE%\\.ember\\venv\\Scripts\\python.exe",
|
|
304
|
+
"args": ["-m", "ember", "serve"],
|
|
305
|
+
"env": {
|
|
306
|
+
"EMBER_MODE": "project",
|
|
307
|
+
"EMBER_PROJECT_ROOT": "<your-project-root>"
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
`install.ps1` prints the exact snippet (with your resolved `%USERPROFILE%` path) at the end of the install.
|
|
315
|
+
|
|
316
|
+
**Model download (gated)**
|
|
317
|
+
|
|
318
|
+
EmbeddingGemma-300m requires a one-time license acceptance and `huggingface-cli login` before the download will succeed. See the [Reference](#reference) note above.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Contributing
|
|
323
|
+
|
|
324
|
+
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Issues
|
|
325
|
+
labelled **`good first issue`** are a friendly place to start.
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
[MIT](LICENSE) © 2026 David Sandler
|
mnemox-0.2.0/README.md
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/logo.svg" alt="Ember" width="420">
|
|
4
|
+
|
|
5
|
+
### Your Claude Code sessions never forget again.
|
|
6
|
+
|
|
7
|
+
Local-first memory via MCP — one SQLite file, on-device embeddings,<br>
|
|
8
|
+
encrypted cross-machine sync. No cloud. No Docker.
|
|
9
|
+
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://www.python.org/)
|
|
12
|
+
[](https://modelcontextprotocol.io/)
|
|
13
|
+
[](#status)
|
|
14
|
+
|
|
15
|
+
<img src="assets/demo.svg" alt="Ember recalls a past decision in a fresh Claude Code session" width="760">
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## The problem
|
|
22
|
+
|
|
23
|
+
- **Claude forgets between sessions.** Every `/clear` or new window throws away the context you built — decisions, trade-offs, gotchas — and you re-explain them from scratch.
|
|
24
|
+
- **Cloud memory pulls your context off-machine and costs money.** mem0 & co. ship your project history to someone else's servers and meter it.
|
|
25
|
+
- **Self-hosted memory means heavy infra.** Qdrant + Neo4j + Docker is a lot of moving parts just to remember what you decided yesterday.
|
|
26
|
+
|
|
27
|
+
**Ember solves it with one SQLite file on your machine.**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Why Ember
|
|
32
|
+
|
|
33
|
+
| | **Ember 🔥** | mem0 (cloud) | OpenMemory | Self-hosted stack |
|
|
34
|
+
|---------------------------------------|:------------:|:------------:|:----------:|:-----------------:|
|
|
35
|
+
| Runs fully local (no cloud) | ✅ | ❌ | ⚠️ partial | ✅ |
|
|
36
|
+
| No heavy infra (no Docker/Qdrant/Neo4j) | ✅ | ✅ | ❌ | ❌ |
|
|
37
|
+
| Single-file store (SQLite) | ✅ | ❌ | ❌ | ❌ |
|
|
38
|
+
| MCP-native | ✅ | ⚠️ | ⚠️ | ⚠️ |
|
|
39
|
+
| Zero-knowledge E2E sync | ✅ | ❌ | ❌ | ❌ |
|
|
40
|
+
|
|
41
|
+
Ember is the only one that is **local, single-file, MCP-native, zero-infra, and privately synced** at the same time.
|
|
42
|
+
|
|
43
|
+
> ¹ mem0 "no heavy infra" = managed SaaS — you run nothing, but your context goes to their cloud.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
Already using Claude Code? Just tell it: *"set up Ember for me"* — it can run the installer and wire up your `.mcp.json`.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 60-second quickstart
|
|
52
|
+
|
|
53
|
+
**1. Install** (creates a dedicated venv at `~/.ember/venv` and fetches the embedding model):
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
git clone https://github.com/ajadi/ember && cd ember
|
|
57
|
+
./install.sh
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**2. Connect to Claude.** Add one entry to your project's `.mcp.json`
|
|
61
|
+
(replace `<your-project-root>` with the absolute path to your project):
|
|
62
|
+
|
|
63
|
+
```json
|
|
64
|
+
{
|
|
65
|
+
"mcpServers": {
|
|
66
|
+
"ember": {
|
|
67
|
+
"command": "~/.ember/venv/bin/python",
|
|
68
|
+
"args": ["-m", "ember", "serve"],
|
|
69
|
+
"env": {
|
|
70
|
+
"EMBER_MODE": "project",
|
|
71
|
+
"EMBER_PROJECT_ROOT": "<your-project-root>"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**3. Verify.** Restart Claude Code and ask it to write and recall a memory — the
|
|
79
|
+
`ember_write`, `ember_search`, and `ember_list` tools appear in the MCP tool list.
|
|
80
|
+
|
|
81
|
+
> `ember init` prints the exact `.mcp.json` snippet for your platform, including
|
|
82
|
+
> the absolute Python path. See [Reference](#reference) for details.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
87
|
+
|
|
88
|
+
```mermaid
|
|
89
|
+
flowchart LR
|
|
90
|
+
A["atoms<br/>(decisions, notes,<br/>questions, retros)"] --> B["SQLite<br/>(one file)"]
|
|
91
|
+
B --> C["MCP server<br/>(python -m ember serve)"]
|
|
92
|
+
C --> D["Claude Code"]
|
|
93
|
+
D -- "ember_write / ember_search" --> C
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Claude writes **atoms** (decisions, observations, questions, retrospectives) into a
|
|
97
|
+
single local SQLite file. On recall, Ember ranks them with multi-tier retrieval
|
|
98
|
+
(FTS5 BM25 + on-device cosine fusion) and serves them straight back over MCP.
|
|
99
|
+
|
|
100
|
+
- **All local.** Memory lives in one SQLite file on your machine — nothing leaves it.
|
|
101
|
+
- **On-device embeddings.** EmbeddingGemma-300m runs locally via ONNX; no embedding API calls.
|
|
102
|
+
- **Private by design.** Cross-machine sync is end-to-end encrypted — the relay sees only ciphertext. Your memories never leave your control in plaintext.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Status
|
|
107
|
+
|
|
108
|
+
**✅ Works today (Phase 1–3)**
|
|
109
|
+
- Local-first MCP memory server (`python -m ember serve`) with 7 tools: write, search, get, list, invalidate, flush, stats
|
|
110
|
+
- On-device EmbeddingGemma-300m embeddings (ONNX, no network)
|
|
111
|
+
- Single-file SQLite store, `project` and `global` modes
|
|
112
|
+
- Multi-tier retrieval R0–R3 (exact, cosine, FTS5 BM25, fusion)
|
|
113
|
+
- Auto-invalidation of superseded memories by cosine similarity
|
|
114
|
+
- Transparent `sqlite-vec` auto-upgrade for large stores (graceful fallback to pure-Python cosine)
|
|
115
|
+
- Universal native-hook capture loop with durable spool + `ember drain`
|
|
116
|
+
- CLI: `init` / `serve` / `mirror` / `drain` / `backfill`
|
|
117
|
+
- Capture memory from Forge workflows (optional adapter)
|
|
118
|
+
- **Encrypted, zero-knowledge cross-machine sync** via a self-hostable hub — your memories never leave your control in plaintext (real-world multi-machine-over-network validation in progress)
|
|
119
|
+
- Oplog backfill — retroactively sync memories written before sync was enabled (`ember backfill`)
|
|
120
|
+
|
|
121
|
+
**📋 Planned**
|
|
122
|
+
- Hosted zero-knowledge sync hub (managed option)
|
|
123
|
+
|
|
124
|
+
> Actively developed — **star to follow.**
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Reference
|
|
129
|
+
|
|
130
|
+
<details>
|
|
131
|
+
<summary><strong>CLI commands</strong></summary>
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
ember [--version]
|
|
135
|
+
init [--mode {project,global,server}] # initialise store + write config.json
|
|
136
|
+
serve # start the MCP server over stdio
|
|
137
|
+
mirror --project-id <id> [--output-dir memory] [--db-path PATH]
|
|
138
|
+
drain [--queue-path PATH] [--db-path PATH] [--project-id ID]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- **`init`** — creates the store and writes `config.json`. Idempotent: re-running preserves `project_id` and `created`, refreshes `ember_version` / `last_init`. Prints the exact `.mcp.json` snippet for your platform. `--mode server` initialises a server-mode store and config (`client_id` + `hub_url`) for hub sync; set `EMBER_HUB_TOKEN` in the environment.
|
|
142
|
+
- **`serve`** — starts the Ember MCP server over stdio (register this in `.mcp.json`).
|
|
143
|
+
- **`mirror`** — renders stored atoms to Markdown under `memory/` (or `--output-dir`).
|
|
144
|
+
- **`drain`** — drains the capture queue into the store (used by the capture loop).
|
|
145
|
+
|
|
146
|
+
| Mode | DB location | config.json |
|
|
147
|
+
|------|-------------|-------------|
|
|
148
|
+
| `project` (default) | `<project-root>/.ember/ember.db` | `<project-root>/.ember/config.json` |
|
|
149
|
+
| `global` | `~/.ember/global.db` | `~/.ember/config.json` |
|
|
150
|
+
| `server` | `<project-root>/.ember/ember.db` | `<project-root>/.ember/config.json` (server: client_id + hub_url) |
|
|
151
|
+
|
|
152
|
+
</details>
|
|
153
|
+
|
|
154
|
+
<details>
|
|
155
|
+
<summary><strong>Environment variables</strong></summary>
|
|
156
|
+
|
|
157
|
+
| Variable | Description | Default |
|
|
158
|
+
|----------|-------------|---------|
|
|
159
|
+
| `EMBER_MODE` | `project` or `global` | `project` |
|
|
160
|
+
| `EMBER_PROJECT_ROOT` | Root directory for project-mode DB | `cwd` |
|
|
161
|
+
| `EMBER_DB_PATH` | Explicit DB path (overrides mode routing) | — |
|
|
162
|
+
| `EMBER_MODEL_DIR` | Override for ONNX model cache directory | `~/.ember/models/embeddinggemma-300m/` |
|
|
163
|
+
| `EMBER_INVALIDATION_THRESHOLD` | Cosine threshold for auto-invalidation (0–1] | `0.92` |
|
|
164
|
+
| `ANTHROPIC_API_KEY` | Enables optional `ember_flush` enrichment via Claude Haiku; absent ⇒ enrichment skipped | — |
|
|
165
|
+
|
|
166
|
+
</details>
|
|
167
|
+
|
|
168
|
+
<details>
|
|
169
|
+
<summary><strong>Global mode .mcp.json</strong></summary>
|
|
170
|
+
|
|
171
|
+
One shared DB for all projects:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{
|
|
175
|
+
"mcpServers": {
|
|
176
|
+
"ember": {
|
|
177
|
+
"command": "~/.ember/venv/bin/python",
|
|
178
|
+
"args": ["-m", "ember", "serve"],
|
|
179
|
+
"env": { "EMBER_MODE": "global" }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
</details>
|
|
186
|
+
|
|
187
|
+
<details>
|
|
188
|
+
<summary><strong>Model cache</strong></summary>
|
|
189
|
+
|
|
190
|
+
EmbeddingGemma-300m ONNX weights are stored at
|
|
191
|
+
`~/.ember/models/embeddinggemma-300m/` (overridable via `EMBER_MODEL_DIR`).
|
|
192
|
+
`install.sh` fetches them on first run and skips the download afterwards.
|
|
193
|
+
|
|
194
|
+
**One-time setup (gated model):** EmbeddingGemma-300m requires a Hugging Face
|
|
195
|
+
account and license acceptance before the first download:
|
|
196
|
+
|
|
197
|
+
1. Accept the license at <https://huggingface.co/google/embeddinggemma-300m>
|
|
198
|
+
2. Run `huggingface-cli login` (token from <https://huggingface.co/settings/tokens>)
|
|
199
|
+
3. Re-run the installer (or fetch manually below).
|
|
200
|
+
|
|
201
|
+
To fetch manually:
|
|
202
|
+
|
|
203
|
+
```sh
|
|
204
|
+
huggingface-cli download google/embeddinggemma-300m \
|
|
205
|
+
--local-dir ~/.ember/models/embeddinggemma-300m
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
</details>
|
|
209
|
+
|
|
210
|
+
<details>
|
|
211
|
+
<summary><strong>MCP tools</strong></summary>
|
|
212
|
+
|
|
213
|
+
| Tool | Purpose |
|
|
214
|
+
|------|---------|
|
|
215
|
+
| `ember_write` | Write a memory record (atom). |
|
|
216
|
+
| `ember_search` | Multi-tier retrieval (BM25 + cosine fusion); tier `R0`–`R3`. |
|
|
217
|
+
| `ember_get` | Fetch a single record by ID (project-scoped). |
|
|
218
|
+
| `ember_list` | List records for a project, newest first. |
|
|
219
|
+
| `ember_invalidate` | Soft-delete (invalidate) a record. |
|
|
220
|
+
| `ember_flush` | Optional Haiku enrichment pass (requires `ANTHROPIC_API_KEY`; skipped otherwise). |
|
|
221
|
+
| `ember_stats` | Record counts and last-flush timestamp. |
|
|
222
|
+
|
|
223
|
+
</details>
|
|
224
|
+
|
|
225
|
+
<details>
|
|
226
|
+
<summary><strong>Optional dependencies</strong></summary>
|
|
227
|
+
|
|
228
|
+
Vector-search acceleration (transparent; activates automatically for large stores):
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
pip install "ember[vec]"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Without `sqlite-vec`, Ember stays on pure-Python cosine — no configuration needed.
|
|
235
|
+
|
|
236
|
+
</details>
|
|
237
|
+
|
|
238
|
+
<details>
|
|
239
|
+
<summary><strong>Platform support</strong></summary>
|
|
240
|
+
|
|
241
|
+
| Platform | Status |
|
|
242
|
+
|----------|--------|
|
|
243
|
+
| macOS (Apple Silicon / Intel) | Supported |
|
|
244
|
+
| Linux (x86-64, arm64) | Supported |
|
|
245
|
+
| Windows | Best-effort |
|
|
246
|
+
|
|
247
|
+
See [Windows setup (best-effort)](#windows-setup-best-effort) below.
|
|
248
|
+
|
|
249
|
+
</details>
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Windows setup (best-effort)
|
|
254
|
+
|
|
255
|
+
> Windows support is best-effort. The native installer (`install.ps1`) covers the common case; edge cases (antivirus, execution-policy restrictions, PATH quirks) may need manual adjustment.
|
|
256
|
+
|
|
257
|
+
**Prerequisites**
|
|
258
|
+
|
|
259
|
+
- Python 3.10+ — download from [python.org](https://www.python.org/) or run:
|
|
260
|
+
```
|
|
261
|
+
winget install Python.Python.3.12
|
|
262
|
+
```
|
|
263
|
+
Ensure Python is on your `PATH` (the installer wizard has an "Add Python to PATH" checkbox).
|
|
264
|
+
|
|
265
|
+
**Recommended shell**
|
|
266
|
+
|
|
267
|
+
- **PowerShell** — use `install.ps1` (native Windows, no git-bash required):
|
|
268
|
+
```powershell
|
|
269
|
+
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned # once, if needed
|
|
270
|
+
.\install.ps1
|
|
271
|
+
```
|
|
272
|
+
- **git-bash** — alternatively run the POSIX `install.sh` inside git-bash.
|
|
273
|
+
|
|
274
|
+
**After install — `.mcp.json` command path**
|
|
275
|
+
|
|
276
|
+
On Windows the Python executable is `Scripts\python.exe`, not `bin/python`:
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"mcpServers": {
|
|
281
|
+
"ember": {
|
|
282
|
+
"command": "%USERPROFILE%\\.ember\\venv\\Scripts\\python.exe",
|
|
283
|
+
"args": ["-m", "ember", "serve"],
|
|
284
|
+
"env": {
|
|
285
|
+
"EMBER_MODE": "project",
|
|
286
|
+
"EMBER_PROJECT_ROOT": "<your-project-root>"
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
`install.ps1` prints the exact snippet (with your resolved `%USERPROFILE%` path) at the end of the install.
|
|
294
|
+
|
|
295
|
+
**Model download (gated)**
|
|
296
|
+
|
|
297
|
+
EmbeddingGemma-300m requires a one-time license acceptance and `huggingface-cli login` before the download will succeed. See the [Reference](#reference) note above.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
## Contributing
|
|
302
|
+
|
|
303
|
+
Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). Issues
|
|
304
|
+
labelled **`good first issue`** are a friendly place to start.
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
[MIT](LICENSE) © 2026 David Sandler
|