@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
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Installing with npx
|
|
2
|
+
|
|
3
|
+
`openmem` is an npm package whose CLI runs the same setup wizard as `./setup` in a
|
|
4
|
+
checkout. The package name lives in one place, the `name` field of `package.json` (the CLI
|
|
5
|
+
command stays `openmem` if you switch to a scoped name such as
|
|
6
|
+
`openmem`; older installs may still see `openmem`).
|
|
7
|
+
|
|
8
|
+
Requirements: Node ≥ 20.12 (the floor of `@clack/prompts`), Docker with the compose v2
|
|
9
|
+
plugin (`docker compose version`), `curl`. Linux and macOS are supported; there is no
|
|
10
|
+
bash dependency in the CLI (macOS ships bash 3.2).
|
|
11
|
+
|
|
12
|
+
Wizard phases and flags live in the repository: [docs/setup-wizard.md](setup-wizard.md). Runtime architecture: [architecture.md](architecture.md).
|
|
13
|
+
|
|
14
|
+
## Install paths
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npx @bcmyguest/openmem # interactive setup, nothing installed globally
|
|
18
|
+
npx @bcmyguest/openmem setup # same as the bare command
|
|
19
|
+
npx @bcmyguest/openmem configure --yes # non-interactive setup and start
|
|
20
|
+
npx @bcmyguest/openmem up # start stack
|
|
21
|
+
npx @bcmyguest/openmem install-mcp --yes
|
|
22
|
+
npx @bcmyguest/openmem switch mem0 --yes
|
|
23
|
+
npm i -g openmem # then: openmem setup | up | down | ...
|
|
24
|
+
# From a git checkout (package not required on the registry):
|
|
25
|
+
git clone https://github.com/bcmyguest/openmem && cd openmem
|
|
26
|
+
npm install && npx . setup # same wizard; also: npm run setup / ./setup
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
No global `pm` command is installed: it collides with Android's `pm`. `./pm` and `npm run pm`
|
|
30
|
+
exist only inside a checkout; prefer `npx @bcmyguest/openmem …` (or `npx . …` in a checkout).
|
|
31
|
+
|
|
32
|
+
### Commands
|
|
33
|
+
|
|
34
|
+
| Command | What it does |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `openmem` / `setup` | interactive setup; extra flags go to the wizard (`--yes`, `--dry-run`, `--no-smoke`, `--rebuild`) |
|
|
37
|
+
| `configure` | non-interactive setup and start (`setup --yes`) |
|
|
38
|
+
| `up` / `down` | start / stop the stack with the saved configuration |
|
|
39
|
+
| `doctor` | validate the configuration without the smoke test |
|
|
40
|
+
| `install-mcp` | merge **openmem** unified MCP (`memory_*`) by default; NotebookLM when sync is on or `--notebooklm`; native mem0/Cognee with `--provider-only`; `--no-unified-mcp` to skip |
|
|
41
|
+
| `install-coding-agent` | `install-mcp` + session hooks for all providers; optional `--hindsight-plugin` runs `@vectorize-io/hindsight-coding-agents` on Hindsight stacks |
|
|
42
|
+
| `wiring` | report `MEMORY_PROVIDER`, API URLs, and `mcp.json` alignment (`--json`) |
|
|
43
|
+
| `switch <provider>` | change `MEMORY_PROVIDER` (optional stack restart + MCP; no data migration) |
|
|
44
|
+
| `providers [--json]` | list the provider manifests shipped in the package with their status |
|
|
45
|
+
| `init [--force] [--dry-run] [--json]` | create or upgrade the stack root without running the wizard |
|
|
46
|
+
| `--version`, `--help` | |
|
|
47
|
+
|
|
48
|
+
`--version`, `--help` and `providers` touch nothing on disk. Every other command first
|
|
49
|
+
brings the stack root up to date, then runs the wizard.
|
|
50
|
+
|
|
51
|
+
## Stack root
|
|
52
|
+
|
|
53
|
+
Under npx the package directory is a read-only, garbage-collected cache, but the wizard
|
|
54
|
+
writes `.env`, `.build-hash` and `compose.override.yaml` and drives compose files and docker
|
|
55
|
+
build contexts relative to its repo root. The CLI therefore keeps a stable, writable
|
|
56
|
+
**stack root**:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
${PM_STACK_ROOT:-${XDG_DATA_HOME:-~/.local/share}/personal-memory/stack}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Layout after `openmem init`:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
stack/
|
|
66
|
+
.pm-stack-manifest.json sha256 of every shipped file as last written (do not edit)
|
|
67
|
+
compose.yaml shipped
|
|
68
|
+
compose.bench.yaml shipped
|
|
69
|
+
indexer/ bin/ sync/ shipped (docker build contexts)
|
|
70
|
+
config/ shipped templates: *.example, index.yml, notebooklm.yml,
|
|
71
|
+
litellm.*.yaml, coding-agent.json
|
|
72
|
+
providers/<id>/compose*.yaml shipped provider compose fragments
|
|
73
|
+
.env .build-hash compose.override.yaml personal-memory.toml ... generated: never touched
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The wizard code itself (`wizard/`, `scripts/`, provider manifests and hooks) is **not**
|
|
77
|
+
copied: it runs from the package, so `@clack/prompts` resolves from the package's own `node_modules`.
|
|
78
|
+
Per-user config stays where it always was: `~/.config/hindsight/` and
|
|
79
|
+
`~/.config/personal-memory/config.toml`.
|
|
80
|
+
|
|
81
|
+
### Environment variables
|
|
82
|
+
|
|
83
|
+
| Variable | Meaning |
|
|
84
|
+
| --- | --- |
|
|
85
|
+
| `PM_STACK_ROOT` | Mutable stack root = the wizard's `ctx.repoRoot` (compose project dir, `.env`, generated files, docker build context). Overrides the default location. |
|
|
86
|
+
| `PM_USE_CHECKOUT=1` | Use the package directory itself as the stack root and copy nothing. Wins over `PM_STACK_ROOT`. A directory containing `.git` next to `cli/` behaves this way automatically. |
|
|
87
|
+
| `PM_PACKAGE_ROOT` | Read-only code root (provider manifests and hooks, `scripts/setup.mjs`, `wizard/lib`), never written to. Set by the CLI; defaults to the package directory. |
|
|
88
|
+
| `PM_PROJECT` | compose project name (default `openmem`). |
|
|
89
|
+
| `XDG_DATA_HOME` | Base for the default stack root (must be absolute). |
|
|
90
|
+
|
|
91
|
+
`wizard/bin/setup.mjs` and `wizard/bin/pm.mjs` read `PM_STACK_ROOT` and `PM_PACKAGE_ROOT`
|
|
92
|
+
(defaulting both to the checkout root) and export them to child processes. Running them
|
|
93
|
+
directly from inside an npm package directory without `PM_STACK_ROOT` is refused.
|
|
94
|
+
|
|
95
|
+
## Upgrades
|
|
96
|
+
|
|
97
|
+
Each command compares the package's shipped files with the stack root using the manifest:
|
|
98
|
+
|
|
99
|
+
- Missing file: created (restored if it was shipped before).
|
|
100
|
+
- Identical: left alone.
|
|
101
|
+
- On disk equals what the previous version wrote: overwritten with the new version
|
|
102
|
+
(atomic write: temp file in the same directory, then rename).
|
|
103
|
+
- Modified by you, or present but not tracked, or a symlink: **kept**, reported as
|
|
104
|
+
`CONFLICT <path>`. The wizard still runs against your version. Merge by hand, or run
|
|
105
|
+
`openmem init --force`, which overwrites it and saves yours as
|
|
106
|
+
`<file>.user-<timestamp>.bak`.
|
|
107
|
+
- No longer shipped: left in place and reported as a note.
|
|
108
|
+
- Generated files (`.env`, `.build-hash`, `compose.override.yaml`, `personal-memory.toml`,
|
|
109
|
+
anything not in the manifest) are never overwritten or deleted.
|
|
110
|
+
|
|
111
|
+
After an upgrade the wizard's `.build-hash` check rebuilds the images when their sources
|
|
112
|
+
changed.
|
|
113
|
+
|
|
114
|
+
## Uninstall
|
|
115
|
+
|
|
116
|
+
```sh
|
|
117
|
+
openmem down # stops the stack (docker compose down)
|
|
118
|
+
npm uninstall -g openmem # if installed globally
|
|
119
|
+
rm -rf "${XDG_DATA_HOME:-$HOME/.local/share}/personal-memory" # the stack root
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`~/.config/hindsight/` (secrets, `index.yml`) and `~/.config/personal-memory/` are kept
|
|
123
|
+
until you delete them yourself.
|
|
124
|
+
|
|
125
|
+
## Linux and macOS notes
|
|
126
|
+
|
|
127
|
+
- Linux: the user must be able to run `docker` without sudo. `host.docker.internal`
|
|
128
|
+
is mapped through `extra_hosts` in `compose.yaml`.
|
|
129
|
+
- macOS: use Docker Desktop or Colima with the compose v2 plugin and allow file sharing
|
|
130
|
+
for your home directory (the indexer bind-mounts `$HOME` read-only).
|
|
131
|
+
- Windows is untested; use WSL2.
|
|
132
|
+
|
|
133
|
+
## Troubleshooting
|
|
134
|
+
|
|
135
|
+
- `CONFLICT <path>`: see Upgrades. It is a warning; the stack still works.
|
|
136
|
+
- `cannot prepare the stack root`: the directory is not writable. Set `PM_STACK_ROOT` to
|
|
137
|
+
a writable path.
|
|
138
|
+
- `read-only ... Run it through the CLI`: you ran `wizard/bin/*.mjs` from inside the npm
|
|
139
|
+
cache. Use `npx @bcmyguest/openmem` or set `PM_STACK_ROOT`.
|
|
140
|
+
- `missing dependencies (@clack/prompts ...)`: reinstall the package (`npm i -g
|
|
141
|
+
openmem`), or in a checkout run `npm install` at the checkout root.
|
|
142
|
+
- `... is not valid JSON` for `.pm-stack-manifest.json`: delete the manifest; shipped
|
|
143
|
+
files that differ from the package are then reported as untracked conflicts instead of
|
|
144
|
+
being overwritten.
|
|
145
|
+
- Port already in use: set `HINDSIGHT_PORT` / `HINDSIGHT_CP_PORT`, or let the wizard pick
|
|
146
|
+
a free port.
|
|
147
|
+
|
|
148
|
+
## Maintainers: publishing
|
|
149
|
+
|
|
150
|
+
Before the first publish (these are human steps; nothing in this repo does them):
|
|
151
|
+
|
|
152
|
+
1. **License.** The repository ships `LICENSE` (Apache-2.0) and `package.json` matches.
|
|
153
|
+
2. **Public source.** `npm publish --provenance` needs a public GitHub repository.
|
|
154
|
+
3. **Pack gate.** `npm run pack:check` must pass (no operator home paths in shipped files).
|
|
155
|
+
4. **Create the npm package.** Log in with 2FA (`npm login`), then publish `0.1.0` once by
|
|
156
|
+
hand (`npm publish --access public`). The name `openmem` was verified free on
|
|
157
|
+
2026-10-19 (so was `openmem`); re-check with `npm view openmem`.
|
|
158
|
+
5. **Trusted publishing.** On npmjs.com, package Settings -> Trusted Publisher -> GitHub
|
|
159
|
+
Actions: owner `bcmyguest`, repository `openmem`, workflow `release.yml`.
|
|
160
|
+
6. **Release.** Run the *Prepare release* workflow on `main` (or bump `package.json`, tag
|
|
161
|
+
`vX.Y.Z`, and push the tag). `release.yml` runs CI, then publishes with `--provenance`
|
|
162
|
+
when the version is not already on npm, then creates the GitHub Release.
|
|
163
|
+
|
|
164
|
+
Local rehearsal without publishing:
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
npm run pack:check
|
|
168
|
+
npm pack --pack-destination /tmp/pm-pack
|
|
169
|
+
cd "$(mktemp -d)" && npx --yes /tmp/pm-pack/openmem-*.tgz --version
|
|
170
|
+
```
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Mise-like config (`config.toml`)
|
|
2
|
+
|
|
3
|
+
openmem is a **meta** orchestrator (see [architecture.md](architecture.md) on the site; [memory-providers.md](memory-providers.md) in the repo for contributors). Its
|
|
4
|
+
declarative config is intentionally similar to **[mise](https://mise.jdx.dev/)**:
|
|
5
|
+
|
|
6
|
+
| mise | openmem |
|
|
7
|
+
| --- | --- |
|
|
8
|
+
| `~/.config/mise/config.toml` + `.mise.toml` | `~/.config/personal-memory/config.toml` + `openmem.toml` |
|
|
9
|
+
| `[tools]` plugins | `[memory] provider = "…"` + `providers/*/manifest.json` |
|
|
10
|
+
| `[env]` | Host ports / compose project under `[stack]` |
|
|
11
|
+
| `[tasks]` | `npx @bcmyguest/openmem up` / `down` / `doctor` / `install-mcp` / `switch` |
|
|
12
|
+
| `mise install` applies config | `npx @bcmyguest/openmem configure --yes` applies config |
|
|
13
|
+
|
|
14
|
+
We **do not** replace mise (or mem0/Hindsight native config). You can use both: mise installs
|
|
15
|
+
Node/Docker; this file describes **how agent memory runs on this machine**.
|
|
16
|
+
|
|
17
|
+
## Files
|
|
18
|
+
|
|
19
|
+
| Path | Purpose |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `config/openmem.toml.example` | Shipped template; copy to your user config |
|
|
22
|
+
| `~/.config/personal-memory/config.toml` | **Primary** user config (gitignored on your machine) |
|
|
23
|
+
| `./openmem.toml` | Optional per-checkout overrides (legacy `personal-memory.toml` still loads) |
|
|
24
|
+
| `~/.config/hindsight/wizard.conf` | Last configure run (`MEMORY_PROVIDER`, ports, …); updated when setup applies |
|
|
25
|
+
|
|
26
|
+
## Precedence
|
|
27
|
+
|
|
28
|
+
1. CLI flags (`npx @bcmyguest/openmem setup --up`, `--down`, …)
|
|
29
|
+
2. Environment (`MEMORY_PROVIDER`, `PM_BACKEND`, `HINDSIGHT_PORT`, …)
|
|
30
|
+
3. `~/.config/personal-memory/config.toml`
|
|
31
|
+
4. `openmem.toml` / `config/openmem.toml` in the checkout stack root (legacy `personal-memory.toml` names still load)
|
|
32
|
+
5. Existing `wizard.conf` (provider, ports, model backend from the last wizard run)
|
|
33
|
+
|
|
34
|
+
Interactive `./setup` uses this file for **defaults** (Clack pre-selects); your answers still win.
|
|
35
|
+
|
|
36
|
+
## Sections
|
|
37
|
+
|
|
38
|
+
- **`[memory]`** — `provider` id (`hindsight`, future `mem0`, …).
|
|
39
|
+
- **`[stack]`** — compose project name and host ports.
|
|
40
|
+
- **`[wizard]`** — default action (`configure`, `up`, `down`).
|
|
41
|
+
- **`[model]`** — meta **LLM routing** for the Hindsight stack only; other providers add
|
|
42
|
+
`[memory.<id>]` tables (see `[memory.mem0]` below).
|
|
43
|
+
- **`[memory.mem0]`** — the mem0 provider (URL-only: you run a mem0 REST server, this stack points
|
|
44
|
+
the indexer at it). Never holds a key.
|
|
45
|
+
|
|
46
|
+
```toml
|
|
47
|
+
[memory]
|
|
48
|
+
provider = "mem0"
|
|
49
|
+
|
|
50
|
+
[memory.mem0]
|
|
51
|
+
api_url = "http://127.0.0.1:18888" # the server as this host sees it
|
|
52
|
+
# env_file = "~/.config/personal-memory/mem0.env" # optional; where MEM0_API_KEY lives
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`api_url` is resolved as: `MEM0_API_URL`, then `PM_MEM0_API_URL`, then this table, then the stack
|
|
56
|
+
`.env`, then `wizard.conf`, then the default `http://127.0.0.1:18888`. The indexer container
|
|
57
|
+
gets the same URL with `127.0.0.1`/`localhost` rewritten to `host.docker.internal`
|
|
58
|
+
(`MEM0_INDEXER_URL` in the stack `.env`). The API key is written by `./setup` (from
|
|
59
|
+
`MEM0_API_KEY` under `--yes`, or a prompt) as the single line `MEM0_API_KEY=your-key-here` in the env file
|
|
60
|
+
(`MEM0_ENV_FILE`, then `env_file`, then `~/.config/personal-memory/mem0.env`; mode 600 in a mode
|
|
61
|
+
700 directory). You can also create that file by hand; a server run with `AUTH_DISABLED` needs
|
|
62
|
+
none. The key never goes into the stack `.env`, `wizard.conf` or `config.toml`. A non-default
|
|
63
|
+
`env_file` is exported to compose as `MEM0_ENV_FILE` for the run; export it yourself when you run
|
|
64
|
+
`docker compose` by hand.
|
|
65
|
+
- **`[memory.cognee]`** — the Cognee provider (a pinned `cognee/cognee` container on a loopback
|
|
66
|
+
port, single-user mode, no authentication). Never holds a key.
|
|
67
|
+
|
|
68
|
+
```toml
|
|
69
|
+
[memory]
|
|
70
|
+
provider = "cognee"
|
|
71
|
+
|
|
72
|
+
[memory.cognee]
|
|
73
|
+
port = 8766 # host port; the container listens on 8000
|
|
74
|
+
env_file = "~/.config/personal-memory/cognee.env" # cognify settings (GLiNER/FastEmbed by default)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`port` is resolved as: `COGNEE_PORT`, then this table, then the stack `.env`, then the port
|
|
78
|
+
saved in `wizard.conf`, then the default `8766`. Both env file locations follow the same order:
|
|
79
|
+
the variable (`COGNEE_ENV_FILE`, `COGNEE_INDEXER_ENV_FILE`), then `env_file` /
|
|
80
|
+
`indexer_env_file` in this table, then the stack `.env`, then the defaults
|
|
81
|
+
`~/.config/personal-memory/cognee.env` and `~/.config/personal-memory/cognee-indexer.env`.
|
|
82
|
+
The second file is optional and is the one the indexer container reads; it holds only
|
|
83
|
+
`COGNEE_API_KEY`. A non-default location (`~` is expanded, a relative path is taken relative
|
|
84
|
+
to the stack root) is written to the stack `.env` as a path, so a plain `docker compose` finds
|
|
85
|
+
the same files; the file contents never go there. Keep custom files inside
|
|
86
|
+
`~/.config/personal-memory`: that is the directory hidden from the indexer's read-only `$HOME`
|
|
87
|
+
mount, and setup warns about a file elsewhere under `$HOME`.
|
|
88
|
+
|
|
89
|
+
Documents are stored but not searchable until cognify can run. **Default cognify path** (no
|
|
90
|
+
API key): local GLiNER extraction + FastEmbed embeddings. `./setup` / `--yes` with no LLM
|
|
91
|
+
answers writes that block into the env file (mode 600 in a mode 700 directory), merging into
|
|
92
|
+
any existing file and replacing only the keys it was given; it prints the path and the key
|
|
93
|
+
names, never a value. Where the answers come from:
|
|
94
|
+
|
|
95
|
+
| Variable (environment) | Written to the env file as |
|
|
96
|
+
| --- | --- |
|
|
97
|
+
| `PM_COGNEE_LLM_API_KEY`; under `--yes` or `--dry-run` also plain `LLM_API_KEY` | `LLM_API_KEY` |
|
|
98
|
+
| `PM_COGNEE_LLM_PROVIDER`, `PM_COGNEE_LLM_MODEL`, `PM_COGNEE_LLM_ENDPOINT` | `LLM_PROVIDER`, `LLM_MODEL`, `LLM_ENDPOINT` |
|
|
99
|
+
| `PM_COGNEE_EMBEDDING_PROVIDER`, `_MODEL`, `_ENDPOINT`, `_DIMENSIONS` | the same names without `PM_COGNEE_` |
|
|
100
|
+
| `PM_COGNEE_EMBEDDING_API_KEY`; under `--yes` or `--dry-run` also plain `EMBEDDING_API_KEY` | `EMBEDDING_API_KEY` |
|
|
101
|
+
| `PM_COGNEE_HUGGINGFACE_TOKENIZER` | `HUGGINGFACE_TOKENIZER` |
|
|
102
|
+
| `PM_COGNEE_GRAPH_EXTRACTOR`, `PM_COGNEE_AUTO_FEEDBACK` | `GRAPH_EXTRACTOR`, `AUTO_FEEDBACK` |
|
|
103
|
+
|
|
104
|
+
**Default (GLiNER + FastEmbed)** when no cognify answers are given:
|
|
105
|
+
|
|
106
|
+
```env
|
|
107
|
+
GRAPH_EXTRACTOR=gliner_demo
|
|
108
|
+
EMBEDDING_PROVIDER=fastembed
|
|
109
|
+
EMBEDDING_MODEL=BAAI/bge-small-en-v1.5
|
|
110
|
+
EMBEDDING_DIMENSIONS=384
|
|
111
|
+
AUTO_FEEDBACK=false
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Compose pins `HF_HOME` / `FASTEMBED_CACHE_PATH` under the `cognee-data` volume so model
|
|
115
|
+
downloads survive container recreates. Changing embedding dimensions requires rebuilding
|
|
116
|
+
vectors (prune datasets or recreate the volume).
|
|
117
|
+
|
|
118
|
+
**Local Ollama** (LLM + Ollama embeddings): set `PM_COGNEE_LLM_PROVIDER=ollama` (and optionally
|
|
119
|
+
`PM_COGNEE_LLM_MODEL=...`). The wizard fills in a complete local block when fields are missing:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
PM_COGNEE_LLM_PROVIDER=ollama PM_COGNEE_LLM_MODEL=llama3.2 ./setup --yes
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
That writes (defaults only where unset):
|
|
126
|
+
|
|
127
|
+
```env
|
|
128
|
+
LLM_PROVIDER=ollama
|
|
129
|
+
LLM_API_KEY=ollama
|
|
130
|
+
LLM_ENDPOINT=http://host.docker.internal:11434
|
|
131
|
+
EMBEDDING_PROVIDER=ollama
|
|
132
|
+
EMBEDDING_MODEL=nomic-embed-text:latest
|
|
133
|
+
EMBEDDING_ENDPOINT=http://host.docker.internal:11434/api/embed
|
|
134
|
+
EMBEDDING_DIMENSIONS=768
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Ollama LLM + FastEmbed is also valid: set `PM_COGNEE_EMBEDDING_PROVIDER=fastembed` (and model /
|
|
138
|
+
dimensions) alongside `PM_COGNEE_LLM_PROVIDER=ollama`. Use the bare Ollama host (`…:11434`),
|
|
139
|
+
not `…:11434/v1` — Cognee's Ollama path appends `/api/generate` itself. **Host Ollama**
|
|
140
|
+
(listening on the Docker bridge or all interfaces): `host.docker.internal` is correct.
|
|
141
|
+
**Compose Ollama** published as `127.0.0.1:11434` only (this repo's default): that address is
|
|
142
|
+
unreachable via `host.docker.internal` — set `PM_COGNEE_OLLAMA_COMPOSE=1` (or reuse
|
|
143
|
+
`MEMORY_OLLAMA_IN_COMPOSE=1` from a Hindsight Ollama setup) so the wizard writes
|
|
144
|
+
`http://ollama:11434`, and attach the Cognee container to the same Docker network as the
|
|
145
|
+
`ollama` service. Slow local models may need `COGNEE_SKIP_CONNECTION_TEST=true` in
|
|
146
|
+
`cognee.env`. The interactive setup offers GLiNER+FastEmbed (default), Ollama, or an OpenAI
|
|
147
|
+
key (hidden prompt). Do not type the key into a non-Clack `./setup` prompt — put
|
|
148
|
+
`LLM_API_KEY` in `cognee.env` (mode 600) by hand (Ollama accepts any non-empty value), or use
|
|
149
|
+
the UI / `--yes` with `PM_COGNEE_LLM_API_KEY`. Secret variables (including plain `LLM_API_KEY` /
|
|
150
|
+
`EMBEDDING_API_KEY` / `COGNEE_API_KEY`) are removed from the wizard's environment before it
|
|
151
|
+
starts docker. Secrets never go into the stack `.env`, `wizard.conf`, `config.toml` or the
|
|
152
|
+
summary. Authentication is off: `ENABLE_BACKEND_ACCESS_CONTROL` is pinned false in compose and
|
|
153
|
+
overrides the env file (see `providers/cognee/compose.yaml`).
|
|
154
|
+
- **`[tasks.*]`** — descriptions for `npx @bcmyguest/openmem` / `./pm` (see `wizard/bin/pm.mjs` and
|
|
155
|
+
`cli/openmem.mjs`). Built-in tasks:
|
|
156
|
+
- `configure` / `up` / `down` / `doctor` — map to the setup wizard with the matching flags
|
|
157
|
+
- `install-mcp` — runs `cli/install-memory-mcp.mjs` (NotebookLM MCP on Hindsight; mem0/Cognee
|
|
158
|
+
with `--provider-only`; merges into `~/.cursor/mcp.json`)
|
|
159
|
+
- `switch <provider>` — runs `cli/switch-memory-provider.mjs`: sets `MEMORY_PROVIDER` in
|
|
160
|
+
`wizard.conf`, updates `[memory].provider` in `config.toml` when present
|
|
161
|
+
(`updatePmConfigProvider`), optionally restarts the stack and re-points provider MCP.
|
|
162
|
+
Flags: `--yes`, `--dry-run`, `--no-stack`, `--no-mcp`. Does not migrate data between
|
|
163
|
+
backends. See [README — Switch memory provider](../README.md#switch-memory-provider).
|
|
164
|
+
- `feed-sync` — runs `cli/feed-sync.mjs` (RSS + OpenAlex → `feeds.out_dir` in `index.yml`).
|
|
165
|
+
- `install-coding-agent` — unified MCP + session hooks (all providers); optional `--hindsight-plugin`; see
|
|
166
|
+
[coding-agent hooks](coding-agent-hooks.md).
|
|
167
|
+
|
|
168
|
+
## MCP (unified `memory_*` tools)
|
|
169
|
+
|
|
170
|
+
| Variable | Default | Purpose |
|
|
171
|
+
| --- | --- | --- |
|
|
172
|
+
| `PM_MEMORY_ADD_ASYNC` | `true` (implicit) | Hindsight `memory_add` sends `async: true` unless the tool passes `async: false`. Async ingest returns in ~200ms and avoids Cursor/Claude MCP `-32001` timeouts while extraction runs in the background. Set `PM_MEMORY_ADD_ASYNC=false` to force synchronous ingest. |
|
|
173
|
+
|
|
174
|
+
After changing MCP code, re-run `npx @bcmyguest/openmem install-coding-agent --yes` (or copy the repo into `~/.local/share/personal-memory/agent-runtime`) and **restart** the openmem MCP server in Cursor.
|
|
175
|
+
|
|
176
|
+
## Apply
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
cp config/openmem.toml.example ~/.config/personal-memory/config.toml
|
|
180
|
+
# edit provider, ports, model backend
|
|
181
|
+
npx @bcmyguest/openmem configure --yes
|
|
182
|
+
# checkout before publish: npx . configure --yes
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
After a successful configure, the wizard **writes back** `~/.config/personal-memory/config.toml` so
|
|
186
|
+
the file matches what is running (mise-style source of truth).
|
|
187
|
+
|
|
188
|
+
## Doctor
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npx @bcmyguest/openmem doctor
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Runs the same checks as setup step “Validate memory setup” without mutating the stack.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Provider wizard hooks (sub-wizards)
|
|
2
|
+
|
|
3
|
+
The meta wizard (`./setup`, `./pm`) owns cross-provider steps. Each **provider plugin** ships a
|
|
4
|
+
**`providers/<id>/wizard.mjs`** module, the same relationship as asdf/mise plugins: the core tool
|
|
5
|
+
runs the plugin's hooks; it does not reimplement Node, Rust, mem0, or a model router.
|
|
6
|
+
|
|
7
|
+
The meta wizard knows nothing about any one provider. `wizard/lib/run-wizard.mjs`,
|
|
8
|
+
`wizard/lib/ports.mjs` and `wizard/lib/validate-setup.mjs` contain no provider names (a test greps
|
|
9
|
+
for this). A provider that exports no hook for a phase gets a clean no-op for that phase: there is
|
|
10
|
+
no default provider and no fallback implementation.
|
|
11
|
+
|
|
12
|
+
## Hook API version
|
|
13
|
+
|
|
14
|
+
`helpers.apiVersion` is `2`. It is bumped when a helper is removed or changes meaning; adding a
|
|
15
|
+
helper does not bump it. Version 1 (the `chooseBackend` helper and `fallback:` argument) is gone.
|
|
16
|
+
The v1 phase names still work unchanged.
|
|
17
|
+
|
|
18
|
+
## Package root vs stack root
|
|
19
|
+
|
|
20
|
+
| Field | Env | Meaning | Used for |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `ctx.repoRoot` | `PM_STACK_ROOT` | Mutable stack root | compose project dir (`cwd` of every `docker compose` call), `.env`, `compose.override.yaml`, `.build-hash`, generated files |
|
|
23
|
+
| `ctx.packageRoot` | `PM_PACKAGE_ROOT` (default: `repoRoot`) | Read-only code root | `providers/` manifests and hook modules, `scripts/setup.mjs`, `scripts/gen-masks.mjs` |
|
|
24
|
+
|
|
25
|
+
For a git checkout they are the same directory. For an installed package the integrator passes the
|
|
26
|
+
stack root as `repoRoot` (`runWizard(stackRoot, argv)`) and the package directory through
|
|
27
|
+
`PM_PACKAGE_ROOT`. `runWizard` exports `PM_PACKAGE_ROOT` so child code sees it.
|
|
28
|
+
`PM_PROVIDERS_DIR` overrides the providers directory entirely (tests use it for fake providers).
|
|
29
|
+
Provider code must write only under `ctx.repoRoot` and read bundled files only under
|
|
30
|
+
`ctx.packageRoot`.
|
|
31
|
+
|
|
32
|
+
## Execution order
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
meta.preflight
|
|
36
|
+
meta.provider pick memory provider (Clack / TOML / --yes)
|
|
37
|
+
provider.init quiet: seed ctx defaults (also runs before preflight)
|
|
38
|
+
provider.resolvePorts host ports (also after the provider is chosen)
|
|
39
|
+
provider.afterProvider
|
|
40
|
+
provider.configureModelRouting models, keys, logins
|
|
41
|
+
meta.wizardConf written unless the provider already saved it
|
|
42
|
+
meta.setupEnv indexer state dir, then provider.setupEnv or scripts/setup.mjs
|
|
43
|
+
meta.index index.yml
|
|
44
|
+
meta.notebooklm optional profile
|
|
45
|
+
provider.beforeStack compose fragments, migrations
|
|
46
|
+
meta.stack build, up, health, provider.afterStackHealthy, then smoke
|
|
47
|
+
meta.codingAgent generic npx plugin, then provider.setupCodingAgent
|
|
48
|
+
meta.validate generic checks, then provider.extendValidation
|
|
49
|
+
meta.syncConfig config.toml (provider.configToml sections)
|
|
50
|
+
meta.summary provider.summary
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Stack-only actions** (`./setup --up`, `./pm up`) skip the configure phases:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
meta.preflight -> meta.provider -> hydrate -> provider.resolvePorts -> provider.beforeStack
|
|
57
|
+
-> meta.stack -> meta.validate -> meta.summary
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Down** runs `meta.preflight -> meta.stackDown -> meta.summary`. There are no down hooks yet.
|
|
61
|
+
|
|
62
|
+
## Hook module contract
|
|
63
|
+
|
|
64
|
+
Path: `providers/<id>/wizard.mjs` (ESM), found through the manifest:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
"wizardHooks": { "module": "wizard.mjs" }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The path must stay inside the provider directory. Every export is an optional
|
|
71
|
+
`async function(ctx, helpers)`; implement only what you need. Hooks marked announced print
|
|
72
|
+
`provider <id>: <phase>` when they run; quiet hooks return a value to the meta wizard.
|
|
73
|
+
|
|
74
|
+
| Export | Kind | Return | When it runs |
|
|
75
|
+
| --- | --- | --- | --- |
|
|
76
|
+
| `init` | quiet | ignored | Seed provider defaults on `ctx` before anything reads them |
|
|
77
|
+
| `hydrate` | quiet | ignored | Restore provider state from the saved `wizard.conf` |
|
|
78
|
+
| `afterProvider` | announced | ignored | Right after the provider is selected |
|
|
79
|
+
| `configureModelRouting` | announced | ignored | Model backend, API keys, logins. Honor `ctx.skipBackendStep` (Clack already asked) |
|
|
80
|
+
| `resolvePorts` | announced | ignored | Choose free host ports (`helpers.choosePort`, `helpers.resolveHostPort`) |
|
|
81
|
+
| `stackEnv` | quiet | `{ description?, env? }` | What the generic `scripts/setup.mjs` run should print and receive |
|
|
82
|
+
| `setupEnv` | announced | ignored | Replace the generic secrets/env step; call `helpers.runStackSetup` to still run `scripts/setup.mjs` |
|
|
83
|
+
| `beforeStack` | announced | ignored | After env and index, before `docker compose up` |
|
|
84
|
+
| `apiBase` | quiet | string | HTTP base URL when it is not `http://127.0.0.1:<compose.hostPortEnv>` |
|
|
85
|
+
| `smoke` | announced | ignored | Replace the manifest HTTP smoke test |
|
|
86
|
+
| `afterStackHealthy` | announced | ignored | After health, before smoke (e.g. pull compose Ollama models) |
|
|
87
|
+
| `setupCodingAgent` | announced | ignored | After the generic coding-agent plugin step |
|
|
88
|
+
| `extendValidation` | announced | ignored | Push to `ctx.validationErrors` / `ctx.validationChecks`; runs after the generic checks |
|
|
89
|
+
| `configToml` | quiet | `{ stack?, memory?, <table>: {...} }` | Sections for `config.toml`: `stack` merges into `[stack]`, `memory` sub-tables (for example `memory.mem0`) merge into `[memory]` and `provider` there is always set by the wizard, every other key is a table |
|
|
90
|
+
| `summary` | quiet | `{ running?, configFiles?, notes?, logServices? }` | Lines for the closing summary |
|
|
91
|
+
| `clackSetup` | none | `{ env }` | Called by the Clack front end as `(ctxStub, ui, helpers)` |
|
|
92
|
+
| `prepareStackEnv` | script | `{ entries, drop, report }` | Called by `scripts/setup.mjs`; `.env` always gets `HOST_UID`/`HOST_GID` |
|
|
93
|
+
| `migrateEnv` | script | n/a | `scripts/setup.mjs --migrate-env` |
|
|
94
|
+
| `setupNotices` | script | `string[]` | Lines `scripts/setup.mjs` prints at the end |
|
|
95
|
+
|
|
96
|
+
`prepareStackEnv`, `migrateEnv` and `setupNotices` receive `{ repo, home, env }` (`repo` is the
|
|
97
|
+
stack root) and run in a separate Node process, so they may not use `helpers`.
|
|
98
|
+
|
|
99
|
+
Unrecognised exports are ignored. Providers must not import `wizard/lib/run-wizard.mjs`; it
|
|
100
|
+
imports them. Everything the meta wizard owns reaches a hook through `helpers`.
|
|
101
|
+
|
|
102
|
+
## Helpers
|
|
103
|
+
|
|
104
|
+
`createHelpers()` in `wizard/lib/provider-wizard/helpers.mjs` returns a frozen object. Functions
|
|
105
|
+
that take `ctx` honor `--dry-run` (they print instead of acting).
|
|
106
|
+
|
|
107
|
+
| Helper | Purpose |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| `apiVersion` | `2` |
|
|
110
|
+
| `step`, `info`, `ok`, `warn`, `die` | Logging; `die` exits 1 |
|
|
111
|
+
| `problem(ctx, msg)` | `die`, or `warn` in a dry run |
|
|
112
|
+
| `ask`, `confirm` | Prompts (answers come from `ctx.yes` and `PM_*` env when non-interactive) |
|
|
113
|
+
| `act(ctx, desc, cmd, args, {env, cwd})`, `actWithEnv` | Run a command, printed only in a dry run |
|
|
114
|
+
| `commandExists(name)` | PATH lookup |
|
|
115
|
+
| `envValue(file, key)`, `expandHome`, `ensureConfigDir(ctx)` | Paths and wizard.conf reads |
|
|
116
|
+
| `curlGet`, `curlJson`, `curlRequest` | HTTP via curl |
|
|
117
|
+
| `portFree`, `choosePort(ctx, label, port, {envVars})`, `resolveHostPort(ctx, label)` | Ports; `resolveHostPort` reads the manifest `compose.hostPortEnv` and `defaultHostPort` |
|
|
118
|
+
| `composeArgs(ctx, ...rest)` | `docker compose` argv: project, optional `-f` files, optional `--profile` |
|
|
119
|
+
| `saveWizardConf(ctx, extra, {pmSections})` | Write `wizard.conf` (and `config.toml` sections); no-op in a dry run. Always includes `MEMORY_PROVIDER` |
|
|
120
|
+
| `runStackSetup(ctx, opts)` | Run `<packageRoot>/scripts/setup.mjs` against the stack root |
|
|
121
|
+
| `apiBase(ctx)` | The provider's resolved HTTP base URL |
|
|
122
|
+
|
|
123
|
+
## Manifest fields the meta wizard reads
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
"compose": {
|
|
127
|
+
"profile": "mem0",
|
|
128
|
+
"files": ["compose.mem0.yaml"],
|
|
129
|
+
"hostPortEnv": "MEM0_PORT",
|
|
130
|
+
"defaultHostPort": 8000,
|
|
131
|
+
"healthService": "mem0",
|
|
132
|
+
"logServices": ["mem0"]
|
|
133
|
+
},
|
|
134
|
+
"wizard": { "recallHint": "check the server ({compose} logs mem0)" }
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- `compose.profile` adds `--profile <name>`; `compose.files` adds `-f` flags after `compose.yaml`
|
|
138
|
+
and after `compose.override.yaml` when that exists. Both apply to every compose call: `up`,
|
|
139
|
+
`down`, `build`, `ps`, and the indexer run. Files must be inside the stack root (no absolute
|
|
140
|
+
paths, no `..`). With neither field the command text is exactly what it was before.
|
|
141
|
+
- `compose.services` is documentation only: `up` is scoped by the profile, not by service list.
|
|
142
|
+
- The API base URL comes from `compose.hostPortEnv` and `defaultHostPort`, or from an `apiBase`
|
|
143
|
+
hook. `ctx.apiUrl` (`--api-url`) wins over both.
|
|
144
|
+
- `wizard.recallHint` is the error hint when the smoke recall fails. `{compose}` expands to the
|
|
145
|
+
full compose command prefix and `{project}` to the project name. Without it the generic
|
|
146
|
+
message uses `compose.logServices` or `compose.healthService`.
|
|
147
|
+
- A provider with no model backend sets none of `MEMORY_BACKEND`, `MEMORY_MODEL`, ...; generic
|
|
148
|
+
validation does not require them.
|
|
149
|
+
|
|
150
|
+
## Delegated commands (asdf-style)
|
|
151
|
+
|
|
152
|
+
A manifest may declare commands the provider owns outright:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
"wizardHooks": {
|
|
156
|
+
"module": "wizard.mjs",
|
|
157
|
+
"delegates": {
|
|
158
|
+
"mem0-login": { "description": "Run mem0 CLI login", "run": ["mem0", "login"] }
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`./pm mem0-login` runs `run` with inherited stdio when that provider is active. Prefer delegates
|
|
164
|
+
over reimplementing provider CLIs in Node.
|
|
165
|
+
|
|
166
|
+
## Hindsight
|
|
167
|
+
|
|
168
|
+
Everything about LiteLLM routes, lemond, Ollama, custom OpenAI-compatible backends and the Clack
|
|
169
|
+
model prompts lives in `providers/hindsight/`:
|
|
170
|
+
|
|
171
|
+
| File | Role |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `wizard.mjs` | Thin hook exports; re-exports `prepareStackEnv`, `migrateEnv`, `setupNotices` |
|
|
174
|
+
| `lib/state.mjs` | `ensureState`, backend defaults, `wizard.conf` reads |
|
|
175
|
+
| `lib/model-backend.mjs` | Backend choice (lemond / ollama / custom), reflect model, model pulls |
|
|
176
|
+
| `lib/litellm-routes.mjs` | Write the LiteLLM route file and `hindsight.env`; saves `wizard.conf` |
|
|
177
|
+
| `lib/probe.mjs` | Probe lemond/ollama endpoints and list models |
|
|
178
|
+
| `lib/config.mjs` | `defaultsFromConfig`, `applyConfigEnv`, `configToml` (`[stack]` ports, `[model]`) |
|
|
179
|
+
| `lib/ports.mjs` | `resolvePorts` for the API and control-plane ports |
|
|
180
|
+
| `lib/env-setup.mjs` | `stackEnv`, `setupEnv` (secrets, LiteLLM env) |
|
|
181
|
+
| `lib/stack-env.mjs` | `prepareStackEnv`, `migrateEnv`, `setupNotices` for `scripts/setup.mjs` |
|
|
182
|
+
| `lib/validate.mjs` | Hindsight validation (model backend, route file, ports) |
|
|
183
|
+
| `lib/summary.mjs` | Closing summary lines |
|
|
184
|
+
| `lib/coding-agent.mjs` | seed/materialize `~/.hindsight/coding-agent.json` (real file) and opt-in paths check |
|
|
185
|
+
| `lib/clack.mjs` | `clackSetup`: backend and model prompts for the Clack front end |
|
|
186
|
+
|
|
187
|
+
Its `wizard.conf` keeps `MEMORY_PROVIDER`, `MEMORY_BACKEND`, `MEMORY_MODEL`, `MEMORY_API_BASE` and
|
|
188
|
+
`MEMORY_REFLECT_MODEL`. The manifest sets `compose.profile: "hindsight"`, so a
|
|
189
|
+
non-Hindsight provider never starts its services.
|
|
190
|
+
|
|
191
|
+
`configureModelRouting` takes `ctx.skipBackendStep` (`WIZARD_SKIP_BACKEND_STEP=1`) to skip the
|
|
192
|
+
prompts when Clack has already collected the answers.
|
|
193
|
+
|
|
194
|
+
## Loader
|
|
195
|
+
|
|
196
|
+
`wizard/lib/provider-wizard/run-steps.mjs`:
|
|
197
|
+
|
|
198
|
+
- `loadProviderWizard(manifest)`: import `providers/<id>/wizard.mjs`, cached per file; `{}` when absent
|
|
199
|
+
- `callProviderHook(ctx, phase, helpers)`: returns `{ ran, value }`; announces the announced phases
|
|
200
|
+
- `runProviderPhase(ctx, phase, helpers)`: the same, returning whether the hook ran
|
|
201
|
+
- `runDelegatedCommand`, `listDelegateCommands`: manifest `delegates`
|
|
202
|
+
|
|
203
|
+
## Tests
|
|
204
|
+
|
|
205
|
+
- `scripts/tests/test_provider_wizard_hooks.mjs`: helpers `apiVersion`, frozen helpers, hook loader,
|
|
206
|
+
stubbed-helpers tests of the Hindsight `configureModelRouting` (`--yes`, `skipBackendStep`, the
|
|
207
|
+
three backends), static checks (no provider imports `run-wizard.mjs`; no provider names in the
|
|
208
|
+
meta files)
|
|
209
|
+
- `scripts/tests/test_provider_manifests.mjs`: manifest schema incl. `compose.profile`/`files`
|
|
210
|
+
- `scripts/tests/test_wizard.sh`: dry-run and real-run scenarios with a docker stub, including a
|
|
211
|
+
provider with no hooks, a provider with every v2 hook (fixtures in
|
|
212
|
+
`scripts/tests/fixtures/providers/`, selected with `PM_PROVIDERS_DIR`), and a package-root /
|
|
213
|
+
stack-root split
|
|
214
|
+
|
|
215
|
+
## Adding hooks (checklist)
|
|
216
|
+
|
|
217
|
+
1. Add `wizardHooks.module` (and `compose.*`) to `manifest.json`
|
|
218
|
+
2. Create `providers/<id>/wizard.mjs`; implement only the phases you need
|
|
219
|
+
3. Keep provider state on `ctx` through `init`/`hydrate`; return `configToml`/`summary` data instead of writing in the meta files
|
|
220
|
+
4. Add `delegates` only when a native CLI must run on the host
|
|
221
|
+
5. Document native vs meta ownership in manifest `settings`
|
|
222
|
+
6. Extend the tests and the [add-memory-provider](../.agents/skills/add-memory-provider/SKILL.md) skill
|