open-memex 0.4.0-alpha.1 → 0.4.0-alpha.4

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 CHANGED
@@ -29,6 +29,7 @@ Consequences:
29
29
  npm install # once
30
30
  npm run typecheck # tsc --noEmit — the only lint/type gate
31
31
  npm run cli -- where | list | search "q" | add ... | forget <id> | reindex
32
+ npm run cli -- <command> --help # per-command help (AI assistants discover flags this way)
32
33
  npm run cli -- sync-status # last sync time/kind + outbox drafts + repo review states + uncommitted files
33
34
  npm run cli -- submit <id...> [--onto <branch>] [--base <branch>] # drafts → .ai/open-memex/ (local branch+commit)
34
35
  npm run cli -- propose <id...> --to project [--local-approve] # copy personal → project outbox (batch OK)
package/README.md CHANGED
@@ -262,6 +262,7 @@ open-memex doctor # environment health check
262
262
  open-memex capture --dry-run "记住我喜欢简洁的回答" # preview keyword capture
263
263
  open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
264
264
  open-memex --help # this reference
265
+ open-memex <command> --help # help for one command
265
266
  open-memex --version # installed version
266
267
  ```
267
268
 
@@ -282,6 +283,11 @@ Project drafts live in the **appdata outbox** (git-invisible, branch-independent
282
283
  only user-approved drafts move into `<repo>/.ai/open-memex/`, where they follow
283
284
  branches and PRs. Nothing moves without you naming it.
284
285
 
286
+ In an AI chat with the MCP server connected, just say **"sync memory"**
287
+ (or "同步记忆") — the agent runs the status check, summarizes the outbox drafts,
288
+ and asks which ones to sync. The agent also proposes this on its own at session
289
+ start and at work checkpoints.
290
+
285
291
  ```sh
286
292
  open-memex sync-status
287
293
  # show when the index was last synced (and what triggered it), the outbox
@@ -352,8 +358,11 @@ server with cwd set to your project root (`init` handles this for you).
352
358
 
353
359
  > **Note:** MCP is request/response — it gives the agent tools, not the opencode
354
360
  > plugin's automatic keyword capture or first-turn context injection. Proactive
355
- > memory use depends on the agent's instructions (the Copilot instructions
356
- > that `init` writes).
361
+ > memory use depends on the agent's instructions: the server sends session-start
362
+ > guidance (call `memory_status` at session start and at checkpoints) in the MCP
363
+ > handshake `instructions`, and `init` writes the fuller version into the
364
+ > editor's instruction files. Both are advisory — no MCP consumer offers a hard
365
+ > session-start hook.
357
366
 
358
367
  ## Roadmap
359
368
 
package/README.zh-CN.md CHANGED
@@ -260,6 +260,7 @@ open-memex doctor # 环境健康检查
260
260
  open-memex capture --dry-run "记住我喜欢简洁的回答" # 预览关键词捕获
261
261
  open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
262
262
  open-memex --help # 本帮助
263
+ open-memex <command> --help # 单个命令的帮助
263
264
  open-memex --version # 已安装版本
264
265
  ```
265
266
 
@@ -280,6 +281,10 @@ project 草稿先住在 **appdata outbox**(git 看不见、跟分支无关)
280
281
  点名批准的草稿,才会被移入 `<repo>/.ai/open-memex/`,之后随分支和 PR 走。
281
282
  没经过你点名,什么都不会动。
282
283
 
284
+ 在接了 MCP 服务器的 AI 对话里,直接说 **"同步记忆"**(或 "sync memory")——
285
+ agent 会查状态、把 outbox 草稿逐条摘要、问你同步哪几条。agent 也会在新对话
286
+ 开始和任务检查点主动提这件事。
287
+
283
288
  ```sh
284
289
  open-memex sync-status
285
290
  # 看索引上次同步的时间和触发方、outbox(待同步)、repo 里的评审状态
@@ -344,7 +349,10 @@ project scope 从进程工作目录解析,所以配置 server 时 cwd 要指
344
349
 
345
350
  > **注意:** MCP 是请求/响应式的——它给 agent 提供 tools,但没有 opencode
346
351
  > 插件的关键词自动捕获和首轮上下文注入。想让 agent 主动用记忆,
