onemem 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. onemem-0.1.0/.github/workflows/ci.yml +41 -0
  2. onemem-0.1.0/.gitignore +27 -0
  3. onemem-0.1.0/DESIGN.md +130 -0
  4. onemem-0.1.0/LICENSE +21 -0
  5. onemem-0.1.0/PKG-INFO +171 -0
  6. onemem-0.1.0/README.md +126 -0
  7. onemem-0.1.0/bench/README.md +60 -0
  8. onemem-0.1.0/bench/answer_accuracy.py +138 -0
  9. onemem-0.1.0/bench/freeze.py +236 -0
  10. onemem-0.1.0/bench/metrics.py +84 -0
  11. onemem-0.1.0/bench/reduction.py +73 -0
  12. onemem-0.1.0/bench/reembed_strong.py +86 -0
  13. onemem-0.1.0/bench/run_bench.py +111 -0
  14. onemem-0.1.0/docs/.nojekyll +0 -0
  15. onemem-0.1.0/docs/demo-poster.jpg +0 -0
  16. onemem-0.1.0/docs/demo.mp4 +0 -0
  17. onemem-0.1.0/docs/index.html +5506 -0
  18. onemem-0.1.0/docs/meniscus-logo.png +0 -0
  19. onemem-0.1.0/onemem/__init__.py +3 -0
  20. onemem-0.1.0/onemem/api/__init__.py +1 -0
  21. onemem-0.1.0/onemem/api/app.py +42 -0
  22. onemem-0.1.0/onemem/api/events.py +66 -0
  23. onemem-0.1.0/onemem/chunker.py +72 -0
  24. onemem-0.1.0/onemem/cli/__init__.py +1 -0
  25. onemem-0.1.0/onemem/cli/main.py +2011 -0
  26. onemem-0.1.0/onemem/config.py +141 -0
  27. onemem-0.1.0/onemem/db.py +229 -0
  28. onemem-0.1.0/onemem/embedding_interface.py +28 -0
  29. onemem-0.1.0/onemem/entity_extractor.py +153 -0
  30. onemem-0.1.0/onemem/event_intake.py +143 -0
  31. onemem-0.1.0/onemem/exceptions.py +29 -0
  32. onemem-0.1.0/onemem/fact_retrieval.py +784 -0
  33. onemem-0.1.0/onemem/home.py +49 -0
  34. onemem-0.1.0/onemem/mcp_server.py +214 -0
  35. onemem-0.1.0/onemem/model_interface.py +22 -0
  36. onemem-0.1.0/onemem/models.py +19 -0
  37. onemem-0.1.0/onemem/onemem_types.py +12 -0
  38. onemem-0.1.0/onemem/pipeline.py +392 -0
  39. onemem-0.1.0/onemem/provider_defaults.toml +9 -0
  40. onemem-0.1.0/onemem/providers/__init__.py +167 -0
  41. onemem-0.1.0/onemem/providers/_schema.py +34 -0
  42. onemem-0.1.0/onemem/providers/anthropic.py +116 -0
  43. onemem-0.1.0/onemem/providers/local_embedding.py +99 -0
  44. onemem-0.1.0/onemem/providers/openai_compat.py +147 -0
  45. onemem-0.1.0/onemem/schema.sql +102 -0
  46. onemem-0.1.0/onemem/spend_gate.py +55 -0
  47. onemem-0.1.0/onemem/startup.py +24 -0
  48. onemem-0.1.0/onemem/time_bounds.py +53 -0
  49. onemem-0.1.0/onemem/tokens.py +8 -0
  50. onemem-0.1.0/onemem/transcript_ingest.py +132 -0
  51. onemem-0.1.0/onemem/vocab_reconciliation.py +85 -0
  52. onemem-0.1.0/onemem-plugin/.claude-plugin/plugin.json +9 -0
  53. onemem-0.1.0/pyproject.toml +67 -0
  54. onemem-0.1.0/scripts/dev-onemem +7 -0
  55. onemem-0.1.0/tests/__init__.py +1 -0
  56. onemem-0.1.0/tests/conftest.py +31 -0
  57. onemem-0.1.0/tests/test_chunker.py +19 -0
  58. onemem-0.1.0/tests/test_cli.py +805 -0
  59. onemem-0.1.0/tests/test_config.py +46 -0
  60. onemem-0.1.0/tests/test_db.py +268 -0
  61. onemem-0.1.0/tests/test_entity_extractor.py +91 -0
  62. onemem-0.1.0/tests/test_event_intake.py +65 -0
  63. onemem-0.1.0/tests/test_fact_retrieval.py +257 -0
  64. onemem-0.1.0/tests/test_mcp_contract.py +43 -0
  65. onemem-0.1.0/tests/test_models.py +28 -0
  66. onemem-0.1.0/tests/test_pipeline.py +124 -0
  67. onemem-0.1.0/tests/test_providers.py +115 -0
  68. onemem-0.1.0/tests/test_retrieval.py +116 -0
  69. onemem-0.1.0/tests/test_spend_gate.py +94 -0
  70. onemem-0.1.0/tests/test_time_bounds.py +24 -0
  71. onemem-0.1.0/tests/test_types.py +8 -0
  72. onemem-0.1.0/tests/test_vocab_reconciliation.py +103 -0
  73. onemem-0.1.0/tests/test_workflow.py +90 -0
  74. onemem-0.1.0/uv.lock +2397 -0
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, release-prep]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-python@v5
14
+ with:
15
+ python-version: "3.11"
16
+ - name: Install (all extras + dev)
17
+ run: pip install -e ".[all,dev]"
18
+ - name: Run tests
19
+ run: pytest -q
20
+ - name: CLI entry point
21
+ run: men --help
22
+
23
+ clean-install:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: actions/setup-python@v5
28
+ with:
29
+ python-version: "3.11"
30
+ - name: Build wheel
31
+ run: |
32
+ pip install build
33
+ python -m build
34
+ - name: Install the built wheel with extras
35
+ run: |
36
+ WHEEL=$(ls dist/*.whl)
37
+ pip install "${WHEEL}[all]"
38
+ - name: Verify entry points and imports
39
+ run: |
40
+ men --help
41
+ python -c "import onemem, onemem.config, onemem.db, onemem.fact_retrieval, onemem.mcp_server, onemem.pipeline"
@@ -0,0 +1,27 @@
1
+ .env
2
+
3
+ # python
4
+ __pycache__/
5
+ *.pyc
6
+ .venv/
7
+ venv/
8
+ .meniscus-dev/
9
+ .pytest_cache/
10
+ *.egg-info/
11
+ .DS_Store
12
+
13
+ .mcp.json
14
+
15
+ # benchmark data & frozen memories (large; regenerable via bench/)
16
+ bench/data/
17
+ bench/out/
18
+ bench/memories*/
19
+ bench/*.log
20
+
21
+ demo/
22
+
23
+ notes/
24
+
25
+ # build artifacts
26
+ /dist/
27
+ /build/
onemem-0.1.0/DESIGN.md ADDED
@@ -0,0 +1,130 @@
1
+ # oneMEM — Design
2
+
3
+ A local, structured, long-term memory for AI agents and people. oneMEM receives
4
+ unstructured text (chat turns, notes, imported files), distills it into **atomic facts**,
5
+ stores everything **append-only** in one SQLite file, and makes it retrievable through a
6
+ **deterministic hybrid search** — no LLM in the read path. Any MCP-capable agent reads and
7
+ writes the same memory.
8
+
9
+ ---
10
+
11
+ ## 1. Principles
12
+
13
+ - **Append-only.** Raw events are never overwritten or deleted. Facts are only ever added.
14
+ Every fact traces back to the exact source event it came from, so nothing is lost and
15
+ everything is recoverable.
16
+ - **Deterministic retrieval.** Reading memory is a fixed formula over indexes — no model
17
+ call. The same query against the same data always returns the same result, and every
18
+ ranking decision is inspectable with plain SQL.
19
+ - **Local and single-file.** One SQLite database on the user's machine. No server, no
20
+ cloud, no account. Back it up by copying a file.
21
+ - **Small models at the edges.** An LLM is used only at *write* time (to distill facts) and
22
+ optionally at *read* time (to phrase an answer). The retrieval itself never calls a model,
23
+ so a small/cheap model is enough and nothing heavy runs locally.
24
+
25
+ ## 2. Data model
26
+
27
+ All state lives in one SQLite file:
28
+
29
+ - **`events`** — raw ingested content, verbatim, timestamped, with a `source`. The source of
30
+ truth. `extraction_status` tracks whether facts have been distilled yet.
31
+ - **`facts`** — atomic statements distilled from an event by the LLM. Each fact links to its
32
+ `event_id` (provenance) and carries its text and position.
33
+ - **`entities`** — canonical named things (people, projects, tools) with a normalized form
34
+ for matching; `entity_aliases` maps surface variants to a canonical entity.
35
+ - **`fact_entity_edges`** — which entities each fact mentions (the entity retrieval door).
36
+ - **`extractions`** — one row per distillation run (provider, model, prompt version), so the
37
+ provenance of every fact is auditable.
38
+ - **`fact_embeddings`** — a `sqlite-vec` (vec0) virtual table holding each fact's vector.
39
+ - **`facts_fts`** — an FTS5 virtual table over fact text (the keyword door), kept in sync.
40
+
41
+ Facts and their embeddings/edges are only appended. Correcting the record means adding a new
42
+ event, never mutating an old one.
43
+
44
+ ## 3. Ingestion pipeline
45
+
46
+ 1. **Intake** — content is stored as one or more `events` (large inputs are chunked). Intake
47
+ always commits first, so an event is durable even if distillation later fails. Duplicate
48
+ content is deduplicated by a content hash of `(source, content)`.
49
+ 2. **Distillation** — a small LLM (via whichever provider is configured — see §7) reads each
50
+ pending event and extracts atomic facts. Filler turns with nothing worth keeping produce
51
+ zero facts and are marked complete (not retried forever).
52
+ 3. **Entity reconciliation** — entities named by the facts are resolved to canonical rows
53
+ (via normalization + aliases) and linked through `fact_entity_edges`.
54
+ 4. **Embedding** — each fact is embedded locally with `bge-base-en-v1.5` (768-d) and written
55
+ to `fact_embeddings`; `facts_fts` indexes the text.
56
+
57
+ Processing runs as a parallel batch and is resumable: if the model becomes unavailable,
58
+ processed events stay done and the rest remain pending for the next run.
59
+
60
+ ## 4. Retrieval — deterministic hybrid fusion
61
+
62
+ Retrieval scores candidate facts through three independent **doors**, then fuses them. No
63
+ model is involved.
64
+
65
+ - **Vector door** — cosine similarity between the query embedding and each fact embedding.
66
+ Queries are embedded with an instruction prefix; facts are embedded plain. A wide candidate
67
+ pool is fetched (far more than the return limit) so fusion sees a broad set.
68
+ - **Keyword door** — FTS5 (BM25) over fact text. The query is tokenized and OR-matched, so a
69
+ fact matching *any* term is a candidate; the fact's *rank position* feeds fusion.
70
+ - **Entity door** — facts linked to an explicitly named entity (used when a caller passes an
71
+ entity argument).
72
+
73
+ **Fusion (magnitude noisy-OR).** Each door contributes independently; a single strong door
74
+ can win on its own merit:
75
+
76
+ ```
77
+ fused = 1 − (1 − W_VECTOR·vector) · (1 − W_FTS·fts) · (1 − W_ENTITY·entity)
78
+ ```
79
+
80
+ where `vector` is the raw cosine, `fts` is a reciprocal-rank term `RRF_K/(RRF_K + position)`,
81
+ and `entity` is 1 if the entity door matched. Vector is the senior partner; keyword is a
82
+ booster/tiebreaker.
83
+
84
+ **Adaptive cut.** Results are sorted by fused score and cut on the *shape* of the curve, not
85
+ a fixed `k`: keep every fact scoring at least a ratio of the top score, bounded to
86
+ `[MIN_RETURN, limit]`. A sharp, specific query returns a tight set; a broad query returns
87
+ more. Counting/enumeration questions (detected by trigger phrases like "how many", "every")
88
+ bypass the ratio cut and return the whole plateau.
89
+
90
+ **Source collapse.** If the facts selected from one event cost as many tokens as the raw
91
+ event, the raw event is returned instead — full fidelity when distillation didn't save
92
+ anything.
93
+
94
+ ## 5. Episodic reconstruction
95
+
96
+ oneMEM does **not** store episodes or threads. Instead, "what happened around this moment"
97
+ is reconstructed *at read time*: given an anchor (a matched fact, an event id, or a
98
+ timestamp), events in a time window are segmented into sessions by gaps longer than
99
+ `SESSION_GAP_SECONDS`, and the relevant segment is returned with its facts. Episodes are a
100
+ read-time view over the append-only events, never materialized state.
101
+
102
+ ## 6. Interfaces
103
+
104
+ - **CLI (`men`)** — `init` (interactive setup: provider, key, capture, MCP wiring), `add`,
105
+ `import`, `process`, `ask`, `watch` (silent transcript capture), `sql`, `tables`, `status`,
106
+ `doctor`, `help`, and event inspection (`list events`, `show event`). `men ask` plans a
107
+ query, retrieves deterministically, and phrases an answer.
108
+ - **MCP** — exactly **two** tools, so an agent's surface stays minimal:
109
+ - `onemem_recall` — the single read entry point. One call; the argument selects the
110
+ operation (topic search, a time window, a reconstructed session, or the raw source
111
+ behind a fact). Returns structured facts with timestamps and source ids — not a finished
112
+ answer.
113
+ - `onemem_log` — an invisible background write; the agent logs what's worth remembering
114
+ without announcing it.
115
+
116
+ ## 7. Providers
117
+
118
+ - **LLM** — bring your own key. Any OpenAI-compatible backend works (OpenRouter, OpenAI,
119
+ Gemini, Groq, xAI, Hugging Face, a local Ollama server, or any other OpenAI-compatible
120
+ endpoint via `provider = "custom"`); Anthropic is wired separately against Claude's native
121
+ API.
122
+ - **Embeddings** — `bge-base-en-v1.5` run **locally** (768-d), no API. Query embeddings use a
123
+ retrieval instruction prefix.
124
+
125
+ ## 8. What makes it inspectable
126
+
127
+ Because it is one SQLite file and retrieval is a fixed formula, nothing is hidden. `men sql`
128
+ and `men tables` expose the raw events, facts, entities, edges, and scores — the exact data
129
+ an agent sees. Every fact links to its source event; every extraction records the model that
130
+ produced it. Memory you can audit is memory you can trust.
onemem-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 magic_bubblez
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.
onemem-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.5
2
+ Name: onemem
3
+ Version: 0.1.0
4
+ Summary: One memory. Every AI. You own it. — Local structured memory for AI agents
5
+ Project-URL: Homepage, https://github.com/YOUR_USERNAME/onemem
6
+ Project-URL: Repository, https://github.com/YOUR_USERNAME/onemem
7
+ Project-URL: Issues, https://github.com/YOUR_USERNAME/onemem/issues
8
+ Author: oneMEM
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai-agents,llm,long-term-memory,mcp,memory,retrieval,sqlite
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: click>=8.0
23
+ Requires-Dist: pydantic>=2.0
24
+ Requires-Dist: python-dotenv>=1.0
25
+ Requires-Dist: requests>=2.0
26
+ Provides-Extra: all
27
+ Requires-Dist: fastapi>=0.100; extra == 'all'
28
+ Requires-Dist: mcp[cli]<2,>=1.27; extra == 'all'
29
+ Requires-Dist: sentence-transformers>=2.0; extra == 'all'
30
+ Requires-Dist: sqlite-vec>=0.1; extra == 'all'
31
+ Requires-Dist: uvicorn>=0.20; extra == 'all'
32
+ Provides-Extra: api
33
+ Requires-Dist: fastapi>=0.100; extra == 'api'
34
+ Requires-Dist: uvicorn>=0.20; extra == 'api'
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.0; extra == 'dev'
38
+ Provides-Extra: local-embedding
39
+ Requires-Dist: sentence-transformers>=2.0; extra == 'local-embedding'
40
+ Provides-Extra: mcp
41
+ Requires-Dist: mcp[cli]<2,>=1.27; extra == 'mcp'
42
+ Provides-Extra: vec
43
+ Requires-Dist: sqlite-vec>=0.1; extra == 'vec'
44
+ Description-Content-Type: text/markdown
45
+
46
+ <div align="center">
47
+
48
+ # oneMEM
49
+
50
+ ### One memory. Every AI. You own it.
51
+
52
+ Local, structured memory for AI agents—in one SQLite file on your machine.
53
+
54
+ [![PyPI](https://img.shields.io/pypi/v/onemem?label=PyPI&color=6C3AED)](https://pypi.org/project/onemem/)
55
+ [![License: MIT](https://img.shields.io/badge/license-MIT-14B8A6)](LICENSE)
56
+
57
+ </div>
58
+
59
+ oneMEM gives AI tools a shared local memory. It turns useful context into compact facts and surfaces the minimum amount of memory sufficient for a query. Every connected agent reads and writes the same SQLite file.
60
+
61
+ ```text
62
+ AI agents ───┐
63
+ Code editors ┼── MCP ── oneMEM ── ~/.onemem/onemem.db
64
+ Local tools ─┘
65
+ ```
66
+
67
+ ## Install
68
+
69
+ oneMEM requires Python 3.11 or newer and an API key for any supported language-model provider. Embeddings run locally; there is no embedding service or API key to configure.
70
+
71
+ ```console
72
+ uv tool install "onemem[all]"
73
+ onemem init
74
+ ```
75
+
76
+ `onemem init` does the rest:
77
+
78
+ 1. asks which model provider you want to use;
79
+ 2. recommends a model or lets you enter another model ID;
80
+ 3. verifies the key and model before saving them;
81
+ 4. initializes the local database and embedding model;
82
+ 5. offers background capture; and
83
+ 6. connects detected AI tools over MCP.
84
+
85
+ Nothing is uploaded to a oneMEM server. Configuration and credentials stay under `~/.onemem/`; the API key is sent only to the provider you select.
86
+
87
+ ## Try it
88
+
89
+ Add something directly:
90
+
91
+ ```console
92
+ onemem add "Chose SQLite because it needs zero operations and one-file backups."
93
+ ```
94
+
95
+ Ask for it later:
96
+
97
+ ```console
98
+ onemem ask "What storage did I choose, and why?"
99
+ ```
100
+
101
+ Or ask from a connected agent. It receives two MCP tools:
102
+
103
+ - `onemem_recall` retrieves relevant memory.
104
+ - `onemem_log` stores something worth remembering.
105
+
106
+ ## MCP setup
107
+
108
+ oneMEM works with any client that can run a local `stdio` MCP server, including Claude Code, Codex, Cursor, and Windsurf. `onemem init` automatically configures clients whose command-line tools it detects; other clients only need the `onemem-mcp` executable path.
109
+
110
+ ```console
111
+ claude mcp add --scope user onemem -- "$(command -v onemem-mcp)"
112
+ codex mcp add onemem -- "$(command -v onemem-mcp)"
113
+ ```
114
+
115
+ ## Commands
116
+
117
+ | Command | Purpose |
118
+ |---|---|
119
+ | `onemem init` | Complete interactive setup |
120
+ | `onemem add "memory"` | Store one note or observation |
121
+ | `onemem ask "question"` | Retrieve relevant facts and answer a question |
122
+ | `onemem watch --start` | Start capturing in the background |
123
+ | `onemem doctor` | Check the environment |
124
+ | `onemem status` | Show event, fact, entity counts |
125
+
126
+ ## Where data lives
127
+
128
+ | Path | Contents |
129
+ |---|---|
130
+ | `~/.onemem/onemem.db` | Events, facts, entities, embeddings |
131
+ | `~/.onemem/config.toml` | Active provider, model, and runtime settings |
132
+ | `~/.onemem/.env` | Provider API keys |
133
+
134
+ ## How retrieval works
135
+
136
+ ```text
137
+ session or imported text
138
+
139
+ append-only raw event
140
+
141
+ compact facts + local embeddings + entity anchors
142
+
143
+ deterministic fusion of semantic, keyword, and entity retrieval
144
+
145
+ minimum relevant memory returned to the agent
146
+ ```
147
+
148
+ oneMEM uses an LLM only to interpret and compact language and, optionally, to synthesize the final answer. Storage, indexing, and retrieval are ordinary code.
149
+
150
+ ## Benchmarks
151
+
152
+ Measured on a 100-instance stratified sample of [LongMemEval-S](https://arxiv.org/abs/2410.10813):
153
+
154
+ | Metric | Result |
155
+ |---|---:|
156
+ | Retrieval recall | **0.89** |
157
+ | Context reduction | **99.1%** |
158
+ | End-to-end answer accuracy | **72%** |
159
+
160
+ ## Development
161
+
162
+ ```console
163
+ git clone https://github.com/YOUR_USERNAME/onemem.git
164
+ cd onemem
165
+ uv sync --all-extras
166
+ uv run pytest -q
167
+ ```
168
+
169
+ ## License
170
+
171
+ MIT — Based on [Meniscus](https://github.com/magic-bubblez/meniscus) by magic_bubblez.
onemem-0.1.0/README.md ADDED
@@ -0,0 +1,126 @@
1
+ <div align="center">
2
+
3
+ # oneMEM
4
+
5
+ ### One memory. Every AI. You own it.
6
+
7
+ Local, structured memory for AI agents—in one SQLite file on your machine.
8
+
9
+ [![PyPI](https://img.shields.io/pypi/v/onemem?label=PyPI&color=6C3AED)](https://pypi.org/project/onemem/)
10
+ [![License: MIT](https://img.shields.io/badge/license-MIT-14B8A6)](LICENSE)
11
+
12
+ </div>
13
+
14
+ oneMEM gives AI tools a shared local memory. It turns useful context into compact facts and surfaces the minimum amount of memory sufficient for a query. Every connected agent reads and writes the same SQLite file.
15
+
16
+ ```text
17
+ AI agents ───┐
18
+ Code editors ┼── MCP ── oneMEM ── ~/.onemem/onemem.db
19
+ Local tools ─┘
20
+ ```
21
+
22
+ ## Install
23
+
24
+ oneMEM requires Python 3.11 or newer and an API key for any supported language-model provider. Embeddings run locally; there is no embedding service or API key to configure.
25
+
26
+ ```console
27
+ uv tool install "onemem[all]"
28
+ onemem init
29
+ ```
30
+
31
+ `onemem init` does the rest:
32
+
33
+ 1. asks which model provider you want to use;
34
+ 2. recommends a model or lets you enter another model ID;
35
+ 3. verifies the key and model before saving them;
36
+ 4. initializes the local database and embedding model;
37
+ 5. offers background capture; and
38
+ 6. connects detected AI tools over MCP.
39
+
40
+ Nothing is uploaded to a oneMEM server. Configuration and credentials stay under `~/.onemem/`; the API key is sent only to the provider you select.
41
+
42
+ ## Try it
43
+
44
+ Add something directly:
45
+
46
+ ```console
47
+ onemem add "Chose SQLite because it needs zero operations and one-file backups."
48
+ ```
49
+
50
+ Ask for it later:
51
+
52
+ ```console
53
+ onemem ask "What storage did I choose, and why?"
54
+ ```
55
+
56
+ Or ask from a connected agent. It receives two MCP tools:
57
+
58
+ - `onemem_recall` retrieves relevant memory.
59
+ - `onemem_log` stores something worth remembering.
60
+
61
+ ## MCP setup
62
+
63
+ oneMEM works with any client that can run a local `stdio` MCP server, including Claude Code, Codex, Cursor, and Windsurf. `onemem init` automatically configures clients whose command-line tools it detects; other clients only need the `onemem-mcp` executable path.
64
+
65
+ ```console
66
+ claude mcp add --scope user onemem -- "$(command -v onemem-mcp)"
67
+ codex mcp add onemem -- "$(command -v onemem-mcp)"
68
+ ```
69
+
70
+ ## Commands
71
+
72
+ | Command | Purpose |
73
+ |---|---|
74
+ | `onemem init` | Complete interactive setup |
75
+ | `onemem add "memory"` | Store one note or observation |
76
+ | `onemem ask "question"` | Retrieve relevant facts and answer a question |
77
+ | `onemem watch --start` | Start capturing in the background |
78
+ | `onemem doctor` | Check the environment |
79
+ | `onemem status` | Show event, fact, entity counts |
80
+
81
+ ## Where data lives
82
+
83
+ | Path | Contents |
84
+ |---|---|
85
+ | `~/.onemem/onemem.db` | Events, facts, entities, embeddings |
86
+ | `~/.onemem/config.toml` | Active provider, model, and runtime settings |
87
+ | `~/.onemem/.env` | Provider API keys |
88
+
89
+ ## How retrieval works
90
+
91
+ ```text
92
+ session or imported text
93
+
94
+ append-only raw event
95
+
96
+ compact facts + local embeddings + entity anchors
97
+
98
+ deterministic fusion of semantic, keyword, and entity retrieval
99
+
100
+ minimum relevant memory returned to the agent
101
+ ```
102
+
103
+ oneMEM uses an LLM only to interpret and compact language and, optionally, to synthesize the final answer. Storage, indexing, and retrieval are ordinary code.
104
+
105
+ ## Benchmarks
106
+
107
+ Measured on a 100-instance stratified sample of [LongMemEval-S](https://arxiv.org/abs/2410.10813):
108
+
109
+ | Metric | Result |
110
+ |---|---:|
111
+ | Retrieval recall | **0.89** |
112
+ | Context reduction | **99.1%** |
113
+ | End-to-end answer accuracy | **72%** |
114
+
115
+ ## Development
116
+
117
+ ```console
118
+ git clone https://github.com/YOUR_USERNAME/onemem.git
119
+ cd onemem
120
+ uv sync --all-extras
121
+ uv run pytest -q
122
+ ```
123
+
124
+ ## License
125
+
126
+ MIT — Based on [Meniscus](https://github.com/magic-bubblez/meniscus) by magic_bubblez.
@@ -0,0 +1,60 @@
1
+ # Benchmarks
2
+
3
+ oneMEM is measured on [LongMemEval-S](https://arxiv.org/abs/2410.10813), a long-term-memory
4
+ benchmark of long chat histories with labelled evidence turns. The headline numbers in the
5
+ top-level README come from the scripts here, on a 100-instance stratified sample.
6
+
7
+ ## Reproducing the numbers
8
+
9
+ ### 1. Get the dataset
10
+
11
+ Download LongMemEval-S (`longmemeval_s.json`) from the official release linked in the
12
+ [paper](https://arxiv.org/abs/2410.10813) and place it at:
13
+
14
+ ```
15
+ bench/data/longmemeval_s.json
16
+ ```
17
+
18
+ ### 2. Build the frozen memories (one-time; costs LLM calls)
19
+
20
+ Building a memory runs one extraction call per chat turn, so we build once and persist each
21
+ instance to `bench/memories/<id>.db` (plus a `.json` sidecar). Every later retrieval experiment
22
+ runs against these frozen memories with **zero** LLM calls, so any measured difference is purely
23
+ the retrieval config.
24
+
25
+ ```bash
26
+ export OPENROUTER_API_KEY="sk-..."
27
+ # The published numbers used deepseek-v4-flash as the extraction model:
28
+ ONEMEM_FREEZE_MODEL=deepseek/deepseek-v4-flash python bench/freeze.py bench/data/longmemeval_s.json 100
29
+ ```
30
+
31
+ The run is spend-guarded (`MAX_RUN_COST_USD` in `config.py`) and resumable — rerun to continue.
32
+ Frozen memories are gitignored (large); you rebuild them locally.
33
+
34
+ ### 3. Retrieval metrics (free — no LLM)
35
+
36
+ ```bash
37
+ python bench/metrics.py # recall + set-complete (all@k) per question type -> 0.89 recall
38
+ python bench/reduction.py # injected vs full-history tokens -> ~99.1% reduction
39
+ ```
40
+
41
+ ### 4. End-to-end answer accuracy (small; spend-capped)
42
+
43
+ A reader model answers from the retrieved facts; a judge model grades it against the gold answer.
44
+ Both are set via env vars, and the run is capped at `$2` (`MAX_EVAL_COST_USD`).
45
+
46
+ ```bash
47
+ EVAL_READER=openai/gpt-5 python bench/answer_accuracy.py # strong reader -> 72%
48
+ python bench/answer_accuracy.py # default small reader -> ~54%
49
+ ```
50
+
51
+ ## Which script substantiates which number
52
+
53
+ | Claim | Script | Notes |
54
+ |---|---|---|
55
+ | Retrieval recall 0.89 | `bench/metrics.py` | fraction of gold evidence in the returned set |
56
+ | Context reduction ~99.1% | `bench/reduction.py` | 1 − injected/full-history tokens |
57
+ | Answer accuracy 72% / ~54% | `bench/answer_accuracy.py` | 72% with a GPT-5 reader, ~54% with a small reader; LLM-judged |
58
+
59
+ `metrics.py` and `reduction.py` call `search_facts` directly and make no LLM calls, so they are
60
+ fully deterministic and reproduce exactly on identical frozen memories.