@bcmyguest/openmem 0.0.0-stage → 0.8.0

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 (230) hide show
  1. package/.agents/skills/openmem/SKILL.md +34 -0
  2. package/LICENSE +190 -0
  3. package/README.md +140 -2
  4. package/bin/hindsight-project-index +530 -0
  5. package/cli/coding-agent/access-policy.mjs +38 -0
  6. package/cli/coding-agent/agents.mjs +34 -0
  7. package/cli/coding-agent/bank-from-cwd.mjs +140 -0
  8. package/cli/coding-agent/capabilities.mjs +34 -0
  9. package/cli/coding-agent/context-store.mjs +81 -0
  10. package/cli/coding-agent/context-trim.mjs +897 -0
  11. package/cli/coding-agent/file-io.mjs +72 -0
  12. package/cli/coding-agent/hook-harnesses.mjs +88 -0
  13. package/cli/coding-agent/hook-runner.mjs +284 -0
  14. package/cli/coding-agent/install-access.mjs +119 -0
  15. package/cli/coding-agent/install-context-proxy.mjs +333 -0
  16. package/cli/coding-agent/install-rtk.mjs +60 -0
  17. package/cli/coding-agent/install-shim.mjs +201 -0
  18. package/cli/coding-agent/opencode-config.mjs +107 -0
  19. package/cli/coding-agent/opencode-plugin.mjs +132 -0
  20. package/cli/coding-agent/opencode2-plugin/index.js +299 -0
  21. package/cli/coding-agent/recall-frame.mjs +29 -0
  22. package/cli/coding-agent/remove-upstream-access.mjs +122 -0
  23. package/cli/coding-agent/runtime.mjs +40 -0
  24. package/cli/coding-agent/session-db.mjs +626 -0
  25. package/cli/coding-agent/session-facade.mjs +86 -0
  26. package/cli/coding-agent/toml-edit.mjs +161 -0
  27. package/cli/cognee-mcp.mjs +260 -0
  28. package/cli/context-management.mjs +254 -0
  29. package/cli/feed-sync.mjs +27 -0
  30. package/cli/install-coding-agent.mjs +298 -0
  31. package/cli/install-memory-mcp.mjs +426 -0
  32. package/cli/is-main.mjs +18 -0
  33. package/cli/mcp/context-sql-runner.mjs +58 -0
  34. package/cli/mcp/context-store.mjs +670 -0
  35. package/cli/mcp/context.mjs +61 -0
  36. package/cli/mcp/export/cognee-dataset-name.mjs +12 -0
  37. package/cli/mcp/export/cognee.mjs +119 -0
  38. package/cli/mcp/export/hindsight.mjs +48 -0
  39. package/cli/mcp/export/index.mjs +26 -0
  40. package/cli/mcp/export/mem0.mjs +31 -0
  41. package/cli/mcp/knowledge.mjs +333 -0
  42. package/cli/mcp/llm-synthesize.mjs +50 -0
  43. package/cli/mcp/mem0-scope-id.mjs +22 -0
  44. package/cli/mcp/memory-facade.mjs +521 -0
  45. package/cli/mcp/memory-reflect-consolidate.mjs +120 -0
  46. package/cli/mcp/notebooklm-banks.mjs +21 -0
  47. package/cli/mcp/notebooklm-hindsight-rest.mjs +45 -0
  48. package/cli/mcp/notebooklm-provider.mjs +225 -0
  49. package/cli/mcp/pmm-records.mjs +23 -0
  50. package/cli/mcp/portability.mjs +158 -0
  51. package/cli/mcp/stdio.mjs +65 -0
  52. package/cli/mcp/unified-mcp-install.mjs +65 -0
  53. package/cli/mem0-mcp.mjs +108 -0
  54. package/cli/notebooklm-mcp.mjs +236 -0
  55. package/cli/openmem-mcp.mjs +38 -0
  56. package/cli/openmem.mjs +222 -0
  57. package/cli/roots.mjs +85 -0
  58. package/cli/schedule.mjs +176 -0
  59. package/cli/stack.mjs +438 -0
  60. package/cli/switch-memory-provider.mjs +358 -0
  61. package/cli/wiring-report.mjs +125 -0
  62. package/compose.bench.yaml +12 -0
  63. package/compose.yaml +227 -0
  64. package/config/coding-agent.json +13 -0
  65. package/config/hindsight.env.example +26 -0
  66. package/config/index.yml +54 -0
  67. package/config/litellm.lemond.yaml +40 -0
  68. package/config/litellm.ollama.yaml +33 -0
  69. package/config/notebooklm.yml +33 -0
  70. package/config/openmem.toml.example +124 -0
  71. package/docs/OPENMEM.md +23 -0
  72. package/docs/architecture.md +245 -0
  73. package/docs/assets/README.md +10 -0
  74. package/docs/assets/setup-demo.gif +0 -0
  75. package/docs/coding-agent-hooks.md +75 -0
  76. package/docs/coding-agent-scopes.md +22 -0
  77. package/docs/coding-agents.md +71 -0
  78. package/docs/cognee.md +37 -0
  79. package/docs/compatibility.md +80 -0
  80. package/docs/concepts.md +135 -0
  81. package/docs/context-management.md +255 -0
  82. package/docs/context-proxy.md +115 -0
  83. package/docs/context-research.md +215 -0
  84. package/docs/context-store.md +277 -0
  85. package/docs/hindsight.md +77 -0
  86. package/docs/index-sources-roadmap.md +38 -0
  87. package/docs/index-sources.md +39 -0
  88. package/docs/indexer-sinks.md +122 -0
  89. package/docs/indexing.md +57 -0
  90. package/docs/manual-stack-setup.md +74 -0
  91. package/docs/mcp-install-guide.md +4 -0
  92. package/docs/mcp-setup.md +104 -0
  93. package/docs/mem0.md +141 -0
  94. package/docs/memory-portability.md +73 -0
  95. package/docs/memory-providers.md +246 -0
  96. package/docs/meridian-litellm.md +198 -0
  97. package/docs/model-configuration.md +106 -0
  98. package/docs/notebooklm.md +83 -0
  99. package/docs/npx-install.md +172 -0
  100. package/docs/openmem-config.md +194 -0
  101. package/docs/provider-wizard-hooks.md +222 -0
  102. package/docs/quickstart.md +107 -0
  103. package/docs/setup-wizard.md +117 -0
  104. package/docs/sources-feeds.md +39 -0
  105. package/docs/sources-readwise.md +23 -0
  106. package/docs/sources-zotero.md +22 -0
  107. package/glama.json +4 -0
  108. package/indexer/Dockerfile +38 -0
  109. package/indexer/code_outline.py +146 -0
  110. package/indexer/feed_sync.py +107 -0
  111. package/indexer/index_config.py +290 -0
  112. package/indexer/pytest.ini +5 -0
  113. package/indexer/sinks/__init__.py +148 -0
  114. package/indexer/sinks/_http.py +44 -0
  115. package/indexer/sinks/cognee.py +329 -0
  116. package/indexer/sinks/hindsight.py +107 -0
  117. package/indexer/sinks/mem0.py +247 -0
  118. package/indexer/watch.py +240 -0
  119. package/package.json +96 -4
  120. package/providers/_template/compose.yaml +52 -0
  121. package/providers/cognee/OPERATOR.md +82 -0
  122. package/providers/cognee/compose.yaml +89 -0
  123. package/providers/cognee/lib/clack.mjs +157 -0
  124. package/providers/cognee/lib/coding-agent.mjs +26 -0
  125. package/providers/cognee/lib/cognee-mcp-install.mjs +153 -0
  126. package/providers/cognee/lib/config.mjs +98 -0
  127. package/providers/cognee/lib/env-file.mjs +194 -0
  128. package/providers/cognee/lib/env-setup.mjs +83 -0
  129. package/providers/cognee/lib/llm-env.mjs +382 -0
  130. package/providers/cognee/lib/ports.mjs +25 -0
  131. package/providers/cognee/lib/smoke.mjs +246 -0
  132. package/providers/cognee/lib/stack-env.mjs +134 -0
  133. package/providers/cognee/lib/state.mjs +101 -0
  134. package/providers/cognee/lib/summary.mjs +56 -0
  135. package/providers/cognee/lib/validate.mjs +97 -0
  136. package/providers/cognee/manifest.json +56 -0
  137. package/providers/cognee/wizard.mjs +134 -0
  138. package/providers/graphiti/manifest.json +15 -0
  139. package/providers/hindsight/lib/clack.mjs +347 -0
  140. package/providers/hindsight/lib/coding-agent.mjs +204 -0
  141. package/providers/hindsight/lib/config.mjs +79 -0
  142. package/providers/hindsight/lib/env-setup.mjs +72 -0
  143. package/providers/hindsight/lib/litellm-routes.mjs +196 -0
  144. package/providers/hindsight/lib/meridian.mjs +307 -0
  145. package/providers/hindsight/lib/model-backend.mjs +243 -0
  146. package/providers/hindsight/lib/notebooklm-mcp-install.mjs +127 -0
  147. package/providers/hindsight/lib/ollama-compose.mjs +51 -0
  148. package/providers/hindsight/lib/ports.mjs +30 -0
  149. package/providers/hindsight/lib/probe.mjs +54 -0
  150. package/providers/hindsight/lib/stack-env.mjs +125 -0
  151. package/providers/hindsight/lib/state.mjs +80 -0
  152. package/providers/hindsight/lib/summary.mjs +57 -0
  153. package/providers/hindsight/lib/validate.mjs +81 -0
  154. package/providers/hindsight/manifest.json +58 -0
  155. package/providers/hindsight/wizard.mjs +150 -0
  156. package/providers/letta/manifest.json +29 -0
  157. package/providers/mem0/OPERATOR.md +143 -0
  158. package/providers/mem0/compose.yaml +79 -0
  159. package/providers/mem0/lib/coding-agent.mjs +58 -0
  160. package/providers/mem0/lib/config.mjs +45 -0
  161. package/providers/mem0/lib/configure.mjs +201 -0
  162. package/providers/mem0/lib/dotenv.mjs +71 -0
  163. package/providers/mem0/lib/env-file.mjs +110 -0
  164. package/providers/mem0/lib/http.mjs +69 -0
  165. package/providers/mem0/lib/litellm.mjs +457 -0
  166. package/providers/mem0/lib/mcp-install.mjs +165 -0
  167. package/providers/mem0/lib/secret.mjs +30 -0
  168. package/providers/mem0/lib/smoke.mjs +179 -0
  169. package/providers/mem0/lib/stack-env.mjs +255 -0
  170. package/providers/mem0/lib/state.mjs +67 -0
  171. package/providers/mem0/lib/summary.mjs +88 -0
  172. package/providers/mem0/lib/url.mjs +106 -0
  173. package/providers/mem0/lib/validate.mjs +158 -0
  174. package/providers/mem0/manifest.json +47 -0
  175. package/providers/mem0/wizard.mjs +146 -0
  176. package/providers/zep/manifest.json +29 -0
  177. package/proxy/config.yaml +33 -0
  178. package/proxy/openmem_context/__init__.py +6 -0
  179. package/proxy/openmem_context/adapters.py +504 -0
  180. package/proxy/openmem_context/compress.py +53 -0
  181. package/proxy/openmem_context/core.py +606 -0
  182. package/proxy/openmem_context/embed.py +212 -0
  183. package/proxy/openmem_context/recall.py +49 -0
  184. package/proxy/openmem_context/session.py +70 -0
  185. package/proxy/openmem_context/sessiondb.py +276 -0
  186. package/proxy/openmem_context/settings.py +134 -0
  187. package/proxy/openmem_context/store.py +129 -0
  188. package/proxy/openmem_context/tokens.py +123 -0
  189. package/proxy/openmem_context/ttl.py +78 -0
  190. package/proxy/openmem_context_hook.py +34 -0
  191. package/scripts/check-pack.mjs +219 -0
  192. package/scripts/gen-masks.mjs +83 -0
  193. package/scripts/gen-masks.sh +4 -0
  194. package/scripts/promotion-provider-smoke.mjs +34 -0
  195. package/scripts/run-setup.sh +30 -0
  196. package/scripts/setup.mjs +107 -0
  197. package/scripts/setup.sh +5 -0
  198. package/scripts/spin-up.sh +45 -0
  199. package/scripts/wizard.sh +5 -0
  200. package/server.json +34 -0
  201. package/sync/Dockerfile +27 -0
  202. package/sync/memory_backend.py +87 -0
  203. package/sync/notebooklm_sync.py +664 -0
  204. package/wizard/bin/pm.mjs +97 -0
  205. package/wizard/bin/setup.mjs +33 -0
  206. package/wizard/lib/compose-version.mjs +32 -0
  207. package/wizard/lib/compose.mjs +70 -0
  208. package/wizard/lib/context-step.mjs +140 -0
  209. package/wizard/lib/curl.mjs +103 -0
  210. package/wizard/lib/docker-build.mjs +148 -0
  211. package/wizard/lib/exec.mjs +41 -0
  212. package/wizard/lib/indexer.mjs +6 -0
  213. package/wizard/lib/litellm-env.mjs +55 -0
  214. package/wizard/lib/load-machine-env.mjs +4 -0
  215. package/wizard/lib/log.mjs +32 -0
  216. package/wizard/lib/notebooklm-agent-access.mjs +92 -0
  217. package/wizard/lib/notebooklm.mjs +214 -0
  218. package/wizard/lib/parse-args.mjs +87 -0
  219. package/wizard/lib/paths.mjs +39 -0
  220. package/wizard/lib/pm-config.mjs +371 -0
  221. package/wizard/lib/ports.mjs +94 -0
  222. package/wizard/lib/prompts.mjs +85 -0
  223. package/wizard/lib/provider-wizard/helpers.mjs +98 -0
  224. package/wizard/lib/provider-wizard/run-steps.mjs +129 -0
  225. package/wizard/lib/providers/registry.mjs +262 -0
  226. package/wizard/lib/run-clack.mjs +108 -0
  227. package/wizard/lib/run-wizard.mjs +750 -0
  228. package/wizard/lib/validate-setup.mjs +62 -0
  229. package/wizard/lib/wizard-action.mjs +34 -0
  230. package/wizard/lib/wizard-conf.mjs +71 -0