347
- > 靠的是 agent 的 instructions(`init` 写的 Copilot instructions)。
352
+ > 靠的是 agent 的 instructions:服务器在 MCP 握手的 `instructions` 里自带
353
+ > session-start 指引(开场调 `memory_status`、检查点再调),`init` 则把更完整
354
+ > 的版本写进编辑器的 instruction 文件。两者都是建议性的——MCP 客户端没有
355
+ > 强制的 session-start hook。
348
356
 
349
357
  ## 路线图(Roadmap)
350
358
 
package/dist/cli.js CHANGED
@@ -18,6 +18,168 @@ import { resolveMcpCommand } from "./init.js";
18
18
  import fs from "node:fs";
19
19
  import path from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
+ /** Per-command help, printed by `open-memex <command> --help`.
22
+ AI assistants discover the CLI through --help, so every command needs one. */
23
+ const COMMAND_HELP = {
24
+ where: `Show which project scope the current directory resolves to, and where its data lives.
25
+
26
+ Usage: open-memex where`,
27
+ list: `List memories in a scope, newest first.
28
+
29
+ Usage: open-memex list [--scope project|personal] [--type T] [--limit N]
30
+
31
+ Flags:
32
+ --scope project (default) or personal
33
+ --type filter by memory type
34
+ --limit max results
35
+
36
+ Examples:
37
+ open-memex list
38
+ open-memex list --scope personal --limit 20`,
39
+ search: `Search memories by keyword (BM25 full-text), best matches first.
40
+
41
+ Usage: open-memex search "query" [--scope project|personal|both] [--type T] [--limit N]
42
+
43
+ Flags:
44
+ --scope project (default), personal, or both
45
+ --type filter by memory type
46
+ --limit max results
47
+
48
+ Example:
49
+ open-memex search "deploy checklist" --scope both`,
50
+ add: `Save a fact, preference, decision, or note to local memory.
51
+
52
+ Usage: open-memex add "content" [--scope project|personal] [--type T] [--tag t1,t2]
53
+
54
+ Flags:
55
+ --scope project (default) or personal (personal never leaves this machine)
56
+ --type memory type (default: fact)
57
+ --tag comma-separated tags
58
+
59
+ Example:
60
+ open-memex add "We deploy on Fridays" --scope project --tag process`,
61
+ supersede: `Replace a memory with a newer version. The old one is kept as history.
62
+
63
+ Usage: open-memex supersede <id> "new content" [--type T] [--tag t1,t2]`,
64
+ status: `Change a memory's lifecycle status.
65
+
66
+ Usage: open-memex status <id> active|deprecated|retracted|archived`,
67
+ forget: `Delete a memory by id.
68
+
69
+ Usage: open-memex forget <id>`,
70
+ propose: `Copy personal memories into the project outbox as review drafts.
71
+ The personal originals stay put. Nothing enters git at this step.
72
+
73
+ Usage: open-memex propose <id...> --to project [--local-approve]
74
+
75
+ Flags:
76
+ --to project (required)
77
+ --local-approve mark the copies approved right away (solo-dev shortcut)
78
+
79
+ Example:
80
+ open-memex propose 01ABC 01DEF --to project`,
81
+ promote: `Advance a project memory one step up the review ladder
82
+ (proposed → approved → published), or reject it with a note.
83
+ Every transition is appended to the memory's review_history.
84
+ Rejected memories are never deleted — they can be revised and resubmitted.
85
+
86
+ Usage: open-memex promote <id> [--reject] [--resubmit] [--note "..."] [--by NAME]
87
+
88
+ Flags:
89
+ --reject move back to rejected (requires --note)
90
+ --resubmit move a rejected memory back to proposed
91
+ --note reason for the transition (recorded in review_history)
92
+ --by reviewer name (defaults to the git user)
93
+
94
+ Examples:
95
+ open-memex promote 01ABC --note "verified against the runbook"
96
+ open-memex promote 01ABC --reject --note "outdated after the migration"`,
97
+ resolve: `List conflicted memories, or 3-way-merge one.
98
+
99
+ Usage: open-memex resolve [id-or-path]
100
+
101
+ With no argument, lists conflicts. With an id or file path, shows the
102
+ 3-way merge (base / outbox / repo) so you can resolve it by hand.
103
+ Conflicts are never auto-resolved.`,
104
+ "sync-status": `Show the project memory sync pipeline: when the index last synced
105
+ and what triggered it, drafts waiting in the outbox (appdata), memories in the
106
+ repo awaiting review or published, and repo files not yet committed.
107
+
108
+ Usage: open-memex sync-status`,
109
+ submit: `Move outbox drafts into a git branch for review: creates a branch
110
+ (default mem/sync-*), copies the drafts into the repo memory dir as proposed
111
+ (local-approved copies keep their approval), commits locally, and moves the
112
+ outbox originals out. Prints the push and PR commands — those need your
113
+ explicit approval and are never run automatically.
114
+
115
+ Usage: open-memex submit <id...> [--onto <branch>] [--base <branch>]
116
+
117
+ Flags:
118
+ --onto submit onto the current branch instead of creating mem/sync-*
119
+ --base base branch for the PR suggestion (default: the branch you're on)
120
+
121
+ Example:
122
+ open-memex submit 01ABC 01DEF`,
123
+ "pr-status": `Map the current branch's GitHub PR state back onto review_state:
124
+ merged → published, approval → approved (approved_by = the reviewer),
125
+ changes-requested → suggestion only (never auto-rejects).
126
+ Each memory in the PR is mapped independently; a human rejection is never
127
+ overwritten. Report-only by default.
128
+
129
+ Usage: open-memex pr-status [--apply]
130
+
131
+ Flags:
132
+ --apply write the transitions locally (still never pushes)`,
133
+ reindex: `Rebuild the SQLite index from the markdown files.
134
+
135
+ Usage: open-memex reindex`,
136
+ scopes: `List the known scopes (personal + project).
137
+
138
+ Usage: open-memex scopes`,
139
+ migrate: `Move memories between scopes, or convert a legacy my-o-memory data dir.
140
+
141
+ Usage: open-memex migrate [--from <key>] [--to <key>] [--dry-run] [--on-conflict newer|overwrite|skip]
142
+ open-memex migrate --to-v2 [--dry-run]
143
+
144
+ Flags:
145
+ --from / --to scope keys (default: current project → personal)
146
+ --dry-run preview without moving anything
147
+ --on-conflict newer (default), overwrite, or skip
148
+ --to-v2 convert a legacy my-o-memory data dir to the v2 layout
149
+
150
+ Always preview with --dry-run first; nothing moves without confirmation.`,
151
+ mcp: `Start the stdio MCP server (the same server editors connect to).
152
+
153
+ Usage: open-memex mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
154
+
155
+ Flags:
156
+ --print-config print the MCP client config instead of starting the server`,
157
+ init: `One-command project setup: writes the MCP config for your editor and the
158
+ agent memory instructions. Existing files are merged, never clobbered.
159
+
160
+ Usage: open-memex init [--client vscode|cursor|opencode|visualstudio]
161
+ [--instructions personal|project] [--force] [--yes]
162
+
163
+ Flags:
164
+ --client editor to configure (default: auto-detect)
165
+ --instructions personal (default, ~/.copilot/copilot-instructions.md) or project
166
+ --force overwrite existing config
167
+ --yes accept all defaults, never prompt`,
168
+ config: `Show config, or set a key.
169
+
170
+ Usage: open-memex config [set <key> <value>]
171
+
172
+ Example:
173
+ open-memex config set sync.autoPull false`,
174
+ capture: `Preview what the keyword-capture watcher would extract from text.
175
+
176
+ Usage: open-memex capture --dry-run "text"`,
177
+ doctor: `Environment health check: Node version, config source, scope resolution,
178
+ storage writability, then boots a real MCP server and runs initialize +
179
+ tools/list against it — all eleven tools must show up.
180
+
181
+ Usage: open-memex doctor`,
182
+ };
21
183
  function usage(exitCode = 1) {
22
184
  console.log(`open-memex CLI
23
185
 
@@ -72,7 +234,9 @@ the \`--from\` key when migrating.
72
234
  git remote after memories were already stored under the cwd-based key.
73
235
  \`migrate --to-v2\` converts v1 memory files to the v2 format (§19):
74
236
  user→personal scope rename, epoch→RFC 3339 times, priority→importance,
75
- type: instruction→role split. Always preview with --dry-run first.`);
237
+ type: instruction→role split. Always preview with --dry-run first.
238
+
239
+ Run \`open-memex <command> --help\` for details on a single command.`);
76
240
  process.exit(exitCode);
