flywheel-mneme 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. flywheel_mneme-0.4.2/LICENSE +110 -0
  2. flywheel_mneme-0.4.2/PKG-INFO +373 -0
  3. flywheel_mneme-0.4.2/README.md +353 -0
  4. flywheel_mneme-0.4.2/pyproject.toml +34 -0
  5. flywheel_mneme-0.4.2/setup.cfg +4 -0
  6. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/PKG-INFO +373 -0
  7. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/SOURCES.txt +60 -0
  8. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/dependency_links.txt +1 -0
  9. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/entry_points.txt +2 -0
  10. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/requires.txt +3 -0
  11. flywheel_mneme-0.4.2/src/flywheel_mneme.egg-info/top_level.txt +1 -0
  12. flywheel_mneme-0.4.2/src/mneme/__init__.py +14 -0
  13. flywheel_mneme-0.4.2/src/mneme/__main__.py +4 -0
  14. flywheel_mneme-0.4.2/src/mneme/bench.py +113 -0
  15. flywheel_mneme-0.4.2/src/mneme/cli.py +524 -0
  16. flywheel_mneme-0.4.2/src/mneme/compose.py +115 -0
  17. flywheel_mneme-0.4.2/src/mneme/consolidate.py +125 -0
  18. flywheel_mneme-0.4.2/src/mneme/drift.py +137 -0
  19. flywheel_mneme-0.4.2/src/mneme/embed.py +66 -0
  20. flywheel_mneme-0.4.2/src/mneme/entity.py +129 -0
  21. flywheel_mneme-0.4.2/src/mneme/extract.py +90 -0
  22. flywheel_mneme-0.4.2/src/mneme/ingest.py +147 -0
  23. flywheel_mneme-0.4.2/src/mneme/inspect.py +118 -0
  24. flywheel_mneme-0.4.2/src/mneme/llm_extract.py +112 -0
  25. flywheel_mneme-0.4.2/src/mneme/mcp.py +333 -0
  26. flywheel_mneme-0.4.2/src/mneme/memory.py +257 -0
  27. flywheel_mneme-0.4.2/src/mneme/origin.py +509 -0
  28. flywheel_mneme-0.4.2/src/mneme/recall.py +201 -0
  29. flywheel_mneme-0.4.2/src/mneme/receipt.py +187 -0
  30. flywheel_mneme-0.4.2/src/mneme/replay.py +319 -0
  31. flywheel_mneme-0.4.2/src/mneme/scenario.py +74 -0
  32. flywheel_mneme-0.4.2/src/mneme/schema.py +44 -0
  33. flywheel_mneme-0.4.2/src/mneme/source.py +308 -0
  34. flywheel_mneme-0.4.2/src/mneme/store.py +519 -0
  35. flywheel_mneme-0.4.2/src/mneme/temporal.py +74 -0
  36. flywheel_mneme-0.4.2/tests/test_audit_integrity.py +65 -0
  37. flywheel_mneme-0.4.2/tests/test_bench.py +82 -0
  38. flywheel_mneme-0.4.2/tests/test_compose.py +233 -0
  39. flywheel_mneme-0.4.2/tests/test_consolidate.py +85 -0
  40. flywheel_mneme-0.4.2/tests/test_crucible_replay.py +1271 -0
  41. flywheel_mneme-0.4.2/tests/test_drift_content.py +217 -0
  42. flywheel_mneme-0.4.2/tests/test_embed.py +70 -0
  43. flywheel_mneme-0.4.2/tests/test_entity.py +63 -0
  44. flywheel_mneme-0.4.2/tests/test_forget.py +89 -0
  45. flywheel_mneme-0.4.2/tests/test_ingest.py +291 -0
  46. flywheel_mneme-0.4.2/tests/test_inspect.py +86 -0
  47. flywheel_mneme-0.4.2/tests/test_llm_extract.py +88 -0
  48. flywheel_mneme-0.4.2/tests/test_mneme.py +138 -0
  49. flywheel_mneme-0.4.2/tests/test_multiuser.py +60 -0
  50. flywheel_mneme-0.4.2/tests/test_origin_recheck.py +425 -0
  51. flywheel_mneme-0.4.2/tests/test_provenance_grounding.py +44 -0
  52. flywheel_mneme-0.4.2/tests/test_recall_receipt.py +67 -0
  53. flywheel_mneme-0.4.2/tests/test_recency.py +65 -0
  54. flywheel_mneme-0.4.2/tests/test_repo_art.py +212 -0
  55. flywheel_mneme-0.4.2/tests/test_scenario_mcp.py +451 -0
  56. flywheel_mneme-0.4.2/tests/test_scope_isolation.py +343 -0
  57. flywheel_mneme-0.4.2/tests/test_temporal.py +76 -0
  58. flywheel_mneme-0.4.2/tests/test_tour.py +11 -0
  59. flywheel_mneme-0.4.2/tests/test_union_and_migration.py +76 -0
  60. flywheel_mneme-0.4.2/tests/test_verify_audit_cli.py +59 -0
  61. flywheel_mneme-0.4.2/tests/test_verify_recall.py +53 -0
  62. flywheel_mneme-0.4.2/tests/test_version_metadata.py +95 -0
