common-memory-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (284) hide show
  1. package/.env.sample +3 -0
  2. package/CHANGELOG.md +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +120 -0
  5. package/SECURITY.md +48 -0
  6. package/dist/cli/codex/transcript-0.153.4.d.ts +20 -0
  7. package/dist/cli/codex/transcript-0.153.4.d.ts.map +1 -0
  8. package/dist/cli/codex/transcript-0.153.4.js +78 -0
  9. package/dist/cli/codex/transcript-0.153.4.js.map +1 -0
  10. package/dist/cli/codex-config.d.ts +2 -0
  11. package/dist/cli/codex-config.d.ts.map +1 -0
  12. package/dist/cli/codex-config.js +5 -0
  13. package/dist/cli/codex-config.js.map +1 -0
  14. package/dist/cli/codex-hook.d.ts +18 -0
  15. package/dist/cli/codex-hook.d.ts.map +1 -0
  16. package/dist/cli/codex-hook.js +140 -0
  17. package/dist/cli/codex-hook.js.map +1 -0
  18. package/dist/cli/codex-session.d.ts +3 -0
  19. package/dist/cli/codex-session.d.ts.map +1 -0
  20. package/dist/cli/codex-session.js +3 -0
  21. package/dist/cli/codex-session.js.map +1 -0
  22. package/dist/cli/flush-command.d.ts +6 -0
  23. package/dist/cli/flush-command.d.ts.map +1 -0
  24. package/dist/cli/flush-command.js +30 -0
  25. package/dist/cli/flush-command.js.map +1 -0
  26. package/dist/cli/host-launch.d.ts +28 -0
  27. package/dist/cli/host-launch.d.ts.map +1 -0
  28. package/dist/cli/host-launch.js +16 -0
  29. package/dist/cli/host-launch.js.map +1 -0
  30. package/dist/cli/host-process.d.ts +3 -0
  31. package/dist/cli/host-process.d.ts.map +1 -0
  32. package/dist/cli/host-process.js +35 -0
  33. package/dist/cli/host-process.js.map +1 -0
  34. package/dist/cli/host-session.d.ts +22 -0
  35. package/dist/cli/host-session.d.ts.map +1 -0
  36. package/dist/cli/host-session.js +204 -0
  37. package/dist/cli/host-session.js.map +1 -0
  38. package/dist/cli/import-command.d.ts +20 -0
  39. package/dist/cli/import-command.d.ts.map +1 -0
  40. package/dist/cli/import-command.js +98 -0
  41. package/dist/cli/import-command.js.map +1 -0
  42. package/dist/cli/interactive-process.d.ts +3 -0
  43. package/dist/cli/interactive-process.d.ts.map +1 -0
  44. package/dist/cli/interactive-process.js +15 -0
  45. package/dist/cli/interactive-process.js.map +1 -0
  46. package/dist/cli/main.d.ts +3 -0
  47. package/dist/cli/main.d.ts.map +1 -0
  48. package/dist/cli/main.js +151 -0
  49. package/dist/cli/main.js.map +1 -0
  50. package/dist/cli/mcp-config.d.ts +16 -0
  51. package/dist/cli/mcp-config.d.ts.map +1 -0
  52. package/dist/cli/mcp-config.js +108 -0
  53. package/dist/cli/mcp-config.js.map +1 -0
  54. package/dist/cli/network-test.d.ts +4 -0
  55. package/dist/cli/network-test.d.ts.map +1 -0
  56. package/dist/cli/network-test.js +28 -0
  57. package/dist/cli/network-test.js.map +1 -0
  58. package/dist/cli/operations.d.ts +26 -0
  59. package/dist/cli/operations.d.ts.map +1 -0
  60. package/dist/cli/operations.js +55 -0
  61. package/dist/cli/operations.js.map +1 -0
  62. package/dist/cli/session-drain.d.ts +3 -0
  63. package/dist/cli/session-drain.d.ts.map +1 -0
  64. package/dist/cli/session-drain.js +34 -0
  65. package/dist/cli/session-drain.js.map +1 -0
  66. package/dist/cli/storage-paths.d.ts +4 -0
  67. package/dist/cli/storage-paths.d.ts.map +1 -0
  68. package/dist/cli/storage-paths.js +15 -0
  69. package/dist/cli/storage-paths.js.map +1 -0
  70. package/dist/cli/tui-integrations.d.ts +4 -0
  71. package/dist/cli/tui-integrations.d.ts.map +1 -0
  72. package/dist/cli/tui-integrations.js +143 -0
  73. package/dist/cli/tui-integrations.js.map +1 -0
  74. package/dist/cli/tui-prompts.d.ts +22 -0
  75. package/dist/cli/tui-prompts.d.ts.map +1 -0
  76. package/dist/cli/tui-prompts.js +64 -0
  77. package/dist/cli/tui-prompts.js.map +1 -0
  78. package/dist/cli/tui-settings.d.ts +21 -0
  79. package/dist/cli/tui-settings.d.ts.map +1 -0
  80. package/dist/cli/tui-settings.js +198 -0
  81. package/dist/cli/tui-settings.js.map +1 -0
  82. package/dist/cli/tui.d.ts +4 -0
  83. package/dist/cli/tui.d.ts.map +1 -0
  84. package/dist/cli/tui.js +292 -0
  85. package/dist/cli/tui.js.map +1 -0
  86. package/dist/cli/work-config.d.ts +24 -0
  87. package/dist/cli/work-config.d.ts.map +1 -0
  88. package/dist/cli/work-config.js +147 -0
  89. package/dist/cli/work-config.js.map +1 -0
  90. package/dist/config/config.d.ts +41 -0
  91. package/dist/config/config.d.ts.map +1 -0
  92. package/dist/config/config.js +193 -0
  93. package/dist/config/config.js.map +1 -0
  94. package/dist/config/private-env.d.ts +8 -0
  95. package/dist/config/private-env.d.ts.map +1 -0
  96. package/dist/config/private-env.js +38 -0
  97. package/dist/config/private-env.js.map +1 -0
  98. package/dist/config/runtime.d.ts +32 -0
  99. package/dist/config/runtime.d.ts.map +1 -0
  100. package/dist/config/runtime.js +85 -0
  101. package/dist/config/runtime.js.map +1 -0
  102. package/dist/core/contracts/errors.d.ts +10 -0
  103. package/dist/core/contracts/errors.d.ts.map +1 -0
  104. package/dist/core/contracts/errors.js +23 -0
  105. package/dist/core/contracts/errors.js.map +1 -0
  106. package/dist/core/safety/external-preflight.d.ts +7 -0
  107. package/dist/core/safety/external-preflight.d.ts.map +1 -0
  108. package/dist/core/safety/external-preflight.js +47 -0
  109. package/dist/core/safety/external-preflight.js.map +1 -0
  110. package/dist/core/safety/redaction.d.ts +2 -0
  111. package/dist/core/safety/redaction.d.ts.map +1 -0
  112. package/dist/core/safety/redaction.js +4 -0
  113. package/dist/core/safety/redaction.js.map +1 -0
  114. package/dist/core/safety/rules.d.ts +6 -0
  115. package/dist/core/safety/rules.d.ts.map +1 -0
  116. package/dist/core/safety/rules.js +14 -0
  117. package/dist/core/safety/rules.js.map +1 -0
  118. package/dist/core/safety/scanner.d.ts +11 -0
  119. package/dist/core/safety/scanner.d.ts.map +1 -0
  120. package/dist/core/safety/scanner.js +18 -0
  121. package/dist/core/safety/scanner.js.map +1 -0
  122. package/dist/core/transaction/fsync.d.ts +6 -0
  123. package/dist/core/transaction/fsync.d.ts.map +1 -0
  124. package/dist/core/transaction/fsync.js +41 -0
  125. package/dist/core/transaction/fsync.js.map +1 -0
  126. package/dist/index.d.ts +16 -0
  127. package/dist/index.d.ts.map +1 -0
  128. package/dist/index.js +13 -0
  129. package/dist/index.js.map +1 -0
  130. package/dist/mcp/ingress.d.ts +61 -0
  131. package/dist/mcp/ingress.d.ts.map +1 -0
  132. package/dist/mcp/ingress.js +134 -0
  133. package/dist/mcp/ingress.js.map +1 -0
  134. package/dist/mcp/server.d.ts +4 -0
  135. package/dist/mcp/server.d.ts.map +1 -0
  136. package/dist/mcp/server.js +92 -0
  137. package/dist/mcp/server.js.map +1 -0
  138. package/dist/mcp/stdio.d.ts +5 -0
  139. package/dist/mcp/stdio.d.ts.map +1 -0
  140. package/dist/mcp/stdio.js +115 -0
  141. package/dist/mcp/stdio.js.map +1 -0
  142. package/dist/memory-manager/contracts/diagnostic.d.ts +14 -0
  143. package/dist/memory-manager/contracts/diagnostic.d.ts.map +1 -0
  144. package/dist/memory-manager/contracts/diagnostic.js +17 -0
  145. package/dist/memory-manager/contracts/diagnostic.js.map +1 -0
  146. package/dist/memory-manager/contracts/disclosure.d.ts +12 -0
  147. package/dist/memory-manager/contracts/disclosure.d.ts.map +1 -0
  148. package/dist/memory-manager/contracts/disclosure.js +8 -0
  149. package/dist/memory-manager/contracts/disclosure.js.map +1 -0
  150. package/dist/memory-manager/contracts/errors.d.ts +15 -0
  151. package/dist/memory-manager/contracts/errors.d.ts.map +1 -0
  152. package/dist/memory-manager/contracts/errors.js +25 -0
  153. package/dist/memory-manager/contracts/errors.js.map +1 -0
  154. package/dist/memory-manager/contracts/model-port.d.ts +38 -0
  155. package/dist/memory-manager/contracts/model-port.d.ts.map +1 -0
  156. package/dist/memory-manager/contracts/model-port.js +2 -0
  157. package/dist/memory-manager/contracts/model-port.js.map +1 -0
  158. package/dist/memory-manager/network/client.d.ts +13 -0
  159. package/dist/memory-manager/network/client.d.ts.map +1 -0
  160. package/dist/memory-manager/network/client.js +122 -0
  161. package/dist/memory-manager/network/client.js.map +1 -0
  162. package/dist/memory-manager/network/route.d.ts +31 -0
  163. package/dist/memory-manager/network/route.d.ts.map +1 -0
  164. package/dist/memory-manager/network/route.js +148 -0
  165. package/dist/memory-manager/network/route.js.map +1 -0
  166. package/dist/memory-manager/openai/abort.d.ts +4 -0
  167. package/dist/memory-manager/openai/abort.d.ts.map +1 -0
  168. package/dist/memory-manager/openai/abort.js +19 -0
  169. package/dist/memory-manager/openai/abort.js.map +1 -0
  170. package/dist/memory-manager/openai/bounded-body.d.ts +2 -0
  171. package/dist/memory-manager/openai/bounded-body.d.ts.map +1 -0
  172. package/dist/memory-manager/openai/bounded-body.js +49 -0
  173. package/dist/memory-manager/openai/bounded-body.js.map +1 -0
  174. package/dist/memory-manager/openai/openai-chat-adapter.d.ts +16 -0
  175. package/dist/memory-manager/openai/openai-chat-adapter.d.ts.map +1 -0
  176. package/dist/memory-manager/openai/openai-chat-adapter.js +51 -0
  177. package/dist/memory-manager/openai/openai-chat-adapter.js.map +1 -0
  178. package/dist/memory-manager/openai/openai-responses-adapter.d.ts +15 -0
  179. package/dist/memory-manager/openai/openai-responses-adapter.d.ts.map +1 -0
  180. package/dist/memory-manager/openai/openai-responses-adapter.js +14 -0
  181. package/dist/memory-manager/openai/openai-responses-adapter.js.map +1 -0
  182. package/dist/memory-manager/openai/options.d.ts +14 -0
  183. package/dist/memory-manager/openai/options.d.ts.map +1 -0
  184. package/dist/memory-manager/openai/options.js +29 -0
  185. package/dist/memory-manager/openai/options.js.map +1 -0
  186. package/dist/memory-manager/openai/remote-http.d.ts +33 -0
  187. package/dist/memory-manager/openai/remote-http.d.ts.map +1 -0
  188. package/dist/memory-manager/openai/remote-http.js +207 -0
  189. package/dist/memory-manager/openai/remote-http.js.map +1 -0
  190. package/dist/memory-manager/openai/response-decoder.d.ts +3 -0
  191. package/dist/memory-manager/openai/response-decoder.d.ts.map +1 -0
  192. package/dist/memory-manager/openai/response-decoder.js +57 -0
  193. package/dist/memory-manager/openai/response-decoder.js.map +1 -0
  194. package/dist/memory-manager/openai/retry.d.ts +8 -0
  195. package/dist/memory-manager/openai/retry.d.ts.map +1 -0
  196. package/dist/memory-manager/openai/retry.js +18 -0
  197. package/dist/memory-manager/openai/retry.js.map +1 -0
  198. package/dist/pi-extension/extraction-runtime.d.ts +51 -0
  199. package/dist/pi-extension/extraction-runtime.d.ts.map +1 -0
  200. package/dist/pi-extension/extraction-runtime.js +87 -0
  201. package/dist/pi-extension/extraction-runtime.js.map +1 -0
  202. package/dist/pi-extension/index.d.ts +19 -0
  203. package/dist/pi-extension/index.d.ts.map +1 -0
  204. package/dist/pi-extension/index.js +172 -0
  205. package/dist/pi-extension/index.js.map +1 -0
  206. package/dist/v2/canonical.d.ts +53 -0
  207. package/dist/v2/canonical.d.ts.map +1 -0
  208. package/dist/v2/canonical.js +321 -0
  209. package/dist/v2/canonical.js.map +1 -0
  210. package/dist/v2/contract.d.ts +34 -0
  211. package/dist/v2/contract.d.ts.map +1 -0
  212. package/dist/v2/contract.js +53 -0
  213. package/dist/v2/contract.js.map +1 -0
  214. package/dist/v2/document-import.d.ts +100 -0
  215. package/dist/v2/document-import.d.ts.map +1 -0
  216. package/dist/v2/document-import.js +259 -0
  217. package/dist/v2/document-import.js.map +1 -0
  218. package/dist/v2/errors.d.ts +6 -0
  219. package/dist/v2/errors.d.ts.map +1 -0
  220. package/dist/v2/errors.js +29 -0
  221. package/dist/v2/errors.js.map +1 -0
  222. package/dist/v2/import.d.ts +26 -0
  223. package/dist/v2/import.d.ts.map +1 -0
  224. package/dist/v2/import.js +48 -0
  225. package/dist/v2/import.js.map +1 -0
  226. package/dist/v2/lock.d.ts +3 -0
  227. package/dist/v2/lock.d.ts.map +1 -0
  228. package/dist/v2/lock.js +47 -0
  229. package/dist/v2/lock.js.map +1 -0
  230. package/dist/v2/memory-maintainer.md +38 -0
  231. package/dist/v2/read-guidance.d.ts +3 -0
  232. package/dist/v2/read-guidance.d.ts.map +1 -0
  233. package/dist/v2/read-guidance.js +3 -0
  234. package/dist/v2/read-guidance.js.map +1 -0
  235. package/dist/v2/reader.d.ts +25 -0
  236. package/dist/v2/reader.d.ts.map +1 -0
  237. package/dist/v2/reader.js +38 -0
  238. package/dist/v2/reader.js.map +1 -0
  239. package/dist/v2/registry.d.ts +14 -0
  240. package/dist/v2/registry.d.ts.map +1 -0
  241. package/dist/v2/registry.js +46 -0
  242. package/dist/v2/registry.js.map +1 -0
  243. package/dist/v2/runtime.d.ts +133 -0
  244. package/dist/v2/runtime.d.ts.map +1 -0
  245. package/dist/v2/runtime.js +326 -0
  246. package/dist/v2/runtime.js.map +1 -0
  247. package/dist/v2/session-drain.d.ts +14 -0
  248. package/dist/v2/session-drain.d.ts.map +1 -0
  249. package/dist/v2/session-drain.js +16 -0
  250. package/dist/v2/session-drain.js.map +1 -0
  251. package/dist/v2/session.d.ts +54 -0
  252. package/dist/v2/session.d.ts.map +1 -0
  253. package/dist/v2/session.js +158 -0
  254. package/dist/v2/session.js.map +1 -0
  255. package/dist/v2/writer.d.ts +40 -0
  256. package/dist/v2/writer.d.ts.map +1 -0
  257. package/dist/v2/writer.js +327 -0
  258. package/dist/v2/writer.js.map +1 -0
  259. package/docs/00-index.md +19 -0
  260. package/docs/03-target-architecture.md +49 -0
  261. package/docs/init-v0.1-closeout.md +152 -0
  262. package/docs/init-v0.1-design.md +237 -0
  263. package/docs/init-v0.1-verification.md +303 -0
  264. package/docs/outbound-network-design.md +100 -0
  265. package/docs/outbound-network-verification.json +300 -0
  266. package/docs/provider-verification.md +94 -0
  267. package/docs/releasing.md +138 -0
  268. package/docs/session-integration.md +134 -0
  269. package/docs/tui-workbench.md +173 -0
  270. package/docs/usage.md +815 -0
  271. package/docs/v2-ablation-results.json +12035 -0
  272. package/docs/v2-ablation.md +117 -0
  273. package/docs/v2-evaluation-repeat-results.json +7 -0
  274. package/docs/v2-evaluation-scripted-results.json +67 -0
  275. package/docs/v2-evaluation.md +35 -0
  276. package/docs/v2-optimization-plan.md +23 -0
  277. package/docs/v2-performance-baseline-runtime.js.txt +231 -0
  278. package/docs/v2-performance-baseline.json +338 -0
  279. package/docs/v2-performance-behavior-equivalence.json +17 -0
  280. package/docs/v2-performance-results.json +585 -0
  281. package/docs/v2-performance.md +88 -0
  282. package/docs/v2-replacement-test-map.md +14 -0
  283. package/docs/v2-verification.md +49 -0
  284. package/package.json +87 -0
