mattrguerra/better-memory-pipelinemainPrivate on GitHub, published here in full

README.md

Language Markdown3.6 KB78 lines

README.md

  1. # better-memory
  2. [![test](https://github.com/mattrguerra/better-memory-pipeline/actions/workflows/test.yml/badge.svg)](https://github.com/mattrguerra/better-memory-pipeline/actions/workflows/test.yml)
  3. A nightly pipeline that turns a personal Obsidian knowledge base into memory any Claude
  4. can recall from: on a phone, a desktop or the web, without reading the vaults.
  5. Matt Guerra built and runs it on his own vaults. The code, the schedule and the distiller
  6. are the real ones; the vaults in this repo are an invented sample (a fictional ceramics
  7. teacher, Rowan Adler), because the real ones are private by definition.
  8. ## How it works
  9. ```
  10. vaults (Obsidian, several roots)
  11. |
  12. | gate.py nightly at 20:00 (launchd). Not AI. The security boundary.
  13. | - walls off private folders, dotfolders and traversal, fail-closed
  14. | - skips vault scaffolding, keeps one explainer note per nested vault
  15. | - hashes each safe note's post-gate content; stages only new or changed notes
  16. | content_gate.py optional second wall, on content instead of paths
  17. v
  18. ~/cowork-staging/staging/ flat files: vault__folder__note.md (tonight's delta)
  19. ~/cowork-staging/.manifest.json the hash record that drives change detection
  20. |
  21. | distiller nightly at 20:30. A Claude skill run as a Cowork task.
  22. v
  23. Notion "better-memory" one page per entity, typed Relations: a knowledge graph
  24. |
  25. v
  26. any Claude with the Notion connector reads it for recall; nothing else writes it
  27. ```
  28. ## Try it
  29. ```bash
  30. VAULT_ROOTS="$PWD/sample-vaults/workbench:$PWD/sample-vaults/identity" \
  31. STAGING_DIR="$PWD/.staging" python3 gate.py
  32. ls .staging/staging
  33. python3 -m unittest discover -s tests
  34. ```
  35. Python 3.10+, no dependencies.
  36. ## The invariants that make it safe
  37. - **The wall is enforced by the filesystem, not by the model.** The distiller is only
  38. ever given the staging directory, never a vault. The private folders are not
  39. "excluded by instruction"; they are physically absent from everything the model can
  40. read.
  41. - **The gate fails closed.** Paths resolve before they are checked, so `..` and
  42. symlinks out of a vault are refused. On startup the gate probes its own walls with
  43. known-private paths and refuses to run if any probe gets through.
  44. - **Staging is disposable.** Every run wipes it and rebuilds it, so the distiller never
  45. reads yesterday's leftovers.
  46. - **Only the nightly task writes the database.** Every interactive session reads it,
  47. so recall never races a live edit.
  48. ## Design decisions
  49. - **Content-hash manifest, not a `finished/` folder:** an edited note re-stages and an unchanged one is skipped.
  50. - **Hash after the gate:** only a change in what is actually staged re-stages a note.
  51. - **One explainer per nested vault:** instruction files, indexes, templates and run logs are skipped, but each nested vault keeps one note saying what it is for.
  52. - **Section gate off by design:** private material is already behind path walls, so its pattern lists are empty and an empty list matches nothing.
  53. ## What's here
  54. | Path | What it is |
  55. |---|---|
  56. | `gate.py` | The path gate: walls, self-check, scaffolding rules, change detection. |
  57. | `content_gate.py` | The optional content gate: frontmatter flags, line patterns, remove or redact, fail-closed. |
  58. | `distiller/` | The distiller skill, its schedule and binding, and the Notion schema. |
  59. | `scheduling/` | The launchd job and the nightly wrapper. |
  60. | `sample-vaults/` | Two invented vaults that exercise every rule. |
  61. | `examples/` | A real gate run on the sample, and one distilled page. |
  62. | `tests/` | The test suite, stdlib `unittest`. |
  63. | `docs/INSTALL.md` | Installing it on a Mac. |