@@ -0,0 +1,110 @@
1
+ # Functional Source License, Version 1.1, MIT Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-MIT
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 Zain Dana Harper
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the MIT license that is effective on the second anniversary of the date we make
91
+ the Software available. On or after that date, you may use the Software under
92
+ the MIT license, in which case the following will apply:
93
+
94
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
95
+ this software and associated documentation files (the "Software"), to deal in
96
+ the Software without restriction, including without limitation the rights to
97
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
98
+ of the Software, and to permit persons to whom the Software is furnished to do
99
+ so, subject to the following conditions:
100
+
101
+ The above copyright notice and this permission notice shall be included in all
102
+ copies or substantial portions of the Software.
103
+
104
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
105
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
106
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
107
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
108
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
109
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
110
+ SOFTWARE.
@@ -0,0 +1,373 @@
1
+ Metadata-Version: 2.4
2
+ Name: flywheel-mneme
3
+ Version: 0.4.2
4
+ Summary: Accountable agent memory with layered retrieval, source provenance, re-derivable recall receipts, and drift checks. Zero runtime dependencies.
5
+ Author: Zain Dana Harper
6
+ License-Expression: LicenseRef-FSL-1.1-MIT
7
+ Project-URL: Homepage, https://github.com/HarperZ9/mneme
8
+ Keywords: agent-memory,llm-memory,long-term-memory,provenance,retrieval,bm25,rag
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest>=8; extra == "test"
19
+ Dynamic: license-file
20
+
21
+ <p align="center"><img src="docs/art/mneme-header.svg" alt="mneme: Source provenance, reproducible ranking, and drift checks." width="100%"></p>
22
+
23
+ # mneme
24
+
25
+ > Accountable agent memory. Mneme records source provenance for stored
26
+ > memories, returns recall receipts that reproduce ranking, and detects source
27
+ > drift when checks run.
28
+
29
+ ## Install
30
+
31
+ ### Released v0.4.2 wheel
32
+
33
+ The public `v0.4.2` wheel is the current released package. It covers the released memory, recall, drift, provenance, accountable forgetting, local-origin freshness, and MCP Crucible export/replay workflows documented below.
34
+
35
+ ```bash
36
+ python -m pip install flywheel-mneme
37
+ ```
38
+
39
+ `flywheel-mneme` is the HarperZ9 distribution, published with PEP 740 attestations. The bare name `mneme-memory` on PyPI belongs to an unrelated project.
40
+
41
+ To check the bytes yourself rather than trust the index, install the release wheel directly:
42
+
43
+ ```bash
44
+ python -m pip install "https://github.com/HarperZ9/mneme/releases/download/v0.4.2/flywheel_mneme-0.4.2-py3-none-any.whl"
45
+ ```
46
+
47
+ ### Source install
48
+
49
+ For development from a source checkout:
50
+
51
+ ```bash
52
+ python -m pip install -e .
53
+ ```
54
+
55
+ For a non-editable install from the public source repository:
56
+
57
+ ```bash
58
+ python -m pip install "flywheel-mneme @ git+https://github.com/HarperZ9/mneme.git"
59
+ ```
60
+
61
+ Zero runtime dependencies · fully local · deterministic · fair-source.
62
+
63
+ ## Why it matters
64
+
65
+ Agent memory systems need evidence for two operational questions:
66
+
67
+ - **Why did you recall *this* memory?** Mneme returns the ranked hits, component
68
+ scores, and fusion rule so the ranking can be reproduced.
69
+ - **Is this memory still grounded in its cited source?** Mneme records source
70
+ hashes and re-checks them to detect drift, missing sources, or unverifiable
71
+ grounding.
72
+
73
+ Mneme stores that evidence with the memory workflow instead of leaving it as a
74
+ separate operator note.
75
+
76
+ ## The 4-tier memory model
77
+
78
+ ```
79
+ L0 turn raw dialogue -> stored verbatim
80
+ L1 atom atomic user facts -> extracted, each bound to its turn
81
+ L2 scenario scene blocks of related atoms
82
+ L3 persona the user profile -> synthesized, citing its atoms
83
+ ```
84
+
85
+ Retrieval is hybrid: BM25 (pure Python, always on) fused with an optional
86
+ embedding channel by Reciprocal Rank Fusion, with no required embedding API.
87
+
88
+ <p align="center"><img src="docs/art/recall-lane.svg" alt="Eight stages from a raw turn to a receipt, ending in reproduced or did not reproduce." width="100%"></p>
89
+
90
+ ## Accountability features
91
+
92
+ **A recall you can re-derive.** Every `recall` returns a receipt with the ranked
93
+ hits, their BM25 and vector scores, and the exact fusion rule. And `verify_recall`
94
+ ships the check: it re-runs the scorer over the same rows and confirms the ranking,
95
+ so a fabricated or tampered recall is caught even if its definition hash still
96
+ matches, and a store that changed no longer reproduces. The recall is auditable by a
97
+ function you can put in CI, not a claim you take on faith.
98
+
99
+ ```python
100
+ from mneme import recall, verify_recall
101
+
102
+ r = recall("deploy steps", rows, strategy="hybrid", embedder=embed)
103
+ assert verify_recall(r, rows, embedder=embed) # re-derived from the store, not trusted
104
+ ```
105
+
106
+ ```bash
107
+ mneme remember chat session.json --user alice
108
+ mneme recall "where does the user live" --user alice --json
109
+ # -> {"schema":"mneme.recall/1","hits":[{"memory_id":"…","bm25":2.14,"fused":…}],
110
+ # "recheck":"mneme recall --query Q --state DB (re-run the scorer, reproduce the ranking)"}
111
+ ```
112
+
113
+ **A drift check for source changes.** `drift` re-derives every memory's
114
+ grounding against the current store: `MATCH` (source present and unchanged),
115
+ `DRIFT` (a source changed under the memory), `UNVERIFIABLE` (a source is gone).
116
+
117
+ ```bash
118
+ mneme drift # -> {"overall":"DRIFT","drifted":["…"], …} exit 1 on drift
119
+ ```
120
+
121
+ <p align="center"><img src="docs/art/drift-lane.svg" alt="Eight stages from a stored memory to a verdict of match, drift, or unverifiable." width="100%"></p>
122
+
123
+ Two details make that verdict hard to fake. A memory row has to reproduce its own
124
+ content hash before any of its sources are looked at, which catches a direct edit
125
+ of the text, the source list, or the criterion. Each cited source is then re-hashed
126
+ from its actual fields rather than read back from the hash stored beside it,
127
+ because trusting that stored value would let someone edit the database directly,
128
+ leave a stale hash in place, and collect a `MATCH`. The check re-derives on both
129
+ sides before it will agree with itself.
130
+
131
+ The three verdicts are also ordered when they roll up across a store: any `DRIFT`
132
+ makes the whole report `DRIFT`, otherwise any `UNVERIFIABLE` makes it
133
+ `UNVERIFIABLE`, and only a clean sweep reports `MATCH`. That order fails closed. A
134
+ memory whose source has been deleted is never rounded up to a match on the grounds
135
+ that nothing contradicted it, so absence of evidence is reported as absence rather
136
+ than as agreement.
137
+
138
+ <p align="center"><img src="docs/art/grounding-verdicts.svg" alt="Nine conditions a memory's grounding check can land on, one to a row, each with the verdict it produces. Four produce DRIFT: unreadable provenance, a memory row edited in place, a source whose bytes disagree with the address it carries, and a source that hashes differently than it did at extraction. Four produce UNVERIFIABLE: a missing memory, a memory citing no sources at all, a cited source that has left the store, and a source present but never snapshotted. One produces MATCH: all cited sources are present and re-hash to what was recorded. The row for a source whose bytes disagree with the address stored beside it is accented, because that is the one case a check reading only the stored address would call a match." width="100%"></p>
139
+
140
+ Nine conditions reach one of those three verdicts, and the drawing above
141
+ lists every one of them. Four resolve to `DRIFT` and four to
142
+ `UNVERIFIABLE`. Exactly one reaches `MATCH`, which is the shape of a check
143
+ that has to earn agreement rather than assume it.
144
+
145
+ **Provenance on every memory.** Every atom names the turn it came from, the
146
+ extractor, the criterion, and a content hash. The persona is not free text: it
147
+ cites its atoms, so it is drift-checkable too.
148
+
149
+ ## Library
150
+
151
+ ```python
152
+ from mneme import AgentMemory
153
+
154
+ mem = AgentMemory("mem.db") # or ":memory:"
155
+ mem.remember("chat", [{"role": "user", "text": "I live in Denver and love dark roast."}],
156
+ user="alice")
157
+
158
+ receipt = mem.recall("coffee preference", user="alice") # RecallReceipt, re-derivable
159
+ print(mem.drift()["overall"]) # MATCH until a source changes
160
+ ```
161
+
162
+ An embedder (`AgentMemory(..., embedder=fn)`) turns on the vector channel; an
163
+ LLM `Extractor` plugs in for richer atoms. Neither is required: the
164
+ deterministic floor works with no model and no API.
165
+
166
+ ## The ecosystem: memory that traces to its source
167
+
168
+ Point mneme at an accountable intake tool ([gather](https://github.com/HarperZ9/gather),
169
+ the sibling flagship) and the provenance chain can run end to end:
170
+
171
+ ```
172
+ origin ref --(intake sha256)--> mneme turn --> mneme atom --> recall
173
+ ```
174
+
175
+ ```bash
176
+ mneme ingest research items.json --user alice # gather-shaped {id,text,source,ref,method,sha256}
177
+ mneme recall "where is the user based" --user alice
178
+ mneme chain <memory_id> # -> the supplied origin ref + intake hash
179
+ mneme origin-recheck <memory_id> --allowed-root docs/
180
+ ```
181
+
182
+ An agent that remembers what it researched, and can prove a recalled memory
183
+ traces to the receipt supplied by its intake tool. For supported local Gather
184
+ docs receipts, `origin-recheck` can re-read the operator-approved file under
185
+ `--allowed-root` and compare Gather's normalized decoded text hash. Legacy
186
+ receipts do not prove raw byte integrity, and unsupported refs remain
187
+ `UNVERIFIABLE` rather than silently promoted. `origin-recheck` opens Mneme state
188
+ read-only, refuses local path aliases and unsupported refs, and reports `MATCH`,
189
+ `DRIFT`, or `UNVERIFIABLE` without including source content in the report.
190
+ Any intake tool that emits the receipt shape composes; mneme never imports gather. Named-user `remember` and
191
+ Gather ingest derive source turn IDs from the user, session, supplied item/turn
192
+ ID, and for Gather the origin hash. The shared default user keeps the legacy
193
+ raw-ID namespace, except new default-user writes cannot use Mneme's reserved
194
+ internal source ID prefix.
195
+
196
+ And the loop closes at the other end. `mneme to-crucible` emits a schema-v2
197
+ [crucible](https://github.com/HarperZ9/crucible) export: each memory is a claim
198
+ paired with Mneme's source-bound drift measurement. Crucible independently
199
+ recomputes and seals `MATCH`, `DRIFT`, or `UNVERIFIABLE` from that measurement.
200
+ Each exported measurement now carries a declarative `mneme.recheck/1`
201
+ descriptor. After Crucible writes an assessment-bound replay template, Mneme
202
+ can re-read the supplied state and fill its replay pack without importing
203
+ Crucible or embedding a database path or executable command in the descriptor:
204
+
205
+ ```bash
206
+ crucible recheck REGISTRY --template replay-template.json
207
+ python -c "import sqlite3; s=sqlite3.connect('file:mneme.db?mode=ro', uri=True); d=sqlite3.connect('mneme-replay-snapshot.db'); s.backup(d); d.execute('PRAGMA journal_mode=DELETE'); d.close(); s.close()"
208
+ mneme --state mneme-replay-snapshot.db replay-crucible replay-template.json --out replay-pack.json
209
+ crucible recheck REGISTRY --pack replay-pack.json --json
210
+ ```
211
+
212
+ The replay command fails closed when the assessment triple, claim binding,
213
+ descriptor, original measurement contract, or target memory grounding differs.
214
+ Ordinary source drift remains a replay result (`1.0`); a missing source remains
215
+ unverifiable (`null`). Crucible still does not independently re-read Mneme's
216
+ source. The source recheck is Mneme-owned, and Crucible verifies that the
217
+ replayed measurement exactly reproduces its sealed contract.
218
+
219
+ The command consumes `crucible.replay-template/1` from a caller-owned,
220
+ quiescent, single-link rollback-journal snapshot. The example uses SQLite's
221
+ backup API to materialize one; keep that file unchanged until replay returns.
222
+
223
+ Open the source read-only when you take that snapshot, exactly as the example
224
+ does. A read-write handle on a WAL database whose writer exited without a clean
225
+ close will recover and checkpoint it: measured on Windows, that rewrote the main
226
+ file and deleted both sidecars. The read-only handle leaves the main file and
227
+ the WAL byte-identical. It can still update the `-shm` index, because SQLite
228
+ readers coordinate through shared memory. Stop source writers first when even
229
+ that is unacceptable.
230
+
231
+ Replay refuses WAL, SHM, or journal sidecars and hardlink aliases, fingerprints
232
+ the source around a consistent private SQLite backup, and reads only that
233
+ process-owned copy in immutable mode. It then verifies and preserves the compact
234
+ descriptor-only
235
+ `crucible.replay-set/1` binding, and emits `crucible.replay-pack/1`. The binding
236
+ records descriptor and skipped-row counts without disclosing descriptorless
237
+ assessment rows. Historical schema-less templates remain compatible only when
238
+ they have no replay binding and their complete measurement seal reproduces;
239
+ bound templates require the canonical schema. Read-only schema compatibility is
240
+ checked without migration, and a completed, synced pack is published atomically
241
+ without overwriting an existing path. Output paths that alias the state database
242
+ or a standard SQLite sidecar are rejected. Malformed provenance is rejected
243
+ before descriptor or pack creation. Replay does not modify the supplied
244
+ snapshot or its sidecar namespace. Changes detected while the private copy is
245
+ created fail the handoff; later source changes cannot affect that copy.
246
+
247
+ Library callers use the same contract explicitly and always close the private
248
+ snapshot owner:
249
+
250
+ ```python
251
+ memory = AgentMemory(
252
+ "mneme-replay-snapshot.db",
253
+ read_only=True,
254
+ immutable_snapshot=True,
255
+ )
256
+ try:
257
+ pack = memory.replay_crucible(template)
258
+ finally:
259
+ memory.close()
260
+ ```
261
+
262
+ ```
263
+ gather (intake) --> mneme (drift + replay) --> crucible (sealed recomputation)
264
+ ```
265
+
266
+ The export keeps measurement and assessment separate without claiming independent
267
+ source certification.
268
+
269
+ ## Accountable forgetting
270
+
271
+ Mneme deletes facts with an audit trail: `forget` and `update` leave a
272
+ hash-chained tombstone, what was forgotten, its hash, and why, so the deletion
273
+ record remains reviewable for GDPR-style "right to be forgotten" workflows.
274
+
275
+ ```bash
276
+ mneme forget <memory_id> --reason "user requested deletion"
277
+ mneme audit # -> {"entries":1,"chain_intact":true,"log":[{"op":"forget", …}]}
278
+ ```
279
+
280
+ `update` edits a memory's text while keeping its provenance and recording the
281
+ before/after hash. Tamper a tombstone and the chain breaks.
282
+
283
+ ## Agents plug in over MCP
284
+
285
+ ```bash
286
+ mneme mcp # JSON-RPC 2.0 over stdio; MNEME_STATE points at the DB
287
+ ```
288
+
289
+ The released `v0.4.2` wheel exposes the MCP memory, recall, drift, provenance, origin recheck, forget, audit, status, doctor, Crucible export, and Crucible replay tools.
290
+
291
+ MCP tools `mneme.to_crucible` and `mneme.replay_crucible` reuse the same replay library boundaries as the CLI. A recall
292
+ through MCP returns the same re-derivable receipt, so the agent (or its operator)
293
+ can see and re-check why a memory was surfaced; the accountability travels with
294
+ the tool result. `mneme.to_crucible` returns the existing
295
+ `mneme.crucible-export/2` object from the server-bound `MNEME_STATE`; MCP
296
+ callers must pass either `user` to select one tenant inside that configured
297
+ state, or `all_users: true` to deliberately export every tenant visible to the
298
+ server. Optional `session` filters must be non-empty strings; `layer` is limited
299
+ to `L1`, `L2`, or `L3`. The `user` value is a selector, not an authentication
300
+ boundary; the host still owns which state DB the server may open. Crucible
301
+ export and replay fail when `MNEME_STATE` is unset or empty. `mneme.replay_crucible`
302
+ consumes a decoded `crucible.replay-template/1` object and returns
303
+ `crucible.replay-pack/1` from the same explicitly configured state. State paths
304
+ and executable commands stay out of the untrusted recheck descriptors. All-row
305
+ templates (`skipped_count: 0`) are checked against the assessment measurement
306
+ seal. Mixed templates with skipped rows are refused until the template carries a
307
+ verifier-enforced full denominator that binds the disclosed descriptors, skipped
308
+ count, and undisclosed rows to the assessment; Mneme cannot authenticate
309
+ undisclosed rows from an external assessment from a caller-recomputed binding
310
+ alone.
311
+
312
+ ## Benchmark you can re-run
313
+
314
+ Token-reduction benchmarks are more useful when paired with answer-retention
315
+ checks. Mneme reports both for the included benchmark.
316
+
317
+ ```bash
318
+ mneme bench
319
+ # token_reduction: 76.6% (full history 125 tok -> avg recalled 29 tok)
320
+ # answer_recall: 100% (5 probes, every needed fact survived the reduction)
321
+ ```
322
+
323
+ The included reduction is reported **alongside** answer recall, so a run that
324
+ forgets required answers is visible in the result. The receipt carries the
325
+ per-probe detail and the exact token estimator, so a third party can re-run the
326
+ measurement over the same conversation and compare the number. Point it at your
327
+ own conversation with `--turns convo.json --probes probes.json`.
328
+
329
+ ## Scenarios (L2)
330
+
331
+ ```bash
332
+ mneme scenarios alice # cluster the session's atoms into scene blocks
333
+ ```
334
+
335
+ Atoms sharing a theme cluster deterministically into L2 scenarios; each scenario
336
+ cites its atoms, so it is drift-checkable too (a scenario whose atom is gone is
337
+ `UNVERIFIABLE`, never silently kept).
338
+
339
+ ## Guarantees
340
+
341
+ - **Zero runtime dependencies** (stdlib `sqlite3`). `pytest` is the only dev dep.
342
+ - **Deterministic core.** Stored hashes and default rankings are derived from
343
+ the supplied turns, so the same input rebuilds the same memory state.
344
+ - **Tests are the contract.** The core workflows above have regression coverage
345
+ with false-success controls for recall, drift, audit, and ingestion.
346
+
347
+ ## Development
348
+
349
+ For a local development checkout:
350
+
351
+ ```bash
352
+ python -m pip install -e ".[test]"
353
+ python -m pytest
354
+ ```
355
+
356
+ Use synthetic SQLite state for tests and examples. `mneme mcp` reads `MNEME_STATE`; do not point examples, demos, or interop checks at a live user database. Release publication remains gated by `DELIVERY.md`, CI, version/tag alignment, and explicit operator action.
357
+
358
+ ## License
359
+
360
+ Mneme is fair-source: open to read, run, and build on, with commercial use reserved so the project can fund its own development. See [LICENSE](LICENSE).
361
+
362
+ ## What this believes
363
+
364
+ This tool is one lane of a family that holds a single belief steady across
365
+ every surface: knowledge open to anyone who can attain the means; acceptance
366
+ decided by external checks, never reputation; every result re-runnable;
367
+ honest nulls first-class; ownership earned by comprehension; learning woven
368
+ into the work. The full text lives in [CREDO.md](CREDO.md).
369
+ The long form of this belief: [The Unbundling](https://github.com/HarperZ9/flywheel/blob/fix/release-model-identity/docs/essays/2026-07-13-the-unbundling.md).
370
+
371
+ ---
372
+
373
+ **[Zentropy Labs](https://github.com/ZentropyLabs-ai)** · order out of entropy. An independent lab building evidence-first tools that leave a re-checkable artifact behind. Built by Zain Dana Harper in Seattle. The full workbench is at [Project Telos](https://harperz9.github.io).