package/docs/usage.md ADDED
@@ -0,0 +1,815 @@
1
+ # Common Memory v0.2 — 使用与配置
2
+
3
+ Durable, user-owned memory maintenance for Pi and local MCP hosts, plus authorized
4
+ read-only disclosure of the resulting Markdown to Pi, Codex CLI and other local MCP
5
+ consumers. Markdown is the authority for current long-term content; SQLite stores
6
+ pending deliveries, observations, jobs, leases, source links and recovery metadata.
7
+ There is no Fact/Recall/Undo compatibility layer, search index, temporary memory
8
+ product, or resident background service. Reading returns the current documents as
9
+ they are; there is no retrieval ranking.
10
+
11
+ Init v0.1 (`docs/init-v0.1-design.md`, `docs/init-v0.1-verification.md`) adds the
12
+ cross-agent loop: another agent (ChatGPT desktop) imports its existing understanding
13
+ through `memory_init`, the user imports local Markdown files with `common-memory import`,
14
+ the unchanged Writer decides what to keep from either, and Codex CLI (native session hooks or MCP `memory_read`)
15
+ and Pi (system-prompt injection) read the same canonical files. On Windows, Common
16
+ Memory runs inside WSL and the ChatGPT/Codex desktop app reaches it through `wsl.exe`
17
+ (`common-memory mcp-config --wsl`).
18
+
19
+ 配套的 Writer 评测规范已迁移到独立仓库:[Memory Benchmark](https://github.com/Mr-remon219/memory-benchmark)。
20
+
21
+ ## Setup
22
+
23
+ Requires Node.js 24. Install with `npm install -g common-memory-core@0.2.0`, then run
24
+ `common-memory`. Source contributors can use `npm ci && npm run build` followed by
25
+ `node dist/cli/main.js`. The default interactive workbench brings
26
+ configuration, memory browsing/import, projects and permissions, integration management,
27
+ and queue/session maintenance into one navigable interface. The local wizard writes
28
+ `~/.common-memory/config.json` and, when local credentials are supplied, a private
29
+ `.env` file (`COMMON_MEMORY_HOME` overrides this location). Configure an OpenAI-compatible
30
+ API root and choose a request mode in `remote.api` (omitted means `responses`).
31
+ Responses uses strict Structured Outputs; `chat_completions` uses JSON object mode
32
+ with the complete maintenance schema in the system message. Both use the same Core
33
+ validation and commit path. Keys are never stored in canonical memory.
34
+ V2 requires configuration `schemaVersion: 2`; pre-V2 configuration/data is not migrated
35
+ or automatically deleted. Existing V2 configurations remain valid; the V2 jobs table
36
+ receives an idempotent, transactional nullable diagnostic column when opened.
37
+
38
+ Optional fields in `remote` (Settings → Advanced tuning in the workbench, or edit
39
+ `config.json`). API keys remain in private `.env`; ordinary model edits can keep existing
40
+ or external credentials, and preserve unrelated configuration:
41
+
42
+ | Field | Accepted values / effect |
43
+ | --- | --- |
44
+ | `api` | `responses` (default) or `chat_completions`; explicit selection, no fallback |
45
+ | `maxOutputTokens` | Integer 1–16384; default 4096; `max_output_tokens` for Responses, `max_tokens` for Chat |
46
+ | `reasoningEffort` | Responses only: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`; sent as `reasoning.effort` |
47
+ | `thinking` | Chat only: `{ "type": "enabled" }` or `{ "type": "disabled" }` |
48
+ | `enableThinking` | Chat only: boolean, sent as `enable_thinking`; mutually exclusive with `thinking` |
49
+
50
+ Unconfigured thinking/effort fields are omitted. The endpoint and model must support
51
+ the selected fields; there is no brand detection, automatic parameter translation or
52
+ arbitrary body-field forwarding. The default Writer deadline remains 60 seconds.
53
+ Current provider evidence and the reusable verification procedure are recorded in
54
+ [Provider verification](provider-verification.md); earlier experiments remain in
55
+ [Init v0.1 closeout verification](init-v0.1-closeout.md).
56
+
57
+ Register the built package as a Pi extension using the package's `pi.extensions`
58
+ entry. It records input origins, durably records actual user `message_end` deliveries,
59
+ then binds stable transcript entries after Pi appends them. Assistant failure does not
60
+ discard delivered evidence. Input alone is not evidence. Ambiguous, detectably transformed, or
61
+ extension-originated messages are quarantined rather than silently trusted. No
62
+ assistant/tool/system/thinking/compaction text is supplied as new evidence.
63
+
64
+ The extension reads authorized memory once when the process first starts the session,
65
+ including startup with resumed history. It freezes only the Common Memory appended
66
+ block, combining that block with the host's current `event.systemPrompt` on each
67
+ `before_agent_start`. Reload, same-process resume, compact, branch navigation, fork
68
+ and `/new` do not trigger a new automatic read. Each session has separate counters.
69
+ The native `memory_read` tool remains available for explicit fresh reads, with the
70
+ same guidance and scope rules as MCP. Personal recommendations need a read when
71
+ relevant personal context is missing; generic explanations do not mechanically read.
72
+ Missing fields are unknown and memory content is data, not instructions.
73
+
74
+ Pi and Codex now use a durable session cache. One delivered user interaction counts
75
+ once at final settled, including steering and delivered follow-ups. The tenth settled
76
+ interaction immediately seals a session-only batch. A 21-turn session produces
77
+ 10 + 10 + a one-turn exit tail. The logical batch may need several Writer requests,
78
+ always split between whole interactions; a single oversized interaction is retained
79
+ locally and quarantined. Assistant and tool text is context only, with separate
80
+ `conversation_context` disclosure permission (not added to existing configurations).
81
+ See [session design and validation](session-integration.md).
82
+
83
+ Optional `sessionCache` limits (omitted fields use these defaults):
84
+
85
+ ```json
86
+ "sessionCache": {
87
+ "maxSessionBytes": 8388608,
88
+ "maxTotalBytes": 67108864,
89
+ "contextTailTurns": 2
90
+ }
91
+ ```
92
+
93
+ These are conservative engineering defaults, without capacity measurements or a
94
+ claim that two turns resolve every reference. Limits account for cached bodies,
95
+ input candidates, deliveries and Codex inbox bodies. Capacity rejection retains
96
+ existing content and recovery state; terminal metadata can still be persisted.
97
+ Old configurations remain valid and do not acquire `conversation_context` permission.
98
+
99
+ ## Model network configuration
100
+
101
+ Common Memory owns one outbound client per configured model, shared by the CLI, MCP
102
+ and Pi paths. Run `common-memory config --network` to select a route. This changes
103
+ model calls only; it does not configure the host's other network clients.
104
+
105
+ | Mode | Request route |
106
+ | --- | --- |
107
+ | `direct` | Independent direct Agent; ignores HTTP/ALL proxy variables and the host global dispatcher |
108
+ | `env` | HTTPS: HTTPS_PROXY → HTTP_PROXY → ALL_PROXY; HTTP: HTTP_PROXY → ALL_PROXY; honors the supported NO_PROXY rules |
109
+ | `custom` | Explicit HTTP/HTTPS proxy; optional own bypass list, independent of host NO_PROXY; SOCKS5 is experimental |
110
+ | Old config without `remote.proxy` | Legacy host route, whose actual behavior is unknown to Common Memory; preserved until network settings are explicitly saved |
111
+
112
+ New installations default to `remote.proxy: {"mode":"env"}`. Existing schemaVersion 2
113
+ files retain field absence on load/save and ordinary API configuration, so upgrading
114
+ alone does not change their route. Legacy borrows the fetch captured at client creation
115
+ and preserves historic private environment loading, except for newly reserved network
116
+ secret names. It is a compatibility exception to network isolation.
117
+
118
+ In the new modes, proxy variables and API keys are read locally with **process env
119
+ before Common Memory's private `.env`**. For each standard proxy variable group, the
120
+ process source wins before checking lowercase/uppercase spelling; lowercase wins
121
+ within that source. A present empty value clears that group. No new-mode loading
122
+ changes `process.env`, global fetch, global dispatchers or global certificate trust.
123
+ The route and connections are fixed for the client's lifetime, including retries;
124
+ restart active MCP/Pi clients after changing configuration.
125
+
126
+ The wizard saves a custom proxy URL only as private `COMMON_MEMORY_PROXY_URL`, with
127
+ `remote.proxy: {"mode":"custom","urlEnv":"COMMON_MEMORY_PROXY_URL"}` in JSON. URL
128
+ credentials are supported. Optional extra CA certificates are referenced through
129
+ `remote.caFileEnv: "COMMON_MEMORY_CA_FILE"`; the private value is a PEM file path.
130
+ The CA file is limited to 1 MiB and is added to Node's default trust only for this
131
+ client. Certificate and hostname verification stay enabled. Other custom `urlEnv`
132
+ or `caFileEnv` names are read from external process env only. Reserved private network
133
+ keys are never exported by the legacy loader either.
134
+
135
+ NO_PROXY (or custom `noProxy`) accepts comma/whitespace-separated hostnames,
136
+ `example.com`, `.example.com` and `*.example.com` (apex plus subdomains), exact IPv4/
137
+ IPv6, optional ports and standalone `*` anywhere in the list. IPv6 ports require
138
+ brackets. Matching normalizes case, IDNA, trailing dots and IP spelling; it compares
139
+ effective ports, so HTTPS with omitted port matches `:443`. It performs no DNS lookup:
140
+ `localhost` does not imply `127.0.0.1` or `::1`. **CIDR ranges, URL/path entries and other
141
+ wildcards are rejected** with `no_proxy_invalid`; they are not silently ignored.
142
+ An environment containing CIDR entries needs an explicit supported bypass list or a
143
+ custom route. A failing selected proxy never falls back to direct.
144
+
145
+ Windows/macOS GUI processes can inherit different environment variables from terminals;
146
+ configure the private settings when that is the desired common source. WSL uses its
147
+ own visible environment and reachable proxy address; Common Memory does not guess a
148
+ Windows host address or copy Windows proxy settings. OS VPN/TUN routing still applies
149
+ in every mode. PAC/WPAD, SOCKS4 and NTLM/Kerberos are unsupported.
150
+
151
+ `status` describes configuration, selection/bypass reason and actual storage paths;
152
+ it does not open network connections. `network-test` explicitly sends a small synthetic
153
+ model API request without opening SQLite or writing memory. Its success does not prove
154
+ Writer commits. Proxy authentication (`PROXY_AUTHENTICATION`, `proxyStatus:407`) is
155
+ separate from provider API key authentication (`AUTHENTICATION`, `httpStatus:401/403`).
156
+ Errors expose controlled stages/reasons, not proxy credentials or provider bodies.
157
+
158
+ Configured model clients and configured Writers expose async `close()` and own their
159
+ connections. CLI/MCP/Pi await shutdown. Integrators creating them directly must also
160
+ `await close()`; a plain `Writer` still borrows its `MemoryModelPort` and does not close
161
+ caller-owned resources. The port itself remains analysis-only.
162
+
163
+ Research, explicit environment limits and acceptance evidence:
164
+ [network design and review](outbound-network-design.md).
165
+
166
+ ## Interactive workbench
167
+
168
+ Run **`common-memory`** in a terminal. Home leads to:
169
+
170
+ | Area | Tasks |
171
+ | --- | --- |
172
+ | Overview | Configuration, actual storage paths, network selection and queue health; refresh locally |
173
+ | Memory | Browse authorized consumer documents with pagination; import local Markdown with explicit confirmation |
174
+ | Projects & permissions | Register/view/remove projects; independently manage disclosure, write scopes and provenance |
175
+ | Integrations | Local readiness; Pi's official package/resource manager; Codex/Work bundle preview/export; MCP configuration preview/export |
176
+ | Maintenance | Job diagnostics and dead-job retry; session summaries without bodies; flush and durable handoff recovery |
177
+ | Settings | Model/API/credentials, network/CA, explicit synthetic connection test, advanced tuning/limits/storage |
178
+
179
+ Use arrows and Enter, Space for multi-select, and Back to return. Esc/Ctrl+C cancels a
180
+ form; cancellation at Home exits. Pending work remains durable. No model call is made
181
+ just by opening the workbench. A generated integration is **not** reported as installed,
182
+ trusted or connected: Codex/Work/MCP config merging and hook trust stay in the host.
183
+ Pi management invokes the official `pi` command on PATH only after confirmation.
184
+
185
+ The interface requires both stdin and stdout to be TTYs. With no arguments outside a
186
+ TTY it prints entry-point guidance and exits; direct `config` wizards fail explicitly
187
+ rather than waiting for input. Scriptable commands and machine protocol entries remain
188
+ available. The same operations serve both CLI and TUI; read-only MCP still never opens
189
+ SQLite. See [design, entry-point inventory and limits](tui-workbench.md).
190
+
191
+ ## Commands
192
+
193
+ These remain supported for automation and direct shortcuts; they are not prerequisites
194
+ for using the workbench.
195
+
196
+ ```sh
197
+ common-memory
198
+ common-memory config
199
+ common-memory config --network
200
+ common-memory status
201
+ common-memory network-test
202
+ common-memory show [--workspace /absolute/project/path]
203
+ common-memory import <file.md> [--workspace /absolute/project/path] [--author user|agent|third_party|mixed|unknown] [--label <text>] [--no-wait]
204
+ common-memory flush
205
+ common-memory session-drain [--home <absolute-path>]
206
+ common-memory retry <dead-job-id>
207
+ common-memory project register /absolute/project/path "Display name"
208
+ common-memory project list
209
+ common-memory project remove <id>
210
+ common-memory mcp-config [--wsl] [--distro <name>] [--user <name>] [--workspace /absolute/project/path]...
211
+ ```
212
+
213
+ `show` prints the memory directory and exactly what consumers (MCP `memory_read`, Pi)
214
+ receive for `global` plus the optional registered workspace, using the same
215
+ authorization. The canonical files themselves are plain Markdown under
216
+ `<dataRoot>/memory/` and can be opened with any editor.
217
+
218
+ ### Importing a Markdown file
219
+
220
+ `common-memory import <file.md>` brings one local Markdown file into memory through the
221
+ same Writer that handles user turns and Init. It never copies the file into
222
+ `profile.md` or bypasses the Core. The import step is input preprocessing only:
223
+
224
+ - The file must be a regular `.md`/`.markdown` file (no symlinks), strict UTF-8 without
225
+ NUL bytes, non-empty after trimming, and at most 256 KiB. Anything else is rejected
226
+ with a code (`FILE_NOT_FOUND`, `UNSUPPORTED_FILE_TYPE`, `INVALID_ENCODING`,
227
+ `EMPTY_DOCUMENT`, `DOCUMENT_TOO_LARGE`) before anything is queued. Nothing is truncated.
228
+ - A file that fits the 32 KiB per-item budget is one observation, verbatim. Larger files
229
+ are split only at Markdown structure: headings start new units, blank lines separate
230
+ paragraphs, fenced code is never split, and whole sections stay together when they fit.
231
+ Every part records the ancestor headings it sits under (`heading_path`) and its position
232
+ (`part i of n`). A single paragraph or fence larger than the budget rejects the whole
233
+ import (`IMPORT_CHUNK_TOO_LARGE`); an unterminated fence makes the rest of the file one
234
+ fence. The 32 KiB budget is fixed; with a lowered `disclosure.maxTotalBytes` the Writer
235
+ may still quarantine a part that does not fit its request (`OVERSIZED_COMPLETE_TURN`).
236
+ - The Writer's outbound safety scan runs before queuing; a violating part is reported as
237
+ `SENSITIVE_CONTENT_REJECTED part i/n: <rule ids>` and the file is not imported.
238
+ - `--author` records who the importer says wrote the file (default `unknown`), `--label`
239
+ a display label (default the file name). Both are recorded metadata for the maintainer;
240
+ neither grants authority. Even `--author user` remains `document_import`, not a user
241
+ statement, because Markdown is a format and choosing to import a file is not asserting
242
+ each sentence in it.
243
+ - Identity is the content digest within the target context (`md-<sha256>`): the same bytes
244
+ under another file name, label or author are the same material (reported as a duplicate,
245
+ nothing new is queued, the original metadata stays); changed bytes are a new import.
246
+ Scope comes from `--workspace` (a registered project in `disclosure.allowedScopes`) or
247
+ defaults to `global`.
248
+
249
+ All parts are queued in one transaction with a flush request, then the command runs the
250
+ Writer loop like `flush` and prints per-part states (`pending`, `claimed`, `processed`,
251
+ `quarantined`, `dead`), the documents each part is retained in, and a final `complete`
252
+ flag that is true only when every part was processed. Parts are committed batch by batch
253
+ with their own receipts; a partially processed import is reported as incomplete (exit
254
+ code 1), never as success. Re-running `import` on the same file resumes pending or
255
+ retrying parts (dead jobs need `common-memory retry <job-id>`); a quarantined part is
256
+ final for that content and needs a changed file. `--no-wait` only queues. Enable the
257
+ provenance first:
258
+ `disclosure.allowedProvenance` must contain `document_import` (wizard option "Imported
259
+ Markdown documents"), otherwise `IMPORT_DISABLED`. Text inside the file is data: memory
260
+ commands, links and code in it are never executed or followed, and the import cannot
261
+ forget, remove or replace Sections that user turns produced (see "What Init means").
262
+
263
+ Project IDs are generated locally. Registry matching uses real paths and the longest
264
+ ancestor, frozen at capture time. Registration alone grants no permission: separately
265
+ authorize `project:<id>` under Projects & permissions in the workbench, or add it to
266
+ `disclosure.allowedScopes` and `writableScopes` in config.
267
+ Removing a registration leaves its Markdown intact. `status` reports pending,
268
+ quarantined, dead jobs and unbound deliveries without printing raw conversations.
269
+ It also shows the config path and resolved storage paths (including symlink targets);
270
+ absent storage is displayed without creating it. `flush` exits 1 if this invocation
271
+ fails, is cancelled, quarantines an observation, or ends with pending/claimed/dead
272
+ observations. An idle scheduler waiting for backoff or an active lease is incomplete.
273
+ Historical quarantine and retired jobs do not block an otherwise empty queue; flush
274
+ does not bypass backoff or take another process's lease.
275
+ Pi also provides `/memory-flush` for queued maintenance. It does not seal an unfinished
276
+ session batch. On actual quit, Pi hands off the tail and wakes a detached consumer;
277
+ reload and session switching preserve the open cache. `common-memory session-drain`
278
+ recovers durable handoffs and waits through retry backoff and leases.
279
+
280
+ ## MCP access (stdio)
281
+
282
+ Build with `npm ci && npm run build`. Configure Common Memory using the existing
283
+ CLI, then give your MCP host an explicit command and argument array. Node 24 is
284
+ required. No running Pi process is needed; the existing Pi peer/package layout is
285
+ unchanged. The SDK stdio entry serves modern and legacy clients. No HTTP port,
286
+ automatic host installer, Roots discovery, Resources, Prompts or retrieval is added.
287
+
288
+ ### Capability profiles
289
+
290
+ Each MCP process registers only the tools its launch arguments allow. `--capability`
291
+ is repeatable; the default without it is `relay`, the pre-existing behaviour.
292
+
293
+ | `--capability` | Tools registered | Needs Writer / API key | Intended host |
294
+ | --- | --- | --- | --- |
295
+ | `relay` (default) | `memory_submit_user_turn`, `memory_status` | yes (background processing) | trusted local agent relaying verbatim user turns |
296
+ | `init` | `memory_init`, `memory_status` | yes | ChatGPT desktop: one-shot import of its existing understanding |
297
+ | `read` | `memory_read`, `memory_status` | **no** (never opens the runtime database) | Codex CLI and other read-only consumers |
298
+
299
+ Capability is fixed per process at launch; a tool argument, client-reported name or
300
+ prompt can never widen it. Run one process per host role. Where two hosts share one
301
+ configuration file (see Codex below), use the host's own allow list and profiles as the
302
+ second layer.
303
+
304
+ For project input, use `--workspace /absolute/project/path` (repeatable). Register
305
+ projects with the existing CLI and separately authorize their disclosure/write scopes.
306
+ Use `--global` explicitly to allow global contexts. There is no cwd fallback. Each call
307
+ selects an allowed `contextId`; changed/unregistered workspace mappings are rejected
308
+ rather than silently rebound. Project source does not prohibit authorized Global
309
+ promotion: the existing Writer still decides applicability. Reading follows the same
310
+ contexts: a process launched for workspace A never returns project B's document, and
311
+ a process without `--global` never returns Profile/Preferences.
312
+
313
+ The server publishes MCP `instructions` describing when to use its tools. Tool discovery
314
+ and proactive calls depend on the host and model; configuring MCP alone does not
315
+ guarantee a read before an answer. Native Codex hooks below inject memory independently
316
+ of tool calls. Memory content is data, never agent instructions.
317
+
318
+ ### Tools
319
+
320
+ - `memory_status {}`: this connection's capabilities, enabled features and allowed
321
+ context IDs.
322
+ - `memory_submit_user_turn { submissionId, conversationId?, contextId, text }`
323
+ (`relay`): submit one **complete user expression verbatim**, not an assistant summary
324
+ or a Markdown operation. IDs must be 1–128 ASCII letters/digits/underscores/hyphens.
325
+ - `memory_init { importId, contextId, sourceLabel, basis, understanding, gaps? }`
326
+ (`init`): import another agent's **visible existing material, quoted or faithfully summarized** of the user (`global`) or the current
327
+ project (`project:<id>`). `basis` ∈ `saved_memories | chat_history |
328
+ current_conversation | project_context | mixed | unknown`; `understanding` ≤ 32 KiB;
329
+ `gaps` describes what the agent could not access. The payload is stored as one
330
+ `agent_import` observation. `sourceLabel` is a recorded label, not an identity.
331
+ Reuse `importId` on retry: identical payloads are duplicates, changed payloads are
332
+ `SUBMISSION_CONFLICT`. Init requests an immediate flush, so the Core processes it at
333
+ the next stable boundary instead of waiting for the usual thresholds.
334
+ - `memory_read { contextId? }` (`read`): current Profile and Preferences for `global`
335
+ and the project document for an allowed project context; without `contextId`, every
336
+ allowed context. Returns Markdown plus `{ documents: [{ target, content, bytes,
337
+ empty }], empty }`. Documents are returned whole (the Writer keeps each ≤ 16 KiB);
338
+ an empty result says that nothing is stored so consumers do not invent facts.
339
+ - `memory_status { submissionId, conversationId? }` / `memory_status { importId }`:
340
+ that item's `state` (`pending`, `claimed`, `processed`, `quarantined`, `dead`), the
341
+ documents it is currently retained in (`retainedIn`, derived from Section source
342
+ links, never titles or bodies), the existing `issue` code, and `diagnostic`
343
+ (`stage`, local `reason`, optional `httpStatus`, `retryable`). It also returns
344
+ `jobId`, `jobState`, `attempts` and `retryAt` (Unix milliseconds, null unless
345
+ waiting for a job retry). Diagnostics follow the current linked job and survive
346
+ restart; processed observations hide earlier failures, while local job history
347
+ retains them. Provider messages/bodies are never persisted as diagnostics.
348
+ `retryable` describes the adapter's advice and does not change Runtime scheduling. `processed` with an
349
+ empty `retainedIn` means the Core kept nothing (ignored or reorganized only).
350
+
351
+ ### What Init means
352
+
353
+ Init is a product action — "bring what another agent already understands about me
354
+ into my memory" — not MCP initialization and not a claim to export that agent's
355
+ internal memory. Record the material actually visible in this session, its source,
356
+ conditions and gaps; a product or mode name does not establish source or coverage.
357
+ [Official documentation](https://learn.chatgpt.com/docs/customization/memories)
358
+ separates ChatGPT memory from local Codex memory, while the
359
+ user-confirmed Work-local session read local Codex material and completed Init
360
+ ([evidence and limits](init-v0.1-verification.md#work-local-evidence-2026-09-08)).
361
+ Whether that session also received cloud memory is unknown. The Core treats the submission as
362
+ untrusted agent-reported data: the maintainer receives `source_kind: "agent_import"`
363
+ with the label, basis and gaps, must keep the source nature visible in any retained
364
+ Section (for example "Imported from chatgpt-desktop on 2026-09-07 …"), must not
365
+ present it as the user's words, and must not overwrite conflicting user-stated content.
366
+ The executor enforces the hard part structurally for every import kind (`agent_import`
367
+ and `document_import` alike): imports are batched separately from user turns, and a
368
+ decision backed only by import evidence (or an evidence-free `maintain` in an import-only
369
+ batch) may append new Sections or rework Sections whose every linked source is itself an
370
+ import, but is rejected if it tries to `forget` (`UNAUTHORIZED_FORGET_EVIDENCE`), remove,
371
+ or replace a user-derived or unlinked Section (`UNAUTHORIZED_IMPORT_OVERWRITE`). A Section the user edited by hand counts as the
372
+ user's even if an import created it: its stale title links are not trusted. What the
373
+ executor cannot judge is semantic: whether an added assertion has factual support,
374
+ whether the claimed source is correct, whether a new attributed Section contradicts a
375
+ user-stated one, or whether first-person text in a file describes the user; the packaged
376
+ maintainer instructions make those the model's responsibility and require visible
377
+ attribution. Init therefore never clears existing documents or
378
+ runtime state; existing safety scanning, size limits, scope authorization, CAS, lease
379
+ fencing and recovery apply unchanged. Init does request a flush, which — like
380
+ `/memory-flush` — also lets already queued user turns be processed at the next stable
381
+ boundary. There is no preview or approval queue in the Core: the user's explicit
382
+ request plus the host's approval prompt for non-read-only tools are the confirmation,
383
+ and `memory_status.retainedIn`, `common-memory show` and the Markdown files are the
384
+ post-hoc review.
385
+
386
+ Init is enabled only when the process was launched with `--capability init` **and**
387
+ `disclosure.allowedProvenance` contains `agent_observation` (the wizard option
388
+ "Agent-reported understanding"); otherwise `memory_init` returns `INIT_DISABLED`.
389
+
390
+ ### Migrate selected, checkable material
391
+
392
+ 1. Save the original Memory Summary or legacy Saved Memories actually visible to the
393
+ account, including available dates and source references. The [Memory FAQ](https://help.openai.com/en/articles/8590148)
394
+ says the summary omits some memory and response source lists may be incomplete.
395
+ For missing topics, ask the source agent targeted questions and preserve checkable
396
+ references; leave unsupported new guesses in separate review notes.
397
+ 2. Review the selected material before submission. Preserve historical goals, dates,
398
+ conditions, tentative claims and project boundaries. Put what the agent cannot
399
+ access in gaps; “unknown” does not mean the user has no such history. Exclude this
400
+ migration's connection, import and readback status. Approval to migrate does not
401
+ make every claim true.
402
+ 3. Use `common-memory import selected.md --author agent --label "ChatGPT visible memory"`
403
+ for user-selected Markdown generated by an agent (choose the actual author class
404
+ for other material). It remains `document_import`, authorized through
405
+ `document_import` in `disclosure.allowedProvenance`. An agent's submission uses
406
+ `memory_init`, remains `agent_import`, and requires `agent_observation` authorization.
407
+ Direct quotation does not turn either import into authenticated user statements.
408
+ 4. An isolated trial is recommended: configure a separate `COMMON_MEMORY_HOME` with
409
+ `common-memory config` and verify its `dataRoot` is also a new temporary directory.
410
+ Merely changing the home while copying a production `dataRoot` does not isolate it.
411
+ Authorize the chosen scope/provenance and remote provider there, then run the
412
+ existing import and `show` commands against that configuration. For MCP, launch
413
+ the trial process with that separate configuration and verify the generated
414
+ `mcp-config` paths. Do not connect consumers to the trial store.
415
+ 5. Compare the trial result with the selected sources. Submit through the same
416
+ existing entry point to the intended destination and review **that destination's**
417
+ `common-memory show` output (with `--workspace` for a project). Check omissions,
418
+ altered conditions, scope, unknowns and new assertions. A trial cannot guarantee
419
+ identical model decisions when rerun against the destination's existing state.
420
+
421
+ The Init guidance is a **soft semantic defense**: it cannot prove provenance, prevent
422
+ all unsupported facts or semantic conflicts, or replace result review. v0.1 adds no
423
+ migration state machine, consumer pause/resume interface or Core approval queue.
424
+ There is no full-chat parser, profile generator or remote server in this workflow;
425
+ remote MCP would not itself expand the source agent's visible memory.
426
+
427
+ ### ChatGPT desktop app (init only)
428
+
429
+ The ChatGPT desktop app configures MCP servers for its Codex host in the same
430
+ `config.toml` as Codex CLI (Settings → MCP servers, or edit the file). Add an
431
+ init-only server; the host prompts before non-read-only tools:
432
+
433
+ ```toml
434
+ [mcp_servers.common_memory_init]
435
+ command = "/absolute/path/to/node"
436
+ args = ["/absolute/path/to/common-memory/dist/cli/main.js", "mcp",
437
+ "--client-id", "chatgpt-desktop", "--capability", "init", "--global"]
438
+ env = { COMMON_MEMORY_HOME = "/absolute/path/to/.common-memory" }
439
+ default_tools_approval_mode = "approve"
440
+ ```
441
+
442
+ When the desktop app runs on Windows and Common Memory lives in WSL, use the WSL bridge
443
+ described under "Windows / WSL deployment" below: run `common-memory mcp-config --wsl`
444
+ inside WSL and paste its output. It pins the distribution, Linux user, configuration
445
+ directory, dataRoot, node binary and CLI entry, so the host cannot land on another store.
446
+
447
+ Then, in a chat that can use that host's MCP servers, ask: “把本次实际可见、已选定的既有理解导入
448
+ Common Memory;保留来源、时间、条件和不确定性,列明无法访问的材料,排除本次迁移执行状态。” The agent should call `memory_init`, then `memory_status` with the same
449
+ `importId` to report what was retained. Use `common-memory show` locally to review.
450
+ ChatGPT web and the desktop **Chat** mode do not read this configuration; use the
451
+ selected Markdown workflow above for this version. A remote HTTPS connector
452
+ is outside this version and would not guarantee access to more source material.
453
+
454
+ ### ChatGPT Work local sessions and explicit refresh
455
+
456
+ Build first, then generate a reviewable bundle for the **actual agent environment**:
457
+
458
+ ```sh
459
+ # macOS agent + runtime, or agent + runtime in the same WSL environment:
460
+ common-memory work-config --mode posix --output /absolute/new/bundle
461
+ # Native Windows agent with this runtime inside WSL:
462
+ common-memory work-config --mode windows-wsl --distro Ubuntu --user linux-user \
463
+ --output /mnt/c/Users/you/common-memory-bundle \
464
+ --bridge-path 'C:\Users\you\common-memory-bundle\common-memory-bridge.ps1'
465
+ ```
466
+
467
+ Choose the mode from the agent process and its configuration directory. Terminal type
468
+ and `WSL_DISTRO_NAME` alone do not identify where the desktop agent runs. Linux POSIX
469
+ configuration validation does not establish Linux Desktop product support. The bridge
470
+ pins absolute `wsl.exe`, distro, user, Node, CLI and Common Memory home. Store its
471
+ PowerShell launcher on a Windows local path; `--bridge-path` defaults to the Windows
472
+ translation of the output path. UNC locations may require signing under
473
+ the machine's execution policy. The generator does not change that policy.
474
+
475
+ Inspect `common-memory.config.toml`, then merge it into the actual Work agent's
476
+ configuration, and install `skills/memory-refresh` in that agent's skills directory.
477
+ Use repeatable `--workspace <absolute-runtime-path>` for registered project read access.
478
+ Review and trust Hook commands through `/hooks`. Generated files never overwrite
479
+ existing files. Work gets independent read and init MCP processes. The existing
480
+ `chatgpt-desktop` import identity is preserved for retry receipts; session capture and
481
+ read use `chatgpt-work`. Ordinary Chat is outside this integration.
482
+
483
+ For Codex, `codex-config --mode posix --output /absolute/new/bundle` generates the
484
+ same explicit Skill and a profile with init disabled. The no-argument form still
485
+ prints configuration. Use `--mode windows-wsl` with the bridge options for a native
486
+ Windows Codex host. Keep Work and Codex profiles separate when sharing a config home.
487
+
488
+ `/memory-refresh` has `allow_implicit_invocation: false`. Its generated command calls
489
+ `session-refresh --home <absolute-path> --client <client>` using the host process and
490
+ `CODEX_THREAD_ID`. Missing or nonmatching identity fails; cwd alone never selects a
491
+ session. Reading and replacement are transactional: failure leaves the prior snapshot
492
+ and pending delivery intact. `PostToolUse` injects the new block, with the next
493
+ `UserPromptSubmit` as fallback. Refresh does not reset the ten-turn count or import
494
+ anything. Pi provides the same command natively and replaces its frozen system block.
495
+
496
+ A live activation survives switching away, unsubscribe/resubscribe, same-process
497
+ resume, compact, clear and reload. A real `SessionEnd` closes it and drops its snapshot;
498
+ a subsequent startup/resume creates an independent activation while the old durable
499
+ inbox and tail drain remain recoverable. New-process resume reads once. Historical
500
+ messages may retain old snapshots: the host API appends context, while the adapter
501
+ owns and replaces one active slot. See [session integration](session-integration.md)
502
+ for validation and remaining real-UI limitations.
503
+
504
+ ### Codex CLI (session hooks and read-only MCP)
505
+
506
+ For automatic injection, build Common Memory and run `common-memory codex-config`
507
+ (or `node dist/cli/main.js codex-config`). Save its stdout as
508
+ `common-memory.config.toml` under the **actual Codex CLI `CODEX_HOME`**
509
+ (default `~/.codex`). Inspect and merge any existing file with that name; do not
510
+ blindly overwrite it. The generator only prints configuration: it does not edit
511
+ base configuration, profiles or the hook trust store.
512
+
513
+ Launch `codex --profile common-memory`, then use Codex's official `/hooks` interface
514
+ to review and trust the generated commands. No trust bypass is generated.
515
+ The commands pin the current Node binary, built CLI entry and Common Memory
516
+ configuration directory as absolute, POSIX shell-quoted paths. Regenerate after
517
+ moving the installation or changing Node or `COMMON_MEMORY_HOME`.
518
+ Codex CLI and Common Memory must run in the same POSIX environment, including WSL;
519
+ macOS uses the same direct launch. For a native Windows agent with a WSL runtime, generate the bridge bundle below.
520
+
521
+ The generated synchronous hooks cover `SessionStart`, `UserPromptSubmit`, `Stop`,
522
+ `PostToolUse`, `Interrupt` and `SessionEnd`, with a three-second timeout. They use the local SQLite
523
+ FULL-synchronous durable inbox, then launch `session-drain` detached with independent
524
+ stdio. The inbox contains the transcript tail itself, so normal exit does not depend
525
+ on the transcript surviving. Consumers delete that copy only in the transaction that
526
+ admits it into the session cache. No model runs in the hook process.
527
+
528
+ Only the first qualifying `SessionStart` (`startup` or `resume`) for the process and
529
+ activation reads memory. Compact/clear/reload reattach the cached block without reading canonical files; ordinary turns do not repeat it. Startup
530
+ output remains bounded to 64 KiB and hook input to 1 MiB. Automatic snapshots are
531
+ frozen; call MCP `memory_read` for an independent current read, or explicitly invoke `/memory-refresh` to replace the frozen slot. Read failure returns
532
+ a controlled unavailable block. Ingress/protocol/capacity failures exit nonzero.
533
+
534
+ The rollout parser is isolated at `src/cli/codex/transcript-0.153.4.ts`; it accepts
535
+ only Codex CLI 0.153.4 metadata. User delivery requires `user_message` or `item_completed/UserMessage` events matching the separately recorded
536
+ UserPromptSubmit candidate for that turn, never arbitrary `response_item` user content, hook context, environment messages or
537
+ compaction summaries. `task_complete` / `turn_aborted` seal interactions. Stop starts
538
+ completion reconciliation immediately; a delayed final record needs no next prompt.
539
+ Unconfirmed completion keeps its durable watch for a later `session-drain` retry;
540
+ a reconciliation attempt is bounded to 60 seconds. Unknown formats do not advance
541
+ the cursor. Linux/WSL process identity uses boot ID, host PID and start time; native
542
+ macOS uses the host PID and process start time. The Windows bridge passes the native host PID and creation time, and converts cwd/transcript paths into the fixed WSL runtime.
543
+
544
+ Protocol reference: [official Codex hooks](https://learn.chatgpt.com/docs/hooks).
545
+ The earlier `scripts/smoke-codex-hooks.py` repeated-snapshot assertions are historical
546
+ and superseded by the session tests; they are not validation of this implementation.
547
+ Current synthetic coverage and remaining real-client gaps are recorded in
548
+ [session integration](session-integration.md). No personal data or live model
549
+ calls are needed for the tests.
550
+
551
+ MCP-only users can keep the read-only setup below; session hooks and MCP can coexist.
552
+ Hooks do not add MCP capabilities. To keep a desktop init server out of Codex, merge
553
+ `mcp_servers.common_memory_init.enabled = false` at the correct TOML table location
554
+ (or launch with `-c mcp_servers.common_memory_init.enabled=false`).
555
+
556
+
557
+ ```toml
558
+ [mcp_servers.common_memory]
559
+ command = "/absolute/path/to/node"
560
+ args = ["/absolute/path/to/common-memory/dist/cli/main.js", "mcp",
561
+ "--client-id", "codex-cli", "--capability", "read", "--global",
562
+ "--workspace", "/absolute/project/path"]
563
+ env = { COMMON_MEMORY_HOME = "/absolute/path/to/.common-memory" }
564
+ enabled_tools = ["memory_read", "memory_status"]
565
+ default_tools_approval_mode = "auto"
566
+ ```
567
+
568
+ `--workspace` is optional and must be a registered project whose `project:<id>` is in
569
+ `disclosure.allowedScopes`. The process is read-only by construction (server side) and
570
+ `enabled_tools` repeats that on the host side. If the same `config.toml` also holds the
571
+ ChatGPT init server, keep Codex CLI from seeing it with a profile file
572
+ `~/.codex/memory-reader.config.toml` containing
573
+ `mcp_servers.common_memory_init.enabled = false` and run `codex --profile
574
+ memory-reader`, or pass `-c mcp_servers.common_memory_init.enabled=false`. Disable
575
+ Codex's own local memories (`features.memories = false`) when you need to prove that
576
+ an answer came from Common Memory. `common-memory mcp-config` prints this block with the
577
+ paths of the runtime you are actually using.
578
+
579
+ ### Windows / WSL deployment
580
+
581
+ On Windows, Common Memory runs in WSL only: one configuration authority
582
+ (`COMMON_MEMORY_HOME`, default `~/.common-memory` of the Linux user), one dataRoot, one
583
+ build. PowerShell and the ChatGPT/Codex desktop app are thin bridges that start the WSL
584
+ process with `wsl.exe`; there is no Windows-native Core, second store, installer or
585
+ resident service. Different MCP processes still start per host role (`init`, `read`) and
586
+ share the data the Core manages.
587
+
588
+ Inside WSL, after `npm run build` and `common-memory config`:
589
+
590
+ ```sh
591
+ common-memory mcp-config --wsl [--workspace /home/<user>/project]
592
+ ```
593
+
594
+ prints ready-to-paste `[mcp_servers.*]` blocks of the form
595
+
596
+ ```toml
597
+ [mcp_servers.common_memory_init]
598
+ command = "wsl.exe"
599
+ args = ["-d", "Ubuntu", "-u", "<linux-user>", "-e", "/usr/bin/env",
600
+ "COMMON_MEMORY_HOME=/home/<linux-user>/.common-memory",
601
+ "/home/<linux-user>/.local/share/fnm/node-versions/v24.20.0/installation/bin/node",
602
+ "/home/<linux-user>/common-memory/dist/cli/main.js", "mcp",
603
+ "--client-id", "chatgpt-desktop", "--capability", "init", "--global"]
604
+ default_tools_approval_mode = "approve"
605
+ ```
606
+
607
+ with a header recording the distribution (`WSL_DISTRO_NAME`), Linux user, configuration
608
+ directory, dataRoot, node and CLI entry that were in effect. `-d`/`-u` fix the
609
+ distribution and user instead of relying on the WSL defaults; `-e` runs no login shell,
610
+ so `PATH` and shell profiles are unavailable and every path is absolute. Paste the blocks
611
+ into the Windows `%USERPROFILE%\.codex\config.toml` (ChatGPT desktop / Codex host). The
612
+ WSL `~/.codex/config.toml` used by Codex CLI inside WSL takes the non-`--wsl` output.
613
+ Workspaces are WSL paths registered with `common-memory project register`; a Windows path
614
+ string (`C:\...`) is not a registered project and is rejected rather than mapped. Pi is
615
+ supported when it runs inside the same WSL distribution; Windows-native Pi is not covered.
616
+ `docs/init-v0.1-verification.md` records that a read-only process launched through
617
+ `wsl.exe -d Ubuntu -u <user> -e ...` returns byte-identical `memory_read` content to a
618
+ direct launch of the same store (`tests/cli/demo-and-bridge.test.ts`, skipped off-WSL).
619
+
620
+ ### Relay (pre-existing)
621
+
622
+ Submissions are disabled unless `--accept-client-reported-user-turns` is set and
623
+ existing config permits user-expression disclosure. This flag explicitly trusts this
624
+ local host to relay user expressions: MCP cannot prove original user delivery or
625
+ faithful copying. The server records `mcp_user_submission`, never fabricates Pi
626
+ `rpc` delivery events. The flag gates new admissions, not retroactive revocation of
627
+ already accepted evidence. Only use trusted local agents belonging to the same user.
628
+
629
+ Use a distinct stable `--client-id` for each independent integration. Client identity
630
+ is a local namespace, **not authentication**. Reuse the same submission/conversation
631
+ IDs on retry, including after restart. Conflicting payloads are rejected. Without a
632
+ conversation ID, each submission has its own logical session. Two clients may use the
633
+ same IDs without colliding, but sharing a client ID deliberately shares that namespace.
634
+
635
+ Legacy relay sessions can share a same-scope/provenance batch under the existing
636
+ scheduler. Pi/Codex session batches are separate from relay/import and from each
637
+ other. The store is not a multi-tenant authorization boundary. All processes sharing a dataRoot must use the
638
+ same configuration authority and compatible release; stop old processes before upgrade.
639
+
640
+ Accepted means durably queued, not immediately committed. Background processing uses
641
+ the existing thresholds. Cancellation is best-effort; request cancellation after
642
+ admission does not retract evidence. Known SDK 2.0.0 limitation: cancellation with
643
+ JSON-RPC request ID `0` is ignored upstream (a same-tick call/cancel was reproduced);
644
+ use nonzero request IDs if cancellation-before-admission matters. No SDK patch or
645
+ request-ID compatibility shim is included in this first integration.
646
+ On EOF (all platforms) or SIGTERM (POSIX), the server queues a flush, aborts its own
647
+ Writer and closes after local cleanup. On Windows, Node's SIGTERM emulation kills
648
+ unconditionally: use stdin EOF for graceful shutdown; forced termination relies on
649
+ lease expiry and restart recovery. Pending work survives for the next Pi/MCP process
650
+ or `common-memory flush`.
651
+ Legacy relay/import shutdown does not launch a consumer. Session hooks/Pi quit do
652
+ launch an independent consumer, which may outlive both the host and MCP. Existing recovery wins over cancellation
653
+ once a durable commit has begun. Logs go to stderr; stdout is reserved for MCP.
654
+
655
+ Full runtime diagnostics, retry, flush, configuration and project management are
656
+ available in the default workbench and as CLI operations. Quotas, hot revocation,
657
+ optional-Pi packaging and broader compatibility matrices remain deferred. No personal data or live models are needed
658
+ for the MCP fake-provider protocol tests.
659
+
660
+ ## Maintenance
661
+
662
+ Canonical files:
663
+
664
+ ```text
665
+ <dataRoot>/memory/profile.md
666
+ <dataRoot>/memory/preferences.md
667
+ <dataRoot>/memory/projects/<id>.md
668
+ ```
669
+
670
+ Models receive full user turns and current authorized documents, and choose retain,
671
+ forget, maintain or ignore using `memory_maintenance_v2`. Only put/remove Section
672
+ operations are accepted; confidence is not an admission threshold. Unmodified
673
+ Sections retain their bytes. The packaged `dist/v2/memory-maintainer.md` is trusted
674
+ instruction text; document and conversation content cannot override it.
675
+
676
+ Every projected observation carries a host-assigned `source_kind`: `user_turn`
677
+ (delivered user expressions from Pi or the MCP relay), `agent_import` (an Init
678
+ submission, with `import.source_label`, `import.basis` and `import.gaps`) or
679
+ `document_import` (one part of a `common-memory import` file, with `import.source_label`,
680
+ `import.file_name`, `import.declared_author`, `import.part {index, count}` and
681
+ `import.heading_path`). The observation's stored `source` maps to one disclosure
682
+ provenance class (`user_explicit`, `agent_observation`, `document_import`); that single
683
+ mapping decides admission, batching, the import guard and authorization. A batch holds one
684
+ scope and one provenance class: user turns, agent imports and document imports never
685
+ share a batch (parts of different Markdown files may). Before any network call the Writer
686
+ checks the batch's class against `disclosure.allowedProvenance`; an unauthorized batch is
687
+ quarantined locally, one head observation per run (`UNAUTHORIZED_PROVENANCE`, like
688
+ `UNAUTHORIZED_SOURCE`), so an init-only or import-only configuration processes what it
689
+ authorizes and never discloses user turns. Import
690
+ observations may support retain with visible attribution; as sole evidence they cannot
691
+ forget, remove or replace Sections that any user turn produced (see "What Init means").
692
+ The request projection gained these fields; the response schema, receipts, database
693
+ schema and existing Markdown are unchanged and need no migration.
694
+
695
+ Scope (`global` or the current project) means applicability. Profile, Preferences and
696
+ Project Markdown are target documents, not semantic domains. The maintainer uses
697
+ non-exhaustive domains such as background/abilities, goals/learning, communication,
698
+ collaboration/decisions, technology/tools, constraints/resources and current state
699
+ as cross-document guidance, not fixed slots. It may reuse or reorganize Sections;
700
+ there is no automatic taxonomy migration and no `domain` or `memory_type` field.
701
+ Domain ≠ Admission ≠ Lifetime ≠ Scope: classification alone does not justify retention.
702
+
703
+ Runtime/database observation `scope` remains source metadata. Model observations and
704
+ context-only turns expose it as `source_scope`. Every decision requires
705
+ `applicability: "global" | "project" | "uncertain"`; global targets authorized Profile
706
+ or Preferences, project targets only the current source project's Markdown (including
707
+ project-limited personal facts/preferences), and uncertain permits only ignore.
708
+ Operations within a decision share its applicability; a batch may contain separate
709
+ decisions for different scopes. The protocol remains `memory_maintenance_v2`, but old
710
+ responses lacking applicability are rejected rather than inferred: custom model
711
+ responses must be updated. Existing Markdown, database, receipts and package exports
712
+ need no migration.
713
+
714
+ Project-source information may introduce, update, correct or qualify Global state only
715
+ through retain with remember/update/correct admission, current valid evidence and the
716
+ existing lifetime judgment. Source scope alone never promotes information. Maintain
717
+ is not promotion: it only reorganizes state already in its target document, without
718
+ introducing new information or corrections. Authorized Global maintain in a Project
719
+ batch may use `evidence: []`; any supplied evidence must be current and valid.
720
+ Retain and forget still require valid current-batch evidence, never context-only turns.
721
+
722
+ Promotion alone leaves Project Markdown unchanged. Duplicate cleanup requires an
723
+ explicit, separate Project maintain decision that preserves unrelated content, not
724
+ forget; both scopes may commit atomically. Global retention associates the current
725
+ promotion evidence, not automatically the old Project Section's historical sources.
726
+ Disclosure, writable scopes, current-project registration, authorized target/section
727
+ handles, path and content safety, complete-snapshot CAS, lease fencing and recovery
728
+ continue to gate writes; cross-project A→B writes remain forbidden.
729
+
730
+ Legacy relay/import triggers: 6 delivered expressions, 16 KiB, 120-second idle debounce, 10-minute
731
+ oldest backlog, lifecycle flush, or explicit flush. Session caches instead seal after exactly ten
732
+ settled interactions, or an actual exit tail; scheduler settings cannot override ten. Empty queues do not call models.
733
+ Request limit is 128 KiB, document soft budget 8 KiB and hard cap 16 KiB. Full turns
734
+ are never truncated; oversized turns are quarantined. Limits are configurable in
735
+ `scheduler` and disclosure `maxTotalBytes` (Writer also exposes deadline/size options).
736
+
737
+ Commits use repository lock → runtime DB transaction, lease fencing, complete-read
738
+ CAS, and recoverable Markdown + permanent immutable receipt publication. No network
739
+ runs under these locks. File-success/DB-failure recovery consumes the original batch
740
+ without another model call; unexpected user edits fail closed. Receipts contain hashes
741
+ and references, not historical Markdown or raw model responses.
742
+
743
+ Processed observation bodies are pruned after 7 days; pending/quarantined bodies
744
+ are not silently consumed. Forget clears current state and related processed bodies,
745
+ not Pi transcripts or underlying storage media, and does not prohibit future explicit
746
+ re-expression from being remembered.
747
+
748
+ ## Validation and limitations
749
+
750
+ ```sh
751
+ npm ci
752
+ node scripts/verify.mjs
753
+ # 修改包导出/消费方式时,构建后追加:
754
+ npm run test:consumer # 真实 tarball 隔离安装,需要 npm registry;不调用真实模型
755
+ npm pack --dry-run
756
+ # 隔离数据目录 + 合成维护模型:Init 与 Markdown 导入 → 本地文件 → 读取 演示(不证明真实模型语义):
757
+ npm run build && node scripts/demo-init-synthetic.mjs [--home <new-or-empty-dir>] [--markdown notes.md]
758
+ # 构建后验证 smoke 自身的 Responses / Chat 流程(本地 fake Provider,无需 Key):
759
+ npm run test:provider-smoke
760
+ # 真实 Provider:使用现有格式的配置副本,仅复制 remote;Key 来自进程环境:
761
+ node scripts/smoke-provider.mjs --config /path/to/provider-config.json --live
762
+ ```
763
+
764
+ The provider smoke requires an explicit `remote.proxy` mode, uses fresh temporary
765
+ storage, and checks source-linked durable receipts plus restarted reads. A processed
766
+ `ignore` does not pass retention. See [the procedure and evidence levels](provider-verification.md)
767
+ for network conditions, reports, and the retained DeepSeek entry point.
768
+
769
+ The demo only writes into a fresh directory (a new temp directory by default); it refuses
770
+ a non-empty `--home` and never deletes or overwrites an existing configuration, `.env` or
771
+ data directory. It prints the Codex/Pi/`show`/`mcp-config` invocations for its data
772
+ directory. Real ChatGPT desktop, Codex CLI and Pi sessions are recorded separately in
773
+ `docs/init-v0.1-verification.md`, which distinguishes synthetic tests, real client
774
+ protocol/host integration, and the real end-to-end loop.
775
+
776
+ ### Reading limitations
777
+
778
+ Reads are lock-free file reads of atomically published Markdown; a crash between
779
+ staging and publication is repaired by the next Writer start, so a read-only process
780
+ can briefly see the previous published state. Reads never migrate, repair or create
781
+ canonical files. Consumers receive whole documents; only the Writer bounds their size.
782
+ The `instructions`/description text asks consumers to use memory for questions about
783
+ the user; whether a given client model actually calls `memory_read` for a given
784
+ question is client behaviour, not something this server can enforce.
785
+
786
+ Tests use scripted model responses to prove protocol, capture, scheduling and commit
787
+ behavior; they do not prove that a real model will classify scope correctly or avoid
788
+ misusing maintain for state changes. Those semantic judgments remain the model's
789
+ responsibility; the executor does not use text-comparison heuristics to infer them. Real-provider evaluation
790
+ requires explicit credentials and budget and is not run automatically. Transformed
791
+ inputs are conservatively quarantined; session assistant/tool context requires
792
+ independent `conversation_context` disclosure permission. No old user data directory is cleaned.
793
+
794
+ ### Capture trust boundary
795
+
796
+ Pi does not expose an end-to-end original-input token. Common Memory validates the
797
+ input event it receives; an earlier extension can transform text before that event
798
+ reaches this extension, which is not distinguishable through the public API. Place
799
+ Common Memory before input-transforming extensions and treat earlier extensions as
800
+ trusted host components. Transformations after its capture (including built-in prompt
801
+ templates), mixed queued authorities/scopes and ambiguous candidates are isolated.
802
+ This is conservative host-event provenance, not proof against a malicious extension.
803
+ Mixed/image input is quarantined with complete text and an unsupported-content marker;
804
+ image blobs are not collected. Session assistant/tool and prior-turn context is
805
+ marked context_only and never authorizes a write. The default context tail is two
806
+ same-session/scope turns, resolved by reference; forget/prune clears related context.
807
+
808
+ Manual edits to a document invalidate its title-based source links. On the next
809
+ committed maintenance, its stale links and associated processed observation bodies
810
+ are conservatively cleared in the recoverable receipt; current Markdown and other
811
+ documents are not deleted. This avoids retaining orphan evidence after a manual
812
+ rename followed by forget, at the cost of that document's short-term evidence buffer.
813
+ Advanced library configuration exposes `documentSoftBytes`, `documentHardBytes`,
814
+ `retentionMs`, `deadlineMs` and `maxRequestBytes` on Writer. Pi compatibility is pinned
815
+ to 0.84.4, whose callback/queue ordering was inspected for this implementation.