77
241
  }
78
242
  function parseFlags(argv) {
@@ -172,6 +336,16 @@ async function main() {
172
336
  console.log(`open-memex ${pkg.version}`);
173
337
  return;
174
338
  }
339
+ // Per-command help: `open-memex <command> --help`. Checked before loadConfig()
340
+ // so it works even when the environment is broken.
341
+ if (rest.includes("--help") || rest.includes("-h")) {
342
+ const h = COMMAND_HELP[cmd];
343
+ if (h) {
344
+ console.log(`open-memex ${cmd}\n\n${h}`);
345
+ return;
346
+ }
347
+ usage(0);
348
+ }
175
349
  const cfg = loadConfig();
176
350
  const project = resolveProjectScope(process.cwd());
177
351
  // `migrate --to-v2` is a pure file operation (V2-DESIGN §19) — it runs
package/dist/init.js CHANGED
@@ -62,6 +62,9 @@ Syncing them into the repo for review is an explicit, user-approved step:
62
62
  - At session start, and when you finish a meaningful chunk of work, call
63
63
  \`memory_status\`. If the outbox has drafts, summarize them (one line each) and ask
64
64
  the user which ones to sync. Sync NOTHING the user did not name.
65
+ - When the user says "sync memory" (or "同步记忆"), treat it as a request to run
66
+ the sync flow above: call \`memory_status\`, summarize the outbox drafts, and ask
67
+ which ones to sync.
65
68
  - When the user approves, ask ONE follow-up: a separate memory-only branch/PR
66
69
  (recommended), or fold the memories into the current branch alongside code?
67
70
  A "yes, you do it" answer covers the whole chain — branch, local commit,
package/dist/mcp.js CHANGED
@@ -26,6 +26,32 @@ import { db } from "./store/db.js";
26
26
  import { syncScope } from "./store/sync.js";
27
27
  import { addMemory, searchMemories, listMemories, supersedeMemory, forgetMemory, statusMemories, submitMemoriesOp, proposeMemoriesOp, promoteMemoryOp, resolveMemoryOp, prStatusOp, memoryAddArgs, memorySearchArgs, memoryListArgs, memorySupersedeArgs, memoryForgetArgs, memoryStatusArgs, memorySubmitArgs, memoryProposeArgs, memoryPromoteArgs, memoryResolveArgs, memoryPrStatusArgs, TOOL_DESCRIPTIONS, } from "./tools/ops.js";
28
28
  const SERVER_VERSION = "0.2.0-alpha";
29
+ /**
30
+ * D26: session-start guidance delivered through the MCP handshake itself.
31
+ * The init-written instruction files only exist if the user ran
32
+ * `open-memex init --client`; the initialize `instructions` reach every MCP
33
+ * client at connect time. Still advisory — no MCP consumer offers a hard
34
+ * session-start hook — but it is the strongest signal available.
35
+ */
36
+ const SERVER_INSTRUCTIONS = `You are connected to an open-memex local memory MCP server
37
+ (eleven memory_* tools: add, search, list, supersede, forget, status, submit,
38
+ propose, promote, resolve, pr_status).
39
+
40
+ - At the START of this session, call memory_status. If the project outbox has
41
+ drafts waiting for review, summarize them (one line each) and ask the user
42
+ which ones to sync into the repo. Sync NOTHING the user did not name.
43
+ - When the user says "sync memory" (or "同步记忆"), treat it as a request to run
44
+ the sync flow: call memory_status, summarize the outbox drafts, and ask which
45
+ ones to sync.
46
+ - When you finish a meaningful chunk of work, call memory_status again as a checkpoint.
47
+ - BE PROACTIVE: when the user shares something worth remembering across sessions
48
+ (a decision, a preference, a project convention, a fix and its cause), call
49
+ memory_add without being asked. Keep each memory to one self-contained statement.
50
+ - Before asking the user about past decisions, conventions, or preferences they
51
+ may have told you before, call memory_search first.
52
+ - Memories default to this project's scope; use the personal scope for facts
53
+ about the user that hold across all projects.
54
+ - personal scope memories NEVER leave this machine.`;
29
55
  /** Adapt a framework-agnostic op result to an MCP tool response. */
30
56
  function toMcp(p) {
31
57
  return p.then((r) => ({ content: [{ type: "text", text: r.output }] }), (e) => ({
@@ -57,7 +83,7 @@ export async function runMcpServer() {
57
83
  return fn(args);
58
84
  };
59
85
  };
60
- const server = new McpServer({ name: "open-memex", version: SERVER_VERSION });
86
+ const server = new McpServer({ name: "open-memex", version: SERVER_VERSION }, { instructions: SERVER_INSTRUCTIONS });
61
87
  server.registerTool("memory_add", {
62
88
  description: TOOL_DESCRIPTIONS.memory_add,
63
89
  inputSchema: z.object(memoryAddArgs),
package/dist/tools/ops.js CHANGED
@@ -25,7 +25,7 @@ export const TOOL_DESCRIPTIONS = {
25
25
  memory_list: "List memories in a scope, newest first. Useful for browsing what is remembered, or verifying that a save landed.",
26
26
  memory_supersede: "Replace an existing memory with a newer version. The old memory is kept as history (status: superseded) and retrieval returns the new one. Use when a saved fact becomes outdated and should be replaced rather than duplicated.",
27
27
  memory_forget: "Delete a memory by id. Use when the user asks to forget something.",
28
- memory_status: "Show the project memory sync pipeline: drafts waiting in the outbox (appdata), memories in the repo awaiting review or published, and any repo files not yet committed. Call this at session start and at task checkpoints, then ask the user which drafts to sync.",
28
+ memory_status: "Show the project memory sync pipeline: drafts waiting in the outbox (appdata), memories in the repo awaiting review or published, and any repo files not yet committed. Call this at session start and at task checkpoints, then ask the user which drafts to sync. The user may also trigger this flow by saying 'sync memory' (or '同步记忆').",
29
29
  memory_submit: "Move outbox drafts into a git branch for review: creates a branch (default mem/sync-*), copies the drafts into the repo memory dir as proposed, commits locally, and moves the outbox originals out. Prints the push and PR commands — those need the user's explicit approval and are never run automatically.",
30
30
  memory_propose: "Copy personal memories into the project outbox as review drafts. The personal originals stay put.",
31
31
  memory_promote: "Advance a project memory one step up the review ladder (proposed → approved → published), or reject it with a note. Rejected memories are never deleted — they can be revised and resubmitted.",
package/docs/V2-DESIGN.md CHANGED
@@ -699,6 +699,27 @@ requirement: personal data never touches third-party services). Benchmarks to tr
699
699
  is never overridden by a PR signal. *Rationale: the PR is where the team
700
700
  actually reviews — the mapping closes the loop without inventing new
701
701
  review UI. Approved 2026-09-28.*
702
+ - **D34** — The MCP server sends session-start guidance in the handshake
703
+ `instructions`: call `memory_status` at session start (and at work
704
+ checkpoints); if the outbox has drafts, summarize and ask the user which to
705
+ sync; proactive `memory_add`; `memory_search` before asking about the past;
706
+ personal never leaves the machine. *Rationale: the init-written instruction
707
+ files only exist if the user ran `init --client` — the handshake reaches
708
+ every MCP client at connect time. Still advisory: no MCP consumer offers a
709
+ hard session-start hook, and we do not claim otherwise. Approved 2026-09-28.*
710
+ - **D35** — "sync memory" (or "同步记忆") is a natural-language trigger for the
711
+ sync flow: the agent calls `memory_status`, summarizes the outbox drafts, and
712
+ asks the user which ones to sync — same flow as the session-start proposal,
713
+ but user-initiated. Taught in the MCP handshake instructions, the
714
+ init-written instruction files, and the `memory_status` tool description.
715
+ *Rationale: the user should not have to remember command names to sync;
716
+ saying it in words must work. Approved 2026-09-28.*
717
+ - **D33** — Every CLI command answers `open-memex <command> --help` (and `-h`)
718
+ with its own usage, flags, and examples; checked before config/DB load so
719
+ help works even in a broken environment. Unknown commands with `--help`
720
+ fall back to the global usage. *Rationale: AI assistants discover the CLI
721
+ through --help first — a command that silently swallows --help as a flag
722
+ teaches the agent nothing. Approved 2026-09-28.*
702
723
 
703
724
  ## Open Questions
704
725
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-memex",
3
- "version": "0.4.0-alpha.1",
3
+ "version": "0.4.0-alpha.4",
4
4
  "description": "Local-first memory layer and protocol for AI coding agents. Markdown source of truth, SQLite FTS5 index, zero cloud.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/cli.ts CHANGED
@@ -25,6 +25,189 @@ import fs from "node:fs";
25
25
  import path from "node:path";
26
26
  import { fileURLToPath } from "node:url";
27
27
 
28
+ /** Per-command help, printed by `open-memex <command> --help`.
29
+ AI assistants discover the CLI through --help, so every command needs one. */
30
+ const COMMAND_HELP: Record<string, string> = {
31
+ where: `Show which project scope the current directory resolves to, and where its data lives.
32
+
33
+ Usage: open-memex where`,
34
+
35
+ list: `List memories in a scope, newest first.
36
+
37
+ Usage: open-memex list [--scope project|personal] [--type T] [--limit N]
38
+
39
+ Flags:
40
+ --scope project (default) or personal
41
+ --type filter by memory type
42
+ --limit max results
43
+
44
+ Examples:
45
+ open-memex list
46
+ open-memex list --scope personal --limit 20`,
47
+
48
+ search: `Search memories by keyword (BM25 full-text), best matches first.
49
+
50
+ Usage: open-memex search "query" [--scope project|personal|both] [--type T] [--limit N]
51
+
52
+ Flags:
53
+ --scope project (default), personal, or both
54
+ --type filter by memory type
55
+ --limit max results
56
+
57
+ Example:
58
+ open-memex search "deploy checklist" --scope both`,
59
+
60
+ add: `Save a fact, preference, decision, or note to local memory.
61
+
62
+ Usage: open-memex add "content" [--scope project|personal] [--type T] [--tag t1,t2]
63
+
64
+ Flags:
65
+ --scope project (default) or personal (personal never leaves this machine)
66
+ --type memory type (default: fact)
67
+ --tag comma-separated tags
68
+
69
+ Example:
70
+ open-memex add "We deploy on Fridays" --scope project --tag process`,
71
+
72
+ supersede: `Replace a memory with a newer version. The old one is kept as history.
73
+
74
+ Usage: open-memex supersede <id> "new content" [--type T] [--tag t1,t2]`,
75
+
76
+ status: `Change a memory's lifecycle status.
77
+
78
+ Usage: open-memex status <id> active|deprecated|retracted|archived`,
79
+
80
+ forget: `Delete a memory by id.
81
+
82
+ Usage: open-memex forget <id>`,
83
+
84
+ propose: `Copy personal memories into the project outbox as review drafts.
85
+ The personal originals stay put. Nothing enters git at this step.
86
+
87
+ Usage: open-memex propose <id...> --to project [--local-approve]
88
+
89
+ Flags:
90
+ --to project (required)
91
+ --local-approve mark the copies approved right away (solo-dev shortcut)
92
+
93
+ Example:
94
+ open-memex propose 01ABC 01DEF --to project`,
95
+
96
+ promote: `Advance a project memory one step up the review ladder
97
+ (proposed → approved → published), or reject it with a note.
98
+ Every transition is appended to the memory's review_history.
99
+ Rejected memories are never deleted — they can be revised and resubmitted.
100
+
101
+ Usage: open-memex promote <id> [--reject] [--resubmit] [--note "..."] [--by NAME]
102
+
103
+ Flags:
104
+ --reject move back to rejected (requires --note)
105
+ --resubmit move a rejected memory back to proposed
106
+ --note reason for the transition (recorded in review_history)
107
+ --by reviewer name (defaults to the git user)
108
+
109
+ Examples:
110
+ open-memex promote 01ABC --note "verified against the runbook"
111
+ open-memex promote 01ABC --reject --note "outdated after the migration"`,
112
+
113
+ resolve: `List conflicted memories, or 3-way-merge one.
114
+
115
+ Usage: open-memex resolve [id-or-path]
116
+
117
+ With no argument, lists conflicts. With an id or file path, shows the
118
+ 3-way merge (base / outbox / repo) so you can resolve it by hand.
119
+ Conflicts are never auto-resolved.`,
120
+
121
+ "sync-status": `Show the project memory sync pipeline: when the index last synced
122
+ and what triggered it, drafts waiting in the outbox (appdata), memories in the
123
+ repo awaiting review or published, and repo files not yet committed.
124
+
125
+ Usage: open-memex sync-status`,
126
+
127
+ submit: `Move outbox drafts into a git branch for review: creates a branch
128
+ (default mem/sync-*), copies the drafts into the repo memory dir as proposed
129
+ (local-approved copies keep their approval), commits locally, and moves the
130
+ outbox originals out. Prints the push and PR commands — those need your
131
+ explicit approval and are never run automatically.
132
+
133
+ Usage: open-memex submit <id...> [--onto <branch>] [--base <branch>]
134
+
135
+ Flags:
136
+ --onto submit onto the current branch instead of creating mem/sync-*
137
+ --base base branch for the PR suggestion (default: the branch you're on)
138
+
139
+ Example:
140
+ open-memex submit 01ABC 01DEF`,
141
+
142
+ "pr-status": `Map the current branch's GitHub PR state back onto review_state:
143
+ merged → published, approval → approved (approved_by = the reviewer),
144
+ changes-requested → suggestion only (never auto-rejects).
145
+ Each memory in the PR is mapped independently; a human rejection is never
146
+ overwritten. Report-only by default.
147
+
148
+ Usage: open-memex pr-status [--apply]
149
+
150
+ Flags:
151
+ --apply write the transitions locally (still never pushes)`,
152
+
153
+ reindex: `Rebuild the SQLite index from the markdown files.
154
+
155
+ Usage: open-memex reindex`,
156
+
157
+ scopes: `List the known scopes (personal + project).
158
+
159
+ Usage: open-memex scopes`,
160
+
161
+ migrate: `Move memories between scopes, or convert a legacy my-o-memory data dir.
162
+
163
+ Usage: open-memex migrate [--from <key>] [--to <key>] [--dry-run] [--on-conflict newer|overwrite|skip]
164
+ open-memex migrate --to-v2 [--dry-run]
165
+
166
+ Flags:
167
+ --from / --to scope keys (default: current project → personal)
168
+ --dry-run preview without moving anything
169
+ --on-conflict newer (default), overwrite, or skip
170
+ --to-v2 convert a legacy my-o-memory data dir to the v2 layout
171
+
172
+ Always preview with --dry-run first; nothing moves without confirmation.`,
173
+
174
+ mcp: `Start the stdio MCP server (the same server editors connect to).
175
+
176
+ Usage: open-memex mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
177
+
178
+ Flags:
179
+ --print-config print the MCP client config instead of starting the server`,
180
+
181
+ init: `One-command project setup: writes the MCP config for your editor and the
182
+ agent memory instructions. Existing files are merged, never clobbered.
183
+
184
+ Usage: open-memex init [--client vscode|cursor|opencode|visualstudio]
185
+ [--instructions personal|project] [--force] [--yes]
186
+
187
+ Flags:
188
+ --client editor to configure (default: auto-detect)
189
+ --instructions personal (default, ~/.copilot/copilot-instructions.md) or project
190
+ --force overwrite existing config
191
+ --yes accept all defaults, never prompt`,
192
+
193
+ config: `Show config, or set a key.
194
+
195
+ Usage: open-memex config [set <key> <value>]
196
+
197
+ Example:
198
+ open-memex config set sync.autoPull false`,
199
+
200
+ capture: `Preview what the keyword-capture watcher would extract from text.
201
+
202
+ Usage: open-memex capture --dry-run "text"`,
203
+
204
+ doctor: `Environment health check: Node version, config source, scope resolution,
205
+ storage writability, then boots a real MCP server and runs initialize +
206
+ tools/list against it — all eleven tools must show up.
207
+
208
+ Usage: open-memex doctor`,
209
+ };
210
+
28
211
  function usage(exitCode = 1): never {
29
212
  console.log(`open-memex CLI
30
213
 
@@ -79,7 +262,9 @@ the \`--from\` key when migrating.
79
262
  git remote after memories were already stored under the cwd-based key.
80
263
  \`migrate --to-v2\` converts v1 memory files to the v2 format (§19):
81
264
  user→personal scope rename, epoch→RFC 3339 times, priority→importance,
82
- type: instruction→role split. Always preview with --dry-run first.`);
265
+ type: instruction→role split. Always preview with --dry-run first.
266
+
267
+ Run \`open-memex <command> --help\` for details on a single command.`);
83
268
  process.exit(exitCode);
