sqlite-graph-memory 0.3.0__py3-none-any.whl

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.
@@ -0,0 +1,452 @@
1
+ Metadata-Version: 2.5
2
+ Name: sqlite-graph-memory
3
+ Version: 0.3.0
4
+ Summary: Associative memory for LLM agents: Graph RAG over a folder of markdown notes, in one SQLite file, with no server to run.
5
+ Project-URL: Homepage, https://github.com/tonydzi/sqlite-graph-memory
6
+ Project-URL: Repository, https://github.com/tonydzi/sqlite-graph-memory
7
+ Project-URL: Changelog, https://github.com/tonydzi/sqlite-graph-memory/blob/main/CHANGELOG.md
8
+ Project-URL: Issues, https://github.com/tonydzi/sqlite-graph-memory/issues
9
+ Author: Anton Dziatkovskii
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 Palo Alto AI Research Lab
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: agent-memory,graph-rag,llm-memory,mcp,obsidian,rag,retrieval,second-brain,sqlite,wikilinks
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Programming Language :: Python :: 3.9
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
42
+ Classifier: Topic :: Text Processing :: Indexing
43
+ Requires-Python: >=3.9
44
+ Requires-Dist: numpy>=1.24
45
+ Provides-Extra: embeddings
46
+ Requires-Dist: numpy<2; (sys_platform == 'darwin' and platform_machine == 'x86_64') and extra == 'embeddings'
47
+ Requires-Dist: sentence-transformers>=2.6; extra == 'embeddings'
48
+ Description-Content-Type: text/markdown
49
+
50
+ # sqlite-graph-memory
51
+
52
+ **Your agent forgets everything between sessions, and plain vector search gives it back
53
+ flat, unrelated chunks. This gives it associative recall over your own markdown notes —
54
+ one SQLite file, no graph database, no ETL pass, no server.**
55
+
56
+ ```bash
57
+ pip install sqlite-graph-memory
58
+ ```
59
+
60
+ > The first PyPI release has not landed yet (the publish workflow is in place).
61
+ > Until it does: `pip install git+https://github.com/tonydzi/sqlite-graph-memory`
62
+ > — same package, same five commands.
63
+
64
+ Graph RAG on SQLite for AI agents — a working pilot, not a framework. It is the extracted
65
+ memory layer of a personal "second brain" agent setup: vector search finds the entry
66
+ points, the `[[wikilinks]]` you already wrote by hand are the graph, and a cross-encoder
67
+ reranks what the hop dragged in.
68
+ SQLite is the only database ([`schema.sql`](src/sqlite_graph_memory/schema.sql)).
69
+
70
+ Status: **pilot**, and the word is load-bearing: it runs daily in one real setup (a ~100k-note
71
+ Obsidian vault driven by Claude Code), but it is deliberately minimal and makes no attempt
72
+ to be general — see [What's intentionally missing](#whats-intentionally-missing), which is
73
+ where the uneven test coverage is described.
74
+ Published as the companion code for an upcoming write-up on lightweight Graph RAG for agents;
75
+ the one design note that is already written is [`docs/bitemporal.md`](docs/bitemporal.md).
76
+
77
+ ## Why
78
+
79
+ Most Graph RAG stacks assume a graph database, an ETL pipeline, and an entity-extraction pass —
80
+ HippoRAG ([arXiv:2405.14831](https://arxiv.org/abs/2405.14831)) derives its KG that way, and
81
+ Graphiti/Zep maintain a temporal one.
82
+ For a single-user agent over a markdown knowledge base, all three are overkill:
83
+
84
+ - The **graph already exists** — Obsidian/Logseq/plain-markdown users hand-curate their
85
+ edges as `[[wikilinks]]`, and `brain_ask.py` just parses them.
86
+ No extraction pass, and edge quality beats anything a model would mine.
87
+ - **SQLite is enough** — the only things worth persisting are derived state (a per-turn
88
+ ledger) and telemetry, and both are defined in [`schema.sql`](schema.sql).
89
+ One file, stdlib driver, zero ops.
90
+ - The expensive part of RAG quality is a **reranker**, not graph infrastructure — see the
91
+ rerank step in `brain_ask.py`.
92
+
93
+ So the pilot's bet: *vector retrieval for entry points, hand-curated wikilinks for
94
+ association, a cross-encoder to keep serendipity honest, SQLite for everything that must
95
+ persist.* All four steps live in one file, `brain_ask.py`, in that order.
96
+
97
+ ## Architecture
98
+
99
+ Three layers, three failure-isolated components:
100
+
101
+ ```
102
+ markdown notes (with [[wikilinks]])
103
+ │
104
+ ├── index_notes.py chunk + embed (e5-base) → .npy/.pkl index
105
+ │
106
+ ├── brain_ask.py recall pipeline:
107
+ │ 1. dense retrieve top-60 chunks, dedup by file
108
+ │ 2. --graph +1-hop wikilink neighbours of top-15 hits (max 40)
109
+ │ 3. rerank cross-encoder → top-12
110
+ │ 4. --ab run vector-only AND vector+graph, diff,
111
+ │ log the delta to SQLite (ab_recall)
112
+ │
113
+ └── turnstate_hook.py agent Stop-hook: after every assistant turn,
114
+ parse the transcript tail and append one row
115
+ (ask, summary, files, tools, commands, decisions)
116
+ to SQLite (turns). 0 LLM tokens, pure stdlib.
117
+ turnstate_show.py = read-only viewer.
118
+ ```
119
+
120
+ [`schema.sql`](schema.sql) documents both tables. The graph is **not** materialized in SQL:
121
+ `brain_ask.py` parses edges from the notes at query time, bounded to 1 hop / 40 neighbours.
122
+ That keeps the graph permanently in sync with the notes at zero maintenance cost; materialize
123
+ an edge table only when hop depth or corpus size demands it.
124
+
125
+ ### Design choices that survived contact with reality
126
+
127
+ - **Graph expansion is candidate generation, not ranking** (`brain_ask.py`). Neighbours go
128
+ into the same reranker pool as vector hits, so an irrelevant linked note gets buried.
129
+ That is what makes 1-hop expansion safe to leave on.
130
+ - **Entity gate** (`looks_like_entity` in `brain_ask.py`). A/B telemetry showed graph
131
+ expansion helps *theme* queries ("approaches to agent memory") but hurts *name/tool*
132
+ lookups ("NotebookLM"): a name's card links to everything, so the hop pulls in noise.
133
+ The heuristic in `brain_ask.py` is deliberately conservative, and switches the graph off
134
+ only for name-shaped queries.
135
+ - **Crash-safety as a policy.** The graph hop (`brain_ask.py`) and the Stop-hook
136
+ (`turnstate_hook.py`) are both wrapped, so any failure degrades to the previous behavior:
137
+ vector-only recall, no ledger row.
138
+ A memory layer must never make the agent worse than having no memory layer.
139
+ - **Measure, don't believe.** `--ab` runs both pipelines on every real query and logs how
140
+ many notes the graph promoted into the top-N, to `ab_recall` in [`schema.sql`](schema.sql).
141
+ Whether "associative memory" earns its keep is a weekly SQL query, not a vibe.
142
+
143
+ ### What's intentionally missing
144
+
145
+ - No entity lane. The production setup has an extra retrieval lane over people/project
146
+ cards; it is too entangled with personal data to publish.
147
+ - No incremental indexing and no packaging. There IS an eval suite now — see
148
+ [Measure before you swap](#measure-before-you-swap--eval) — but it scores retrieval on
149
+ wikilink-derived gold, which is weak supervision and says so out loud. Test coverage is uneven:
150
+ `index_notes.py`, `brain_ask.py` and `mcp_server.py` have unit tests, `turnstate_hook.py`
151
+ has none. Run `pytest -q` for the current count rather than trusting a number written in
152
+ prose here — that is how this file ended up claiming "no tests" while seven were passing.
153
+ The status line above says **pilot** on purpose.
154
+
155
+ ## Quickstart
156
+
157
+ ```bash
158
+ # Indexing and reranking need the embedding stack; the base install leaves it out
159
+ # so that `pip install sqlite-graph-memory` stays small instead of pulling ~2 GB
160
+ # of torch. Ask for it explicitly:
161
+ pip install 'sqlite-graph-memory[embeddings]'
162
+
163
+ # 1. index a folder of markdown notes
164
+ sgm-index /path/to/notes
165
+
166
+ # 2. ask, three ways
167
+ sgm-ask "how do I think about agent memory"
168
+ sgm-ask --graph "how do I think about agent memory"
169
+ sgm-ask --ab "how do I think about agent memory" # logs the diff to SQLite
170
+
171
+ # 3. inspect the A/B telemetry
172
+ sqlite3 turnstate.db "select ts, query, new_in_top, promoted_via_graph from ab_recall order by id desc limit 10"
173
+ ```
174
+
175
+ Run any of them on a base install and they tell you which extra is missing rather than
176
+ raising `ModuleNotFoundError` — that path is covered by `tests/test_optional_extra.py`.
177
+
178
+ To enable the per-turn ledger in Claude Code, register the Stop hook (the exact block is
179
+ `examples/claude-code-stop-hook.json`, which calls `sgm-turnstate-hook`), then:
180
+
181
+ ```bash
182
+ sgm-turnstate-show --stats
183
+ ```
184
+
185
+ Working from a clone instead of an install? `pip install -e '.[embeddings]'` gives you the
186
+ same four commands, and the modules stay importable as
187
+ `from sqlite_graph_memory import brain_ask`.
188
+
189
+ Configuration is env-only and every variable is listed in `.env.example`; everything
190
+ defaults to the current directory. GPU is used automatically if a CUDA torch build is
191
+ present, and CPU works fine for small corpora.
192
+
193
+ ### What `--ab` looks like
194
+
195
+ Output of `brain_ask.py` with `--ab`, on a toy 4-note corpus (real runs use a ~100k-note vault):
196
+
197
+ ```
198
+ A/B RECALL: how should agent memory work
199
+ (Direct=4 vector / Associative=+0 graph; Associative promoted 0 new notes into top-12, 0 of them via graph)
200
+
201
+ --- DIRECT memory (vector) ---
202
+ 1. [ 4.11] agent-memory
203
+ 2. [ -6.50] graph-rag
204
+ 3. [ -8.66] sqlite-ledger
205
+ 4. [ -9.73] cooking
206
+
207
+ --- ASSOCIATIVE memory (vector+graph) ---
208
+ 1. [ 4.11] agent-memory
209
+ 2. [ -6.50] graph-rag
210
+ 3. [ -8.66] sqlite-ledger
211
+ 4. [ -9.73] cooking
212
+ ```
213
+
214
+ On a corpus this small the graph adds nothing — every note is already in the candidate
215
+ pool. The interesting deltas appear at scale, and that is exactly what the `ab_recall`
216
+ table in [`schema.sql`](schema.sql) accumulates evidence for.
217
+
218
+ ## Public benchmark — `bench/`
219
+
220
+ Every number in the next section comes from our private vault, so nobody outside the lab can
221
+ check it. [`bench/`](bench/README.md) is the reproducible half: a generated 202-note vault
222
+ about a fictional lab, 91 questions in seven classes (including 22 whose answer is *not* in
223
+ the vault), and three metrics that matter for agent memory: recall@k on the support notes,
224
+ verbatim citation, and abstaining when the fact is missing.
225
+
226
+ ```bash
227
+ python bench/run.py --system bm25 # one command, stdlib only
228
+ python bench/validate.py # what CI runs on every result file
229
+ ```
230
+
231
+ Our own baseline is on the [leaderboard](bench/LEADERBOARD.md) with its weak spots written
232
+ out: on "what is the current deadline" questions it retrieves both decisions (R@5 1.00) and
233
+ cites the superseded one 6 times out of 6; vector-only ranks ahead of graph mode on this
234
+ vault (R@5 0.88 vs 0.85). Other memory systems (mem0, Letta, Khoj, plain RAG) can join the
235
+ board with one adapter file and a pull request: [bench/CONTRIBUTING.md](bench/CONTRIBUTING.md).
236
+ CI recomputes every submitted number from the per-question outputs, so a typed-in number
237
+ cannot get onto the board.
238
+
239
+ ## Measure before you swap — `eval/`
240
+
241
+ Every "obvious" upgrade to a RAG pipeline — a newer embedder, a stronger reranker, hybrid
242
+ BM25, a different chunker — is a hypothesis. Without a number on *your* corpus, swapping one
243
+ in is superstition with a changelog entry. `eval/` is the smallest honest ruler we could
244
+ build, and it needs no labelling budget and no LLM calls: **the wikilinks you already wrote
245
+ are the relevance labels.**
246
+
247
+ ```bash
248
+ python eval/run_eval.py --selftest # metrics only: no model, no index
249
+ python eval/build_gold.py /path/to/notes --n-per-class 60 # -> eval/gold-<today>.jsonl (freeze it)
250
+ python eval/run_eval.py --gold eval/gold-<today>.jsonl --sqlite
251
+ ```
252
+
253
+ Four question classes, each probing a different part of the pipeline: `title` (a note's own
254
+ title should find it), `body` (its first paragraph should find it), `bridge` (its first
255
+ paragraph should surface the notes it `[[links]]` to — this is what the graph is *for*), and
256
+ `temporal` (an outdated note's title should surface its replacement, via a
257
+ `superseded_by: "[[newer-note]]"` frontmatter field). Every question is scored in both modes,
258
+ vector-only and vector+graph, so "does the graph help?" stops being a matter of taste.
259
+
260
+ `run_eval.py` imports `brain_ask.py` and calls the same functions the agent calls —
261
+ `load_index`, `retrieve_candidates`, `expand_1hop`, `rerank_candidates` — so what you measure
262
+ is what runs. An eval that re-implements the pipeline measures the re-implementation.
263
+ `--sqlite` appends one row per class and mode to a `gold_eval` table, which is how a run six
264
+ weeks from now can be diffed against today's.
265
+
266
+ ### What it cost us to find out
267
+
268
+ Numbers from the home vault (~24k chunks, RU+EN, 2026-09-16), one frozen gold set of 184
269
+ questions (60 title / 60 body / 60 bridge / 4 temporal), vector+graph mode:
270
+
271
+ | class | Recall@12 | nDCG@12 |
272
+ |---|---|---|
273
+ | title | 0.933 -> **0.950** | 0.890 -> **0.895** |
274
+ | body | 0.733 -> **0.800** | 0.600 -> **0.623** |
275
+ | bridge | 0.251 -> **0.451** | 0.176 -> **0.279** |
276
+ | temporal (n=4 — a smoke test, not a result) | 1.000 -> 1.000 | 0.531 -> 0.531 |
277
+
278
+ Those title and temporal nDCG figures are **corrected**, and the correction is the most
279
+ useful thing on this page. An external review panel reading this module found that `ndcg_at`
280
+ credited a gold note twice when the same filename appeared twice in the ranking — and since
281
+ wikilinks address notes by filename, that happens whenever two folders hold a `foo.md`.
282
+ Reproduced immediately: `ndcg_at(['foo','foo'], ['foo'])` returned **1.63**, above the
283
+ maximum the metric can have. It affected 4 of our 184 questions, which inflated title nDCG by
284
+ 0.031 and temporal by 0.108. Recall@12 and MRR were never affected (one is set-based, the
285
+ other stops at the first hit), and because the same four questions inflated both runs, every
286
+ before/after delta survived to the fourth decimal: title +0.0056 became +0.0055. The merge
287
+ and revert decisions below therefore stand — but the absolute levels we would have quoted
288
+ were wrong, and an eval nobody attacks keeps being wrong politely.
289
+
290
+ Two changes earned that. Cleaning duplicate snapshot copies out of the index (27 095 ->
291
+ 24 216 chunks) moved the metric by exactly 0.0000 — it buys nothing on the ruler and stops
292
+ stale copies eating retrieval slots, which is worth knowing precisely *because* the number is
293
+ zero. The change that did move it gave the graph a vote in the **ordering** rather than in the
294
+ candidate set: personalized PageRank over the wikilink graph, fused with the reranker by RRF,
295
+ with the reranker's top 5 positions protected. The root cause was found by measuring instead
296
+ of guessing — 97% of the correct `bridge` answers were *already in the candidate pool* and the
297
+ cross-encoder was dropping them, because the relation is structural, not textual. Widening
298
+ retrieval, the obvious fix, would have done nothing at all.
299
+
300
+ Seven other changes were rejected by the same ruler, under one rule fixed in advance:
301
+ **a regression worse than 0.01 nDCG@12 on any class reverts the change.**
302
+
303
+ | tried | verdict |
304
+ |---|---|
305
+ | BGE-M3 embedder | +0.005…0.007 on title/body/bridge, but temporal −0.011 and Russian −0.013 (English alone +0.080) -> **rejected** |
306
+ | Qwen3-Embedding-0.6B | body Recall 0.767 -> 0.683; reindex 2863 s vs 333 s -> **rejected** |
307
+ | bge-reranker-v2-m3 | −0.011…−0.018 nDCG on every class except English (+0.041) -> **rejected** |
308
+ | Qwen3-Reranker-0.6B | title −0.111 nDCG at 12x the cost -> **rejected** |
309
+ | BM25 + RRF hybrid | temporal −0.035 -> **merged switched off** |
310
+ | heading-path prefix in every chunk | body −0.023, temporal −0.035 -> **reverted** |
311
+ | `sqlite-vec` (vec0) | full scan 11.99 s vs 0.14 s for a plain SQLite table, and its ANN missed 1.2 hits of 60 -> vectors live in SQLite, **the extension does not** |
312
+ | bi-temporal demotion of superseded notes | temporal +0.130 nDCG on a 41-question temporal set, but title −0.012 -> **merged behind a flag, default off** |
313
+
314
+ None of those verdicts is a claim about the models. They are claims about *this corpus with
315
+ this ruler*, which is the only kind of claim a swap decision actually needs — and the reason
316
+ the module is here rather than in a blog post is that your corpus will disagree with ours.
317
+
318
+ ### What this eval cannot tell you
319
+
320
+ Wikilink gold is weak supervision: a linked neighbour is not always the note that answers the
321
+ question. `bridge` is built *from* links, so any method that walks links is flattered there —
322
+ it measures "can the pipeline follow a connection", not "is this the right connection". One
323
+ run scores one version of one index, and rebuilding the gold set between two runs makes the
324
+ two numbers incomparable, which is the quiet way an eval starts lying. On 60 questions a
325
+ ±0.02 nDCG difference is inside the noise: we learned that by watching two candidate freezes
326
+ of the same pipeline disagree on 33 questions out of 184.
327
+
328
+ The metric can be broken on purpose. `EVAL_MUTANT=1` makes nDCG return a perfect 1.000 for
329
+ everything, and `pytest tests/test_eval.py` **must go red** under it. A suite that stays green
330
+ while the metric is broken never tested the metric.
331
+
332
+ ## Roadmap
333
+
334
+ **Now — [v0.1.1](https://github.com/tonydzi/sqlite-graph-memory/releases).**
335
+ The pilot as it runs daily: retrieval pipeline, per-turn ledger and A/B telemetry, all in
336
+ `brain_ask.py` and `turnstate_hook.py`, plus the bi-temporal design note. Known defects live in
337
+ the [tracker](https://github.com/tonydzi/sqlite-graph-memory/issues) rather than in footnotes
338
+ here, and this file deliberately names no issue numbers: they get closed, the prose around them
339
+ does not notice, and that drift is the defect this paragraph used to carry twice over.
340
+
341
+ **Next:**
342
+
343
+ - **The public benchmark** now exists as [`bench/`](bench/README.md) (`bench-v0.1`): a
344
+ synthetic 202-note vault, 91 questions, a leaderboard that other systems can join, and CI that
345
+ reproduces the numbers. Still missing: the full ablation matrix (hops × seed caps ×
346
+ neighbour caps × rerank pool × gating policy). `bench/` has its first two cells, 0 hops and
347
+ 1 hop. The interesting question was never "does graph help" but
348
+ *for which query classes*; `eval/` answers that per class instead of per intuition.
349
+ - **Bi-temporal edges** — design note [`docs/bitemporal.md`](docs/bitemporal.md). When you
350
+ materialize the graph instead of parsing it at query time, give every edge a validity
351
+ window (`valid_from` / `valid_to` / `observed_at`) so a rebuild *closes* superseded facts
352
+ instead of deleting them: history is kept, recall prefers the present, and `as_of` queries
353
+ can reconstruct the past. Non-destructive aging by confidence decay. The day-1 A/B result
354
+ — context size ~unchanged, retrieved candidates ~60% fresher by mean age — is written up
355
+ with its caveats in `docs/bitemporal.md`: the volume win is longitudinal, so that is one
356
+ day on one corpus, not a benchmark.
357
+ - A write-up on the pattern ("Graph RAG without graph extraction") is in progress.
358
+
359
+ Every noticeable change ships as a new release, so the
360
+ [release feed](https://github.com/tonydzi/sqlite-graph-memory/releases) — not
361
+ the commit graph — is where you can see whether "pilot" has stopped being the right word.
362
+
363
+ ## Models
364
+
365
+ - Embeddings: `intfloat/multilingual-e5-base` (multilingual; the home corpus is RU+EN)
366
+ - Reranker: `cross-encoder/mmarco-mMiniLMv2-L12-H384-v1`
367
+
368
+ Both are set as constants (`E5_MODEL`, `RERANK_MODEL`) in `brain_ask.py` and small enough
369
+ to run on a laptop GPU; swap freely, since nothing in the pipeline depends on these
370
+ specific models.
371
+
372
+ ## Cite this work
373
+
374
+ If this repo shows up in your research, cite it via [CITATION.cff](CITATION.cff) (GitHub's "Cite this repository" button). Academic identity: Anton Dzyatkovsky publishes as **Anton Dziatkovskii** ([ORCID 0000-0001-7408-3054](https://orcid.org/0000-0001-7408-3054)).
375
+
376
+ ## AI contributors
377
+
378
+ This project is built by a human + AI team, and the git log says so: Claude
379
+ writes most of the code, Codex and Grok review it, Gemini feeds the research.
380
+ Each is credited on a commit **only if its output changed that commit's
381
+ content** — no decorative credits. Lab-wide policy, one source for every repo:
382
+ [AI-CONTRIBUTORS.md](https://github.com/tonydzi/.github/blob/main/AI-CONTRIBUTORS.md).
383
+
384
+ ## Cite this work
385
+
386
+ The paper about this system — retrieval design, pilot telemetry, and the query-class-stratified evaluation protocol — is published: [DOI 10.5281/zenodo.22639718](https://doi.org/10.5281/zenodo.22639718) (preprint, CC BY 4.0). Machine-readable citation: [CITATION.cff](CITATION.cff).
387
+
388
+ ## License
389
+
390
+ MIT
391
+
392
+ <!-- CONTACT-FOOTER -->
393
+ ## Contact
394
+
395
+ Questions, war stories, or you want to run this on your own fleet:
396
+
397
+ - 👤 Author: **Anton Dziatkovskii** — Telegram [@tonydzi](https://t.me/tonydzi) · WhatsApp [+1 341 222 9178](https://wa.me/13412229178) · X [@Tony_Stef_](https://x.com/Tony_Stef_)
398
+ - 📣 Channels: [@ClawRus](https://t.me/ClawRus) (RU) · [@ClawEng](https://t.me/ClawEng) (EN)
399
+ - 🌐 [palo-alto.ai](https://palo-alto.ai) · [Palo Alto AI Research Lab](https://github.com/tonydzi)
400
+ - 🧪 **Engineers: want to test-drive this setup?** Message me — I hand out free starter seeds to engineers who test and report back.
401
+
402
+ ## Contributors welcome — and there is a queue
403
+
404
+ Issues labelled [`accepted`](https://github.com/tonydzi/sqlite-graph-memory/issues?q=is%3Aissue+is%3Aopen+label%3Aaccepted)
405
+ are scoped, free to take, and nobody is on them. Comment **"claiming this"** — no permission needed —
406
+ and it is yours for 7 days. New here? Start with
407
+ [`good first issue`](https://github.com/tonydzi/sqlite-graph-memory/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
408
+
409
+ **You keep the copyright to your code.** No CLA, no assignment, ever — your contribution goes in
410
+ under this repo's existing license, the same terms as ours. We answer every issue and PR within
411
+ 48 hours, including "no, and here is why"; our silence is our bug, so ping the thread.
412
+
413
+ Full deal: [CONTRIBUTING.md](https://github.com/tonydzi/.github/blob/main/CONTRIBUTING.md)
414
+
415
+ ---
416
+
417
+ <!--ecosystem-map:start-->
418
+
419
+ ## 🧩 One piece of a working system
420
+
421
+ This repository is one piece lifted out of a live operation: one engineer running a fleet of
422
+ machines, built with Claude as implementation collaborator; the machines reach consensus with
423
+ each other and wake the human only for money or the irreversible. It was extracted after it
424
+ survived production, not written as a demo — and it runs on its own: nothing here phones home
425
+ to the rest.
426
+
427
+ **See how the whole thing fits together → [SYSTEM.md](https://github.com/tonydzi/tonydzi/blob/main/SYSTEM.md)**
428
+
429
+ Its closest neighbours in the **memory** layer: [`second-brain-starter-kit`](https://github.com/tonydzi/second-brain-starter-kit) · [`voice2brain`](https://github.com/tonydzi/voice2brain)
430
+
431
+ <!--ecosystem-map:end-->
432
+
433
+ <!-- READ-WITH-AI:START (generated by read_with_ai.py - do not hand-edit) -->
434
+
435
+ ### READ THIS WITH AI
436
+
437
+ One click and an agent reads the repo, pulls out the patterns and helps you apply them to your own work.
438
+
439
+ <a href="https://chatgpt.com/codex?prompt=Read%20this%20repo%3A%20https%3A%2F%2Fgithub.com%2Ftonydzi%2Fsqlite-graph-memory%20%28%E2%80%9Csqlite-graph-memory%E2%80%9D%20-%20Graph%20RAG%20on%20SQLite%20for%20AI%20agents%3A%20vector%20retrieval%20%2B%20hand-curated%20wikilink%20graph%20%2B%20cross-encoder%20rerank%2C%20with%20a%20zero-token%20per-turn%20memory%20ledger.%20Working%20pilot%29.%20Work%20out%20what%20problem%20it%20actually%20solves%2C%20pull%20out%20the%20reusable%20patterns%20and%20help%20me%20apply%20them%20to%20my%20own%20setup.%20Start%20by%20asking%20what%20I%20am%20working%20on."><img alt="Codex - open" src="https://img.shields.io/badge/Codex-open-000000?style=for-the-badge&logo=openai&logoColor=white"></a> <a href="https://chatgpt.com/?q=Read%20this%20repo%3A%20https%3A%2F%2Fgithub.com%2Ftonydzi%2Fsqlite-graph-memory%20%28%E2%80%9Csqlite-graph-memory%E2%80%9D%20-%20Graph%20RAG%20on%20SQLite%20for%20AI%20agents%3A%20vector%20retrieval%20%2B%20hand-curated%20wikilink%20graph%20%2B%20cross-encoder%20rerank%2C%20with%20a%20zero-token%20per-turn%20memory%20ledger.%20Working%20pilot%29.%20Work%20out%20what%20problem%20it%20actually%20solves%2C%20pull%20out%20the%20reusable%20patterns%20and%20help%20me%20apply%20them%20to%20my%20own%20setup.%20Start%20by%20asking%20what%20I%20am%20working%20on."><img alt="ChatGPT - open" src="https://img.shields.io/badge/ChatGPT-open-10a37f?style=for-the-badge&logo=openai&logoColor=white"></a> <a href="https://claude.ai/new?q=Read%20this%20repo%3A%20https%3A%2F%2Fgithub.com%2Ftonydzi%2Fsqlite-graph-memory%20%28%E2%80%9Csqlite-graph-memory%E2%80%9D%20-%20Graph%20RAG%20on%20SQLite%20for%20AI%20agents%3A%20vector%20retrieval%20%2B%20hand-curated%20wikilink%20graph%20%2B%20cross-encoder%20rerank%2C%20with%20a%20zero-token%20per-turn%20memory%20ledger.%20Working%20pilot%29.%20Work%20out%20what%20problem%20it%20actually%20solves%2C%20pull%20out%20the%20reusable%20patterns%20and%20help%20me%20apply%20them%20to%20my%20own%20setup.%20Start%20by%20asking%20what%20I%20am%20working%20on."><img alt="Claude - open" src="https://img.shields.io/badge/Claude-open-d97757?style=for-the-badge&logo=anthropic&logoColor=white"></a>
440
+
441
+ <details>
442
+ <summary>Copy the prompt (works in any agent: Gemini, Grok, a local model, your own CLI)</summary>
443
+
444
+ ```text
445
+ Read this repo: https://github.com/tonydzi/sqlite-graph-memory (“sqlite-graph-memory” - Graph RAG on SQLite for AI agents: vector retrieval + hand-curated wikilink graph + cross-encoder rerank, with a zero-token per-turn memory ledger. Working pilot). Work out what problem it actually solves, pull out the reusable patterns and help me apply them to my own setup. Start by asking what I am working on.
446
+ ```
447
+
448
+ </details>
449
+
450
+ <sub>— TonyDzi, Palo Alto AI Research Lab · second brain, agent coordination, persistent memory: github.com/tonydzi</sub>
451
+
452
+ <!-- READ-WITH-AI:END -->
@@ -0,0 +1,12 @@
1
+ sqlite_graph_memory/__init__.py,sha256=T5govp5VGbquVPCrt9A206zFxMoSc9cyVZiP-1sMBcM,1151
2
+ sqlite_graph_memory/brain_ask.py,sha256=IU8AVk8VvDJr0XC02a7Foil_f0ui0N-Rr_jD734Onbk,14104
3
+ sqlite_graph_memory/index_notes.py,sha256=Hmt0_VVJHS-zXhPPw9h2te8iG1W48f1tJ_H0ALt9aLk,5333
4
+ sqlite_graph_memory/mcp_server.py,sha256=ncswz2La4JICUmvYhiOM5x9KipxbK7PXjxIyepKtgns,8771
5
+ sqlite_graph_memory/schema.sql,sha256=8aySXKw3Azaxyzqbd76mKTfOaDP7FlpkLXtgwA8ZVK4,2543
6
+ sqlite_graph_memory/turnstate_hook.py,sha256=fypGmUcHQkzlRN74tvIG07lr9uAXpp2GjetqthkuMc8,8641
7
+ sqlite_graph_memory/turnstate_show.py,sha256=IED7fmJQM5VgBNwxmEoNSZtujRmWja-qVPg5ckbWVnY,2909
8
+ sqlite_graph_memory-0.3.0.dist-info/METADATA,sha256=Ac_rhb4QZJz0bbKR2XqErNIKX2IiV3BDP9ilCBlSWzI,27081
9
+ sqlite_graph_memory-0.3.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
10
+ sqlite_graph_memory-0.3.0.dist-info/entry_points.txt,sha256=dyQ1KGmf1xgBfDKb3m_2GTXpF4IR4SDGm53oBNZy-CI,280
11
+ sqlite_graph_memory-0.3.0.dist-info/licenses/LICENSE,sha256=p88nZdrfMUiES3_MpUEwhGmqz2hQFpyMh0k0cqdpfU8,1082
12
+ sqlite_graph_memory-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.4
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,6 @@
1
+ [console_scripts]
2
+ sgm-ask = sqlite_graph_memory.brain_ask:main
3
+ sgm-index = sqlite_graph_memory.index_notes:main
4
+ sgm-mcp = sqlite_graph_memory.mcp_server:main
5
+ sgm-turnstate-hook = sqlite_graph_memory.turnstate_hook:main
6
+ sgm-turnstate-show = sqlite_graph_memory.turnstate_show:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Palo Alto AI Research Lab
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.