open-memex 0.1.0 → 0.3.0-alpha
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/AGENTS.md +62 -10
- package/CONTRIBUTING.md +31 -0
- package/README.md +250 -38
- package/README.zh-CN.md +307 -0
- package/bin/open-memex.js +28 -0
- package/docs/SCOPES.md +81 -0
- package/docs/V2-DESIGN.md +588 -0
- package/package.json +12 -3
- package/scripts/smoke-mcp.ts +135 -0
- package/scripts/smoke-pure.ts +250 -9
- package/src/capture/keywords.ts +28 -15
- package/src/cli.ts +347 -26
- package/src/config.ts +91 -13
- package/src/doctor.ts +161 -0
- package/src/index.ts +34 -13
- package/src/init.ts +304 -0
- package/src/mcp.ts +133 -0
- package/src/redact.ts +255 -4
- package/src/retrieve/cjk.ts +63 -0
- package/src/retrieve/inject.ts +2 -2
- package/src/retrieve/search.ts +115 -28
- package/src/scope.ts +7 -2
- package/src/store/db.ts +62 -14
- package/src/store/lifecycle.ts +280 -0
- package/src/store/markdown.ts +163 -11
- package/src/store/sync.ts +53 -9
- package/src/store/v2migrate.ts +190 -0
- package/src/tools/memory.ts +32 -146
- package/src/tools/ops.ts +259 -0
- package/PLAN.md +0 -168
package/AGENTS.md
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
Local-first memory plugin for opencode. See `README.md` and `
|
|
3
|
+
Local-first memory plugin for opencode. See `README.md` (English) and `README.zh-CN.md` (Chinese)
|
|
4
|
+
for user-facing docs; `docs/V2-DESIGN.md` §18 for the roadmap. This file lists only the non-obvious things an agent needs to work in this repo.
|
|
4
5
|
|
|
5
6
|
## Runtime model — read before touching anything
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Three entry points execute the same TypeScript source, with **no build step**:
|
|
8
9
|
|
|
9
10
|
- **opencode host** loads `src/index.ts` under embedded **Bun**. SQLite here is `bun:sqlite` (built-in).
|
|
10
|
-
- **CLI** (`src/cli.ts`) and smoke
|
|
11
|
+
- **CLI** (`src/cli.ts`) and smoke tests run under **Node 22+** with `--experimental-strip-types`. SQLite here is `better-sqlite3` (native module).
|
|
12
|
+
- **MCP server** (`src/mcp.ts`, stdio) runs under **Node 22+** with `--experimental-strip-types`. It exposes the same five memory tools to any MCP client (VS Code Copilot, Cursor, Claude Code). **stdout is the protocol channel — never log to stdout in `mcp.ts`; diagnostics go to stderr.**
|
|
11
13
|
|
|
12
14
|
`src/store/db.ts` picks the backend at runtime by sniffing `globalThis.Bun`. Both backends share the same surface (`new Database(path)`, `.exec`, `.prepare().run/all/get`, `.close`). Any DB code you write must stay on that common subset — do not import `better-sqlite3` or `bun:sqlite` directly outside `db.ts`.
|
|
13
15
|
|
|
16
|
+
Tool logic is host-agnostic and lives in `src/tools/ops.ts` (plain functions + shared zod arg shapes + `TOOL_DESCRIPTIONS`). `src/tools/memory.ts` (opencode) and `src/mcp.ts` are thin adapters — when adding or changing a tool, change `ops.ts` once and both hosts pick it up.
|
|
17
|
+
|
|
14
18
|
Consequences:
|
|
15
19
|
- Imports **must** use explicit `.ts` extensions (`allowImportingTsExtensions: true`, `moduleResolution: "Bundler"`).
|
|
16
20
|
- No transpile / bundle output. Do not add one; opencode loads the `.ts` file directly.
|
|
@@ -22,9 +26,25 @@ Consequences:
|
|
|
22
26
|
npm install # once
|
|
23
27
|
npm run typecheck # tsc --noEmit — the only lint/type gate
|
|
24
28
|
npm run cli -- where | list | search "q" | add ... | forget <id> | reindex
|
|
29
|
+
npm run mcp # start the stdio MCP server
|
|
25
30
|
node --experimental-strip-types scripts\smoke-pure.ts # runs pure-logic checks (no sqlite)
|
|
31
|
+
node --experimental-strip-types scripts\smoke-mcp.ts # MCP handshake + tool round-trip (temp dirs, no real data)
|
|
26
32
|
```
|
|
27
33
|
|
|
34
|
+
After `npm i -g open-memex@alpha` (or `npm link` from source), the `open-memex` bin is on
|
|
35
|
+
PATH: `open-memex mcp` starts the MCP server, `open-memex mcp --print-config <client>`
|
|
36
|
+
prints a client config snippet (client: vscode|cursor|claude|opencode|visualstudio),
|
|
37
|
+
`open-memex init [--client vscode|cursor|opencode|visualstudio] [--force] [--yes]`
|
|
38
|
+
one-command project setup (editor MCP config + .github/copilot-instructions.md;
|
|
39
|
+
resolves the server command at init time — npx fallback when no durable bin is on PATH, D17),
|
|
40
|
+
`open-memex config` prints the effective config, `open-memex capture --dry-run "text"`
|
|
41
|
+
previews keyword capture without writing, `open-memex doctor` runs health checks
|
|
42
|
+
(node version, config, scope resolution, storage writability, MCP handshake).
|
|
43
|
+
`open-memex init` asks editor + two settings on a TTY (`--yes` skips, scripts never
|
|
44
|
+
prompt); `open-memex config set <key> <value>` edits settings after install.
|
|
45
|
+
The bin is a tiny JS launcher (`bin/open-memex.js`) that
|
|
46
|
+
re-execs `src/cli.ts` with type-stripping — no build step, works on Node 22.6+.
|
|
47
|
+
|
|
28
48
|
There is **no `npm test`** and no CI. Verification loop is: `npm run typecheck` + `smoke-pure.ts` + (if touching sqlite) `npm run cli -- reindex` against a scratch `MY_O_MEMORY_HOME`.
|
|
29
49
|
|
|
30
50
|
To load the plugin in opencode locally, `~/.config/opencode/opencode.jsonc` must have:
|
|
@@ -46,28 +66,60 @@ Layout: `memories/<scope_key>/<id>.md` (YAML frontmatter + body) + `index.db` (S
|
|
|
46
66
|
|
|
47
67
|
## Scope keys
|
|
48
68
|
|
|
49
|
-
- `
|
|
69
|
+
- `personal` scope key is literal `"personal"` (v1 called this `user`; renamed in v2, design §19).
|
|
50
70
|
- `project` scope key: `project__<sanitized-name>__<12-hex-sha256>`, seeded from normalized git origin URL, else lowercased cwd. See `src/scope.ts`. Same repo across machines → same key (intentional; enables future git-commit of memories).
|
|
71
|
+
- `org`, `team`, `public` are reserved — the schema rejects writes. See `docs/SCOPES.md`.
|
|
51
72
|
- The scope key **changes** when a repo gains/loses a git origin. `src/index.ts` logs a one-shot warning on load if it finds files under the legacy cwd-only key (`resolveCwdScope`). Use `cli scopes` to enumerate all scope dirs and `cli migrate --from <old>` to reconcile — see `src/store/migrate.ts`. No auto-migration; two unrelated repos at the same cwd would silently merge.
|
|
52
73
|
- Read-only callers must use `memoriesDirPath` (in `src/paths.ts`), never `memoriesDirFor`. The latter `mkdir -p`s the directory as a side effect and will pollute storage with empty scope dirs.
|
|
53
74
|
|
|
54
75
|
## Capture / write path invariants
|
|
55
76
|
|
|
56
77
|
Every write path (tool, keyword hook, CLI `add`) must:
|
|
57
|
-
1. Call `redact(content, cfg.redactPatterns)`.
|
|
58
|
-
2. If `hadSecret` →
|
|
59
|
-
3. `
|
|
78
|
+
1. Call `redact(content, cfg.redactPatterns)`. Built-in provider patterns live in `src/redact.ts` (always on); config `redactPatterns` is for user extras only.
|
|
79
|
+
2. If `hadSecret` → the matched secret is **masked in place** (first 4 characters kept, the rest replaced with `x`) and the write proceeds; never save the unmasked original. `<private>…</private>` spans are stripped to `[REDACTED]` instead (design D14).
|
|
80
|
+
3. Check `findDuplicates` (design §3.4): identical content is idempotent (return existing id); near-duplicates (similarity ≥ 0.8) warn but save — suggest `supersede` when the new content replaces the old.
|
|
81
|
+
4. `writeMemoryFile` first, then `readMemoryFile` + `upsertFromFile` to keep FTS in sync.
|
|
82
|
+
|
|
83
|
+
## Lifecycle invariants (design §3.3)
|
|
84
|
+
|
|
85
|
+
- Statuses: `active → superseded | deprecated | retracted | archived`. Retrieval excludes `retracted`/`archived`, ranks `active` above `deprecated`.
|
|
86
|
+
- Never hand-write `status: superseded` or half a chain. Use the `supersede` code path (`src/store/lifecycle.ts`): the old record keeps its file, flips to `superseded`, and both sides get `supersedes`/`superseded_by`. Only `active` memories can be superseded.
|
|
87
|
+
- Chain integrity is self-healing: on read, a missing counterpart is auto-completed with a warning; a dangling pointer warns but is never fabricated. Don't "fix" chains by editing frontmatter directly — let the read path do it.
|
|
88
|
+
- Frontmatter is `schema_version: 2`. The SQLite index schema is versioned separately and rebuilds automatically on version change — never hand-edit `index.db`.
|
|
60
89
|
|
|
61
|
-
Keyword capture fires from `chat.message` on the
|
|
90
|
+
Keyword capture fires from `chat.message` on the user's message parts (`UserMessage`). Patterns live in `src/capture/keywords.ts` / config `keywordPatterns`; regex group 1 is the memory body. Scope routing: personal patterns (`cfg.keywordPersonalPatterns`) force the personal scope — the rule is 我 → personal (记住我/替我记/我觉得/我喜欢/remember for me), 我们 → current scope (我们认为/我们决定/帮我们记住); personal patterns run first and claim their line so a generic trigger can't double-fire.
|
|
62
91
|
|
|
63
92
|
Context injection happens exactly once per session in `experimental.chat.system.transform`, guarded by an in-memory `Set<sessionID>` in `src/index.ts`. It is not persisted — restarting opencode re-injects on the next first turn.
|
|
64
93
|
|
|
65
|
-
## Design constraints
|
|
94
|
+
## Design constraints — read the frozen design first
|
|
95
|
+
|
|
96
|
+
`docs/V2-DESIGN.md` is the frozen protocol v0.2 (zero open questions). Per its §12:
|
|
97
|
+
AGENTS.md answers "how should AI work here"; the design doc answers "why is it
|
|
98
|
+
built this way" (principles, iron rules, D1–D13 decision log). Before changing
|
|
99
|
+
architecture, scope semantics, lifecycle, or the protocol surface (frontmatter
|
|
100
|
+
schema, MCP tools, CLI contract), read the relevant design section — the decision
|
|
101
|
+
log records what was already considered and rejected.
|
|
102
|
+
|
|
103
|
+
Still hard: no cloud, no silent sync (explicit pull only), Markdown is the source
|
|
104
|
+
of truth, `personal` scope never leaves the machine. Embeddings are an *optional
|
|
105
|
+
capability* per the design — do not add them (or LLM-driven extraction, or a
|
|
106
|
+
knowledge graph) without updating the design doc first. `docs/V2-DESIGN.md` §18 tracks the
|
|
107
|
+
build roadmap; the design doc tracks the *why*.
|
|
108
|
+
|
|
109
|
+
## Branch workflow
|
|
66
110
|
|
|
67
|
-
|
|
111
|
+
`main` (stable, mirrors npm) ← `V2` (v2 integration) ← `V2-dev-p<n>`
|
|
112
|
+
(phase work; draft PRs into `V2`). Never create `V2/<anything>` — git can't
|
|
113
|
+
hold `V2` and `V2/…` simultaneously. Full rules: `CONTRIBUTING.md`.
|
|
68
114
|
|
|
69
115
|
## Style notes
|
|
70
116
|
|
|
71
117
|
- `strict: true`, `verbatimModuleSyntax: false`. Prefer `import type` for types anyway.
|
|
72
118
|
- Log prefix is `[open-memex]`. Gate verbose logs behind `cfg.logLevel === "debug"`.
|
|
73
119
|
- Windows is a first-class target (this workspace is Windows). Use `node:path` and never hardcode `/`.
|
|
120
|
+
- **Docs ship with code.** Every code change updates the docs it affects in the same commit:
|
|
121
|
+
new/changed tools → `README.md` + `README.zh-CN.md` tool tables + MCP section (keep both
|
|
122
|
+
languages in sync); behavior changes → both READMEs
|
|
123
|
+
and the frozen `docs/V2-DESIGN.md` (append a `D<n>` decision entry, never rewrite history);
|
|
124
|
+
new commands → README CLI sections + this file's Commands. A change without its docs
|
|
125
|
+
is not done.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Contributing to open-memex
|
|
2
|
+
|
|
3
|
+
## Branch workflow
|
|
4
|
+
|
|
5
|
+
- `main` — stable. Mirrors the npm release line. Never commit directly;
|
|
6
|
+
only merge from `V2` when a milestone is tested and ready to release.
|
|
7
|
+
- `V2` — integration branch for the v2 line. Phase work lands here via
|
|
8
|
+
pull request. Merges to `main` only after the milestone is dogfooded
|
|
9
|
+
(plugin tested in opencode, `migrate --to-v2 --dry-run` clean on real data).
|
|
10
|
+
- `V2-dev-p<n>` — phase dev branches (e.g. `V2-dev-p1`). Open as **draft**
|
|
11
|
+
PRs against `V2`; mark ready and merge after local testing passes.
|
|
12
|
+
|
|
13
|
+
**Naming rule:** never create `V2/<anything>` — git cannot hold a branch
|
|
14
|
+
named `V2` and a branch named `V2/…` at the same time (ref file vs.
|
|
15
|
+
directory conflict). Use the flat `V2-dev-*` form instead.
|
|
16
|
+
|
|
17
|
+
## Before opening a PR
|
|
18
|
+
|
|
19
|
+
- `npm run typecheck` is clean
|
|
20
|
+
- `node --experimental-strip-types scripts/smoke-pure.ts` passes
|
|
21
|
+
- If you touched SQLite/FTS: `open-memex reindex` works against a scratch
|
|
22
|
+
`MY_O_MEMORY_HOME`
|
|
23
|
+
- No secrets in fixtures (redaction tests are the exception)
|
|
24
|
+
|
|
25
|
+
## Design authority
|
|
26
|
+
|
|
27
|
+
Protocol decisions live in `docs/V2-DESIGN.md` (frozen v0.2, decision log
|
|
28
|
+
D1–D13). Changing architecture, scope semantics, lifecycle, or the protocol
|
|
29
|
+
surface (frontmatter schema, MCP tools, CLI contract) requires updating the
|
|
30
|
+
design doc first. `AGENTS.md` has the working notes for AI agents; this file
|
|
31
|
+
has the contributor workflow.
|
package/README.md
CHANGED
|
@@ -1,53 +1,183 @@
|
|
|
1
1
|
# open-memex
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[中文文档](./README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Local-first persistent memory for AI coding agents: an [opencode](https://opencode.ai) plugin
|
|
6
|
+
plus a generic MCP server (VS Code Copilot, Cursor, Claude Code, Visual Studio, …).
|
|
4
7
|
|
|
5
8
|
- **Markdown files** as the source of truth (human-editable, git-friendly)
|
|
6
9
|
- **SQLite FTS5** as a rebuildable index (BM25 keyword search, via `better-sqlite3`)
|
|
7
10
|
- **Zero cloud**, zero account, zero third-party API
|
|
8
|
-
- Loads directly under opencode's embedded Bun runtime; CLI
|
|
11
|
+
- Loads directly under opencode's embedded Bun runtime; CLI and MCP server run under Node — no build step, no Bun install
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### Requirements
|
|
16
|
+
|
|
17
|
+
- **Node.js ≥ 22.6** (`open-memex doctor` verifies this for you)
|
|
18
|
+
|
|
19
|
+
### Step 1 — Install the CLI
|
|
20
|
+
|
|
21
|
+
**npm (recommended):**
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm install -g open-memex@alpha
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This installs the `0.3.0-alpha` prerelease channel. (`latest` still points at the older
|
|
28
|
+
`0.1.0` stable.)
|
|
9
29
|
|
|
10
|
-
|
|
30
|
+
**No install — run via npx:**
|
|
11
31
|
|
|
32
|
+
```sh
|
|
33
|
+
npx -y open-memex@alpha <command> # e.g. npx -y open-memex@alpha init --client vscode
|
|
12
34
|
```
|
|
13
|
-
|
|
35
|
+
|
|
36
|
+
**From source** (bleeding edge, `V2-dev-p2` branch):
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
git clone -b V2-dev-p2 https://github.com/stoneskin/open-memex.git
|
|
40
|
+
cd open-memex
|
|
14
41
|
npm install
|
|
42
|
+
node --experimental-strip-types src/cli.ts <command>
|
|
15
43
|
```
|
|
16
44
|
|
|
17
|
-
|
|
45
|
+
> The `0.3.0-alpha` npm publish is cut from this branch — if `npx` still resolves an
|
|
46
|
+
> older alpha, install from source until the publish lands.
|
|
18
47
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
48
|
+
#### "`open-memex` is not recognized" — PATH setup
|
|
49
|
+
|
|
50
|
+
A global `npm install -g` puts the `open-memex` launcher in npm's global bin folder.
|
|
51
|
+
If your terminal can't find it, that folder isn't on your `PATH`:
|
|
52
|
+
|
|
53
|
+
1. Find the folder: `npm config get prefix`
|
|
54
|
+
- **Windows:** the launcher (`open-memex.cmd`) sits directly in that folder, e.g.
|
|
55
|
+
`C:\Users\<you>\AppData\Roaming\npm`
|
|
56
|
+
- **macOS / Linux:** it's in `<prefix>/bin`, e.g. `/usr/local/bin` or
|
|
57
|
+
`~/.nvm/versions/node/v22.x.x/bin`
|
|
58
|
+
2. Add it to `PATH`:
|
|
59
|
+
- **Windows:** Settings → System → About → Advanced system settings →
|
|
60
|
+
Environment Variables → add the folder to the *User* `Path` → **restart the
|
|
61
|
+
terminal**. Verify with `where open-memex`.
|
|
62
|
+
- **macOS / Linux:** add `export PATH="$(npm prefix -g)/bin:$PATH"` to
|
|
63
|
+
`~/.zshrc` (or `~/.bashrc`), restart the shell, verify with
|
|
64
|
+
`command -v open-memex`.
|
|
65
|
+
3. No admin rights / don't want to touch `PATH`? Use the npx form above — npx
|
|
66
|
+
resolves the package itself and needs no `PATH` changes.
|
|
67
|
+
|
|
68
|
+
### Step 2 — One-command setup for your editor
|
|
69
|
+
|
|
70
|
+
Run from your **project root** (so the project scope resolves to this repo):
|
|
71
|
+
|
|
72
|
+
**VS Code** (Copilot):
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
open-memex init --client vscode
|
|
76
|
+
# …or without a global install:
|
|
77
|
+
npx -y open-memex@alpha init --client vscode
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Writes `.vscode/mcp.json` and `.github/copilot-instructions.md`, then reload the
|
|
81
|
+
window and confirm the `open-memex` server is started in Copilot Chat's MCP panel.
|
|
82
|
+
|
|
83
|
+
**Cursor:**
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
open-memex init --client cursor
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Writes `.cursor/mcp.json` and `.github/copilot-instructions.md`.
|
|
90
|
+
|
|
91
|
+
**opencode** (as a plain MCP consumer):
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
open-memex init --client opencode
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Writes project-level `opencode.jsonc` (`type: "local"`). Prefer the native plugin
|
|
98
|
+
instead? Add `"plugin": ["file:///absolute/path/to/open-memex/src/index.ts"]` to
|
|
99
|
+
`~/.config/opencode/opencode.jsonc` — you get keyword auto-capture and first-turn
|
|
100
|
+
context injection on top of the tools.
|
|
101
|
+
|
|
102
|
+
**Claude Code** (from your project root):
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
claude mcp add open-memex -- open-memex mcp
|
|
106
|
+
# …or print the config snippet: open-memex mcp --print-config claude
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Visual Studio** (from your solution directory):
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
open-memex init --client visualstudio
|
|
24
113
|
```
|
|
25
114
|
|
|
26
|
-
|
|
115
|
+
Writes solution-level `.mcp.json` and `.github/copilot-instructions.md`. Requires
|
|
116
|
+
Visual Studio 2022 17.14+ or Visual Studio 2026 (**Windows-only**). Visual Studio
|
|
117
|
+
also auto-discovers `.vscode/mcp.json` and `.cursor/mcp.json`, so the VS Code setup
|
|
118
|
+
above works too.
|
|
119
|
+
|
|
120
|
+
**Codex:** no `init` client yet — add the server manually via
|
|
121
|
+
`open-memex mcp --print-config` as a starting point (`[mcp_servers]` in
|
|
122
|
+
`config.toml`, or `codex mcp add`).
|
|
123
|
+
|
|
124
|
+
`init` notes:
|
|
27
125
|
|
|
28
|
-
|
|
126
|
+
- On a terminal it interactively asks which editor to set up, whether to enable
|
|
127
|
+
keyword auto-capture, and whether to inject memories on the first turn.
|
|
128
|
+
`--yes` accepts the defaults; scripts / non-TTY never prompt (editor defaults to
|
|
129
|
+
VS Code).
|
|
130
|
+
- Existing config files are **merged, never clobbered** — re-running is safe.
|
|
131
|
+
`--force` overwrites.
|
|
132
|
+
- With no durable `open-memex` on `PATH` (e.g. one-shot npx), `init` writes an
|
|
133
|
+
`npx -y open-memex@alpha mcp` server command into the config so the setup keeps
|
|
134
|
+
working. `npm i -g open-memex@alpha` + `open-memex init --force` switches to the
|
|
135
|
+
faster direct command later.
|
|
136
|
+
|
|
137
|
+
### Step 3 — Verify it works
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
open-memex doctor
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Checks: Node version, config source, scope resolution for the current directory,
|
|
144
|
+
storage writability, then boots a real MCP server and runs `initialize` +
|
|
145
|
+
`tools/list` against it — all five tools must show up.
|
|
146
|
+
|
|
147
|
+
## Tools the agent gets
|
|
29
148
|
|
|
30
149
|
| Tool | What it does |
|
|
31
150
|
|---|---|
|
|
32
|
-
| `memory_add`
|
|
33
|
-
| `memory_search`
|
|
34
|
-
| `memory_list`
|
|
35
|
-
| `
|
|
151
|
+
| `memory_add` | Save a fact, preference, decision, note |
|
|
152
|
+
| `memory_search` | Keyword search (BM25) across project + personal memories |
|
|
153
|
+
| `memory_list` | List memories in a scope, newest first |
|
|
154
|
+
| `memory_supersede` | Replace a memory with a newer version (keeps a supersede chain) |
|
|
155
|
+
| `memory_forget` | Delete a memory by id |
|
|
36
156
|
|
|
37
157
|
## Capture
|
|
38
158
|
|
|
39
|
-
- **Keyword triggers** in user messages
|
|
159
|
+
- **Keyword triggers** in user messages (opencode native plugin): `remember …`,
|
|
160
|
+
`note that …`, `don't forget …`, `TIL …`, `save this …`, plus Chinese
|
|
161
|
+
`记住…` / `记一下` / `记录一下` / `别忘了…`.
|
|
162
|
+
Scope routing: first-person singular goes **personal** (`remember for me`,
|
|
163
|
+
`记住我…`, `替我记…`, `我觉得…`, `我喜欢…`); first-person plural goes to the
|
|
164
|
+
current **project** scope (`我们认为…`, `我们决定…`, `帮我们记住…`).
|
|
40
165
|
- **Explicit tool calls** by the agent (via `memory_add`)
|
|
41
|
-
- **Redaction**: content inside `<private
|
|
166
|
+
- **Redaction**: content inside `<private>…</private>` tags is stripped; detected
|
|
167
|
+
secrets (API keys, tokens, high-entropy credentials) are masked in place — first
|
|
168
|
+
4 characters kept, the rest replaced with `x` — and the memory is saved.
|
|
169
|
+
Preview what a message would capture with `open-memex capture --dry-run "…"`.
|
|
42
170
|
|
|
43
171
|
## Scopes
|
|
44
172
|
|
|
45
173
|
- **project** — scoped to the current repo (keyed off the git origin URL hash, or the cwd if no remote). Default for new memories.
|
|
46
|
-
- **
|
|
174
|
+
- **personal** — global across all your projects, this machine only, never synced. Use for personal preferences. (v1 called this `user`; `migrate --to-v2` renames it.)
|
|
175
|
+
|
|
176
|
+
See [docs/SCOPES.md](./docs/SCOPES.md) for the full scope model: key derivation, migration, visibility, reserved names.
|
|
47
177
|
|
|
48
178
|
## Retrieval
|
|
49
179
|
|
|
50
|
-
On the first turn of every session, `open-memex` injects a `[OPEN-MEMEX]` block into the system prompt containing top-N recent project memories + top-N
|
|
180
|
+
On the first turn of every session, `open-memex` injects a `[OPEN-MEMEX]` block into the system prompt containing top-N recent project memories + top-N personal preferences. The agent can also call `memory_search` on demand.
|
|
51
181
|
|
|
52
182
|
## Storage layout
|
|
53
183
|
|
|
@@ -56,40 +186,122 @@ On the first turn of every session, `open-memex` injects a `[OPEN-MEMEX]` block
|
|
|
56
186
|
$XDG_DATA_HOME/open-memex/ (Linux/macOS)
|
|
57
187
|
├── index.db # SQLite FTS5 index (rebuildable)
|
|
58
188
|
└── memories/
|
|
59
|
-
├──
|
|
189
|
+
├── personal/
|
|
60
190
|
│ └── <id>.md
|
|
61
191
|
└── project__<name>__<hash12>/
|
|
62
192
|
└── <id>.md
|
|
63
193
|
```
|
|
64
194
|
|
|
65
|
-
Each `.md` file has YAML frontmatter (`id, scope_key,
|
|
195
|
+
Each `.md` file has v2 YAML frontmatter (`id, scope, scope_key, visibility, role, type,
|
|
196
|
+
importance, status, tags, created_at, updated_at, schema_version`, …) followed by the
|
|
197
|
+
memory content. You can edit them by hand — the plugin re-syncs on startup by comparing
|
|
198
|
+
file mtimes. Markdown is the source of truth; the SQLite index is derived and rebuildable
|
|
199
|
+
(`open-memex reindex`).
|
|
66
200
|
|
|
67
201
|
## Config
|
|
68
202
|
|
|
69
|
-
Optional file at `~/.config/opencode/open-memex.jsonc
|
|
203
|
+
Optional file at `~/.config/opencode/open-memex.jsonc` (override path with
|
|
204
|
+
`MY_O_MEMORY_CONFIG`; override storage root with `MY_O_MEMORY_HOME`).
|
|
205
|
+
|
|
206
|
+
Defaults:
|
|
207
|
+
|
|
208
|
+
```jsonc
|
|
209
|
+
{
|
|
210
|
+
"maxProjectMemories": 8, // top-N project memories injected on first turn
|
|
211
|
+
"maxProfileItems": 5, // top-N personal items injected on first turn
|
|
212
|
+
"injectOnFirstTurn": true, // [OPEN-MEMEX] system-prompt block
|
|
213
|
+
"keywordCaptureEnabled": true,
|
|
214
|
+
"logLevel": "info" // info | debug
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`open-memex config` prints the effective config (defaults + file).
|
|
219
|
+
Change a setting after install:
|
|
220
|
+
|
|
221
|
+
```sh
|
|
222
|
+
open-memex config set keywordCaptureEnabled false
|
|
223
|
+
open-memex config set maxProjectMemories 12
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Settable keys: `maxProjectMemories`, `maxProfileItems`, `injectOnFirstTurn`,
|
|
227
|
+
`keywordCaptureEnabled`, `logLevel`. Full design: [docs/V2-DESIGN.md](./docs/V2-DESIGN.md).
|
|
70
228
|
|
|
71
|
-
## CLI
|
|
229
|
+
## CLI reference
|
|
72
230
|
|
|
73
|
-
|
|
231
|
+
Setup & health:
|
|
74
232
|
|
|
233
|
+
```sh
|
|
234
|
+
open-memex init [--client vscode|cursor|opencode|visualstudio] [--force] [--yes]
|
|
235
|
+
open-memex config # print effective config
|
|
236
|
+
open-memex config set <key> <value> # change a setting
|
|
237
|
+
open-memex doctor # environment health check
|
|
238
|
+
open-memex capture --dry-run "记住我喜欢简洁的回答" # preview keyword capture
|
|
239
|
+
open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
|
|
75
240
|
```
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
241
|
+
|
|
242
|
+
Memory operations:
|
|
243
|
+
|
|
244
|
+
```sh
|
|
245
|
+
open-memex add "This repo uses better-sqlite3" --type project-config
|
|
246
|
+
open-memex search "auth flow"
|
|
247
|
+
open-memex list --scope project
|
|
248
|
+
open-memex supersede <id> "Updated content"
|
|
249
|
+
open-memex status <id> deprecated
|
|
250
|
+
open-memex forget <id>
|
|
84
251
|
```
|
|
85
252
|
|
|
86
|
-
|
|
87
|
-
|
|
253
|
+
Maintenance:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
open-memex where # show storage + config paths
|
|
257
|
+
open-memex scopes # list project scopes with memory counts
|
|
258
|
+
open-memex reindex # rebuild the SQLite index from markdown
|
|
259
|
+
open-memex migrate --to-v2 [--dry-run] # v1 data → v2
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The CLI runs under Node 22 with the built-in experimental TypeScript loader (no build
|
|
263
|
+
step). From a source checkout, prefix every command with
|
|
264
|
+
`node --experimental-strip-types src/cli.ts` (or `npm run cli -- <command>` for
|
|
265
|
+
simple cases — npm swallows unknown `--flag` args, so prefer direct `node`).
|
|
266
|
+
|
|
267
|
+
## MCP server
|
|
268
|
+
|
|
269
|
+
The same five memory tools over the Model Context Protocol via a stdio server —
|
|
270
|
+
no host-specific plugin needed. Any MCP client can use open-memex.
|
|
271
|
+
|
|
272
|
+
```sh
|
|
273
|
+
open-memex mcp # after a global install
|
|
274
|
+
npx -y open-memex@alpha mcp # no install needed
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
The project scope is resolved from the process working directory, so configure the
|
|
278
|
+
server with cwd set to your project root (`init` handles this for you).
|
|
279
|
+
|
|
280
|
+
> **Note:** MCP is request/response — it gives the agent tools, not the opencode
|
|
281
|
+
> plugin's automatic keyword capture or first-turn context injection. Proactive
|
|
282
|
+
> memory use depends on the agent's instructions (the `.github/copilot-instructions.md`
|
|
283
|
+
> that `init` writes).
|
|
284
|
+
|
|
285
|
+
## Roadmap
|
|
286
|
+
|
|
287
|
+
**`0.3.0-alpha` (this release):** generic MCP server, `open-memex` bin/CLI, one-command
|
|
288
|
+
`init` setup, Chinese keyword capture with personal/project routing, `config` /
|
|
289
|
+
`capture --dry-run` / `doctor` helpers, Visual Studio support.
|
|
290
|
+
|
|
291
|
+
**Coming — `0.3.0-beta`:** team sync — shared memory via git (`propose` / `promote` /
|
|
292
|
+
`resolve` workflow, in-repo memory dir), 1–2 colleague pilot.
|
|
293
|
+
|
|
294
|
+
**Coming — `0.3.0` (stable):** org layer — org memory repo, curator convention,
|
|
295
|
+
distill-to-AGENTS.md assist.
|
|
88
296
|
|
|
89
|
-
|
|
297
|
+
**Future (signal-gated, no version committed):** native agent plugins (Claude Code /
|
|
298
|
+
Codex hooks as enhancement paths over the same MCP tools); local embeddings as a
|
|
299
|
+
benchmark-gated experiment (no embedding model is ever downloaded without explicit
|
|
300
|
+
opt-in); cloud `RemoteProvider` customization only if multi-repo sharing, ACL, or
|
|
301
|
+
compliance needs demand it.
|
|
90
302
|
|
|
91
|
-
|
|
303
|
+
Design details: [docs/V2-DESIGN.md](./docs/V2-DESIGN.md) (append-only decision log D1–D20).
|
|
92
304
|
|
|
93
305
|
## License
|
|
94
306
|
|
|
95
|
-
[
|
|
307
|
+
[Apache-2.0](./LICENSE)
|