@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,150 @@
1
+ /**
2
+ * Hindsight sub-wizard (hook API v2). Owns everything Hindsight-specific that the meta
3
+ * wizard used to do inline: the lemond / Ollama / custom model flow and LiteLLM routes,
4
+ * hindsight.env and litellm.env, the HINDSIGHT_PORT / HINDSIGHT_CP_PORT pair, Hindsight
5
+ * validation, and the summary lines. See lib/ for the implementations and
6
+ * docs/provider-wizard-hooks.md for the hook contract.
7
+ *
8
+ * This module must not import wizard/lib/run-wizard.mjs; it receives `helpers`.
9
+ */
10
+ import { applyConfigEnv, configToml as buildConfigToml } from "./lib/config.mjs";
11
+ import { setupCodingAgent as linkCodingAgent } from "./lib/coding-agent.mjs";
12
+ import { clackSetup as askInClack } from "./lib/clack.mjs";
13
+ import { setupEnv as setupHindsightEnv, stackEnv as hindsightStackEnv } from "./lib/env-setup.mjs";
14
+ import { chooseModelBackend } from "./lib/model-backend.mjs";
15
+ import { ensureComposeOllamaModels } from "./lib/ollama-compose.mjs";
16
+ import { resolvePorts as resolveHindsightPorts } from "./lib/ports.mjs";
17
+ import { backendDefault, confGet, ensureState } from "./lib/state.mjs";
18
+ import { summary as hindsightSummary } from "./lib/summary.mjs";
19
+ import { validateHindsight } from "./lib/validate.mjs";
20
+
21
+ // Called by scripts/setup.mjs (the stack .env writer), not by the wizard.
22
+ export { migrateEnv, prepareStackEnv, setupNotices } from "./lib/stack-env.mjs";
23
+
24
+ /** @typedef {import('../../wizard/lib/provider-wizard/helpers.mjs').ProviderWizardHelpers} Helpers */
25
+
26
+ /**
27
+ * Quiet: fill Hindsight's context fields, map [stack]/[model] TOML defaults into the
28
+ * environment (including LEMOND_BASE from [model].lemond.host).
29
+ * @param {Record<string, any>} ctx
30
+ * @param {Helpers} h
31
+ */
32
+ export async function init(ctx, h) {
33
+ ensureState(ctx);
34
+ applyConfigEnv(ctx.pmMerged || {});
35
+ if (process.env.LEMOND_BASE) ctx.lemondBase = process.env.LEMOND_BASE;
36
+ }
37
+
38
+ /**
39
+ * @param {Record<string, any>} ctx
40
+ * @param {Helpers} h
41
+ */
42
+ export async function afterProvider(ctx, h) {
43
+ h.info("Hindsight uses LiteLLM aliases (memory-retain / reflect / consolidate).");
44
+ }
45
+
46
+ /**
47
+ * Step "3. Model backend": lemond, Ollama, a custom OpenAI-compatible URL or a Claude
48
+ * subscription through Meridian, behind the LiteLLM proxy.
49
+ * @param {Record<string, any>} ctx
50
+ * @param {Helpers} h
51
+ */
52
+ export async function configureModelRouting(ctx, h) {
53
+ await chooseModelBackend(ctx, h);
54
+ }
55
+
56
+ /** Hindsight's API and control-plane ports. */
57
+ export const resolvePorts = resolveHindsightPorts;
58
+
59
+ /**
60
+ * Quiet: description and environment for the stack setup script (scripts/setup.mjs).
61
+ * @param {Record<string, any>} ctx
62
+ */
63
+ export function stackEnv(ctx) {
64
+ return hindsightStackEnv(ctx);
65
+ }
66
+
67
+ /** hindsight.env, litellm.env wiring. */
68
+ export const setupEnv = setupHindsightEnv;
69
+
70
+ /**
71
+ * Quiet: reload the model choice from wizard.conf for `--up`.
72
+ * @param {Record<string, any>} ctx
73
+ * @param {Helpers} h
74
+ */
75
+ export async function hydrate(ctx, h) {
76
+ ensureState(ctx);
77
+ ctx.backend = confGet(ctx, h, "MEMORY_BACKEND") || backendDefault(ctx, h);
78
+ ctx.model = confGet(ctx, h, "MEMORY_MODEL") || ctx.lemondDefaultModel;
79
+ ctx.apiBase = confGet(ctx, h, "MEMORY_API_BASE") || "";
80
+ ctx.reflectModel = confGet(ctx, h, "MEMORY_REFLECT_MODEL") || "";
81
+ ctx.meridianBase = confGet(ctx, h, "MEMORY_MERIDIAN_URL") || "";
82
+ ctx.ollamaInCompose = confGet(ctx, h, "MEMORY_OLLAMA_IN_COMPOSE") === "1";
83
+ applyComposeProfiles(ctx);
84
+ }
85
+
86
+ /**
87
+ * Ensure compose profile `ollama` is on the up command when MEMORY_OLLAMA_IN_COMPOSE=1.
88
+ * @param {Record<string, any>} ctx
89
+ * @param {Helpers} _h
90
+ */
91
+ export async function beforeStack(ctx, _h) {
92
+ ensureState(ctx);
93
+ applyComposeProfiles(ctx);
94
+ }
95
+
96
+ /**
97
+ * Pull models into compose Ollama after the stack is up (host has no ollama CLI).
98
+ * @param {Record<string, any>} ctx
99
+ * @param {Helpers} h
100
+ */
101
+ export async function afterStackHealthy(ctx, h) {
102
+ await ensureComposeOllamaModels(ctx, h);
103
+ }
104
+
105
+ /** @param {Record<string, any>} ctx */
106
+ function applyComposeProfiles(ctx) {
107
+ const extra = [...(ctx.extraComposeProfiles || [])];
108
+ if (ctx.ollamaInCompose && !extra.includes("ollama")) extra.push("ollama");
109
+ ctx.extraComposeProfiles = extra;
110
+ }
111
+
112
+ /**
113
+ * Quiet: tables merged into config.toml.
114
+ * @param {Record<string, any>} ctx
115
+ */
116
+ export function configToml(ctx) {
117
+ ensureState(ctx);
118
+ return buildConfigToml(ctx);
119
+ }
120
+
121
+ /**
122
+ * Quiet: lines for the closing summary.
123
+ * @param {Record<string, any>} ctx
124
+ */
125
+ export function summary(ctx) {
126
+ return hindsightSummary(ctx);
127
+ }
128
+
129
+ /**
130
+ * Appends to ctx.validationErrors / ctx.validationChecks after the shared checks.
131
+ * @param {Record<string, any>} ctx
132
+ * @param {Helpers} h
133
+ */
134
+ export async function extendValidation(ctx, h) {
135
+ validateHindsight(ctx, h);
136
+ }
137
+
138
+ /** Link ~/.hindsight/coding-agent.json and check optInPaths. */
139
+ export const setupCodingAgent = linkCodingAgent;
140
+
141
+ /**
142
+ * Clack-only: ask the model questions, return the environment that makes the wizard
143
+ * skip its own (see WIZARD_SKIP_BACKEND_STEP).
144
+ * @param {Record<string, any>} ctx
145
+ * @param {typeof import("@clack/prompts")} ui
146
+ * @param {Helpers} h
147
+ */
148
+ export async function clackSetup(ctx, ui, h) {
149
+ return askInClack(ctx, ui, h);
150
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "id": "letta",
3
+ "label": "Letta",
4
+ "status": "planned",
5
+ "notes": "Placeholder manifest. Letta (formerly MemGPT) server integration is not wired; track via issues before changing status.",
6
+ "settings": {
7
+ "nativeDocs": "https://docs.letta.com/",
8
+ "nativeConfigPaths": [],
9
+ "wizardOwns": []
10
+ },
11
+ "compose": {
12
+ "profile": "letta",
13
+ "files": [],
14
+ "services": [],
15
+ "healthService": null,
16
+ "healthPath": null,
17
+ "hostPortEnv": null,
18
+ "defaultHostPort": null
19
+ },
20
+ "indexer": {
21
+ "apiUrlEnv": "LETTA_API_URL",
22
+ "sink": "letta"
23
+ },
24
+ "codingAgent": {
25
+ "pluginPackage": null,
26
+ "configTemplate": null
27
+ },
28
+ "wizard": {}
29
+ }
@@ -0,0 +1,143 @@
1
+ # mem0 operator runbook (URL-only)
2
+
3
+ This stack does **not** run a mem0 container. You run a [self-hosted mem0 REST
4
+ server](https://docs.mem0.ai/open-source/features/rest-api); `./setup` only points
5
+ the shared indexer at it.
6
+
7
+ **Not** the hosted platform at `https://api.mem0.ai`. That API shape differs
8
+ (`/v1/…`); the indexer sink and wizard smoke talk to the open-source REST
9
+ server only (no `/v1/` prefix).
10
+
11
+ ## What `./setup` owns vs what you own
12
+
13
+ | You (provider-native) | This stack |
14
+ | --- | --- |
15
+ | Start the mem0 REST server (JWT, Postgres/pgvector, dashboard) | Write `MEM0_API_URL` / `MEM0_INDEXER_URL` into the stack `.env` |
16
+ | Embedder / LLM keys for mem0 itself | Indexer sink (`MEMORY_SINK=mem0`) and host-gateway rewrite |
17
+ | Create an API key (dashboard or `POST /api-keys`) | Store `MEM0_API_KEY` in `~/.config/personal-memory/mem0.env` (mode **600**) |
18
+ | Optional `AUTH_DISABLED=true` (dev only) | Smoke: `GET /docs`, retain, search, delete-by-id |
19
+ | Apply the printed `llm` / `embedder` blocks to mem0 (optional) | Optional stack LiteLLM for mem0's LLM: routes, `litellm.env`, profile `litellm` on `127.0.0.1` |
20
+
21
+ ## URLs
22
+
23
+ - **`MEM0_API_URL`** — host view (what you curl from this machine), e.g.
24
+ `http://127.0.0.1:18888`. Default port in the manifest is **18888**.
25
+ - **`MEM0_INDEXER_URL`** — container view. `./setup` derives it from
26
+ `MEM0_API_URL` by rewriting loopback hosts (`127.0.0.1`, `localhost`,
27
+ `0.0.0.0`, `[::1]`) to `host.docker.internal`. Do not hand-edit it to
28
+ `127.0.0.1` inside the container; validation requires it to match that rewrite.
29
+
30
+ ## Linux loopback
31
+
32
+ `host.docker.internal` is the docker bridge gateway, **not** the host's
33
+ `127.0.0.1`. A mem0 process bound only to `127.0.0.1` is unreachable from the
34
+ indexer container. Bind the server to `0.0.0.0` (or the bridge IP), or put a
35
+ real hostname in `MEM0_API_URL`. An `https://localhost` URL becomes
36
+ `https://host.docker.internal`, which usually fails TLS name checks — use a
37
+ hostname the certificate covers.
38
+
39
+ ## API key file
40
+
41
+ ```text
42
+ ~/.config/personal-memory/mem0.env # mode 600; directory mode 700
43
+ MEM0_API_KEY=<key>
44
+ ```
45
+
46
+ Never put `MEM0_API_KEY` in the stack `.env` (mode 644), `wizard.conf`, or
47
+ `config.toml`. Override the path with `MEM0_ENV_FILE` / `[memory.mem0] env_file`
48
+ if needed; then `./setup` must record that path in the stack `.env`.
49
+
50
+ With **`AUTH_DISABLED=true`** on the server (development only), no key is
51
+ required. Auth-enabled servers need a key or smoke/indexer calls return 401.
52
+
53
+ ## Embedder
54
+
55
+ Search fails if the server's embedder is misconfigured. Smoke looks for the
56
+ fact stored with `infer: false`; a miss points at the embedder key and server
57
+ logs, not at this stack.
58
+
59
+ ## Cleartext keys
60
+
61
+ Over plain `http://` to a non-loopback host, `X-API-Key` travels in cleartext.
62
+ Prefer `https://`, or keep the server on loopback / the same host.
63
+
64
+ ## Coding agents
65
+
66
+ There is no `pluginPackage`. Agents talk to your server via the Python SDK,
67
+ the self-hosted MCP bridge, or direct REST (`POST /memories`, `POST /search`). The
68
+ wizard's coding-agent step prints those paths and can register Cursor MCP; see
69
+ `providers/mem0/lib/coding-agent.mjs`.
70
+
71
+ ### Cursor MCP (`~/.cursor/mcp.json`)
72
+
73
+ Mem0's official MCP (`https://mcp.mem0.ai`) is **platform/cloud only**. For a
74
+ self-hosted REST server this repo registers [`@yeyuan98/mem0-mcp`](https://www.npmjs.com/package/@yeyuan98/mem0-mcp)
75
+ via the launcher `cli/mem0-mcp.mjs` (loads the key from the env file, then
76
+ `npx -y @yeyuan98/mem0-mcp`).
77
+
78
+ ```sh
79
+ MEMORY_PROVIDER=mem0 npx openmem install-mcp --yes
80
+ # checkout: MEMORY_PROVIDER=mem0 node cli/openmem.mjs install-mcp --yes
81
+ # or accept the coding-agent MCP confirm in setup
82
+ ```
83
+
84
+ Shape written (URL and env-file **path** only — never the key value):
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "mem0": {
90
+ "command": "node",
91
+ "args": ["/path/to/openmem/cli/mem0-mcp.mjs"],
92
+ "env": {
93
+ "MEM0_API_URL": "http://127.0.0.1:18888",
94
+ "MEM0_BASE_URL": "http://127.0.0.1:18888",
95
+ "MEM0_ENV_FILE": "~/.config/personal-memory/mem0.env"
96
+ }
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ **API key:** the launcher reads `MEM0_API_KEY` from `MEM0_ENV_FILE` when the
103
+ variable is not already in the process environment. You can also
104
+ `export MEM0_API_KEY=…` (e.g. `set -a; source ~/.config/personal-memory/mem0.env; set +a`)
105
+ before starting Cursor so the agent inherits it. **Never** put `MEM0_API_KEY` in
106
+ `mcp.json`. Existing `hindsight` / `codegraph` / `notebooklm` servers are left alone.
107
+
108
+ Restart Cursor Agent after install.
109
+
110
+ ### Switch to / from mem0
111
+
112
+ ```sh
113
+ npx openmem switch mem0 --yes
114
+ # later: npx openmem switch hindsight --yes
115
+ # checkout: node cli/openmem.mjs switch mem0 --yes
116
+ ```
117
+
118
+ Updates `wizard.conf` (and `config.toml` `[memory].provider` when present), restarts the stack
119
+ unless `--no-stack`, and runs `install-mcp --provider-only` unless `--no-mcp`. Does **not**
120
+ migrate memories. Flags: [README — Switch memory provider](../../README.md#switch-memory-provider).
121
+
122
+ ## Models through the stack LiteLLM
123
+
124
+ Optional (wizard step 3, or `MEM0_LITELLM=1` under `--yes`): mem0's LLM, and
125
+ its embedder when the backend has one, go through the stack LiteLLM. Inputs
126
+ under `--yes`: `MEM0_LITELLM_BACKEND` (`ollama`, `custom`, `anthropic`,
127
+ `meridian`), `MEM0_LITELLM_MODEL`, `MEM0_LITELLM_API_BASE`,
128
+ `MEM0_LITELLM_EMBED_MODEL` (`none` keeps mem0's embedder),
129
+ `MEM0_LITELLM_PORT` (default 4000), `ANTHROPIC_API_KEY`. The wizard writes
130
+ `~/.config/personal-memory/mem0-litellm.yaml`, keeps keys in
131
+ `~/.config/hindsight/litellm.env` (mode 600), and prints the mem0 `llm` /
132
+ `embedder` blocks (provider `openai`, `openai_base_url`
133
+ `http://127.0.0.1:<port>/v1`, `api_key` = `LITELLM_MASTER_KEY`). You apply
134
+ them; the wizard never edits the mem0 server config. Key sources and limits:
135
+ [docs/mem0.md](../../docs/mem0.md#models-through-the-stack-litellm-optional).
136
+
137
+ ## Compose
138
+
139
+ `providers/mem0/compose.yaml` defines no mem0 service — only env +
140
+ `extra_hosts` on the shared `indexer`. Profile `mem0` selects that fragment.
141
+ It also overlays the base `litellm` service: under profile `litellm` it
142
+ publishes `127.0.0.1:${MEM0_LITELLM_PORT:-4000}` (never `0.0.0.0`) and its
143
+ entrypoint exits unless `LITELLM_MASTER_KEY` starts with `sk-`.
@@ -0,0 +1,79 @@
1
+ # mem0 compose fragment (URL-only mode). Layered over compose.yaml; the wizard passes both, then `up -d`:
2
+ # docker compose -f compose.yaml -f providers/mem0/compose.yaml --profile mem0 up -d
3
+ # Add `-f compose.override.yaml` when you use the generated secret masks (Compose skips that file once -f is given).
4
+ #
5
+ # URL-only: this fragment defines NO service. The indexer talks to a mem0 REST server you already run (usually on
6
+ # the host, or on another machine); nothing here starts, builds or pulls a mem0 container. The reason is that the
7
+ # current self-hosted mem0 server (JWT/API-key auth, dashboard, Postgres + pgvector) has no current published image:
8
+ # `mem0/mem0-api-server:latest` on Docker Hub predates the auth. A mem0 service is a documented follow-up: build
9
+ # `server/` from a pinned mem0 git ref next to `pgvector/pgvector:pg17`, pinned and verified. Until then there is no
10
+ # `mem0` profile service, so `--profile mem0` only selects this fragment; it starts the provider-neutral indexer
11
+ # and its state-init step and nothing else.
12
+ #
13
+ # What the base compose.yaml gives you:
14
+ # - `indexer` and `indexer-state-init` have no profile and no provider dependency, so they start for every
15
+ # provider. This fragment points the indexer at the mem0 server.
16
+ # - `hindsight` carries the profile "hindsight" and never starts here.
17
+ # - `litellm` also carries its own profile "litellm". It starts only when the wizard's "route mem0's LLM through the
18
+ # stack LiteLLM" option is on, which writes COMPOSE_PROFILES=mem0,litellm. This fragment then publishes it on
19
+ # 127.0.0.1:${MEM0_LITELLM_PORT:-4000} (loopback only, never 0.0.0.0) for a mem0 server on the host, and the
20
+ # entrypoint below refuses to start without LITELLM_MASTER_KEY (sk-...) from LITELLM_ENV_FILE. See docs/mem0.md.
21
+ # Compose still interpolates every service before it filters by profile, so the stack .env needs LITELLM_CONFIG
22
+ # even when litellm does not run. scripts/setup.mjs (providers/mem0/lib/stack-env.mjs) writes the mem0 route file
23
+ # when the option is on and an inert value otherwise.
24
+ #
25
+ # Loopback caveat (Linux): host.docker.internal resolves to the docker bridge gateway, not to the host's 127.0.0.1.
26
+ # A mem0 server bound only to 127.0.0.1 is therefore NOT reachable from the indexer container. Bind it to 0.0.0.0
27
+ # or to the docker bridge IP, or give MEM0_API_URL a real hostname. An https://localhost URL is rewritten to
28
+ # https://host.docker.internal, which will not match the server certificate name (use a hostname the certificate
29
+ # covers). ./setup prints a note when MEM0_API_URL is a loopback address.
30
+ #
31
+ # Stack .env keys read here (written by ./setup):
32
+ # MEM0_INDEXER_URL the server as the indexer container sees it. The wizard derives it from MEM0_API_URL (the host
33
+ # view) by rewriting localhost, 127.0.0.1, 0.0.0.0 and [::1] to host.docker.internal.
34
+ # MEM0_ENV_FILE optional; default ~/.config/personal-memory/mem0.env. Holds ONLY MEM0_API_KEY=... for the
35
+ # indexer (mode 600, outside the repo). Not needed when the server runs with AUTH_DISABLED.
36
+ # mem0's own server secrets (JWT_SECRET, ADMIN_API_KEY, embedder keys) are the operator's concern
37
+ # and never go through this stack.
38
+
39
+ services:
40
+ indexer:
41
+ environment:
42
+ # Selects indexer/sinks/mem0.py and gives it the server URL (container view, not the host view).
43
+ MEMORY_SINK: mem0
44
+ MEMORY_API_URL: ${MEM0_INDEXER_URL:?run ./setup (mem0 API URL)}
45
+ # required: false lets `config` and `up` run before the key file exists (Compose 2.24+).
46
+ env_file:
47
+ - path: ${MEM0_ENV_FILE:-${HOME}/.config/personal-memory/mem0.env}
48
+ required: false
49
+ # Reach a server on the host through host.docker.internal.
50
+ extra_hosts:
51
+ - "host.docker.internal:host-gateway"
52
+ # No depends_on: the server is external, and the indexer's watcher retries until it answers.
53
+
54
+ notebooklm:
55
+ environment:
56
+ MEMORY_SINK: mem0
57
+ MEMORY_API_URL: ${MEM0_INDEXER_URL:?run ./setup (mem0 API URL)}
58
+ env_file:
59
+ - path: ${MEM0_ENV_FILE:-${HOME}/.config/personal-memory/mem0.env}
60
+ required: false
61
+ extra_hosts:
62
+ - "host.docker.internal:host-gateway"
63
+
64
+ # Only under the "litellm" profile (see the header). Loopback publish for a mem0 server running on this host.
65
+ litellm:
66
+ ports:
67
+ - "127.0.0.1:${MEM0_LITELLM_PORT:-4000}:4000"
68
+ # The port is reachable by every local user and process, so an unauthenticated proxy is not allowed: exit unless
69
+ # the env file supplies an sk- master key. The routes' general_settings.master_key then makes LiteLLM enforce it.
70
+ entrypoint:
71
+ - /bin/sh
72
+ - -c
73
+ - |
74
+ case "$${LITELLM_MASTER_KEY:-}" in
75
+ sk-?*) ;;
76
+ *) echo "litellm: LITELLM_MASTER_KEY=sk-... is missing from LITELLM_ENV_FILE; rerun ./setup" >&2; exit 1 ;;
77
+ esac
78
+ exec docker/prod_entrypoint.sh "$$@"
79
+ - litellm
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Step "9. Coding-agent plugin", mem0 half: there is no npx pluginPackage for the
3
+ * self-hosted REST server. Print concrete SDK / MCP / direct-REST paths, then
4
+ * optionally merge the mem0 MCP into ~/.cursor/mcp.json (--yes or confirm).
5
+ */
6
+ import { installMem0Mcp } from "./mcp-install.mjs";
7
+ import { ensureState } from "./state.mjs";
8
+ import { displayUrl, resolveApiUrl, urlProblem } from "./url.mjs";
9
+
10
+ /** @typedef {import("../../../wizard/lib/provider-wizard/helpers.mjs").ProviderWizardHelpers} Helpers */
11
+
12
+ const SDK_DOCS = "https://docs.mem0.ai/open-source/python-quickstart";
13
+ const MCP_PACKAGE = "https://www.npmjs.com/package/@yeyuan98/mem0-mcp";
14
+ const REST_DOCS = "https://docs.mem0.ai/open-source/features/rest-api";
15
+ const OPERATOR = "providers/mem0/OPERATOR.md";
16
+
17
+ /**
18
+ * @param {Record<string, any>} ctx
19
+ * @param {Helpers} h
20
+ */
21
+ export async function setupCodingAgent(ctx, h) {
22
+ ensureState(ctx);
23
+ const raw = resolveApiUrl(ctx, h);
24
+ const base = urlProblem(raw) ? "(set MEM0_API_URL)" : displayUrl(raw);
25
+
26
+ h.info("mem0 has no coding-agent pluginPackage; use the self-hosted server directly:");
27
+ h.info(` 1. SDK — pip install mem0ai, point Memory at ${base} (see ${SDK_DOCS})`);
28
+ h.info(
29
+ ` 2. MCP — MEMORY_PROVIDER=mem0 npm run install-mcp -- --yes` +
30
+ ` (npx @yeyuan98/mem0-mcp via cli/mem0-mcp.mjs; see ${MCP_PACKAGE} and ${OPERATOR})`,
31
+ );
32
+ h.info(
33
+ ` 3. REST — POST ${base}/memories and POST ${base}/search with X-API-Key` +
34
+ ` (see ${REST_DOCS}; stack wiring in ${OPERATOR})`,
35
+ );
36
+
37
+ const codeRoot = ctx.packageRoot || ctx.repoRoot;
38
+ const stackRoot = ctx.repoRoot;
39
+ const wantMcp =
40
+ Boolean(ctx.yes) ||
41
+ (await h.confirm(ctx, "Register mem0 MCP in ~/.cursor/mcp.json now?", "y"));
42
+ if (wantMcp) {
43
+ await installMem0Mcp(
44
+ {
45
+ home: ctx.home,
46
+ repoRoot: codeRoot,
47
+ stackRoot,
48
+ dry: Boolean(ctx.dry),
49
+ env: process.env,
50
+ },
51
+ h,
52
+ );
53
+ } else {
54
+ h.info("skip MCP merge; later: MEMORY_PROVIDER=mem0 npm run install-mcp -- --yes");
55
+ }
56
+
57
+ h.ok("coding-agent: documented SDK / MCP / REST paths (pluginPackage remains null)");
58
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * mem0's slice of ~/.config/personal-memory/config.toml: the [memory.mem0] table
3
+ * (api_url, optional env_file). Never a key.
4
+ */
5
+ import { ensureState } from "./state.mjs";
6
+
7
+ /**
8
+ * @param {Record<string, unknown>} cfg merged TOML config
9
+ * @returns {{ apiUrl: string, envFile: string }}
10
+ */
11
+ export function defaultsFromConfig(cfg) {
12
+ const memory = /** @type {Record<string, unknown>} */ (cfg?.memory || {});
13
+ const mem0 = /** @type {Record<string, unknown>} */ (memory.mem0 || {});
14
+ return {
15
+ apiUrl: mem0.api_url != null ? String(mem0.api_url).trim() : "",
16
+ envFile: mem0.env_file != null ? String(mem0.env_file).trim() : "",
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Seed ctx.mem0 from [memory.mem0]. Env vars still win over these (see resolveApiUrl).
22
+ * @param {Record<string, any>} ctx
23
+ */
24
+ export function applyConfig(ctx) {
25
+ const state = ensureState(ctx);
26
+ const d = defaultsFromConfig(ctx.pmMerged || {});
27
+ if (d.apiUrl && !state.apiUrl) state.apiUrl = d.apiUrl;
28
+ if (d.envFile && !state.tomlEnvFile) state.tomlEnvFile = d.envFile;
29
+ }
30
+
31
+ /**
32
+ * Tables merged into config.toml: `memory.mem0`, which the wizard merges into [memory] (it
33
+ * always sets `provider` itself).
34
+ * @param {Record<string, any>} ctx
35
+ * @param {string} url the resolved host-view server URL
36
+ * @returns {Record<string, Record<string, unknown>>}
37
+ */
38
+ export function configToml(ctx, url) {
39
+ const state = ensureState(ctx);
40
+ /** @type {Record<string, unknown>} */
41
+ const mem0 = { api_url: url };
42
+ const envFile = (process.env.MEM0_ENV_FILE || state.tomlEnvFile || "").trim();
43
+ if (envFile) mem0.env_file = envFile;
44
+ return { memory: { mem0 } };
45
+ }