@@ -0,0 +1,38 @@
1
+ # Index sources — roadmap
2
+
3
+ Today the indexer **ships** git repos, Obsidian vaults, markdown directory trees (`notes`, `papers`, `bookmarks` in `index.yml`), and a **feed cache** (`feeds` + `feed-sync`). Everything else below is **planned** or **bring-your-own-export** (point a folder at an export until a native connector exists).
4
+
5
+ ## Shipped (filesystem)
6
+
7
+ | Kind | Config | Typical content |
8
+ | --- | --- | --- |
9
+ | Git repo | `roots`, `repos` | Code + tracked docs |
10
+ | Obsidian vault | `vaults` | Notes with `.obsidian` |
11
+ | Notes | `notes.paths` | Plain markdown trees |
12
+ | Papers | `papers.paths` | Paper notes, Zotero md export, reading notes |
13
+ | Bookmarks | `bookmarks.paths` | Saved links as markdown/HTML exports |
14
+ | Feed cache | `feeds.out_dir` + `feed-sync` | RSS / OpenAlex markdown under a watched dir |
15
+
16
+ ## Planned connectors (API / sync jobs)
17
+
18
+ | Source | Idea | Likely bank prefix | Notes |
19
+ | --- | --- | --- | --- |
20
+ | **Zotero** | API or periodic export dir | `papers::zotero` | Prefer export-to-`papers.paths` first |
21
+ | **OpenAlex / OpenResearch** | Metadata + abstract pull | `openresearch::` | Read-only citeable snippets, not full PDF hosting |
22
+ | **Semantic Scholar** | Library sync | `papers::s2` | Same pattern as OpenAlex |
23
+ | **Readwise** | Reader / highlight export | `readwise::` | Official export → markdown dir |
24
+ | **Hypothesis** | Annotation export | `hypothesis::` | Web annotation JSON → indexer adapter |
25
+ | **Pinboard / Linkwarden / Karakeep** | Bookmark API or export | `bookmarks::` | Overlap with `bookmarks.paths` |
26
+ | **RSS / arXiv feed** | `npx @bcmyguest/openmem feed-sync` | `feed::*` | Shipped; see [sources-feeds.md](sources-feeds.md) |
27
+ | **Email** | mbox / selective forward | `mail::` | High privacy risk; opt-in only |
28
+ | **Slack / Discord export** | JSON dump dirs | `chat::` | Enterprise exports only |
29
+ | **NotebookLM** | Already optional Hindsight profile | `notebooklm::*` | Not a generic source type |
30
+
31
+ ## Design rules for new sources
32
+
33
+ 1. **One sink** — all sources retain into the active provider via the same indexer process.
34
+ 2. **Stable bank ids** — prefix + slug; override with `banks:` in `index.yml`.
35
+ 3. **Filesystem first** — if the tool can export to a directory, use `*.paths` before building OAuth sync.
36
+ 4. **No secrets in repo** — API keys in `~/.config/personal-memory/`, not index.yml.
37
+
38
+ Contributing a connector: add a row here, then either a new `*.paths` kind (markdown) or an indexer sidecar script that writes retains through the existing sink.
@@ -0,0 +1,39 @@
1
+ # Index sources
2
+
3
+ The shared indexer reads `~/.config/hindsight/index.yml` (or `config/index.yml` defaults). One active provider sink receives retains from every source.
4
+
5
+ | Source kind | Config | Detection | Default bank prefix |
6
+ | --- | --- | --- | --- |
7
+ | **Git repo** | `roots`, `repos` | Poll `git` fingerprint | `coding-agent::<repo>` |
8
+ | **Obsidian vault** | `roots` + `vaults.auto`, `vaults.paths` | inotify after quiet period | `obsidian::<slug>` |
9
+ | **Notes** | `notes.paths` | inotify | `notes::<slug>` |
10
+ | **Papers** | `papers.paths` | inotify | `papers::<slug>` |
11
+ | **Bookmarks** | `bookmarks.paths` | inotify (.md, .html, .txt) | `bookmarks::<slug>` |
12
+ | **Feed cache** | `feeds` + `feed-sync` | inotify on `feeds.out_dir` | `feed::<slug>` |
13
+
14
+ Markdown trees index `.md` (and Obsidian-style structure) the same way; use separate keys so banks stay readable in Hindsight/mem0 scopes.
15
+
16
+ Override banks with the `banks:` map (longest prefix wins).
17
+
18
+ ```yaml
19
+ notes:
20
+ paths:
21
+ - ~/Documents/plain-markdown
22
+ papers:
23
+ paths:
24
+ - ~/Zotero/storage/export-md
25
+ bookmarks:
26
+ paths:
27
+ - ~/Exports/linkwarden-markdown
28
+ repos:
29
+ - ~/src/my-fork
30
+ vaults:
31
+ paths:
32
+ - ~/Obsidian/Main
33
+ ```
34
+
35
+ Exclude paths with `exclude:` globs. Tune `poll_seconds`, `vault_quiet_seconds`, and `relist_seconds` for watcher behavior.
36
+
37
+ **Guides:** [Feed sync](sources-feeds.md) (RSS / OpenAlex → `feed::*`) · [Zotero exports](sources-zotero.md) · [Readwise exports](sources-readwise.md). Native API connectors and more kinds: [index-sources-roadmap.md](index-sources-roadmap.md).
38
+
39
+ See [indexer sinks](indexer-sinks.md) for how banks map to mem0/Cognee/Hindsight scopes.
@@ -0,0 +1,122 @@
1
+ # Indexer sink drivers
2
+
3
+ The shared indexer (`bin/hindsight-project-index`, watcher, compose `indexer` service) turns
4
+ git repos, Obsidian vaults, markdown trees (`notes` / `papers` / `bookmarks`), and feed-cache
5
+ folders into documents and writes them through a **sink**: a Python module
6
+ under `indexer/sinks/<name>.py`. Provider manifests declare how compose and the wizard wire that
7
+ sink; see [Pluggable memory providers](memory-providers.md) for manifests and wizard ownership.
8
+
9
+ ## Manifest fields vs runtime ids
10
+
11
+ | Concept | Where it lives | Role |
12
+ | --- | --- | --- |
13
+ | **`indexer.sink`** | `providers/<id>/manifest.json` | Module name: `indexer/sinks/<sink>.py`. Becomes `MEMORY_SINK` in compose and `--sink` on the CLI. |
14
+ | **`indexer.sinkDriver`** | same | Human-readable wire-dialect label only (for docs and status pages). **Does not** select a module. |
15
+ | **`indexer.apiUrlEnv`** | same | Name of the env var the wizard documents for the provider API base URL on the host. |
16
+
17
+ Registered providers today:
18
+
19
+ | Provider | `sink` (module) | `sinkDriver` | `apiUrlEnv` |
20
+ | --- | --- | --- | --- |
21
+ | Hindsight (`supported`) | `hindsight` | `hindsight-rest-v1` | `HINDSIGHT_URL` |
22
+ | mem0 | `mem0` | `mem0-rest` | `MEM0_API_URL` |
23
+ | Cognee | `cognee` | `cognee-rest` | `COGNEE_API_URL` |
24
+
25
+ Contract tests: `indexer/tests/sink_contract.py`, provider-specific tests under `indexer/tests/`.
26
+
27
+ ## Choosing a sink and API URL
28
+
29
+ | Input | Meaning |
30
+ | --- | --- |
31
+ | `--sink NAME` | Sink module name. Default: `$MEMORY_SINK`, then `hindsight`. |
32
+ | `MEMORY_SINK` | Set in compose fragments for mem0/Cognee (`providers/*/compose.yaml`). |
33
+ | `--url URL` | Overrides all URL env vars for this run. |
34
+ | `HINDSIGHT_URL` | API base for the **hindsight** sink only (default `http://127.0.0.1:8888`). |
35
+ | `MEMORY_API_URL` | API base for **every non-Hindsight** sink (mem0, Cognee). Required for those sinks when `--url` is omitted. |
36
+
37
+ Resolution order in the CLI: `--url` → `HINDSIGHT_URL` (hindsight sink) or `MEMORY_API_URL` (other
38
+ sinks) → sink-specific default (Hindsight only). Credentials are read inside each sink’s `create()`
39
+ from provider-specific env vars, never from indexed file paths.
40
+
41
+ Provider secret files (mode `600`, outside the repo):
42
+
43
+ | Provider | Typical file | Indexer-relevant keys |
44
+ | --- | --- | --- |
45
+ | mem0 | `~/.config/personal-memory/mem0.env` | `MEM0_API_KEY` → `X-API-Key` on API calls (not on `GET /docs` health) |
46
+ | Cognee | `~/.config/personal-memory/cognee-indexer.env` | `COGNEE_API_KEY` when the server requires auth (default single-user image does not) |
47
+
48
+ Stack `.env` holds host ports and derived URLs (for example `MEM0_INDEXER_URL` for the indexer
49
+ container’s view of mem0). LLM keys for Cognee cognify live in `cognee.env`, not in the indexer env
50
+ file — see [Cognee](cognee.md).
51
+
52
+ ## Indexer `bank` → provider namespace
53
+
54
+ The indexer uses **`bank`** for the logical scope of a source (repo, vault, or `index.yml` override).
55
+ Examples: `coding-agent::my-repo`, `obsidian::my-vault`, `notebooklm::work-notes` (when synced into
56
+ Hindsight). **`doc_id`** is a stable per-document id (`project-index:v1:…`). Each sink maps `bank` /
57
+ `doc_id` to its backend’s scoping model.
58
+
59
+ ### Hindsight (`hindsight-rest-v1`)
60
+
61
+ | Indexer field | Hindsight API |
62
+ | --- | --- |
63
+ | `bank` | Bank id in the path: `/v1/default/banks/{bank}/…` (URL-encoded) |
64
+ | `doc_id` | Carried in retain payload / document identity for updates and deletes |
65
+
66
+ Behavior:
67
+
68
+ - `prepare(bank)` ensures the bank exists, sets retain strategy `project-index`, disables auto-consolidation for indexed banks.
69
+ - Retains are **synchronous** (`async: false`); no `flush()` hook.
70
+ - Default URL when unset: `http://127.0.0.1:8888`. Compose sets `HINDSIGHT_URL: http://hindsight:8888` on the indexer service.
71
+
72
+ NotebookLM sync writes into Hindsight banks `notebooklm::<slug>`; that path is separate from sink
73
+ selection (still the hindsight sink when `MEMORY_PROVIDER=hindsight`).
74
+
75
+ ### mem0 (`mem0-rest`)
76
+
77
+ | Indexer field | mem0 REST field |
78
+ | --- | --- |
79
+ | `bank` | `user_id` (via `scope_id()` — see below) |
80
+ | `doc_id` | `run_id` (same `scope_id` rules) |
81
+ | (fixed) | `agent_id` = `openmem-indexer` (provenance only; lookups use `user_id` + `run_id`) |
82
+
83
+ **`scope_id`:** If the id has no whitespace, it is used as-is. Otherwise whitespace runs become `_`,
84
+ and `~` plus the first 8 hex digits of SHA-256(original) are appended so ids that differ only in
85
+ whitespace stay distinct (for example `obsidian::My Vault` → `obsidian::My_Vault~<8 hex>`).
86
+
87
+ Documents are chunked (max 3000 characters per chunk, `infer: false`). Updates list existing memories
88
+ for `(user_id, run_id)`, write new chunks, then delete old ids. There is no mem0 “bank” to create;
89
+ `prepare` is a no-op.
90
+
91
+ Compose: `MEMORY_SINK=mem0`, `MEMORY_API_URL=${MEM0_INDEXER_URL}` (wizard derives this from host
92
+ `MEM0_API_URL`). Operator runbook: `providers/mem0/OPERATOR.md`, [mem0](mem0.md).
93
+
94
+ ### Cognee (`cognee-rest`)
95
+
96
+ | Indexer field | Cognee concept |
97
+ | --- | --- |
98
+ | `bank` | **Dataset name** derived from `bank` (not the raw string) |
99
+ | `doc_id` | Stored in upload `external_metadata` as `doc_id` (plus `bank`); used to replace/delete rows |
100
+
101
+ **Dataset name:** `<slug>_<8 hex of sha256(bank)>` where `slug` is `bank` lowercased, non-`[a-z0-9]`
102
+ collapsed to `_`, trimmed, max 40 chars (empty → `bank`). Two banks that slug identically still differ
103
+ by hash suffix.
104
+
105
+ Ingestion is **asynchronous**: `retain`/`delete` call REST add/delete; the sink implements **`flush(bank)`**
106
+ to trigger `POST /api/v1/cognify` for that dataset after each changed batch (and retries pending flushes
107
+ from indexer state). Search lags until cognify completes.
108
+
109
+ Compose: `MEMORY_SINK=cognee`, `MEMORY_API_URL: http://cognee:8000`, optional
110
+ `cognee-indexer.env` for `COGNEE_API_KEY`. Operator notes: [Cognee](cognee.md).
111
+
112
+ ## Optional `flush()` (Cognee)
113
+
114
+ Sinks with `capabilities.async_ingest=True` may define `flush(bank)`. The indexer calls it on
115
+ `--apply` after retains/deletes for that bank, and persists `::flush-pending` in state when a flush
116
+ fails. Hindsight has no flush. Details: [Pluggable memory providers — Optional flush](memory-providers.md#optional-flush).
117
+
118
+ ## Related
119
+
120
+ - [Indexing](indexing.md) — sources, `index.yml`, watcher timings
121
+ - [Architecture](architecture.md) — unified MCP mapping to the same backends
122
+ - [MCP setup](mcp-setup.md) — Cursor servers vs indexer sinks
@@ -0,0 +1,57 @@
1
+ # Indexing
2
+
3
+ The indexer indexes each source once at startup, then keeps it current:
4
+
5
+ - **Git repositories:** the outermost repositories under each `roots` entry, plus `repos`. The indexer polls each one every `poll_seconds` (default 60). A poll fingerprints `HEAD` and the tracked-file status (`git status --porcelain -uno`). After one poll with an unchanged fingerprint, the repository is re-indexed. Edits to an already-modified tracked file change no fingerprint until `HEAD` or the status changes. Repositories with a persistent error re-run on each poll. Banks default to `coding-agent::<repo>` unless `banks` maps the path.
6
+ - **Obsidian vaults:** any folder containing `.obsidian/` within a root's depth, plus `vaults.paths`. Each uses the bank `obsidian::<slug>` unless `banks` maps it. Changes are watched with inotify. A vault is re-indexed after `vault_quiet_seconds` (default 30) without changes. Dot-prefixed paths are ignored.
7
+ - **Markdown trees:** `notes.paths`, `papers.paths`, and `bookmarks.paths` (plain folders without `.obsidian/`). Watched with inotify; banks default to `notes::`, `papers::`, and `bookmarks::` slugs. Bookmarks also index `.html` and `.txt` exports. Use `papers.paths` for Zotero markdown export dirs; see [sources-zotero.md](sources-zotero.md) and [sources-readwise.md](sources-readwise.md).
8
+ - **Feed cache:** when `feeds.rss` or `feeds.openalex_queries` is set in `index.yml`, run `npx @bcmyguest/openmem feed-sync` to refresh markdown under `feeds.out_dir`; the indexer watches that directory as kind `feed` (`feed::<slug>` banks). See [sources-feeds.md](sources-feeds.md).
9
+ - **Source discovery:** sources are re-listed every `relist_seconds` (default 600), so new repos, vaults, and configured paths are picked up without a restart.
10
+
11
+ Operator overview: [index-sources.md](index-sources.md).
12
+ - Code files get a tree-sitter outline (signatures, doc comments, imports) instead of a CodeGraph run. Parsing runs in-process; grammars are prefetched into the image at `/opt/tree-sitter-grammars`, so indexing needs no network. Supported languages: Python, JavaScript, TypeScript, TSX, Go, Rust, Java, C, C++, C#, Ruby, Lua, Bash, PHP. Known gaps: Go type declarations and TypeScript type aliases are not captured, and files with syntax errors give partial outlines. Outlines are re-retained once after this change, and the old CodeGraph-based code documents are deleted as stale.
13
+ - `optInPaths` filters sources. A missing file means no filter; an empty list means nothing is indexed.
14
+ - Automatic consolidation is disabled for the whole indexed bank, not only for indexed documents.
15
+ - Document IDs include the absolute source path. The first run after this change re-retains every document, which costs extraction time on the model server.
16
+ - Concurrent `--apply` runs (the watcher and a manual run) serialize through a lock on `state.json.lock`.
17
+
18
+ Set `INDEXER_DRY_RUN=1` to log the commands the watcher would run without executing them. The environment variables `POLL_SECONDS`, `VAULT_QUIET_SECONDS`, and `RELIST_SECONDS` override the timings in `index.yml`.
19
+
20
+ ### Source config: `index.yml`
21
+
22
+ `config/index.yml` in the repository is the default. The indexer reads the first of these that exists:
23
+
24
+ 1. `--config PATH` (manual runs and `--list`)
25
+ 2. `$HINDSIGHT_INDEX_CONFIG`
26
+ 3. `~/.config/hindsight/index.yml` (per machine; the container sees it through `scripts/setup.mjs`'s mount)
27
+ 4. `config/index.yml` (baked into the image at `/opt/config/index.yml`; rebuild after changing it)
28
+
29
+ A file found this way replaces the default entirely. Keys it omits take the built-in values, which match `config/index.yml`. Unknown keys and wrong types fail at startup with the file, key, and reason. `~` expands; a bare `~` in YAML is null, which means home under `roots[].path`.
30
+
31
+ | Key | Meaning |
32
+ | --- | --- |
33
+ | `roots` | `[{path, depth}]`. Repositories are the outermost git repositories found within `depth` levels (default 3). |
34
+ | `repos` | Extra repositories, outside the roots or not. Each must be a git repository. |
35
+ | `vaults.auto` | `true` (default) finds any folder with `.obsidian/` within a root's depth. |
36
+ | `vaults.paths` | Extra vault folders. |
37
+ | `notes.paths`, `papers.paths`, `bookmarks.paths` | Markdown (and bookmark export) directories; see [index-sources.md](index-sources.md). |
38
+ | `feeds.out_dir`, `feeds.rss`, `feeds.openalex_queries` | Feed sync output; requires `npx @bcmyguest/openmem feed-sync`. |
39
+ | `exclude` | Glob patterns on absolute paths. A matching source is skipped. |
40
+ | `banks` | Absolute path prefix to bank id; the longest prefix wins. Applies to all source kinds. Unmatched repos fall back to `~/.config/personal-memory/coding-agent.json` `mapPathToBank`, then legacy `~/.hindsight/coding-agent.json`, then `coding-agent::<repository-name>`. |
41
+ | `max_file_kb` | Largest indexed file, in kilobytes (1 KB = 1000 bytes). Default 128. |
42
+ | `skip_dirs` | Directory names not descended into. Dot-prefixed directories are always skipped. |
43
+ | `poll_seconds`, `vault_quiet_seconds`, `relist_seconds` | Watcher timings. |
44
+
45
+ `optInPaths` in `~/.hindsight/coding-agent.json` still filters sources after discovery.
46
+
47
+ Check the result with `--list` before a first `--apply`. Excluded sources are reported on stderr.
48
+
49
+ Manual runs. The script defaults to a dry run; `--apply` writes:
50
+
51
+ ```sh
52
+ docker compose run --rm --no-deps indexer hindsight-project-index --list
53
+ docker compose run --rm --no-deps indexer hindsight-project-index --repo PATH --apply
54
+ docker compose run --rm --no-deps indexer hindsight-project-index --vault PATH --apply
55
+ ```
56
+
57
+ `--no-deps` avoids starting the `hindsight` service, which the indexer depends on. `PATH` is the host path, which the container also sees.
@@ -0,0 +1,74 @@
1
+ # Manual stack setup
2
+
3
+ Use this when you are not running the [setup wizard](setup-wizard.md). Commands assume your **stack root** is the current directory (git checkout or `PM_STACK_ROOT`).
4
+
5
+ ## Hindsight: minimal path
6
+
7
+ ```sh
8
+ mkdir -p ~/.config/hindsight
9
+ cp config/hindsight.env.example ~/.config/hindsight/hindsight.env
10
+ chmod 600 ~/.config/hindsight/hindsight.env
11
+ node scripts/setup.mjs
12
+ node scripts/setup.mjs --migrate-env # only if hindsight.env still points at lemond/Ollama directly
13
+ docker compose up -d
14
+ curl -fsS http://127.0.0.1:8888/health
15
+ ```
16
+
17
+ `scripts/setup.mjs` must run before any `docker compose` command (including `logs` and `down`). It writes stack `.env`, `compose.override.yaml`, and related files.
18
+
19
+ ## Compose profiles
20
+
21
+ | Profile | Services |
22
+ | --- | --- |
23
+ | `hindsight` | LiteLLM + Hindsight API (default after wizard) |
24
+ | `ollama` | In-compose Ollama for LiteLLM |
25
+ | `notebooklm` | NotebookLM → Hindsight sync |
26
+
27
+ Plain `docker compose up` without profiles starts only the indexer unless `.env` sets `COMPOSE_PROFILES`. The wizard passes every needed `--profile` on each compose invocation.
28
+
29
+ NotebookLM is started **after** the smoke test so sync does not compete with smoke on the LLM.
30
+
31
+ ## Indexer sinks
32
+
33
+ | Variable | Meaning |
34
+ | --- | --- |
35
+ | `MEMORY_SINK` / `--sink` | `hindsight` (default), `mem0`, `cognee`, … |
36
+ | `HINDSIGHT_URL` | Hindsight API from indexer container |
37
+ | `MEMORY_API_URL` | Non-Hindsight memory API |
38
+
39
+ Entrypoint: `bin/hindsight-project-index` via `indexer/sinks/`.
40
+
41
+ ## What setup.mjs generates
42
+
43
+ | Output | Role |
44
+ | --- | --- |
45
+ | `.env` | `HOST_UID`, `HOST_GID`, `LITELLM_CONFIG`, `COMPOSE_PROFILES`, … |
46
+ | `compose.override.yaml` | Masks `~/.ssh`, `~/.gnupg`, `~/.config/hindsight`, agent credential dirs from the indexer; optional mount for `index.yml` |
47
+ | `~/.config/hindsight/litellm.env` | LiteLLM master key (mode 600) if missing |
48
+
49
+ The indexer runs as your UID (`user: "${HOST_UID}:${HOST_GID}"`). Writable state is only the named volume `indexer-state` (mounted at `$HOME/.cache/hindsight-project-index` inside the container); `$HOME` is read-only.
50
+
51
+ Rerun `node scripts/setup.mjs` after UID changes or when new secret directories appear (masks are generated only for paths that exist).
52
+
53
+ ## Seed indexer state volume
54
+
55
+ When moving from a host `state.json` to the volume:
56
+
57
+ ```bash
58
+ docker compose stop indexer
59
+ docker compose run --rm --no-deps indexer-state-init
60
+ docker run --rm --user "$HOST_UID:$HOST_GID" \
61
+ -v "$HOME/.cache/hindsight-project-index:/src:ro" \
62
+ -v personal-memory_indexer-state:/dst openmem-indexer:local \
63
+ cp /src/state.json /dst/
64
+ ```
65
+
66
+ Adjust the volume name with `docker volume ls` if the compose project name differs.
67
+
68
+ ## Bench overlay (optional)
69
+
70
+ `compose.bench.yaml` also publishes Hindsight on the Docker bridge gateway for sandboxes (see the file for the bind address). Keep `compose.override.yaml` in the `-f` list when you add `-f compose.bench.yaml`.
71
+
72
+ ```bash
73
+ docker compose -f compose.yaml -f compose.override.yaml -f compose.bench.yaml up -d hindsight
74
+ ```
@@ -0,0 +1,4 @@
1
+ # MCP install guide
2
+
3
+ This page moved to **[MCP setup](mcp-setup.md)** (published on the docs site).
4
+
@@ -0,0 +1,104 @@
1
+ # MCP setup
2
+
3
+ OpenMem registers **stdio MCP servers** in `~/.cursor/mcp.json` (and wires session hooks via `install-coding-agent`). Day-to-day you want the **unified** `openmem` server (`memory_*` tools). Provider-native and NotebookLM servers are optional add-ons.
4
+
5
+ For why this exists, see [Concepts](concepts.md). Install path: [Quickstart § Wire your coding agent](quickstart.md#3-wire-your-coding-agent-optional). Per-agent support: [Compatibility matrix](compatibility.md).
6
+
7
+ ## Quick path (recommended)
8
+
9
+ Run the wizard first. The MCP server only forwards `memory_*` calls to a running provider; without the stack and `wizard.conf` it has nothing to talk to.
10
+
11
+ ```sh
12
+ npx @bcmyguest/openmem # wizard: provider, stack, smoke test
13
+ npx @bcmyguest/openmem install-coding-agent --yes
14
+ ```
15
+
16
+ That installs:
17
+
18
+ 1. Unified MCP (`openmem`) — `memory_add`, `memory_search`, `memory_recall`, `memory_reflect`, `memory_consolidate`, `memory_forget`, `memory_export` / `memory_import`, ops tools
19
+ 2. OpenMem skill + session hooks (Claude Code, Codex, OpenCode, Cursor CLI)
20
+
21
+ MCP only (no session hooks):
22
+
23
+ ```sh
24
+ npx @bcmyguest/openmem install-mcp --yes
25
+ ```
26
+
27
+ Restart **Cursor Agent** (or your agent’s MCP host) after changes.
28
+
29
+ ## Server families
30
+
31
+ | Server key | How to install | Tools | Backend |
32
+ | --- | --- | --- | --- |
33
+ | **`openmem`** | Default `install-mcp` / `install-coding-agent` | Stable `memory_*` | Active provider (`MEMORY_PROVIDER`): Hindsight, mem0, or Cognee |
34
+ | **Provider-native** (`mem0`, `cognee`) | `install-mcp --provider-only` | Upstream / repo-specific names | Same HTTP API, different tool surface |
35
+ | **`notebooklm`** | When NotebookLM sync is on, or `--notebooklm` | `notebooklm_list_banks`, `notebooklm_search` | Search over synced notebooks on the **active** provider — not a memory engine |
36
+
37
+ Hindsight’s optional in-editor plugin (`install-coding-agent --provider-plugin`) is **not** an MCP entry; it replaces OpenMem’s session hooks on Hindsight stacks and keeps the unified MCP. See [Hindsight](hindsight.md).
38
+
39
+ ## When to use which
40
+
41
+ ### Default: unified `memory_*`
42
+
43
+ Use when you want one tool contract that survives `npx @bcmyguest/openmem switch <provider>` without rewriting prompts.
44
+
45
+ ```sh
46
+ npx @bcmyguest/openmem install-mcp --yes
47
+ npx @bcmyguest/openmem install-mcp --yes --notebooklm # also force NotebookLM MCP
48
+ ```
49
+
50
+ ### Provider-native (optional)
51
+
52
+ Use when you already have prompts for upstream tool names:
53
+
54
+ ```sh
55
+ MEMORY_PROVIDER=mem0 npx @bcmyguest/openmem install-mcp --yes --provider-only
56
+ npx @bcmyguest/openmem install-mcp --yes --provider-only # Cognee when active
57
+ ```
58
+
59
+ - **mem0:** `cli/mem0-mcp.mjs` → `@yeyuan98/mem0-mcp` (URL + path to `mem0.env` in JSON — never the key). Details: [mem0](mem0.md).
60
+ - **Cognee:** `cli/cognee-mcp.mjs` (`cognee_health`, `cognee_search`; `COGNEE_API_URL` only). Details: [Cognee](cognee.md).
61
+
62
+ `install-mcp --provider-only` still merges unified `openmem` unless you also pass `--no-unified-mcp`. Both can coexist in `mcp.json`.
63
+
64
+ ### NotebookLM only
65
+
66
+ ```sh
67
+ npx @bcmyguest/openmem install-mcp --yes --notebooklm-only
68
+ ```
69
+
70
+ Mutually exclusive with `--provider-only`. Read-only search over synced notebooks — not a substitute for project indexing or `memory_*`.
71
+
72
+ ## Flags
73
+
74
+ ```sh
75
+ npx @bcmyguest/openmem install-mcp --yes
76
+ npx @bcmyguest/openmem install-mcp --yes --notebooklm
77
+ npx @bcmyguest/openmem install-mcp --yes --notebooklm-only
78
+ MEMORY_PROVIDER=mem0 npx @bcmyguest/openmem install-mcp --yes --provider-only
79
+ npx @bcmyguest/openmem install-mcp --yes --no-unified-mcp
80
+ npx @bcmyguest/openmem install-mcp --dry-run
81
+ ```
82
+
83
+ | Flag | Effect |
84
+ | --- | --- |
85
+ | `--yes` | No confirmation prompt |
86
+ | `--dry-run` | Print plan; do not write configs |
87
+ | `--notebooklm` | Enable NotebookLM agent access + merge `notebooklm` MCP |
88
+ | `--notebooklm-only` | Only NotebookLM step |
89
+ | `--provider-only` | Native mem0/Cognee MCP for active provider; skip NotebookLM |
90
+ | `--no-unified-mcp` | Do not merge the `openmem` server |
91
+
92
+ **Provider resolution:** `MEMORY_PROVIDER` → `~/.config/hindsight/wizard.conf` → `hindsight`.
93
+
94
+ **Merge behavior:** Existing `hindsight`, `codegraph`, and `notebooklm` entries are preserved; mem0/Cognee entries are updated for the active provider.
95
+
96
+ ## Portability tools
97
+
98
+ On the unified server, `memory_export` / `memory_import` speak **PMM** (Personal Memory Manifest). See [Portable memory (PMM)](memory-portability.md).
99
+
100
+ ## Related
101
+
102
+ - [mem0](mem0.md) · [Cognee](cognee.md) · [Hindsight](hindsight.md)
103
+ - [Architecture](architecture.md) — how `memory_*` maps to provider HTTP
104
+ - [Quickstart](quickstart.md)
package/docs/mem0.md ADDED
@@ -0,0 +1,141 @@
1
+ # mem0
2
+
3
+ **mem0** is a supported OpenMem provider. You run a [self-hosted mem0 REST server](https://docs.mem0.ai/open-source/features/rest-api); OpenMem points the shared indexer and unified `memory_*` MCP at it. One active provider at a time — same agent surface as Hindsight or Cognee.
4
+
5
+ This is **not** the hosted platform at `https://api.mem0.ai` (different API shape). OpenMem talks to the open-source REST server only (no `/v1/` prefix).
6
+
7
+ Upstream project: [mem0ai/mem0](https://github.com/mem0ai/mem0). Stack details for contributors: `providers/mem0/OPERATOR.md`.
8
+
9
+ ## What you run vs what OpenMem runs
10
+
11
+ | You | OpenMem |
12
+ | --- | --- |
13
+ | mem0 REST server (JWT, Postgres/pgvector, embedder keys) | `MEMORY_PROVIDER=mem0`, `MEMORY_SINK=mem0` |
14
+ | API key in `~/.config/personal-memory/mem0.env` (mode **600**) | `MEM0_API_URL` / `MEM0_INDEXER_URL` in stack env |
15
+ | Bind so the indexer container can reach the server | Wizard smoke: docs, retain, search, delete-by-id |
16
+ | | Unified MCP + optional native mem0 MCP |
17
+
18
+ Compose profile `mem0` adds env + `extra_hosts` on the shared **indexer** only — there is no mem0 container in this repo yet. The optional profile `litellm` adds the stack LiteLLM on loopback for mem0's LLM ([below](#models-through-the-stack-litellm-optional)).
19
+
20
+ ## First-time setup
21
+
22
+ 1. Start your mem0 REST server (default OpenMem port expectation: **18888**).
23
+ 2. Put the API key in the env file (skip if `AUTH_DISABLED=true` on the server for local dev only):
24
+
25
+ ```text
26
+ ~/.config/personal-memory/mem0.env
27
+ MEM0_API_KEY=…
28
+ ```
29
+
30
+ Never put `MEM0_API_KEY` in stack `.env`, `wizard.conf`, `config.toml`, or `mcp.json`.
31
+
32
+ 3. Select mem0 in the wizard, or switch later:
33
+
34
+ ```sh
35
+ npx @bcmyguest/openmem # choose mem0 when prompted
36
+ # or:
37
+ npx @bcmyguest/openmem switch mem0 --yes
38
+ ```
39
+
40
+ 4. Confirm:
41
+
42
+ ```sh
43
+ npx @bcmyguest/openmem doctor
44
+ curl -fsS "$MEM0_API_URL/docs" # URL from wizard / stack .env
45
+ ```
46
+
47
+ ## URLs
48
+
49
+ | Variable | Meaning |
50
+ | --- | --- |
51
+ | `MEM0_API_URL` | Host view (what you curl), e.g. `http://127.0.0.1:18888` |
52
+ | `MEM0_INDEXER_URL` | Derived for the indexer container — loopback hosts are rewritten to the Docker bridge gateway. Do not set this to `127.0.0.1` by hand inside the container. |
53
+
54
+ **Linux:** a process bound only to loopback is often unreachable from the indexer container. Bind mem0 to `0.0.0.0` (or a real hostname). Prefer `https://` when the server is not on loopback — `X-API-Key` is cleartext on plain HTTP.
55
+
56
+ Search fails if the server’s embedder is misconfigured; smoke stores with `infer: false` and looks for that fact.
57
+
58
+ ## Models through the stack LiteLLM (optional)
59
+
60
+ mem0 picks its own LLM and embedder. The wizard can instead route mem0's LLM through the stack's LiteLLM, the gateway Hindsight uses, so a model change (Claude included) is one LiteLLM route. In step 3 answer yes to "Route mem0's LLM through the stack LiteLLM", or run `./setup --yes` with `MEM0_LITELLM=1`.
61
+
62
+ | Backend | mem0 LLM (`memory-llm`) | Embeddings (`memory-embed`) | Key in `litellm.env` |
63
+ | --- | --- | --- | --- |
64
+ | Ollama | `ollama_chat/<model>` (default `gemma4:e2b`) | `ollama/nomic-embed-text` by default (`none` keeps mem0's embedder) | none |
65
+ | Custom OpenAI-compatible URL | `openai/<model>` | optional `openai/<model>` (e.g. `text-embedding-3-small`) | `LEMOND_API_KEY` (same variable as Hindsight's custom route) |
66
+ | Anthropic API key | `anthropic/<model>` (default `claude-haiku-5-5`) | none: mem0 keeps its own embedder | `ANTHROPIC_API_KEY` |
67
+ | Claude subscription (Meridian) | `anthropic/<model>` at Meridian ([guide](meridian-litellm.md)); use is governed by Anthropic's [Consumer Terms](https://www.anthropic.com/legal/consumer-terms) | none | `MERIDIAN_API_KEY` |
68
+
69
+ What the wizard does:
70
+
71
+ - writes `~/.config/personal-memory/mem0-litellm.yaml` (routes only; keys are `os.environ/…` references) and points `LITELLM_CONFIG` at it;
72
+ - keeps `LITELLM_MASTER_KEY` and provider keys in `~/.config/hindsight/litellm.env` (mode 600; `LITELLM_ENV_FILE` overrides), creating an `sk-` master key when the file is new;
73
+ - sets `COMPOSE_PROFILES=mem0,litellm`. `litellm` has its own compose profile; `providers/mem0/compose.yaml` publishes it on **`127.0.0.1:${MEM0_LITELLM_PORT:-4000}` only** (the wizard keeps 4000 when free, else offers the next free port) and its entrypoint exits unless `LITELLM_MASTER_KEY` starts with `sk-`;
74
+ - prints the mem0 config blocks below. It does **not** edit your mem0 server config.
75
+
76
+ ```json
77
+ {
78
+ "llm": {"provider": "openai", "config": {"model": "memory-llm", "openai_base_url": "http://127.0.0.1:4000/v1", "api_key": "<LITELLM_MASTER_KEY>"}},
79
+ "embedder": {"provider": "openai", "config": {"model": "memory-embed", "openai_base_url": "http://127.0.0.1:4000/v1", "api_key": "<LITELLM_MASTER_KEY>"}},
80
+ "vector_store": {"config": {"embedding_model_dims": 768}}
81
+ }
82
+ ```
83
+
84
+ The `embedder` and `vector_store` blocks appear only when the backend serves embeddings (768 is `nomic-embed-text`'s size). Apply the blocks yourself: `POST /configure` on the REST server with an admin key, or merge them into the dict you pass to `Memory.from_config`.
85
+
86
+ Why these keys (mem0 `main` at [26cdefb](https://github.com/mem0ai/mem0/tree/26cdefb46600c0fa5953c4b5ee5003c125539fc4)):
87
+
88
+ - The self-hosted REST server bundles only the `openai`, `anthropic` and `gemini` LLM providers and the `openai` and `gemini` embedders ([server/main.py L62-63](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/server/main.py#L62-L63)), so the snippet uses provider `openai` against LiteLLM rather than mem0's `litellm` provider ([docs](https://docs.mem0.ai/components/llms/models/litellm)), which also passes no base URL to `litellm.completion` ([mem0/llms/litellm.py](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/mem0/llms/litellm.py)).
89
+ - The `openai` LLM uses `openai_base_url` and `api_key` from its config, but switches to OpenRouter when `OPENROUTER_API_KEY` is set ([mem0/llms/openai.py](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/mem0/llms/openai.py), [config](https://docs.mem0.ai/components/llms/config)).
90
+ - The `openai` embedder reads `openai_base_url`, `api_key` and `model` ([mem0/embeddings/openai.py](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/mem0/embeddings/openai.py), [config](https://docs.mem0.ai/components/embedders/config)). Leaving `embedding_dims` unset keeps it from sending a `dimensions` parameter.
91
+ - pgvector's collection size is `vector_store.config.embedding_model_dims` (default 1536, [mem0/configs/vector_stores/pgvector.py](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/mem0/configs/vector_stores/pgvector.py)). A different embedder needs a new collection or re-added memories.
92
+ - `POST /configure` deep-merges the body into the running config and persists it ([server/main.py L332-337](https://github.com/mem0ai/mem0/blob/26cdefb46600c0fa5953c4b5ee5003c125539fc4/server/main.py#L332-L337), `update_config` in `server/server_state.py`).
93
+
94
+ Limits: `127.0.0.1` reaches LiteLLM only from a mem0 server running on this host; a mem0 server inside another container needs host networking or a different route. Claude has no embedding model, so the Anthropic and Meridian backends route the LLM only. Whether mem0's extraction prompts (JSON `response_format`) work with every routed model is not verified here; test with an `infer: true` add after switching.
95
+
96
+ ## Banks / scopes
97
+
98
+ mem0 scopes map to **`user_id`**. OpenMem’s MCP `bank` argument and indexer banks become that `user_id`. Default unified MCP scope is `openmem-mcp` unless tools pass `bank`. Project work should pass the resolved project bank so session noise does not land in the default. See [Concepts — Context and banks](concepts.md#context-and-banks).
99
+
100
+ ## Coding agents and MCP
101
+
102
+ **Preferred:** unified OpenMem MCP (`memory_*`) — same tools as Hindsight/Cognee:
103
+
104
+ ```sh
105
+ npx @bcmyguest/openmem install-coding-agent --yes
106
+ # or MCP only:
107
+ npx @bcmyguest/openmem install-mcp --yes
108
+ ```
109
+
110
+ **Optional native mem0 tools** (upstream `@yeyuan98/mem0-mcp` names, not `memory_*`):
111
+
112
+ ```sh
113
+ MEMORY_PROVIDER=mem0 npx @bcmyguest/openmem install-mcp --yes --provider-only
114
+ ```
115
+
116
+ That registers `cli/mem0-mcp.mjs` with `MEM0_API_URL` / `MEM0_BASE_URL` and the **path** to `mem0.env` — never the key value in `mcp.json`. Mem0’s cloud MCP (`https://mcp.mem0.ai`) is **not** for self-hosted REST.
117
+
118
+ Restart Cursor Agent after MCP changes. Full flag matrix: [MCP setup](mcp-setup.md).
119
+
120
+ There is no Hindsight-style coding-agent plugin for mem0; session hooks + unified MCP cover day-to-day agent memory.
121
+
122
+ ## Portability
123
+
124
+ Export/import uses **PMM** via `memory_export` / `memory_import` on the unified MCP. Switching providers does **not** migrate data by itself — export, switch, import (or re-index). See [Portable memory (PMM)](memory-portability.md).
125
+
126
+ ## Switch provider
127
+
128
+ ```sh
129
+ npx @bcmyguest/openmem switch mem0 --yes
130
+ # later:
131
+ npx @bcmyguest/openmem switch hindsight --yes
132
+ ```
133
+
134
+ Updates active provider config, restarts the stack (unless `--no-stack`), refreshes MCP (unless `--no-mcp`). Does **not** migrate memories.
135
+
136
+ ## Related
137
+
138
+ - [Concepts](concepts.md) — interface layer
139
+ - [MCP setup](mcp-setup.md) — unified vs provider-native
140
+ - [Portable memory (PMM)](memory-portability.md)
141
+ - [Architecture](architecture.md) · [Provider status](provider-status.md)