memry 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.
memry-0.2.0/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # memry data
17
+ *.db
18
+ *.db-wal
19
+ *.db-shm
20
+ .memry/
21
+
22
+ # OS / editor
23
+ .DS_Store
24
+ Thumbs.db
25
+ .idea/
26
+ .vscode/*
27
+ !.vscode/extensions.json
28
+
29
+ # Env
30
+ .env
31
+ .env.*
32
+ !.env.example
33
+
34
+ # Personal, machine-specific notes
35
+ *.local.md
36
+ .remember/
memry-0.2.0/LICENSE ADDED
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2026 Memry contributors
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
memry-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: memry
3
+ Version: 0.2.0
4
+ Summary: The open, self-hostable memory layer for AI agents. MCP-native, local-first, research-grade.
5
+ Project-URL: Homepage, https://memry.tech
6
+ Project-URL: Repository, https://github.com/cosmin-novac/memry
7
+ Project-URL: Documentation, https://github.com/cosmin-novac/memry/tree/main/docs
8
+ Author: Memry contributors
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE
11
+ Keywords: agents,ai,llm,mcp,memory,rag
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Requires-Python: >=3.11
19
+ Requires-Dist: httpx>=0.27
20
+ Requires-Dist: mcp>=1.2.0
21
+ Requires-Dist: numpy>=1.26
22
+ Requires-Dist: pydantic>=2.7
23
+ Provides-Extra: ann
24
+ Requires-Dist: usearch>=2.12; extra == 'ann'
25
+ Provides-Extra: anthropic
26
+ Requires-Dist: anthropic>=0.40; extra == 'anthropic'
27
+ Provides-Extra: dev
28
+ Requires-Dist: httpx>=0.27; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0; extra == 'dev'
30
+ Provides-Extra: mem0
31
+ Requires-Dist: mem0ai>=0.1.100; extra == 'mem0'
32
+ Provides-Extra: postgres
33
+ Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Memry
37
+
38
+ **[memry.tech](https://memry.tech)** - the open, self-hostable memory layer for AI agents. One `pip install`, zero services,
39
+ plugged into any agent over MCP - with the intelligence layer (extraction, reconciliation,
40
+ temporal invalidation, decay, context construction) as first-class, replaceable research code.
41
+
42
+ ```
43
+ pip install memry
44
+ memry mcp # ← your agent now has long-term memory
45
+ ```
46
+
47
+ - **MCP-native** - works with Claude Code, Claude Desktop, Cursor, Windsurf, Codex, and any
48
+ other MCP client, over stdio or streamable HTTP.
49
+ - **Local-first** - a single SQLite file. No vector DB, no Postgres, no cloud. Works with
50
+ **zero API keys** (FTS5 BM25 + deterministic hash embeddings), gets smarter the moment you
51
+ set `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`.
52
+ - **Real memory, not a vector dump** - LLM extraction distills conversations into discrete
53
+ facts; reconciliation deduplicates, merges, and **supersedes contradicted memories instead
54
+ of deleting them** (bi-temporal: `valid_from` / `invalid_at` / `superseded_by`).
55
+ - **Explainable retrieval** - hybrid vector + BM25 with reciprocal-rank fusion, boosted by
56
+ recency and importance; every result carries its score signals.
57
+ - **Provenance & audit** - raw episodes are stored immutably; every memory links to its
58
+ source episodes; every mutation is an event you can inspect (`history`).
59
+ - **Forgetting built in** - importance decays with a half-life; a decay sweep soft-forgets
60
+ stale trivia (invalidated, never destroyed).
61
+ - **Entities, disambiguated** - mentions become first-class entities, and a name match is
62
+ never enough to merge: unclear cases stay separate ("three Jonases") with a merge
63
+ proposal you (or the system, once evidence is clear) confirm or reject later.
64
+ - **Category filters** - `search(categories=["diet"])`, `memry search -c diet`,
65
+ `?categories=` on REST, `categories` on the MCP search tool.
66
+ - **Scales when you need it** - optional usearch HNSW index (`memry[ann]`) for vector
67
+ search at scale, and a PostgreSQL + pgvector backend (`memry[postgres]`) for
68
+ multi-writer deployments. SQLite stays the zero-ops default.
69
+ - **Multi-tenant ready** - per-tenant API keys with transparent namespacing and strict
70
+ isolation on the self-hosted server (`MEMRY_TENANTS`), plus an admin key.
71
+ - **Research-grade** - a built-in eval harness (recall@k, MRR, latency) with a synthetic
72
+ dataset, plus a pluggable backend interface with an optional [Mem0](https://github.com/mem0ai/mem0)
73
+ adapter so you can benchmark against it under identical conditions.
74
+
75
+ Apache-2.0. Your agents. Your memories. Your infrastructure.
76
+
77
+ ---
78
+
79
+ ## Quickstart
80
+
81
+ ### 1. As an MCP server (any agent)
82
+
83
+ ```jsonc
84
+ // Claude Desktop / Cursor / Windsurf config
85
+ {
86
+ "mcpServers": {
87
+ "memry": {
88
+ "command": "memry",
89
+ "args": ["mcp"],
90
+ "env": { "ANTHROPIC_API_KEY": "sk-ant-..." } // optional but recommended
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ ```bash
97
+ # Claude Code
98
+ claude mcp add memry -- memry mcp
99
+ ```
100
+
101
+ The server exposes: `save_memories`, `search_memories`, `get_memory_context`,
102
+ `list_memories`, `update_memory`, `delete_memory`, `memory_history`, `memory_stats`.
103
+
104
+ ### 2. As a Python library
105
+
106
+ ```python
107
+ from memry import MemoryStore
108
+
109
+ store = MemoryStore()
110
+
111
+ # write: extraction + reconciliation (or infer=False to store verbatim)
112
+ store.add(
113
+ [{"role": "user", "content": "I'm Ada, a data engineer in Berlin. I prefer uv over pip."}],
114
+ user_id="ada",
115
+ )
116
+
117
+ # read: hybrid search with explainable scores
118
+ for hit in store.search("what tooling does the user prefer?", user_id="ada"):
119
+ print(hit.score, hit.memory.content, hit.signals)
120
+
121
+ # or a ready-to-inject, token-budgeted context block
122
+ ctx = store.reconstruct_context("help me set up a new project", user_id="ada", token_budget=1200)
123
+ print(ctx.text)
124
+ ```
125
+
126
+ ### 3. Self-hosted server (REST + dashboard + MCP)
127
+
128
+ ```bash
129
+ memry serve --host 0.0.0.0 --port 8787
130
+ # dashboard: http://localhost:8787/
131
+ # REST API: http://localhost:8787/api/v1/...
132
+ # MCP (HTTP): http://localhost:8787/mcp
133
+ ```
134
+
135
+ Or with Docker:
136
+
137
+ ```bash
138
+ docker compose up -d # see docker-compose.yml
139
+ ```
140
+
141
+ Or on a fresh VPS (Ubuntu/Debian) with automatic HTTPS - one command, any
142
+ provider ([guide](docs/deploy-vps.md)):
143
+
144
+ ```bash
145
+ curl -fsSL https://raw.githubusercontent.com/cosmin-novac/memry/main/deploy/install.sh \
146
+ | MEMRY_DOMAIN=memory.example.com bash
147
+ ```
148
+
149
+ Set `MEMRY_API_KEY` to require `Authorization: Bearer <key>` on the API.
150
+
151
+ ### 4. CLI
152
+
153
+ ```bash
154
+ memry add "I moved to Amsterdam and joined ASML" -u ada
155
+ memry search "where does ada work" -u ada
156
+ memry context "plan a commute" -u ada
157
+ memry history <memory_id> # full audit trail
158
+ memry sweep # decay: soft-forget stale memories
159
+ memry eval --dataset evals/datasets/synthetic_v1.jsonl
160
+ ```
161
+
162
+ ---
163
+
164
+ ## How it works
165
+
166
+ ```mermaid
167
+ flowchart LR
168
+ A[conversation] --> E[episodes<br/><i>immutable raw log</i>]
169
+ A --> X[extraction<br/><i>LLM distills facts</i>]
170
+ X --> R{reconcile}
171
+ R -- new --> ADD[ADD memory]
172
+ R -- overlaps --> UPD[UPDATE in place]
173
+ R -- contradicts --> SUP[invalidate old<br/>supersede with new]
174
+ R -- duplicate --> NONE[skip]
175
+ ADD & UPD & SUP --> M[(memories<br/>FTS5 + vectors + events)]
176
+ Q[agent query] --> H[hybrid retrieval<br/>RRF + recency + importance]
177
+ M --> H --> C[token-budgeted<br/>context block]
178
+ ```
179
+
180
+ 1. **Episodes first.** Every message is stored verbatim before anything is derived from it.
181
+ Memories are an index; episodes are the source of truth - you can re-run a better
182
+ extraction pipeline over them later.
183
+ 2. **Extraction** (Mem0-style phase 1): an LLM distills discrete, self-contained facts with
184
+ type (semantic / episodic / procedural), importance, categories, and entities. Without an
185
+ LLM, messages are stored verbatim so the system still works.
186
+ 3. **Reconciliation** (phase 2, with Zep-style temporal semantics): each fact is compared to
187
+ its most similar existing memories - duplicates are skipped, refinements rewrite in place,
188
+ and contradictions *invalidate* the old memory and link it to its successor.
189
+ 4. **Retrieval**: BM25 + cosine similarity fused with RRF, then boosted by recency
190
+ (half-life) and importance. Keyword-only when no embedder is configured.
191
+ 5. **Forgetting**: effective importance decays over time; `memry sweep` invalidates
192
+ memories that decayed below threshold.
193
+
194
+ ## Configuration
195
+
196
+ Everything works with defaults. Override via env vars, `~/.memry/config.json`, or `Config(...)`:
197
+
198
+ | Env var | Default | Notes |
199
+ |---|---|---|
200
+ | `MEMRY_DB_PATH` | `~/.memry/memry.db` | single SQLite file |
201
+ | `MEMRY_BACKEND` | `local` | `local` \| `mem0` (needs `memry[mem0]`) |
202
+ | `MEMRY_DEFAULT_USER` | `default` | user scope when the agent doesn't pass one |
203
+ | `MEMRY_LLM_PROVIDER` | auto | `anthropic` \| `openai` \| `ollama` \| `none` - auto-detected from `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` |
204
+ | `MEMRY_LLM_MODEL` | per provider | `claude-opus-4-8` / `gpt-5-mini` / `llama3.1` (use `claude-haiku-4-5` for a cheaper extraction model) |
205
+ | `MEMRY_EMBEDDING_PROVIDER` | auto | `openai` \| `ollama` \| `voyage` \| `hash` \| `none` |
206
+ | `MEMRY_API_KEY` | - | bearer token for the REST/MCP HTTP server |
207
+
208
+ Anthropic extraction requires the optional SDK: `pip install "memry[anthropic]"`.
209
+
210
+ ## Evaluation
211
+
212
+ ```bash
213
+ memry eval --dataset evals/datasets/synthetic_v1.jsonl -k 5
214
+ ```
215
+
216
+ The harness ingests each case through the full write path, then scores retrieval
217
+ (recall@k, MRR, latency p50/p95) - deterministic and offline, so it runs in CI. Format
218
+ LoCoMo/LongMemEval into the same JSONL schema to compare providers, configs, and backends
219
+ (including the Mem0 adapter) under identical conditions. See
220
+ [docs/research/competitive-analysis.md](docs/research/competitive-analysis.md) for the
221
+ landscape survey behind the design.
222
+
223
+ ## Project layout
224
+
225
+ ```
226
+ src/memry/
227
+ models.py # Episode / Memory / MemoryEvent (bi-temporal, provenance)
228
+ config.py # env + file config, provider auto-detection
229
+ store.py # MemoryStore - the public API
230
+ retrieval.py # hybrid search: RRF + recency + importance
231
+ backends/ # storage interface, local SQLite engine, Mem0 adapter
232
+ intelligence/ # extraction, reconciliation, decay, context building
233
+ providers/ # LLMs (Anthropic/OpenAI/Ollama) & embeddings (+hash fallback)
234
+ mcp_server.py # MCP tools (stdio + streamable HTTP)
235
+ rest.py # REST API + dashboard + /mcp mount
236
+ evals/ # retrieval eval harness
237
+ ```
238
+
239
+ ## Development
240
+
241
+ ```bash
242
+ pip install -e ".[dev]"
243
+ pytest
244
+ ```
245
+
246
+ ## License
247
+
248
+ [Apache-2.0](LICENSE)
memry-0.2.0/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # Memry
2
+
3
+ **[memry.tech](https://memry.tech)** - the open, self-hostable memory layer for AI agents. One `pip install`, zero services,
4
+ plugged into any agent over MCP - with the intelligence layer (extraction, reconciliation,
5
+ temporal invalidation, decay, context construction) as first-class, replaceable research code.
6
+
7
+ ```
8
+ pip install memry
9
+ memry mcp # ← your agent now has long-term memory
10
+ ```
11
+
12
+ - **MCP-native** - works with Claude Code, Claude Desktop, Cursor, Windsurf, Codex, and any
13
+ other MCP client, over stdio or streamable HTTP.
14
+ - **Local-first** - a single SQLite file. No vector DB, no Postgres, no cloud. Works with
15
+ **zero API keys** (FTS5 BM25 + deterministic hash embeddings), gets smarter the moment you
16
+ set `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`.
17
+ - **Real memory, not a vector dump** - LLM extraction distills conversations into discrete
18
+ facts; reconciliation deduplicates, merges, and **supersedes contradicted memories instead
19
+ of deleting them** (bi-temporal: `valid_from` / `invalid_at` / `superseded_by`).
20
+ - **Explainable retrieval** - hybrid vector + BM25 with reciprocal-rank fusion, boosted by
21
+ recency and importance; every result carries its score signals.
22
+ - **Provenance & audit** - raw episodes are stored immutably; every memory links to its
23
+ source episodes; every mutation is an event you can inspect (`history`).
24
+ - **Forgetting built in** - importance decays with a half-life; a decay sweep soft-forgets
25
+ stale trivia (invalidated, never destroyed).
26
+ - **Entities, disambiguated** - mentions become first-class entities, and a name match is
27
+ never enough to merge: unclear cases stay separate ("three Jonases") with a merge
28
+ proposal you (or the system, once evidence is clear) confirm or reject later.
29
+ - **Category filters** - `search(categories=["diet"])`, `memry search -c diet`,
30
+ `?categories=` on REST, `categories` on the MCP search tool.
31
+ - **Scales when you need it** - optional usearch HNSW index (`memry[ann]`) for vector
32
+ search at scale, and a PostgreSQL + pgvector backend (`memry[postgres]`) for
33
+ multi-writer deployments. SQLite stays the zero-ops default.
34
+ - **Multi-tenant ready** - per-tenant API keys with transparent namespacing and strict
35
+ isolation on the self-hosted server (`MEMRY_TENANTS`), plus an admin key.
36
+ - **Research-grade** - a built-in eval harness (recall@k, MRR, latency) with a synthetic
37
+ dataset, plus a pluggable backend interface with an optional [Mem0](https://github.com/mem0ai/mem0)
38
+ adapter so you can benchmark against it under identical conditions.
39
+
40
+ Apache-2.0. Your agents. Your memories. Your infrastructure.
41
+
42
+ ---
43
+
44
+ ## Quickstart
45
+
46
+ ### 1. As an MCP server (any agent)
47
+
48
+ ```jsonc
49
+ // Claude Desktop / Cursor / Windsurf config
50
+ {
51
+ "mcpServers": {
52
+ "memry": {
53
+ "command": "memry",
54
+ "args": ["mcp"],
55
+ "env": { "ANTHROPIC_API_KEY": "sk-ant-..." } // optional but recommended
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ```bash
62
+ # Claude Code
63
+ claude mcp add memry -- memry mcp
64
+ ```
65
+
66
+ The server exposes: `save_memories`, `search_memories`, `get_memory_context`,
67
+ `list_memories`, `update_memory`, `delete_memory`, `memory_history`, `memory_stats`.
68
+
69
+ ### 2. As a Python library
70
+
71
+ ```python
72
+ from memry import MemoryStore
73
+
74
+ store = MemoryStore()
75
+
76
+ # write: extraction + reconciliation (or infer=False to store verbatim)
77
+ store.add(
78
+ [{"role": "user", "content": "I'm Ada, a data engineer in Berlin. I prefer uv over pip."}],
79
+ user_id="ada",
80
+ )
81
+
82
+ # read: hybrid search with explainable scores
83
+ for hit in store.search("what tooling does the user prefer?", user_id="ada"):
84
+ print(hit.score, hit.memory.content, hit.signals)
85
+
86
+ # or a ready-to-inject, token-budgeted context block
87
+ ctx = store.reconstruct_context("help me set up a new project", user_id="ada", token_budget=1200)
88
+ print(ctx.text)
89
+ ```
90
+
91
+ ### 3. Self-hosted server (REST + dashboard + MCP)
92
+
93
+ ```bash
94
+ memry serve --host 0.0.0.0 --port 8787
95
+ # dashboard: http://localhost:8787/
96
+ # REST API: http://localhost:8787/api/v1/...
97
+ # MCP (HTTP): http://localhost:8787/mcp
98
+ ```
99
+
100
+ Or with Docker:
101
+
102
+ ```bash
103
+ docker compose up -d # see docker-compose.yml
104
+ ```
105
+
106
+ Or on a fresh VPS (Ubuntu/Debian) with automatic HTTPS - one command, any
107
+ provider ([guide](docs/deploy-vps.md)):
108
+
109
+ ```bash
110
+ curl -fsSL https://raw.githubusercontent.com/cosmin-novac/memry/main/deploy/install.sh \
111
+ | MEMRY_DOMAIN=memory.example.com bash
112
+ ```
113
+
114
+ Set `MEMRY_API_KEY` to require `Authorization: Bearer <key>` on the API.
115
+
116
+ ### 4. CLI
117
+
118
+ ```bash
119
+ memry add "I moved to Amsterdam and joined ASML" -u ada
120
+ memry search "where does ada work" -u ada
121
+ memry context "plan a commute" -u ada
122
+ memry history <memory_id> # full audit trail
123
+ memry sweep # decay: soft-forget stale memories
124
+ memry eval --dataset evals/datasets/synthetic_v1.jsonl
125
+ ```
126
+
127
+ ---
128
+
129
+ ## How it works
130
+
131
+ ```mermaid
132
+ flowchart LR
133
+ A[conversation] --> E[episodes<br/><i>immutable raw log</i>]
134
+ A --> X[extraction<br/><i>LLM distills facts</i>]
135
+ X --> R{reconcile}
136
+ R -- new --> ADD[ADD memory]
137
+ R -- overlaps --> UPD[UPDATE in place]
138
+ R -- contradicts --> SUP[invalidate old<br/>supersede with new]
139
+ R -- duplicate --> NONE[skip]
140
+ ADD & UPD & SUP --> M[(memories<br/>FTS5 + vectors + events)]
141
+ Q[agent query] --> H[hybrid retrieval<br/>RRF + recency + importance]
142
+ M --> H --> C[token-budgeted<br/>context block]
143
+ ```
144
+
145
+ 1. **Episodes first.** Every message is stored verbatim before anything is derived from it.
146
+ Memories are an index; episodes are the source of truth - you can re-run a better
147
+ extraction pipeline over them later.
148
+ 2. **Extraction** (Mem0-style phase 1): an LLM distills discrete, self-contained facts with
149
+ type (semantic / episodic / procedural), importance, categories, and entities. Without an
150
+ LLM, messages are stored verbatim so the system still works.
151
+ 3. **Reconciliation** (phase 2, with Zep-style temporal semantics): each fact is compared to
152
+ its most similar existing memories - duplicates are skipped, refinements rewrite in place,
153
+ and contradictions *invalidate* the old memory and link it to its successor.
154
+ 4. **Retrieval**: BM25 + cosine similarity fused with RRF, then boosted by recency
155
+ (half-life) and importance. Keyword-only when no embedder is configured.
156
+ 5. **Forgetting**: effective importance decays over time; `memry sweep` invalidates
157
+ memories that decayed below threshold.
158
+
159
+ ## Configuration
160
+
161
+ Everything works with defaults. Override via env vars, `~/.memry/config.json`, or `Config(...)`:
162
+
163
+ | Env var | Default | Notes |
164
+ |---|---|---|
165
+ | `MEMRY_DB_PATH` | `~/.memry/memry.db` | single SQLite file |
166
+ | `MEMRY_BACKEND` | `local` | `local` \| `mem0` (needs `memry[mem0]`) |
167
+ | `MEMRY_DEFAULT_USER` | `default` | user scope when the agent doesn't pass one |
168
+ | `MEMRY_LLM_PROVIDER` | auto | `anthropic` \| `openai` \| `ollama` \| `none` - auto-detected from `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` |
169
+ | `MEMRY_LLM_MODEL` | per provider | `claude-opus-4-8` / `gpt-5-mini` / `llama3.1` (use `claude-haiku-4-5` for a cheaper extraction model) |
170
+ | `MEMRY_EMBEDDING_PROVIDER` | auto | `openai` \| `ollama` \| `voyage` \| `hash` \| `none` |
171
+ | `MEMRY_API_KEY` | - | bearer token for the REST/MCP HTTP server |
172
+
173
+ Anthropic extraction requires the optional SDK: `pip install "memry[anthropic]"`.
174
+
175
+ ## Evaluation
176
+
177
+ ```bash
178
+ memry eval --dataset evals/datasets/synthetic_v1.jsonl -k 5
179
+ ```
180
+
181
+ The harness ingests each case through the full write path, then scores retrieval
182
+ (recall@k, MRR, latency p50/p95) - deterministic and offline, so it runs in CI. Format
183
+ LoCoMo/LongMemEval into the same JSONL schema to compare providers, configs, and backends
184
+ (including the Mem0 adapter) under identical conditions. See
185
+ [docs/research/competitive-analysis.md](docs/research/competitive-analysis.md) for the
186
+ landscape survey behind the design.
187
+
188
+ ## Project layout
189
+
190
+ ```
191
+ src/memry/
192
+ models.py # Episode / Memory / MemoryEvent (bi-temporal, provenance)
193
+ config.py # env + file config, provider auto-detection
194
+ store.py # MemoryStore - the public API
195
+ retrieval.py # hybrid search: RRF + recency + importance
196
+ backends/ # storage interface, local SQLite engine, Mem0 adapter
197
+ intelligence/ # extraction, reconciliation, decay, context building
198
+ providers/ # LLMs (Anthropic/OpenAI/Ollama) & embeddings (+hash fallback)
199
+ mcp_server.py # MCP tools (stdio + streamable HTTP)
200
+ rest.py # REST API + dashboard + /mcp mount
201
+ evals/ # retrieval eval harness
202
+ ```
203
+
204
+ ## Development
205
+
206
+ ```bash
207
+ pip install -e ".[dev]"
208
+ pytest
209
+ ```
210
+
211
+ ## License
212
+
213
+ [Apache-2.0](LICENSE)