@bcmyguest/openmem 0.0.0-stage → 0.6.3
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.
- package/LICENSE +190 -0
- package/README.md +136 -2
- package/bin/hindsight-project-index +530 -0
- package/cli/coding-agent/access-policy.mjs +38 -0
- package/cli/coding-agent/agents.mjs +34 -0
- package/cli/coding-agent/bank-from-cwd.mjs +140 -0
- package/cli/coding-agent/capabilities.mjs +23 -0
- package/cli/coding-agent/hook-harnesses.mjs +87 -0
- package/cli/coding-agent/hook-runner.mjs +260 -0
- package/cli/coding-agent/install-access.mjs +93 -0
- package/cli/coding-agent/install-shim.mjs +97 -0
- package/cli/coding-agent/opencode-config.mjs +91 -0
- package/cli/coding-agent/opencode-plugin.mjs +96 -0
- package/cli/coding-agent/runtime.mjs +39 -0
- package/cli/coding-agent/session-facade.mjs +62 -0
- package/cli/cognee-mcp.mjs +260 -0
- package/cli/feed-sync.mjs +11 -0
- package/cli/install-coding-agent.mjs +165 -0
- package/cli/install-memory-mcp.mjs +426 -0
- package/cli/is-main.mjs +18 -0
- package/cli/mcp/context.mjs +61 -0
- package/cli/mcp/export/cognee-dataset-name.mjs +12 -0
- package/cli/mcp/export/cognee.mjs +119 -0
- package/cli/mcp/export/hindsight.mjs +48 -0
- package/cli/mcp/export/index.mjs +26 -0
- package/cli/mcp/export/mem0.mjs +31 -0
- package/cli/mcp/llm-synthesize.mjs +50 -0
- package/cli/mcp/mem0-scope-id.mjs +22 -0
- package/cli/mcp/memory-facade.mjs +455 -0
- package/cli/mcp/memory-reflect-consolidate.mjs +120 -0
- package/cli/mcp/notebooklm-banks.mjs +21 -0
- package/cli/mcp/notebooklm-hindsight-rest.mjs +45 -0
- package/cli/mcp/notebooklm-provider.mjs +225 -0
- package/cli/mcp/pmm-records.mjs +23 -0
- package/cli/mcp/portability.mjs +158 -0
- package/cli/mcp/stdio.mjs +65 -0
- package/cli/mcp/unified-mcp-install.mjs +65 -0
- package/cli/mem0-mcp.mjs +108 -0
- package/cli/notebooklm-mcp.mjs +236 -0
- package/cli/openmem-mcp.mjs +35 -0
- package/cli/openmem.mjs +205 -0
- package/cli/roots.mjs +85 -0
- package/cli/stack.mjs +436 -0
- package/cli/switch-memory-provider.mjs +358 -0
- package/cli/wiring-report.mjs +125 -0
- package/compose.bench.yaml +12 -0
- package/compose.yaml +164 -0
- package/config/coding-agent.json +13 -0
- package/config/hindsight.env.example +24 -0
- package/config/index.yml +54 -0
- package/config/litellm.lemond.yaml +40 -0
- package/config/litellm.ollama.yaml +33 -0
- package/config/notebooklm.yml +33 -0
- package/config/openmem.toml.example +62 -0
- package/docs/OPENMEM.md +23 -0
- package/docs/architecture.md +219 -0
- package/docs/assets/README.md +10 -0
- package/docs/assets/setup-demo.gif +0 -0
- package/docs/coding-agent-hooks.md +51 -0
- package/docs/coding-agent-scopes.md +22 -0
- package/docs/coding-agents.md +51 -0
- package/docs/cognee.md +37 -0
- package/docs/concepts.md +112 -0
- package/docs/hindsight.md +74 -0
- package/docs/index-sources-roadmap.md +38 -0
- package/docs/index-sources.md +39 -0
- package/docs/indexer-sinks.md +122 -0
- package/docs/indexing.md +57 -0
- package/docs/manual-stack-setup.md +74 -0
- package/docs/mcp-install-guide.md +4 -0
- package/docs/mcp-setup.md +101 -0
- package/docs/mem0.md +103 -0
- package/docs/memory-portability.md +73 -0
- package/docs/memory-providers.md +246 -0
- package/docs/model-configuration.md +84 -0
- package/docs/notebooklm.md +83 -0
- package/docs/npx-install.md +170 -0
- package/docs/openmem-config.md +194 -0
- package/docs/provider-wizard-hooks.md +222 -0
- package/docs/quickstart.md +101 -0
- package/docs/setup-wizard.md +116 -0
- package/docs/sources-feeds.md +52 -0
- package/docs/sources-readwise.md +23 -0
- package/docs/sources-zotero.md +22 -0
- package/glama.json +4 -0
- package/indexer/Dockerfile +38 -0
- package/indexer/code_outline.py +146 -0
- package/indexer/feed_sync.py +107 -0
- package/indexer/index_config.py +290 -0
- package/indexer/pytest.ini +5 -0
- package/indexer/sinks/__init__.py +148 -0
- package/indexer/sinks/_http.py +44 -0
- package/indexer/sinks/cognee.py +329 -0
- package/indexer/sinks/hindsight.py +107 -0
- package/indexer/sinks/mem0.py +247 -0
- package/indexer/watch.py +240 -0
- package/package.json +95 -4
- package/providers/_template/compose.yaml +52 -0
- package/providers/cognee/OPERATOR.md +82 -0
- package/providers/cognee/compose.yaml +89 -0
- package/providers/cognee/lib/clack.mjs +157 -0
- package/providers/cognee/lib/coding-agent.mjs +26 -0
- package/providers/cognee/lib/cognee-mcp-install.mjs +153 -0
- package/providers/cognee/lib/config.mjs +98 -0
- package/providers/cognee/lib/env-file.mjs +194 -0
- package/providers/cognee/lib/env-setup.mjs +83 -0
- package/providers/cognee/lib/llm-env.mjs +382 -0
- package/providers/cognee/lib/ports.mjs +25 -0
- package/providers/cognee/lib/smoke.mjs +246 -0
- package/providers/cognee/lib/stack-env.mjs +134 -0
- package/providers/cognee/lib/state.mjs +101 -0
- package/providers/cognee/lib/summary.mjs +56 -0
- package/providers/cognee/lib/validate.mjs +97 -0
- package/providers/cognee/manifest.json +56 -0
- package/providers/cognee/wizard.mjs +134 -0
- package/providers/graphiti/manifest.json +15 -0
- package/providers/hindsight/lib/clack.mjs +245 -0
- package/providers/hindsight/lib/coding-agent.mjs +204 -0
- package/providers/hindsight/lib/config.mjs +73 -0
- package/providers/hindsight/lib/env-setup.mjs +71 -0
- package/providers/hindsight/lib/litellm-routes.mjs +187 -0
- package/providers/hindsight/lib/model-backend.mjs +214 -0
- package/providers/hindsight/lib/notebooklm-mcp-install.mjs +127 -0
- package/providers/hindsight/lib/ollama-compose.mjs +51 -0
- package/providers/hindsight/lib/ports.mjs +30 -0
- package/providers/hindsight/lib/probe.mjs +33 -0
- package/providers/hindsight/lib/stack-env.mjs +132 -0
- package/providers/hindsight/lib/state.mjs +75 -0
- package/providers/hindsight/lib/summary.mjs +43 -0
- package/providers/hindsight/lib/validate.mjs +75 -0
- package/providers/hindsight/manifest.json +58 -0
- package/providers/hindsight/wizard.mjs +149 -0
- package/providers/letta/manifest.json +29 -0
- package/providers/mem0/OPERATOR.md +124 -0
- package/providers/mem0/compose.yaml +57 -0
- package/providers/mem0/lib/coding-agent.mjs +58 -0
- package/providers/mem0/lib/config.mjs +45 -0
- package/providers/mem0/lib/configure.mjs +135 -0
- package/providers/mem0/lib/dotenv.mjs +71 -0
- package/providers/mem0/lib/env-file.mjs +110 -0
- package/providers/mem0/lib/http.mjs +69 -0
- package/providers/mem0/lib/mcp-install.mjs +165 -0
- package/providers/mem0/lib/secret.mjs +30 -0
- package/providers/mem0/lib/smoke.mjs +179 -0
- package/providers/mem0/lib/stack-env.mjs +216 -0
- package/providers/mem0/lib/state.mjs +67 -0
- package/providers/mem0/lib/summary.mjs +60 -0
- package/providers/mem0/lib/url.mjs +106 -0
- package/providers/mem0/lib/validate.mjs +158 -0
- package/providers/mem0/manifest.json +47 -0
- package/providers/mem0/wizard.mjs +133 -0
- package/providers/zep/manifest.json +29 -0
- package/scripts/check-pack.mjs +218 -0
- package/scripts/gen-masks.mjs +83 -0
- package/scripts/gen-masks.sh +4 -0
- package/scripts/promotion-provider-smoke.mjs +34 -0
- package/scripts/run-setup.sh +30 -0
- package/scripts/setup.mjs +94 -0
- package/scripts/setup.sh +5 -0
- package/scripts/spin-up.sh +45 -0
- package/scripts/wizard.sh +5 -0
- package/server.json +34 -0
- package/skills/openmem/SKILL.md +29 -0
- package/sync/Dockerfile +27 -0
- package/sync/memory_backend.py +87 -0
- package/sync/notebooklm_sync.py +664 -0
- package/wizard/bin/pm.mjs +97 -0
- package/wizard/bin/setup.mjs +33 -0
- package/wizard/lib/compose-version.mjs +32 -0
- package/wizard/lib/compose.mjs +70 -0
- package/wizard/lib/curl.mjs +103 -0
- package/wizard/lib/docker-build.mjs +148 -0
- package/wizard/lib/exec.mjs +41 -0
- package/wizard/lib/indexer.mjs +6 -0
- package/wizard/lib/load-machine-env.mjs +4 -0
- package/wizard/lib/log.mjs +32 -0
- package/wizard/lib/notebooklm-agent-access.mjs +92 -0
- package/wizard/lib/notebooklm.mjs +214 -0
- package/wizard/lib/parse-args.mjs +87 -0
- package/wizard/lib/paths.mjs +39 -0
- package/wizard/lib/pm-config.mjs +163 -0
- package/wizard/lib/ports.mjs +94 -0
- package/wizard/lib/prompts.mjs +57 -0
- package/wizard/lib/provider-wizard/helpers.mjs +98 -0
- package/wizard/lib/provider-wizard/run-steps.mjs +129 -0
- package/wizard/lib/providers/registry.mjs +262 -0
- package/wizard/lib/run-clack.mjs +108 -0
- package/wizard/lib/run-wizard.mjs +755 -0
- package/wizard/lib/validate-setup.mjs +62 -0
- package/wizard/lib/wizard-action.mjs +34 -0
- package/wizard/lib/wizard-conf.mjs +71 -0
package/docs/mem0.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
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.
|
|
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
|
+
## Banks / scopes
|
|
59
|
+
|
|
60
|
+
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).
|
|
61
|
+
|
|
62
|
+
## Coding agents and MCP
|
|
63
|
+
|
|
64
|
+
**Preferred:** unified OpenMem MCP (`memory_*`) — same tools as Hindsight/Cognee:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
npx @bcmyguest/openmem install-coding-agent --yes
|
|
68
|
+
# or MCP only:
|
|
69
|
+
npx @bcmyguest/openmem install-mcp --yes
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Optional native mem0 tools** (upstream `@yeyuan98/mem0-mcp` names, not `memory_*`):
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
MEMORY_PROVIDER=mem0 npx @bcmyguest/openmem install-mcp --yes --provider-only
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
Restart Cursor Agent after MCP changes. Full flag matrix: [MCP setup](mcp-setup.md).
|
|
81
|
+
|
|
82
|
+
There is no Hindsight-style coding-agent plugin for mem0; session hooks + unified MCP cover day-to-day agent memory.
|
|
83
|
+
|
|
84
|
+
## Portability
|
|
85
|
+
|
|
86
|
+
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).
|
|
87
|
+
|
|
88
|
+
## Switch provider
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
npx @bcmyguest/openmem switch mem0 --yes
|
|
92
|
+
# later:
|
|
93
|
+
npx @bcmyguest/openmem switch hindsight --yes
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Updates active provider config, restarts the stack (unless `--no-stack`), refreshes MCP (unless `--no-mcp`). Does **not** migrate memories.
|
|
97
|
+
|
|
98
|
+
## Related
|
|
99
|
+
|
|
100
|
+
- [Concepts](concepts.md) — interface layer
|
|
101
|
+
- [MCP setup](mcp-setup.md) — unified vs provider-native
|
|
102
|
+
- [Portable memory (PMM)](memory-portability.md)
|
|
103
|
+
- [Architecture](architecture.md) · [Provider status](provider-status.md)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Portable memory (PMM)
|
|
2
|
+
|
|
3
|
+
OpenMem’s **portability layer** moves memories between providers without baking in a vendor dump format. **PMM** (Personal Memory Manifest) is the first interchange format: export what a backend stores, import into another (or the same) provider, and keep a portable copy for backup or “give me my data” requests.
|
|
4
|
+
|
|
5
|
+
`npx @bcmyguest/openmem switch` rewires the stack only — it does **not** migrate content. Use export → switch → import (or re-index) when you change backends.
|
|
6
|
+
|
|
7
|
+
Status: **`memory_export` / `memory_import`** on the unified MCP are **beta**. PMM v1 is stable; adapters live under `cli/mcp/export/` (orchestrator: `cli/mcp/portability.mjs`). MCP install: [MCP setup](mcp-setup.md).
|
|
8
|
+
|
|
9
|
+
## PMM format (version 1)
|
|
10
|
+
|
|
11
|
+
JSON object, or JSONL with one header line followed by one normalized record per line:
|
|
12
|
+
|
|
13
|
+
| Field | Type | Meaning |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `pmm_version` | `1` | Schema version |
|
|
16
|
+
| `exported_at` | ISO-8601 string | When the export was taken |
|
|
17
|
+
| `source_provider` | string | `hindsight` \| `mem0` \| `cognee` |
|
|
18
|
+
| `scope` | object | Provider-specific filter (bank, `user_id`, datasets, …) |
|
|
19
|
+
| `records` | array | Normalized memory records (see below) |
|
|
20
|
+
|
|
21
|
+
Each **record**:
|
|
22
|
+
|
|
23
|
+
| Field | Type | Meaning |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `id` | string \| null | Provider id when known |
|
|
26
|
+
| `content` | string | Primary text |
|
|
27
|
+
| `metadata` | object | Optional tags, timestamps, provider payload |
|
|
28
|
+
| `scope_key` | string | Bank name, mem0 `user_id`, Cognee dataset, etc. |
|
|
29
|
+
|
|
30
|
+
Import accepts PMM with `merge_strategy`:
|
|
31
|
+
|
|
32
|
+
| Strategy | Behavior |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| `skip_duplicates` (default) | For mem0, skip records whose id or content fingerprint already exists in the same bank |
|
|
35
|
+
| `overwrite` | Re-import all records (may duplicate on backends without idempotent upsert) |
|
|
36
|
+
|
|
37
|
+
**Cross-provider import** (e.g. PMM from mem0 into Hindsight) is best-effort: we map `content` + `scope_key` into the active provider’s add API; embeddings and graph structure are **not** preserved.
|
|
38
|
+
|
|
39
|
+
The MCP export currently collects all records in memory before returning them, including with `format: "jsonl"`. Use a bank filter for large stores; the MCP response is not a file stream. Hindsight export reads the memory-list endpoint and does not include knowledge pages, bank configuration, or source documents. Confirm migrated data before switching providers.
|
|
40
|
+
|
|
41
|
+
## Implementation (orchestrator + adapters)
|
|
42
|
+
|
|
43
|
+
openmem stays a **meta orchestrator**: PMM shape and import live in `cli/mcp/portability.mjs`; each backend implements **list/map** in `cli/mcp/export/` (`hindsight.mjs`, `mem0.mjs`, `cognee.mjs`). New providers add an adapter and one branch in `cli/mcp/export/index.mjs` — no changes to the MCP tool names agents call.
|
|
44
|
+
|
|
45
|
+
## Unified MCP tools
|
|
46
|
+
|
|
47
|
+
On the `openmem` MCP server ([MCP setup](mcp-setup.md), [Architecture](architecture.md)):
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
memory_export { format?: "json"|"jsonl", bank?: string, user_id?: string }
|
|
51
|
+
memory_import { data: string, merge_strategy?: "skip_duplicates"|"overwrite" }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Example flow (Cursor Agent / any host with the unified server):
|
|
55
|
+
|
|
56
|
+
1. `memory_export` with `format: "json"` and optional `bank`
|
|
57
|
+
2. `npx @bcmyguest/openmem switch <other> --yes`
|
|
58
|
+
3. `memory_import` with the exported JSON and `merge_strategy: "skip_duplicates"`
|
|
59
|
+
|
|
60
|
+
Restart Cursor Agent after `npx @bcmyguest/openmem install-mcp --yes`.
|
|
61
|
+
|
|
62
|
+
## Provider behavior
|
|
63
|
+
|
|
64
|
+
| Provider | Export | Import |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| **mem0** | `GET /memories` with `user_id` from `bank` arg (API key from env file) | `POST /memories` per record (`infer: false`) |
|
|
67
|
+
| **Hindsight** | `GET /v1/default/banks` then paginated `GET …/memories/list` per bank (`bank` arg = one bank; omit = all banks) | `POST …/banks/{bank}/memories` per record |
|
|
68
|
+
| **Cognee** | Resolve indexer dataset name from `bank`, `GET /api/v1/datasets`, paginate `GET …/data` (label/name as content; not full file bytes) | `POST /api/v1/add` per record when dataset in scope |
|
|
69
|
+
|
|
70
|
+
## Related
|
|
71
|
+
|
|
72
|
+
- [Architecture — provider interface](architecture.md#how-openmem-interfaces-with-providers)
|
|
73
|
+
- [mem0](mem0.md) · [Cognee](cognee.md)
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Pluggable memory providers
|
|
2
|
+
|
|
3
|
+
This repo ships **one** supported backend: [Hindsight](https://github.com/vectorize-io/hindsight)
|
|
4
|
+
(API + retain/reflect/consolidate, LiteLLM in front of local models). **mem0** and **Cognee** are
|
|
5
|
+
**experimental** plugins (indexer sink, compose profile, wizard hooks, stub tests). Wave 3 hardened
|
|
6
|
+
operator DX (coding-agent steps, secrets, Ollama wiring); live Cognee cognify+search with a small
|
|
7
|
+
local model is not yet a promotion bar — see `docs/WAVE3-orchestrator.md`. Manifests under
|
|
8
|
+
`providers/` show `experimental` vs `supported`.
|
|
9
|
+
|
|
10
|
+
## Meta setup wizard (what this is — and is not)
|
|
11
|
+
|
|
12
|
+
`npm run setup` (checkout), `npx @bcmyguest/openmem setup`, or `./setup` is a **meta** wizard: it
|
|
13
|
+
orchestrates **machine-local plumbing** that is the same idea across providers (Docker project,
|
|
14
|
+
ports, indexer sources, smoke “is the API alive?”, coding-agent config file, compose up/down). It does
|
|
15
|
+
**not** replace each provider’s **native** settings UI, CLI, or config format.
|
|
16
|
+
|
|
17
|
+
| This wizard owns (cross-cutting) | Provider still owns (native) |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| Pick provider + stack action (configure / up / down) | API keys, org/project ids, mem0 graph settings |
|
|
20
|
+
| Host ports, `HOST_UID`/`HOST_GID`, compose project name | Hindsight retain/reflect models beyond our LiteLLM routes |
|
|
21
|
+
| Shared `index.yml` (what to index) | Provider-specific memory schema, filters, user ids |
|
|
22
|
+
| Wiring Hindsight → LiteLLM proxy (when provider is Hindsight) | mem0 dashboard, cloud vs self-hosted choice |
|
|
23
|
+
| Health/smoke probes declared in manifest | Official provider docs, upgrades, migrations |
|
|
24
|
+
|
|
25
|
+
When a provider needs extra fields, the manifest should grow **provider-specific wizard steps** (or
|
|
26
|
+
point to “run `mem0 …` / edit `~/.mem0/…`”) — not cram mem0 into Hindsight’s LiteLLM screens.
|
|
27
|
+
|
|
28
|
+
### Similar patterns elsewhere
|
|
29
|
+
|
|
30
|
+
These are the usual analogues people mean by “meta setup”:
|
|
31
|
+
|
|
32
|
+
- **[mise](https://mise.jdx.dev/) / [asdf](https://asdf-vm.com/)** — one CLI to install and select
|
|
33
|
+
runtimes; each plugin wraps the tool’s own install rules. mise does not replace `.npmrc` or
|
|
34
|
+
`Cargo.toml`.
|
|
35
|
+
- **[Chezmoi](https://www.chezmoi.io/)** — applies dotfiles from a repo; Vim, Git, and SSH keep their
|
|
36
|
+
normal config files on disk.
|
|
37
|
+
- **[Supabase CLI](https://supabase.com/docs/guides/cli)** — `supabase start` brings up Postgres,
|
|
38
|
+
Auth, Studio; each service still has its own env and tuning.
|
|
39
|
+
- **LiteLLM (in this stack)** — meta proxy in front of lemond/Ollama; model servers keep their own
|
|
40
|
+
configs. `./setup`’s “model backend” step is really “how LiteLLM reaches your LLM,” not a full
|
|
41
|
+
lemond replacement.
|
|
42
|
+
- **[Home Assistant](https://www.home-assistant.io/)** — core + integrations; Philips Hue still configured
|
|
43
|
+
in the Hue app, HA only links it.
|
|
44
|
+
- **`npx skills`-style installers** — discover and install artifacts; each skill or package owns its
|
|
45
|
+
content afterward.
|
|
46
|
+
|
|
47
|
+
openmem sits in that category: **one front door** for “memory on this machine for coding agents,”
|
|
48
|
+
not a reimplementation of mem0 or Hindsight settings.
|
|
49
|
+
|
|
50
|
+
Declarative config is **[mise-like](openmem-config.md)**: `~/.config/personal-memory/config.toml`
|
|
51
|
+
plus `./pm` tasks — same *shape* as mise (`[tasks]`, merged config files), different domain.
|
|
52
|
+
|
|
53
|
+
Provider-specific setup runs via **[wizard hooks](provider-wizard-hooks.md)** (`providers/*/wizard.mjs`)
|
|
54
|
+
after meta steps — like asdf plugin install scripts, not reimplemented npm/mem0 CLIs.
|
|
55
|
+
|
|
56
|
+
## Layers (what varies per provider)
|
|
57
|
+
|
|
58
|
+
| Layer | Hindsight today | Should become |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| **Compose stack** | `litellm`, `hindsight`, `indexer`, optional `notebooklm` | Provider manifest lists services / profiles; shared `indexer` where possible |
|
|
61
|
+
| **Model routing** | LiteLLM + `config/litellm.*.yaml` | Hindsight-specific; other providers may use their own LLM config or none |
|
|
62
|
+
| **Indexer sink** | `bin/hindsight-project-index` → REST `/v1/default/banks/{bank}/memories` | Python **sink** interface; one implementation per provider |
|
|
63
|
+
| **Setup wizard** | Node wizard: preflight, env, smoke retain/recall | Provider manifest: health URL, smoke steps, env file names |
|
|
64
|
+
| **Coding-agent UX** | `@vectorize-io/hindsight-coding-agents` + `coding-agent.json` | Per-provider plugin package or generic adapter |
|
|
65
|
+
|
|
66
|
+
NotebookLM sync is **orthogonal** to which provider you picked: enable the `notebooklm` profile and the sync container uses the same `MEMORY_SINK` as the indexer (Hindsight, mem0, or Cognee).
|
|
67
|
+
|
|
68
|
+
Coding-agent session memory uses the **same** in-repo hooks and unified MCP for every provider; optional `--hindsight-plugin` adds the upstream Hindsight plugin on Hindsight stacks only.
|
|
69
|
+
|
|
70
|
+
## Provider manifest
|
|
71
|
+
|
|
72
|
+
Each provider lives under `providers/<id>/manifest.json`. The wizard loads manifests via
|
|
73
|
+
`wizard/lib/providers/registry.mjs`. Fields are intentionally small; expand only when a second
|
|
74
|
+
provider needs them.
|
|
75
|
+
|
|
76
|
+
- **`status`**: `supported` | `experimental` | `planned`
|
|
77
|
+
- **`compose`**: which services belong to this provider, health check, default host port env var
|
|
78
|
+
- **`indexer`**: env var for API base URL, `sink`, and `sinkDriver` (see the table below)
|
|
79
|
+
- **`codingAgent`**: optional npx package and config template path
|
|
80
|
+
- **`wizard`**: smoke test bank name and HTTP paths (templates may include `{bank}`)
|
|
81
|
+
|
|
82
|
+
| `indexer` field | Meaning | Required |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `apiUrlEnv` | Env var that holds the provider's API base URL for the wizard | Per provider |
|
|
85
|
+
| `sink` | The `MEMORY_SINK` value, which equals the `indexer/sinks/<sink>.py` module name. Must match `^[a-z][a-z0-9_]*$` (the same rule as `indexer/sinks/__init__.py`). | `supported` and `experimental`; optional but validated for `planned` |
|
|
86
|
+
| `sinkDriver` | Human-readable wire-dialect label (for example `hindsight-rest-v1`). It names no module and drives no dispatch. | `supported` and `experimental` |
|
|
87
|
+
|
|
88
|
+
`scripts/tests/test_provider_manifests.mjs` checks that every `supported` or `experimental` manifest
|
|
89
|
+
with an `indexer.sink` has a matching `indexer/sinks/<sink>.py`.
|
|
90
|
+
|
|
91
|
+
## Selecting a sink
|
|
92
|
+
|
|
93
|
+
The indexer picks its provider with `--sink NAME`, falling back to the `MEMORY_SINK` environment
|
|
94
|
+
variable, then `hindsight`. Compose fragments for alternate providers set both `MEMORY_SINK` and
|
|
95
|
+
`MEMORY_API_URL` on the `indexer` service from stack `.env` values.
|
|
96
|
+
|
|
97
|
+
| Variable | Used by | Meaning |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| `MEMORY_SINK` | indexer | Sink module name (`indexer.sink` in the manifest). Default `hindsight`. |
|
|
100
|
+
| `MEMORY_API_URL` | indexer, every non-Hindsight sink | Generic API base URL of the provider. |
|
|
101
|
+
| `HINDSIGHT_URL` | indexer, Hindsight sink only | API base URL for Hindsight (default `http://127.0.0.1:8888`). |
|
|
102
|
+
|
|
103
|
+
`--url` overrides either URL variable. A sink reads its credentials from its own environment
|
|
104
|
+
variables inside `create`, never from the document path.
|
|
105
|
+
|
|
106
|
+
Provider secrets (for example `MEM0_API_KEY`, `COGNEE_API_KEY`, `LLM_API_KEY`) live in
|
|
107
|
+
`~/.config/personal-memory/<id>.env`, outside the repo, mode 600. A provider's compose fragment loads
|
|
108
|
+
that file through an `env_file` entry with `required: false`, so a stack without the file still
|
|
109
|
+
starts. Secrets do not belong in the stack `.env` or in `wizard.conf`, and the wizard never prints
|
|
110
|
+
them.
|
|
111
|
+
|
|
112
|
+
### Optional `flush()`
|
|
113
|
+
|
|
114
|
+
A sink for a provider that ingests asynchronously (`capabilities.async_ingest=True`, for example
|
|
115
|
+
Cognee, where `cognify` builds the graph after `add`) may define `flush(bank: str) -> None`. The
|
|
116
|
+
indexer calls it once per bank after that bank's batch of retains and deletes, so the provider starts
|
|
117
|
+
processing once per batch rather than once per document.
|
|
118
|
+
|
|
119
|
+
- The call happens only with `--apply`. The indexer calls `flush(bank)` with an explicit bank when the
|
|
120
|
+
batch retained or deleted at least one document for that bank, **or** when a previous flush for that
|
|
121
|
+
bank is still pending. A dry run never flushes, and `flush(None)` is never called.
|
|
122
|
+
- A sink must treat `flush(bank)` as "process this bank now", even when its own in-memory bookkeeping
|
|
123
|
+
says the bank is clean: the indexer may call it from a fresh process in which that bookkeeping is gone.
|
|
124
|
+
- Pending flushes are persisted. Per-document progress is saved to the indexer state file as it goes, so
|
|
125
|
+
a failed flush (or a run that died after some retains) would otherwise never be retried. For a sink
|
|
126
|
+
with a `flush`, the bank is recorded under the state key `::flush-pending` (a sorted list of banks)
|
|
127
|
+
before the first write of a batch and removed after `flush` succeeds. Every `--apply` run flushes the
|
|
128
|
+
banks it handles that are still pending, even when nothing changed. A bank whose source is no longer
|
|
129
|
+
indexed is left alone. Sinks without `flush` (Hindsight) never get the key, so their state file is
|
|
130
|
+
unchanged.
|
|
131
|
+
- `flush` is not part of the `Sink` protocol, so sinks without it (Hindsight among them) still satisfy
|
|
132
|
+
`isinstance(sink, Sink)` and see no change in behavior. Callers use `sinks.flush_sink(sink, bank)`,
|
|
133
|
+
which does nothing when the sink has no callable `flush`.
|
|
134
|
+
- A flush error is handled like a retain error: the source is reported as failed, the other sources
|
|
135
|
+
still run, and the pending marker stays so the next run flushes again.
|
|
136
|
+
- The watcher (`indexer/watch.py`) spawns this same CLI once per source, so flush runs there too. In
|
|
137
|
+
the indexer container the sink and URL come from `MEMORY_SINK` and `MEMORY_API_URL`.
|
|
138
|
+
|
|
139
|
+
Default provider id: **`hindsight`**. Change it in **interactive `./setup`** (Clack “Memory provider”,
|
|
140
|
+
defaults to `config.toml` and `wizard.conf`), or set `MEMORY_PROVIDER` for `--yes`. The wizard records
|
|
141
|
+
the choice in `wizard.conf`. Stack **up** / **down** are wizard actions (`--up`, `--down`, or Clack
|
|
142
|
+
first step); default action is full **configure and start**.
|
|
143
|
+
|
|
144
|
+
### Changing provider later
|
|
145
|
+
|
|
146
|
+
Prefer **`npx @bcmyguest/openmem switch <id> --yes`** (checkout: `npx . switch <id> --yes`) over a full
|
|
147
|
+
interactive setup re-run when you only need to change backends:
|
|
148
|
+
|
|
149
|
+
- Updates `MEMORY_PROVIDER` in `~/.config/hindsight/wizard.conf`
|
|
150
|
+
- Updates `[memory].provider` in `~/.config/personal-memory/config.toml` when that file exists
|
|
151
|
+
- Unless `--no-stack`: compose down + up for the new provider (with mem0/Cognee readiness checks)
|
|
152
|
+
- Unless `--no-mcp`: runs `install-mcp --provider-only` so Cursor MCP points at the new provider
|
|
153
|
+
|
|
154
|
+
Switching does **not** migrate memories between backends. The NotebookLM compose profile and
|
|
155
|
+
`notebooklm` MCP entry are left alone. Flags and examples:
|
|
156
|
+
[README — Switch memory provider](../README.md#switch-memory-provider).
|
|
157
|
+
|
|
158
|
+
## Suggested implementation phases (separate commits)
|
|
159
|
+
|
|
160
|
+
### Phase A — Registry and docs (this commitset)
|
|
161
|
+
|
|
162
|
+
- Manifests for `hindsight`, `mem0`, and `cognee` (`supported`).
|
|
163
|
+
- Wizard reads manifest for health/smoke URLs; behavior unchanged for Hindsight.
|
|
164
|
+
- Document extension points (this file).
|
|
165
|
+
|
|
166
|
+
### Phase B — Indexer sink interface (implemented)
|
|
167
|
+
|
|
168
|
+
- HTTP retain/delete/health live in `indexer/sinks/`; default sink is `hindsight`.
|
|
169
|
+
- CLI: `--sink <name>` or env `MEMORY_SINK`; non-Hindsight sinks use `MEMORY_API_URL` for the API base.
|
|
170
|
+
- Contract tests: `indexer/tests/sink_contract.py` and `test_sinks.py`. Per-provider bank mapping and compose env: [indexer-sinks.md](indexer-sinks.md).
|
|
171
|
+
|
|
172
|
+
### Phase D — Compose profiles (implemented for Hindsight)
|
|
173
|
+
|
|
174
|
+
- `litellm` and `hindsight` use compose profile `hindsight`; the indexer always starts.
|
|
175
|
+
- `./setup` passes `--profile hindsight` on compose commands; `scripts/setup.mjs` writes `COMPOSE_PROFILES=hindsight` into the stack `.env`.
|
|
176
|
+
- Alternate providers layer `providers/<id>/compose.yaml` with their own profile (`MEMORY_SINK`, `MEMORY_API_URL`, `depends_on`).
|
|
177
|
+
|
|
178
|
+
### Phase C — mem0 and Cognee (Wave 2 + Wave 3 DX)
|
|
179
|
+
|
|
180
|
+
- mem0 is **URL-only** in v1: the indexer talks to a mem0 server the operator already runs, and this
|
|
181
|
+
repo ships no mem0 container yet. A mem0 service built from a pinned upstream ref is a follow-up.
|
|
182
|
+
Operator runbook: `providers/mem0/OPERATOR.md`. Coding-agent: wizard `setupCodingAgent` prints
|
|
183
|
+
SDK/MCP steps (no fake `pluginPackage`); register Cursor MCP with
|
|
184
|
+
`npx @bcmyguest/openmem install-mcp --yes` / `npx @bcmyguest/openmem switch mem0 --yes`.
|
|
185
|
+
- Cognee runs in **docker**: a pinned `cognee/cognee` image on a loopback port with a named volume and
|
|
186
|
+
an optional env file (`~/.config/personal-memory/cognee.env`, mode 600).
|
|
187
|
+
Operator notes: `providers/cognee/OPERATOR.md`. Coding-agent: REST on the loopback port plus a
|
|
188
|
+
read-only stdio MCP (`cli/cognee-mcp.mjs`: `cognee_health` / `cognee_search`) registered by
|
|
189
|
+
`setupCodingAgent` / `npm run install-mcp` when `MEMORY_PROVIDER=cognee`.
|
|
190
|
+
- **Cognee + Ollama:** default endpoints use `host.docker.internal:11434` (host Ollama on the Docker
|
|
191
|
+
bridge). When this stack’s compose profile `ollama` publishes **loopback-only**
|
|
192
|
+
(`127.0.0.1:11434`), that default is refused from the Cognee container. Set
|
|
193
|
+
`PM_COGNEE_OLLAMA_COMPOSE=1` or `MEMORY_OLLAMA_IN_COMPOSE=1` (wizard Clack also detects
|
|
194
|
+
`MEMORY_OLLAMA_IN_COMPOSE=1` in `wizard.conf`) so defaults become `http://ollama:11434` and attach
|
|
195
|
+
Cognee to the same Docker network as the `ollama` service. Cognify still needs a model that can
|
|
196
|
+
emit Cognee’s structured extraction schemas; small local models (for example `gemma4:e2b`) may
|
|
197
|
+
pass HTTP add/cognify start but never finish the graph — treat as an operator/LLM tuning issue,
|
|
198
|
+
not a provider status gate.
|
|
199
|
+
- `hindsight`, `mem0`, and `cognee` manifests are **`supported`**; new backends still land as
|
|
200
|
+
`experimental` until wizard + indexer + smoke are wired.
|
|
201
|
+
- `indexer/sinks/mem0.py` and `indexer/sinks/cognee.py` implementing the sink protocol (Cognee also
|
|
202
|
+
implements the optional `flush()`).
|
|
203
|
+
- Wizard branch: provider select (Clack) before model backend when multiple providers are supported.
|
|
204
|
+
- Coding-agent story: mem0’s own SDK/plugin or a thin local proxy—document limitations.
|
|
205
|
+
|
|
206
|
+
### Phase D — Compose profiles
|
|
207
|
+
|
|
208
|
+
- `docker compose --profile hindsight` vs `--profile mem0` generated or documented from manifests.
|
|
209
|
+
- Avoid duplicating indexer image; only swap `depends_on` and indexer `environment`.
|
|
210
|
+
|
|
211
|
+
## mem0 notes (non-goals for Phase A)
|
|
212
|
+
|
|
213
|
+
mem0’s API and deployment model differ from Hindsight banks and retain/reflect aliases. Expect:
|
|
214
|
+
|
|
215
|
+
- Different **namespace** model instead of `bank` strings.
|
|
216
|
+
- Possibly **no** LiteLLM sidecar in this repo (mem0 cloud or separate compose).
|
|
217
|
+
- Coding-agent integration likely **not** the Hindsight npx package; manifest should name the real install path when known.
|
|
218
|
+
|
|
219
|
+
## Developer deep dives (repo only)
|
|
220
|
+
|
|
221
|
+
These stay under `docs/` and are **not** synced to the Starlight site (see `site/scripts/lib/docs.mjs` —
|
|
222
|
+
only user-facing guides like [Architecture](architecture.md) are listed in `PAGES`).
|
|
223
|
+
|
|
224
|
+
- [Indexer sink drivers](indexer-sinks.md) — `sink` vs `sinkDriver`, env vars, bank/scope mapping for Hindsight, mem0, Cognee
|
|
225
|
+
- [MCP setup](mcp-setup.md) — unified MCP vs `--provider-only` vs NotebookLM MCP
|
|
226
|
+
|
|
227
|
+
## Index sources
|
|
228
|
+
|
|
229
|
+
See [index-sources.md](index-sources.md), [sources-feeds.md](sources-feeds.md), [sources-zotero.md](sources-zotero.md), [sources-readwise.md](sources-readwise.md), and [index-sources-roadmap.md](index-sources-roadmap.md).
|
|
230
|
+
|
|
231
|
+
## Coding-agent session hooks
|
|
232
|
+
|
|
233
|
+
See [coding-agent-hooks.md](coding-agent-hooks.md), [coding-agent-scopes.md](coding-agent-scopes.md), and `npx @bcmyguest/openmem install-coding-agent`.
|
|
234
|
+
|
|
235
|
+
## Site and docs
|
|
236
|
+
|
|
237
|
+
Published pages sync from `docs/*.md` at build time. If you change mermaid in a synced doc (for example `docs/architecture.md`), run `cd site && pnpm render-diagrams` and commit `site/public/diagrams/*.svg`. Then run `SITE_URL=https://bcmyguest.github.io BASE_PATH=/openmem/ pnpm build` in `site/` — the same check as CI and GitHub Pages.
|
|
238
|
+
|
|
239
|
+
## Adding a provider (checklist)
|
|
240
|
+
|
|
241
|
+
1. Add `providers/<id>/manifest.json` with accurate `status`.
|
|
242
|
+
2. Implement indexer sink (Phase B+).
|
|
243
|
+
3. Add compose fragment or profile and document ports/env.
|
|
244
|
+
4. Extend wizard: provider selection, provider-specific steps, smoke test.
|
|
245
|
+
5. Document opt-in / agent config for that provider.
|
|
246
|
+
6. Extend `scripts/tests/test_wizard.sh` or add provider-specific tests.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Model configuration
|
|
2
|
+
|
|
3
|
+
Hindsight never names a model server. It calls the LiteLLM proxy at `http://litellm:4000/v1` with three fixed aliases, and the proxy's YAML maps each alias to a model:
|
|
4
|
+
|
|
5
|
+
| Alias | Hindsight operation |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `memory-retain` | retain (extraction on ingest) |
|
|
8
|
+
| `memory-reflect` | reflect, the base `HINDSIGHT_API_LLM_MODEL`, and mental-model refresh. Needs a model that makes tool calls |
|
|
9
|
+
| `memory-consolidate` | consolidation |
|
|
10
|
+
|
|
11
|
+
## Shipped routes
|
|
12
|
+
|
|
13
|
+
Edit the YAML (or a per-machine override) to change models.
|
|
14
|
+
|
|
15
|
+
| File | Backend | Default split |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| `config/litellm.lemond.yaml` | lemond on the host | Reflect: Gemma 4 E4B GGUF (`unsloth/`); retain and consolidate: E2B |
|
|
18
|
+
| `config/litellm.ollama.yaml` | Ollama on the host | Used when `MEMORY_BACKEND=ollama`; `gemma4:e4b` needs Ollama newer than 0.20.3 |
|
|
19
|
+
|
|
20
|
+
**Why reflect uses a larger model:** E2B often returns no usable tool call on Hindsight reflect (`finish_reason=length`). The shipped lemond route uses E4B for `memory-reflect` only. Qwen3.5-4B works as an alternative if you change the route; pick any model that passes a direct tool-call check and a smoke reflect.
|
|
21
|
+
|
|
22
|
+
## Route selection
|
|
23
|
+
|
|
24
|
+
| Priority | Path |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| 1 | `~/.config/hindsight/litellm.yaml` — full override, mounted read-only into the proxy |
|
|
27
|
+
| 2 | `config/litellm.$MEMORY_BACKEND.yaml` — `lemond` (default) or `ollama` |
|
|
28
|
+
|
|
29
|
+
`scripts/setup.mjs` writes `LITELLM_CONFIG` in the stack `.env`. After changing backend, override, or routes:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
node scripts/setup.mjs
|
|
33
|
+
docker compose up -d litellm
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Optional Ollama backend:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
MEMORY_BACKEND=ollama node scripts/setup.mjs
|
|
40
|
+
docker compose up -d litellm
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Thinking and token limits
|
|
44
|
+
|
|
45
|
+
Thinking is off on all three aliases in the route YAML (`enable_thinking: false` / `think: false`) so replies are not empty when Hindsight sends low `reasoning_effort`.
|
|
46
|
+
|
|
47
|
+
| Layer | Role |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| LiteLLM `litellm_params.max_tokens` | Default when the client omits `max_tokens` (4096 in shipped routes) |
|
|
50
|
+
| `HINDSIGHT_API_*_MAX_COMPLETION_TOKENS` in `hindsight.env` | Hard cap Hindsight enforces (retain 16384; reflect and consolidation 2048) |
|
|
51
|
+
|
|
52
|
+
Retain cap must exceed each retain strategy's chunk size (coding-agent strategies use 12000) or Hindsight returns `400 Invalid retain strategy`.
|
|
53
|
+
|
|
54
|
+
## Secrets
|
|
55
|
+
|
|
56
|
+
`~/.config/hindsight/litellm.env` (mode 600): `LITELLM_MASTER_KEY` (Hindsight uses this as `HINDSIGHT_API_LLM_API_KEY`), plus provider keys referenced as `os.environ/NAME` in the YAML.
|
|
57
|
+
|
|
58
|
+
Example hosted reflect model:
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
- model_name: memory-reflect
|
|
62
|
+
litellm_params:
|
|
63
|
+
model: anthropic/claude-haiku-4-5
|
|
64
|
+
api_key: os.environ/ANTHROPIC_API_KEY
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Hindsight always sends the alias names above; you do not edit model ids in `hindsight.env` for route changes.
|
|
68
|
+
|
|
69
|
+
## Verify and migrate
|
|
70
|
+
|
|
71
|
+
Health check from the compose network:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
docker compose exec litellm python3 -c "import urllib.request;print(urllib.request.urlopen('http://127.0.0.1:4000/health/liveliness').read())"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Older `hindsight.env` files that pointed at lemond/Ollama directly:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
node scripts/setup.mjs --migrate-env
|
|
81
|
+
docker compose up -d
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Migration rewrites LLM lines to use `http://litellm:4000/v1` and the three aliases; other lines stay as they are.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# NotebookLM
|
|
2
|
+
|
|
3
|
+
Opt-in. Syncs notebooks, sources, notes, and (optionally) chats from Google NotebookLM into **`notebooklm::<notebook slug>`** banks on whichever memory provider you run (**Hindsight, mem0, or Cognee** — same `MEMORY_SINK` / indexer sinks as the project indexer). Each notebook gets one bank; duplicate titles get an ID suffix. The service runs only under the `notebooklm` compose profile, so a plain `docker compose up` never starts it unless that profile is enabled.
|
|
4
|
+
|
|
5
|
+
Risks:
|
|
6
|
+
|
|
7
|
+
- The default `client` backend uses the unofficial `notebooklm-py` library (pinned to 0.8.5 with the `markdown` extra). Google can change or block it at any time, and the sync then fails until the library is updated.
|
|
8
|
+
- The stored login is a Google session cookie set. Anyone who reads `~/.config/notebooklm` can act on that Google account. The directory is bind-mounted read-write into the sync container only, and masked from the indexer.
|
|
9
|
+
- Source text and notes are copied into your active memory backend (`notebooklm::*` scope). With Hindsight, retains may invoke the configured model server; mem0/Cognee store chunks via the indexer sink (Cognee runs cognify after each sync batch).
|
|
10
|
+
|
|
11
|
+
Login happens in **`npm run setup`** when you enable NotebookLM: the wizard installs
|
|
12
|
+
`notebooklm-py` (via `uv`) if needed, opens the Google sign-in browser, then writes
|
|
13
|
+
`NOTEBOOKLM_HOME=~/.config/notebooklm` into the process environment and `wizard.conf`.
|
|
14
|
+
Cookies land in `~/.config/notebooklm/profiles/default/storage_state.json` (bind-mounted
|
|
15
|
+
into the sync container). Re-run setup when Google expires the session.
|
|
16
|
+
|
|
17
|
+
Manual equivalent (only if you skip the wizard step):
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
mkdir -p ~/.config/notebooklm
|
|
21
|
+
uv tool install 'notebooklm-py[browser]==0.8.5'
|
|
22
|
+
uv tool run --from 'notebooklm-py[browser]==0.8.5' python -m playwright install chromium
|
|
23
|
+
NOTEBOOKLM_HOME=~/.config/notebooklm notebooklm login # or: ... login --browser-cookies chrome
|
|
24
|
+
NOTEBOOKLM_HOME=~/.config/notebooklm notebooklm auth check --test --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Enable and start:
|
|
28
|
+
|
|
29
|
+
1. Create `~/.config/hindsight/notebooklm.yml` with only the keys you change, for example:
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
enabled: true
|
|
33
|
+
interval_minutes: 60 # default 60
|
|
34
|
+
include_notebooks: ["Work*"] # fnmatch globs, case-insensitive; empty means all
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Compose refuses to start if this file is missing; create it first (`touch` is enough when there are no changes). Keys merge with `config/notebooklm.yml`; lists and scalars replace the shipped value.
|
|
38
|
+
2. Start the service from the repository:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
docker compose --profile notebooklm up -d notebooklm
|
|
42
|
+
docker compose --profile notebooklm logs -f notebooklm
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Without a login, the service logs the login commands and retries every 15 minutes. With `enabled: false` it sleeps and checks again hourly.
|
|
46
|
+
|
|
47
|
+
### Coding-agent access (`notebooklmAccess`)
|
|
48
|
+
|
|
49
|
+
Synced notebooks land in Hindsight banks named `notebooklm::<slug>`. The coding-agent plugin still uses per-repo `coding-agent::*` banks only. Agents can **list/search** NotebookLM banks on demand (no auto-inject) via an opt-in MCP.
|
|
50
|
+
|
|
51
|
+
**Primary paths** (pick one):
|
|
52
|
+
|
|
53
|
+
1. **Wizard** — when you enable NotebookLM sync in setup (step 6), the wizard asks whether to allow coding agents to query those banks via MCP (`notebooklm_list_banks` / `notebooklm_search`). Default is yes after sync is enabled. On yes it writes `notebooklmAccess.enabled: true` into a **real** `~/.hindsight/coding-agent.json` (if that path was a symlink to the repo template, it is copied to a regular file first so machine settings never land in `config/coding-agent.json`) and merges a `notebooklm` entry into `~/.cursor/mcp.json`.
|
|
54
|
+
2. **`npx @bcmyguest/openmem install-mcp`** — same enable + MCP merge when NotebookLM is already on (`notebooklm.yml` `enabled: true`) or with `--notebooklm` / `--notebooklm-only`. See [Coding agents and MCP](coding-agents.md).
|
|
55
|
+
|
|
56
|
+
Restart Cursor Agent after either path. Manual JSON remains a fallback if you skipped the prompt or need to change allowlists later:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
"notebooklmAccess": {
|
|
60
|
+
"enabled": true,
|
|
61
|
+
"banks": ["*"]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `enabled: false` (shipped default) — the NotebookLM MCP exits immediately; setup does not register it.
|
|
66
|
+
- `banks: ["*"]` — every `notebooklm::*` bank; or list slugs / full ids (e.g. `"sitrep-analysis"` or `"notebooklm::sitrep-analysis"`).
|
|
67
|
+
|
|
68
|
+
MCP tools (stdio server `cli/notebooklm-mcp.mjs`):
|
|
69
|
+
|
|
70
|
+
| Tool | Purpose |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| `notebooklm_list_banks` | Allowlisted `notebooklm::*` banks (`bank_id`, `fact_count`) |
|
|
73
|
+
| `notebooklm_search` | Fast full-text list on one allowlisted bank (`bank_id` + `query`; optional `mode=recall` for slow LLM synthesis) |
|
|
74
|
+
|
|
75
|
+
When `enabled` is true, the wizard or `install-mcp` merges a `notebooklm` entry into `~/.cursor/mcp.json` (does not overwrite `hindsight` or `codegraph`). To run the server by hand:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# after enabling notebooklmAccess (wizard, install-mcp, or hand-edit)
|
|
79
|
+
node cli/notebooklm-mcp.mjs
|
|
80
|
+
# or: openmem-notebooklm-mcp
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Enterprise backend (`backend: enterprise`): the documented NotebookLM Enterprise REST API lists recently viewed notebooks only. It returns no source or note text, so this backend syncs notebook metadata only. It is untested against a live Enterprise project.
|