84
269
  }
85
270
 
@@ -204,6 +389,17 @@ async function main() {
204
389
  return;
205
390
  }
206
391
 
392
+ // Per-command help: `open-memex <command> --help`. Checked before loadConfig()
393
+ // so it works even when the environment is broken.
394
+ if (rest.includes("--help") || rest.includes("-h")) {
395
+ const h = COMMAND_HELP[cmd];
396
+ if (h) {
397
+ console.log(`open-memex ${cmd}\n\n${h}`);
398
+ return;
399
+ }
400
+ usage(0);
401
+ }
402
+
207
403
  const cfg = loadConfig();
208
404
  const project = resolveProjectScope(process.cwd());
209
405
 
package/src/init.ts CHANGED
@@ -73,6 +73,9 @@ Syncing them into the repo for review is an explicit, user-approved step:
73
73
  - At session start, and when you finish a meaningful chunk of work, call
74
74
  \`memory_status\`. If the outbox has drafts, summarize them (one line each) and ask
75
75
  the user which ones to sync. Sync NOTHING the user did not name.
76
+ - When the user says "sync memory" (or "同步记忆"), treat it as a request to run
77
+ the sync flow above: call \`memory_status\`, summarize the outbox drafts, and ask
78
+ which ones to sync.
76
79
  - When the user approves, ask ONE follow-up: a separate memory-only branch/PR
77
80
  (recommended), or fold the memories into the current branch alongside code?
78
81
  A "yes, you do it" answer covers the whole chain — branch, local commit,
package/src/mcp.ts CHANGED
@@ -53,6 +53,33 @@ import {
53
53
 
54
54
  const SERVER_VERSION = "0.2.0-alpha";
55
55
 
56
+ /**
57
+ * D26: session-start guidance delivered through the MCP handshake itself.
58
+ * The init-written instruction files only exist if the user ran
59
+ * `open-memex init --client`; the initialize `instructions` reach every MCP
60
+ * client at connect time. Still advisory — no MCP consumer offers a hard
61
+ * session-start hook — but it is the strongest signal available.
62
+ */
63
+ const SERVER_INSTRUCTIONS = `You are connected to an open-memex local memory MCP server
64
+ (eleven memory_* tools: add, search, list, supersede, forget, status, submit,
65
+ propose, promote, resolve, pr_status).
66
+
67
+ - At the START of this session, call memory_status. If the project outbox has
68
+ drafts waiting for review, summarize them (one line each) and ask the user
69
+ which ones to sync into the repo. Sync NOTHING the user did not name.
70
+ - When the user says "sync memory" (or "同步记忆"), treat it as a request to run
71
+ the sync flow: call memory_status, summarize the outbox drafts, and ask which
72
+ ones to sync.
73
+ - When you finish a meaningful chunk of work, call memory_status again as a checkpoint.
74
+ - BE PROACTIVE: when the user shares something worth remembering across sessions
75
+ (a decision, a preference, a project convention, a fix and its cause), call
76
+ memory_add without being asked. Keep each memory to one self-contained statement.
77
+ - Before asking the user about past decisions, conventions, or preferences they
78
+ may have told you before, call memory_search first.
79
+ - Memories default to this project's scope; use the personal scope for facts
80
+ about the user that hold across all projects.
81
+ - personal scope memories NEVER leave this machine.`;
82
+
56
83
  /** Adapt a framework-agnostic op result to an MCP tool response. */
57
84
  function toMcp(p: Promise<ToolResult>) {
58
85
  return p.then(
@@ -91,7 +118,10 @@ export async function runMcpServer() {
91
118
  };
92
119
  };
93
120
 
94
- const server = new McpServer({ name: "open-memex", version: SERVER_VERSION });
121
+ const server = new McpServer(
122
+ { name: "open-memex", version: SERVER_VERSION },
123
+ { instructions: SERVER_INSTRUCTIONS },
124
+ );
95
125
 
96
126
  server.registerTool(
97
127
  "memory_add",
package/src/tools/ops.ts CHANGED
@@ -51,7 +51,7 @@ export const TOOL_DESCRIPTIONS = {
51
51
  "Replace an existing memory with a newer version. The old memory is kept as history (status: superseded) and retrieval returns the new one. Use when a saved fact becomes outdated and should be replaced rather than duplicated.",
52
52
  memory_forget: "Delete a memory by id. Use when the user asks to forget something.",
53
53
  memory_status:
54
- "Show the project memory sync pipeline: drafts waiting in the outbox (appdata), memories in the repo awaiting review or published, and any repo files not yet committed. Call this at session start and at task checkpoints, then ask the user which drafts to sync.",
54
+ "Show the project memory sync pipeline: drafts waiting in the outbox (appdata), memories in the repo awaiting review or published, and any repo files not yet committed. Call this at session start and at task checkpoints, then ask the user which drafts to sync. The user may also trigger this flow by saying 'sync memory' (or '同步记忆').",
55
55
  memory_submit:
56
56
  "Move outbox drafts into a git branch for review: creates a branch (default mem/sync-*), copies the drafts into the repo memory dir as proposed, commits locally, and moves the outbox originals out. Prints the push and PR commands — those need the user's explicit approval and are never run automatically.",
57
57
  memory_propose: