mlx-bun 0.2.0 → 0.3.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 (364) hide show
  1. package/README.md +71 -588
  2. package/docs/README.md +91 -0
  3. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  4. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  5. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  6. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  7. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  8. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  9. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  10. package/docs/design/batching.md +569 -0
  11. package/docs/design/decode-speed-program.md +3178 -169
  12. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  13. package/docs/design/generic-model-support.md +579 -334
  14. package/docs/design/kv-cache.md +680 -0
  15. package/docs/design/orpo-training.md +673 -1239
  16. package/docs/design/speculative-decoding.md +1627 -0
  17. package/docs/design/turboquant.md +2102 -0
  18. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  19. package/docs/design/web-chat-redesign.md +666 -1083
  20. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  21. package/docs/planning/release-notes-v0.3.0.md +35 -0
  22. package/docs/planning/video-series.md +2 -2
  23. package/docs/reference/benchmarks.md +1162 -0
  24. package/docs/reference/cli.md +394 -159
  25. package/docs/reference/distribution.md +321 -182
  26. package/docs/reference/environment.md +348 -0
  27. package/docs/reference/glossary.md +39 -0
  28. package/docs/reference/library-api.md +566 -168
  29. package/docs/reference/memory.md +227 -64
  30. package/docs/reference/models.md +104 -6
  31. package/docs/reference/server-api.md +886 -425
  32. package/docs/reference/server-config.md +638 -330
  33. package/docs/reference/training.md +393 -254
  34. package/docs/reference/troubleshooting.md +166 -0
  35. package/package.json +9 -4
  36. package/src/audio/decode.ts +2 -2
  37. package/src/audio/features.ts +2 -2
  38. package/src/backends/mlx/autoregressive.ts +108 -0
  39. package/src/backends/mlx/batch-group.ts +1646 -0
  40. package/src/backends/mlx/diffusion.ts +39 -0
  41. package/src/backends/mlx/draft-target.ts +47 -0
  42. package/src/backends/mlx/evaluation.ts +105 -0
  43. package/src/backends/mlx/fill-append.ts +45 -0
  44. package/src/backends/mlx/gateway-binding.ts +71 -0
  45. package/src/backends/mlx/graph.ts +38 -0
  46. package/src/backends/mlx/memory-client.ts +189 -0
  47. package/src/backends/mlx/memory-guard.ts +40 -0
  48. package/src/backends/mlx/methods.ts +90 -0
  49. package/src/backends/mlx/model-prompt.ts +164 -0
  50. package/src/backends/mlx/model-serving.ts +79 -0
  51. package/src/backends/mlx/prefill.ts +33 -0
  52. package/src/backends/mlx/request-policy.ts +20 -0
  53. package/src/backends/mlx/rollback.ts +51 -0
  54. package/src/backends/mlx/serial-executor.ts +273 -0
  55. package/src/backends/mlx/speculative.ts +114 -0
  56. package/src/backends/mlx/state-views.ts +26 -0
  57. package/src/backends/mlx/text-engine.ts +73 -0
  58. package/src/cli.ts +58 -25
  59. package/src/client.ts +66 -0
  60. package/src/config.ts +21 -4
  61. package/src/contracts/completion.ts +16 -0
  62. package/src/contracts/execution.ts +49 -0
  63. package/src/contracts/generation.ts +103 -0
  64. package/src/contracts/host.ts +7 -0
  65. package/src/contracts/jobs.ts +66 -0
  66. package/src/contracts/pi-provider.ts +30 -0
  67. package/src/contracts/pi.ts +259 -0
  68. package/src/contracts/resources.ts +18 -0
  69. package/src/contracts/scheduling.ts +27 -0
  70. package/src/contracts/tsconfig.json +14 -0
  71. package/src/diffusion/diffusion-generate.ts +218 -153
  72. package/src/embed.ts +1 -1
  73. package/src/engine/admission.ts +59 -0
  74. package/src/engine/cancellation.ts +38 -0
  75. package/src/engine/engine.ts +56 -0
  76. package/src/engine/execution-coordinator.ts +70 -0
  77. package/src/engine/execution-plan.ts +51 -0
  78. package/src/engine/resources.ts +42 -0
  79. package/src/engine/scheduler.ts +67 -0
  80. package/src/engine/session.ts +247 -0
  81. package/src/eval/README.md +44 -1
  82. package/src/eval/kl.ts +236 -3
  83. package/src/eval/reference-logits.ts +207 -0
  84. package/src/eval/runner.ts +8 -96
  85. package/src/fill/echo-index.ts +188 -0
  86. package/src/fill/fill-session.ts +452 -0
  87. package/src/fill/proposal.ts +68 -0
  88. package/src/fill/schema-rows.ts +506 -0
  89. package/src/fill/tool-boundary.ts +103 -0
  90. package/src/fit.ts +1 -1
  91. package/src/generate.ts +656 -268
  92. package/src/grammar.ts +12 -7
  93. package/src/harness-pi.ts +14 -33
  94. package/src/hub-rest.ts +4 -4
  95. package/src/index.ts +7 -0
  96. package/src/inference/denoising.ts +17 -0
  97. package/src/inference/graph.ts +33 -0
  98. package/src/inference/prefill.ts +39 -0
  99. package/src/inference/rollback.ts +7 -0
  100. package/src/jobs/db.ts +4 -0
  101. package/src/jobs/index.ts +2 -0
  102. package/src/jobs/job-entry.ts +12 -12
  103. package/src/jobs/runner.ts +98 -13
  104. package/src/jobs/task-client.ts +19 -0
  105. package/src/jobs/types.ts +2 -58
  106. package/src/kv-store.ts +109 -49
  107. package/src/lab/README.md +18 -0
  108. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  109. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  110. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +5 -5
  111. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  112. package/src/library.ts +40 -0
  113. package/src/lora.ts +18 -0
  114. package/src/media-fetch.ts +1 -1
  115. package/src/memory/article.ts +1 -1
  116. package/src/memory/chunk.ts +1 -1
  117. package/src/memory/model.ts +30 -169
  118. package/src/memory/prompts.ts +1 -1
  119. package/src/memory/rest.ts +1 -1
  120. package/src/memory/schedule.ts +1 -1
  121. package/src/memory/stages.ts +4 -1
  122. package/src/memory/vault.ts +1 -3
  123. package/src/mlx/array.ts +9 -10
  124. package/src/mlx/compile.ts +12 -2
  125. package/src/mlx/ffi.ts +58 -11
  126. package/src/mlx/materialize.ts +23 -0
  127. package/src/mlx/metal-kernel.ts +10 -11
  128. package/src/mlx/ops.ts +33 -13
  129. package/src/mlx/quantized-rows.ts +36 -0
  130. package/src/mlx/token-bitmask.ts +52 -0
  131. package/src/mlx/turboquant-kv-decode.ts +82 -0
  132. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  133. package/src/mlx/turboquant-ops.ts +33 -3
  134. package/src/mlx/turboquant-tables.ts +2 -2
  135. package/src/model/batched-mask.ts +8 -2
  136. package/src/model/batched-quant.ts +1 -1
  137. package/src/model/batched-rotating-quant.ts +2 -2
  138. package/src/model/batched-rotating.ts +1 -1
  139. package/src/model/compiled-decode.ts +1 -1
  140. package/src/model/diffusion-gemma.ts +8 -8
  141. package/src/model/factory.ts +76 -33
  142. package/src/model/fingerprint.ts +1 -1
  143. package/src/model/flash-attention.ts +3 -3
  144. package/src/model/gemma4-base.ts +26 -9
  145. package/src/model/gemma4.ts +6 -6
  146. package/src/model/generated/gemma4-12b.ts +2 -2
  147. package/src/model/generated/gemma4-26b.ts +2 -2
  148. package/src/model/generated/gemma4-e4b.ts +2 -2
  149. package/src/model/glm52-dsa.ts +13 -9
  150. package/src/model/glm52-memory.ts +1 -1
  151. package/src/model/implementation.ts +69 -0
  152. package/src/model/minicpm5.ts +6 -8
  153. package/src/model/profile.ts +12 -2
  154. package/src/model/qwen-append.ts +12 -0
  155. package/src/model/qwen-conv.ts +52 -0
  156. package/src/model/qwen3_5-checkpoint.ts +164 -0
  157. package/src/model/qwen3_5.ts +140 -56
  158. package/src/model/support.ts +1 -1
  159. package/src/model/trellis-balanced-scatter.ts +51 -0
  160. package/src/model/trellis-linear.ts +672 -0
  161. package/src/model/trellis-shared-m.ts +151 -0
  162. package/src/model/trellis-shared-scatter.ts +144 -0
  163. package/src/model/trellis-splitk-prefill.ts +158 -0
  164. package/src/model/trellis-tiled-prefill.ts +136 -0
  165. package/src/model/trellis-vector-expand.ts +62 -0
  166. package/src/model/trellis-wide-prefill.ts +94 -0
  167. package/src/model/universal/dense.ts +1 -1
  168. package/src/model/universal/modules.ts +8 -1
  169. package/src/native-pack.ts +6 -5
  170. package/src/pi-provider.ts +6 -64
  171. package/src/pi-web.ts +8 -315
  172. package/src/prompt-cache.ts +96 -53
  173. package/src/quantize/allocator.ts +1 -1
  174. package/src/quantize/config-writer.ts +10 -3
  175. package/src/quantize/rotate.ts +4 -4
  176. package/src/quantize/trellis.ts +586 -0
  177. package/src/responses.ts +28 -1
  178. package/src/runtime-config.ts +18 -4
  179. package/src/sampler.ts +4 -4
  180. package/src/serve/batch-scheduler.ts +8 -1671
  181. package/src/serve/chat-request.ts +391 -0
  182. package/src/serve/chat-stage.ts +195 -0
  183. package/src/serve/checkpoint-identity.ts +64 -0
  184. package/src/serve/completion-executor.ts +15 -7
  185. package/src/serve/discovery-routes.ts +12 -13
  186. package/src/serve/generation-gateway.ts +154 -193
  187. package/src/serve/http.ts +159 -0
  188. package/src/serve/inference-request.ts +79 -0
  189. package/src/serve/isolate.ts +297 -105
  190. package/src/serve/lab-routes.ts +3 -0
  191. package/src/serve/lane-registry.ts +2 -1
  192. package/src/serve/model-admin-routes.ts +7 -5
  193. package/src/serve/model-binding.ts +43 -0
  194. package/src/serve/model-host.ts +512 -0
  195. package/src/serve/openai-wire.ts +103 -0
  196. package/src/serve/parent-application.ts +56 -0
  197. package/src/serve/pipeline.ts +33 -0
  198. package/src/serve/preparation.ts +33 -0
  199. package/src/serve/request-plan.ts +19 -15
  200. package/src/serve/request-prep.ts +346 -0
  201. package/src/serve/response-lease.ts +24 -0
  202. package/src/serve/responses-client.ts +69 -0
  203. package/src/serve/session-completion-engine.ts +110 -0
  204. package/src/serve/session-search.ts +1 -1
  205. package/src/serve/static-routes.ts +5 -5
  206. package/src/serve/text-completion-stage.ts +104 -0
  207. package/src/serve/token-streams.ts +519 -0
  208. package/src/server.ts +317 -2649
  209. package/src/spec/assistant-source.ts +10 -44
  210. package/src/spec/deepspec-source.ts +6 -6
  211. package/src/spec/dflash-source.ts +8 -8
  212. package/src/spec/dspark/ab-stats.ts +3 -3
  213. package/src/spec/dspark/calibration.ts +2 -2
  214. package/src/spec/dspark/deepspec-module.ts +2 -2
  215. package/src/spec/dspark/generate-dflash.ts +2 -2
  216. package/src/spec/dspark/generate.ts +2 -2
  217. package/src/spec/dspark/loader.ts +1 -1
  218. package/src/spec/dspark/module-dflash.ts +4 -3
  219. package/src/spec/dspark/module.ts +3 -3
  220. package/src/spec/dspark/quantize-drafter.ts +1 -1
  221. package/src/spec/generate.ts +1 -1
  222. package/src/spec/glm52-mtp-source.ts +1 -1
  223. package/src/spec/ngram-source.ts +1 -1
  224. package/src/spec/prefix-state.ts +45 -0
  225. package/src/spec/qwen-mtp-source.ts +166 -69
  226. package/src/spec/serve-loop.ts +154 -156
  227. package/src/spec/source.ts +42 -10
  228. package/src/spec/two-model.ts +1 -1
  229. package/src/ssd-cache.ts +80 -12
  230. package/src/ssd-durability.ts +25 -13
  231. package/src/tool-call.ts +51 -14
  232. package/src/train/flash-cce.ts +2 -2
  233. package/src/train/forward.ts +6 -0
  234. package/src/train/loss.ts +1 -1
  235. package/src/train/prefix-shared.ts +5 -1
  236. package/src/train/segmented.ts +5 -3
  237. package/src/train/trainer.ts +6 -6
  238. package/src/vision/prompt.ts +1 -1
  239. package/src/vision/qwen3vl-tower.ts +52 -10
  240. package/src/web/app.html +1 -1
  241. package/src/web/app.js +5 -3
  242. package/src/web/src/adapters-panel.ts +3 -3
  243. package/src/web/src/assistant.ts +2 -36
  244. package/src/web/src/chat.ts +4 -4
  245. package/src/web/src/composer.ts +4 -4
  246. package/src/web/src/hub.ts +1 -1
  247. package/src/web/src/markdown.ts +0 -0
  248. package/src/web/src/memory-panel.ts +1 -1
  249. package/src/web/src/model-picker.ts +1 -1
  250. package/src/web/src/palette.ts +1 -1
  251. package/src/web/src/protocol.ts +3 -39
  252. package/src/web/src/sessions.ts +1 -1
  253. package/src/web/src/ui-catalog.ts +4 -18
  254. package/src/web-assets.ts +47 -0
  255. package/src/weights.ts +55 -9
  256. package/docs/archive/investigations/curve-runs/bisector-route.json +0 -98
  257. package/docs/archive/investigations/curve-runs/bisector-trace.json +0 -1393
  258. package/docs/archive/investigations/curve-runs/curve-terrain.json +0 -1179
  259. package/docs/archive/investigations/curve-runs/curve-terrain.svg +0 -42
  260. package/docs/archive/investigations/hlg-ab.html +0 -34
  261. package/docs/archive/investigations/hlg-explorer.html +0 -238
  262. package/docs/archive/investigations/hlg-figs/cliff.svg +0 -1
  263. package/docs/archive/investigations/hlg-figs/cross.svg +0 -1
  264. package/docs/archive/investigations/hlg-figs/edges.svg +0 -1
  265. package/docs/archive/investigations/hlg-figs/k20-grids.svg +0 -1
  266. package/docs/archive/investigations/hlg-figs/k20-peaks.svg +0 -1
  267. package/docs/archive/investigations/hlg-figs/lw-curve.svg +0 -1
  268. package/docs/archive/investigations/hlg-figs/terrain.svg +0 -1
  269. package/docs/archive/investigations/hlg-report.html +0 -262
  270. package/docs/archive/investigations/hlg-runs/hlg-ab.json +0 -149
  271. package/docs/archive/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  272. package/docs/archive/investigations/hlg-runs/hlg-blind.json +0 -107
  273. package/docs/archive/investigations/hlg-runs/hlg-cliff.json +0 -197
  274. package/docs/archive/investigations/hlg-runs/hlg-cross.json +0 -505
  275. package/docs/archive/investigations/hlg-runs/hlg-edge.json +0 -388
  276. package/docs/archive/investigations/hlg-runs/hlg-eval1.json +0 -25
  277. package/docs/archive/investigations/hlg-runs/hlg-frontier.json +0 -86
  278. package/docs/archive/investigations/hlg-runs/hlg-grid.json +0 -242
  279. package/docs/archive/investigations/hlg-runs/hlg-grid2.json +0 -343
  280. package/docs/archive/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  281. package/docs/archive/investigations/hlg-runs/hlg-map.json +0 -383
  282. package/docs/archive/investigations/hlg-runs/run0-original.log +0 -159
  283. package/docs/archive/investigations/hlg-runs/runA-recommended.log +0 -131
  284. package/docs/archive/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  285. package/docs/archive/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  286. package/docs/archive/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  287. package/docs/archive/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  288. package/docs/archive/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  289. package/docs/archive/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  290. package/docs/archive/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  291. package/docs/archive/investigations/hlg-runs/runB-gain-variants.log +0 -192
  292. package/docs/archive/investigations/hlg-runs/runC-pivots.log +0 -162
  293. package/docs/archive/investigations/hlg-runs/runD-oetf.log +0 -132
  294. package/docs/archive/investigations/hlg-runs/runE-eotf.log +0 -162
  295. package/docs/archive/investigations/hlg-runs/runF-shaper-working.log +0 -86
  296. package/docs/archive/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  297. package/docs/archive/investigations/hlg-runs/runH-wsweep.log +0 -176
  298. package/docs/archive/investigations/hlg-runs/runI-asweep.log +0 -176
  299. package/docs/archive/investigations/hlg-runs/runJ-knobmap.log +0 -49
  300. package/docs/archive/investigations/hlg-runs/runK-frontier.log +0 -19
  301. package/docs/archive/investigations/hlg-runs/runL-widemap.log +0 -65
  302. package/docs/archive/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  303. package/docs/archive/investigations/hlg-runs/runN-verify.log +0 -116
  304. package/docs/archive/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  305. package/docs/archive/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  306. package/docs/archive/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  307. package/docs/archive/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  308. package/docs/archive/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  309. package/docs/archive/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  310. package/docs/archive/investigations/hlg-runs/runU-cross-12b.log +0 -33
  311. package/docs/archive/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  312. package/docs/archive/investigations/hlg-runs/runW-lw-12b.log +0 -22
  313. package/docs/archive/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  314. package/docs/archive/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  315. package/docs/archive/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  316. package/docs/archive/mlx-bun-lab-report.html +0 -275
  317. package/docs/archive/wwdc-mlx-bun.html +0 -848
  318. package/docs/design/adapters-end-to-end.md +0 -205
  319. package/docs/design/batching-perf-path.md +0 -255
  320. package/docs/design/batching-v2-plan.md +0 -529
  321. package/docs/design/bucketing-stage.md +0 -197
  322. package/docs/design/compat-cli-surface-design.md +0 -230
  323. package/docs/design/docs-reorg-plan.md +0 -165
  324. package/docs/design/dspark-serving-program.md +0 -371
  325. package/docs/design/dspark-speculative-decoding.md +0 -318
  326. package/docs/design/grammar-spec-batching-integration.md +0 -301
  327. package/docs/design/memory-inference-path.md +0 -422
  328. package/docs/design/memory-synthesis.md +0 -287
  329. package/docs/design/memory-system.md +0 -237
  330. package/docs/design/mlx-lm-serving-execution-seam.md +0 -81
  331. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  332. package/docs/design/omlx-adoption-map.md +0 -98
  333. package/docs/design/orpo-dynamic-lambda.md +0 -220
  334. package/docs/design/orpo-future-enhancements.md +0 -340
  335. package/docs/design/paged-kv-cache.md +0 -214
  336. package/docs/design/parallel-slots.md +0 -567
  337. package/docs/design/parity-tier-dag.md +0 -161
  338. package/docs/design/repo-cleanup-plan.md +0 -231
  339. package/docs/design/runtime-isolation.md +0 -263
  340. package/docs/design/segmented-backward-training.md +0 -543
  341. package/docs/design/spec-decode-larger-targets.md +0 -229
  342. package/docs/design/ssd-kv-cold-tier.md +0 -415
  343. package/docs/design/structured-output.md +0 -484
  344. package/docs/design/tauri-desktop-app.md +0 -127
  345. package/docs/design/the-dreaming-master-plan.md +0 -445
  346. package/docs/design/turboquant-kv.md +0 -235
  347. package/docs/design/turboquant-weights.md +0 -467
  348. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  349. package/docs/design/web-chat-beat-matrix.md +0 -315
  350. package/docs/design/write-pipeline-entity.md +0 -468
  351. package/docs/planning/IDEAS.md +0 -69
  352. package/docs/reference/embedding.md +0 -197
  353. package/docs/reference/features-matrix.md +0 -101
  354. package/docs/reference/orpo-quickstart.md +0 -135
  355. package/src/flags.ts +0 -11
  356. /package/docs/{design → archive/investigations}/colibri-glm52-port.md +0 -0
  357. /package/docs/{planning → archive/planning}/chunk-task-roadmap.md +0 -0
  358. /package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +0 -0
  359. /package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +0 -0
  360. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  361. /package/docs/{planning → archive/planning}/release-notes-v0.2.0.md +0 -0
  362. /package/src/{memory-plan.ts → admission-plan.ts} +0 -0
  363. /package/{docs/archive/investigations → src/serve/assets}/curve-terrain.html +0 -0
  364. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -1,287 +0,0 @@
1
- # Memory synthesis — the local Morpheus (M1 design)
2
-
3
- > **SUPERSEDED (2026-07-01)** by
4
- > [dreaming-nightly-pipeline.md](./dreaming-nightly-pipeline.md). Kept for
5
- > history. Known-dead parts: embedding-based section-routing and silhouette
6
- > signals (**no embeddings anywhere in the project**), bucket-as-optional
7
- > framing, and the periodic-only wikify (RECONCILE/LINK/infobox are nightly
8
- > stages now).
9
-
10
- Status: **design**, 2026-06-26. Companion to [memory-system.md](./memory-system.md)
11
- (the M0 substrate: vault, read tools, CLI, scheduling — all landed). This doc is
12
- the M1 design for the **write side**: the synthesis pipeline that turns raw
13
- conversations into well-formed wiki articles, **on local models**.
14
-
15
- The inspiration and proof-of-concept is Lucien / The Dreaming / Morpheus
16
- (`../lucien`) — it works, but every stage runs on a cloud model (`claude --model
17
- opus`, `pi`). The whole point of M1 is to keep every learning from Lucien and
18
- **solve the cost by running the pipeline locally**, using one local base model +
19
- a per-stage LoRA adapter trained from Lucien's corpus (the e4b chunk adapter is
20
- the first of these — designed components of the appliance, each distilled from
21
- the cloud pipeline's gold output).
22
-
23
- Guiding principle, inherited verbatim from Lucien: **do whatever Wikipedia does.**
24
- Wikipedia turned a crowd of strangers into the largest organized, continuously-
25
- updated knowledge base ever built. We are not going to out-design it — we copy
26
- its conventions (articles, sections, talk pages, citations, wikilinks, edit
27
- history) and supply the per-edit labor with local models instead of volunteers.
28
-
29
- And the division of labor is fixed: **AI does the judgment; deterministic code
30
- enforces the invariants we can't trust AI on** (footnote bijection, wikilink
31
- canonicalization, the conservative write gate).
32
-
33
- ## Current state: ZERO articles
34
-
35
- The vault starts empty. So the pipeline has to handle the **creation flow**, not
36
- just steady-state updates — most of the early design discussion assumed an
37
- existing structured article to patch; from zero there is nothing to patch yet.
38
- The two flows are genuinely different operations and the doc treats them
39
- separately below.
40
-
41
- ## The pipeline (DAG)
42
-
43
- ```
44
- WRITE · the local Morpheus (what `mlx-bun memory synthesize` runs)
45
- ══════════════════════════════════════════════════════════════════
46
-
47
- conversation transcripts (ingest, by cursor)
48
- │
49
- ▼ CHUNK ································· local model + chunk LoRA [e4b ✓]
50
- single-topic (segment + label)
51
- │
52
- ▼ FILTER — worth keeping? ──no──▶ drop
53
- │ yes
54
- ▼ CLASSIFY → bucket(s) many-to-many ──no fit──▶ drop
55
- │ bucket ≈ article; from zero, buckets are PROPOSED (taxonomy emerges)
56
- ▼ SYNTHESIZE ······························ local model + synth LoRA
57
- │ ├─ article does NOT exist → CREATE (sub-cluster → outline → per-section draft)
58
- │ └─ article EXISTS → UPDATE (SECTION-ROUTE → PATCH one section)
59
- │ + conservative write gate (≥70% prose floor, every citation survives, weak → NO-OP)
60
- ▼
61
- article written / one section changed (rest byte-identical)
62
- │
63
- ▼ NORMALIZE (deterministic code, not a model)
64
- │ footnote renumber/repair · wikilink canonicalize
65
- ▼
66
- ▼ WIKIFY (periodic, local model + wikify LoRA) ◀── distinct LLM node
67
- │ "make this a BETTER version" — per-section improve + structural pass
68
- └──▶ Talk-page signals (embedding/silhouette): SPLIT · MERGE · CONTRADICTION
69
-
70
-
71
- READ · any chat agent (M0, landed; read-only via memory_* tools)
72
- ══════════════════════════════════════════════════════════════════
73
- question ─▶ search / toc ─▶ read section · follow [[links]] ─▶ reason ─▶ answer
74
- ```
75
-
76
- ```mermaid
77
- flowchart TD
78
- T[conversation transcripts] --> C["CHUNK · local+LoRA"]
79
- C -->|segment+label| F{worth keeping?}
80
- F -->|no| D1((drop))
81
- F -->|yes| CL["CLASSIFY → bucket(s)"]
82
- CL -->|no fit| D2((drop))
83
- CL --> EX{article exists?}
84
- EX -->|no| CR["CREATE: sub-cluster → outline → per-section draft"]
85
- EX -->|yes| UP["UPDATE: section-route → patch one section"]
86
- CR --> GATE["conservative write gate"]
87
- UP --> GATE
88
- GATE --> NORM["NORMALIZE footnotes + wikilinks · deterministic"]
89
- NORM --> WK["WIKIFY periodic · per-section improve + structural pass"]
90
- WK -->|talk-page| SIG["SPLIT · MERGE · CONTRADICTION"]
91
- ```
92
-
93
- ## The two synthesis flows
94
-
95
- ### CREATE (cold-start / bootstrap — the zero-article case)
96
-
97
- Trigger: a bucket has accumulated enough chunks (≥N, conservative) and has **no
98
- article file yet**. Naively this is whole-article generation from a pile of
99
- chunks — exactly the open-ended task a small local model is *worst* at. So we
100
- decompose it the same way we decompose updates — **section-granular**:
101
-
102
- 1. **Sub-cluster** the bucket's chunks into proto-sections (cluster the chunks
103
- *within* the bucket — the cohesion/embedding machinery applies one level down;
104
- silhouette is a strong cohesion signal, ρ≈0.68 vs the judges).
105
- 2. **Outline** — name each section from its sub-cluster, write the lead. A small
106
- structural task, not long-form prose.
107
- 3. **Draft each section** by synthesizing only its sub-cluster's chunks — the
108
- *same bounded per-section operation* as a patch, just starting from empty.
109
- 4. **Assemble** → article with `# Title`, lead, sections, `## References`, TOC.
110
-
111
- So even creation never asks the model to hold a whole article in its head: it's
112
- sub-cluster → outline → N bounded section drafts. Conservative bootstrap bias:
113
- **under-cover rather than over-cover** — thin buckets stay `{{stub}}` or wait for
114
- more material (Lucien's lesson: twenty good articles beat a sprawling mediocre
115
- set).
116
-
117
- ### UPDATE (steady state — article exists)
118
-
119
- 1. **SECTION-ROUTE** the new chunk to the section(s) it affects, via the TOC —
120
- "this topic affects THESE sections" (e.g. a Reflecting-Pool-renovation chunk →
121
- the *Renovation* section, and possibly an *Abuse-of-Power* section of a Trump
122
- article). Many-to-many at section granularity. If it fits no existing section,
123
- the route is "new section."
124
- 2. **PATCH** just that section: hand the model the section text + the chunk, ask
125
- it to weave the chunk in with a `[^N]` citation. Bounded in, bounded out.
126
- Facet extraction is implicit — the same chunk becomes the renovation facts in
127
- one section and the no-bid-contract framing in another, because the model
128
- writes what's relevant to the section it's editing.
129
- 3. **Everything else stays byte-identical** — only the routed section is rewritten.
130
-
131
- Both flows share the **conservative write gate** (already specced in
132
- `synthesize.ts`): preserve prose, ≥70% word-count floor, every original `conv:`
133
- citation survives, integrate-not-overwrite; a weak local pass is gated to NO-OP
134
- rather than allowed to corrupt the vault.
135
-
136
- ## Why WIKIFY is its own (necessary) node
137
-
138
- Section-patches are greedy and local. Over many of them an article accumulates
139
- cruft: a section sprawls, sentences go redundant, the lead goes stale, section
140
- order drifts. **Wikify is the periodic global pass that keeps the article *good*
141
- — "how do I turn this into a better version of this article" — and it is
142
- necessary; without it you just keep bolting things on.** This is the LLM
143
- editorial-restructure (Lucien's "Editorial restructure" commits), *distinct from*
144
- the deterministic footnote/wikilink normalize that the current `wikify.ts` stub
145
- conflates it with.
146
-
147
- Structure makes even this global pass decompose toward local: wikify can run
148
- **per-section "improve this section"** + a **cheap structural pass over the TOC**
149
- (reorder, fix the lead, re-section, emit split/merge signals) instead of one
150
- whole-article regeneration. So wikify is local-tractable for the same reason
151
- synthesis is: sections.
152
-
153
- ## Data model — pointers, not copies
154
-
155
- The SQLite store (`~/.cache/mlx-bun/memory.sqlite`) is **derived, rebuildable**
156
- state — not the source of truth. The principle that keeps it lean and consistent:
157
- **materialize text in exactly one place; everything else points.**
158
-
159
- - **Messages hold the text, once.** A `messages` table (text per message), keyed
160
- by `(conv, position)`.
161
- - **A chunk is a pointer range, not a copy.** `chunks(id, conv, start, end, label)`
162
- — a segmentation is *where the boundaries are*, so storing it as a message range
163
- + label is the natural representation. Synthesis *dereferences* to message text
164
- only when it reads a chunk. Re-chunking rewrites pointer rows, never text.
165
- - **Assignments are join tables (many-to-many).** `chunk_buckets(chunk_id,
166
- bucket_name)` and, for the section design, `chunk_sections(chunk_id, article,
167
- section_anchor)` — "this chunk affects THESE sections of THESE articles."
168
- - **The article markdown is the only materialized synthesis.** Its `[^N]:
169
- conv:HASH` citations are themselves *pointers back to source conversations*, not
170
- copies. The vault is the precious git-tracked truth for *articles*; the DB is the
171
- rebuildable index for *pipeline state*.
172
-
173
- **The current `db.ts` stub violates this and must be fixed for M1** (it mirrors a
174
- naive copy design, not Lucien's pointer design):
175
- - `conversations.transcript` stores the whole transcript blob AND `chunks.text`
176
- copies each slice → the same text twice. Replace with a `messages` table +
177
- pointer `chunks` (drop `chunks.text`).
178
- - `chunks.bucket TEXT` is one-bucket-per-chunk → breaks many-to-many. Replace with
179
- `chunk_buckets`. Add `chunk_sections` for the section-route output.
180
- - `synthesized_bucket_chunks` → `synthesized_chunk_sections(article, section_anchor,
181
- chunk_id, synthesized_at)` so the patch ledger is per-section (fold each chunk
182
- into each section exactly once).
183
-
184
- Target tables: `messages` · `chunks` (pointers) · `conversations` · `buckets` ·
185
- `chunk_buckets` · `chunk_sections` · `synthesized_chunk_sections` · `watermarks`.
186
-
187
- ### Engine: bun:sqlite now, Turso swappable (for vectors)
188
-
189
- Build M1 on **`bun:sqlite`** — native to Bun, zero-dependency, synchronous, the
190
- most battle-tested DB there is, and already the project's pattern (`JobStore`,
191
- `EvalDB`, `registry`, `MemoryStore`). No reason to pay friction on day one.
192
-
193
- **Turso** (the current product — a from-scratch Rust rewrite of SQLite that is
194
- *embedded / on-device / offline / SQLite-compatible*, NOT the old cloud-sync
195
- product) is the evaluation path. Its one concrete payoff for us is **native vector
196
- search** — and this design is embedding-heavy (section-routing, semantic article
197
- search, the silhouette signals). Reasons to defer rather than adopt now: it's a
198
- young engine vs C SQLite, and the Bun-integration story (native binding vs
199
- FFI/overhead) needs checking.
200
-
201
- The decision is cheap to defer because (a) Turso is SQLite-*compatible* so the
202
- schema/SQL above is identical either way, (b) `MemoryStore` already wraps the DB
203
- behind a small class, so it's a driver swap not a rewrite, and (c) this DB is a
204
- **rebuildable cache** (truth = vault + git), so it's a low-risk place to adopt a
205
- younger engine. Plan: keep the SQL standard, keep the driver swappable, and switch
206
- to Turso *if/when* its vector search beats in-process cosine (or `sqlite-vec`) at a
207
- corpus size that actually needs ANN.
208
-
209
- ## The cascade (why local is possible at all)
210
-
211
- ```
212
- clean single-topic chunks → clean buckets → clean section-routing → bounded section-patch
213
- └──── purity at the root ────┘
214
- ```
215
-
216
- Each stage's locality depends on the prior stage's cleanliness. If a chunk fuses
217
- two topics, it pollutes every section it's routed into. So **chunk purity is the
218
- foundation of the whole local system** — not an abstract metric.
219
-
220
- Caution from the chunk research (research-journal, reports/orpo-chunk-paper):
221
- embeddings measure **cohesion/dispersion well** (silhouette ρ≈0.68 per-conv vs
222
- the LLM judges) but **purity/contamination poorly** (−intraSpread ρ≈0.32, ns
223
- within variants). So a clean-bucket guarantee cannot lean on a cheap embedding
224
- signal — it rides on the local **chunker** actually being good at single-topic
225
- splitting (the e4b adapter's real job), backed where needed by a non-embedding
226
- purity check, not by cosine geometry.
227
-
228
- ## Stage → model → adapter
229
-
230
- | stage | file | model | adapter |
231
- |---|---|---|---|
232
- | chunk | `src/memory/chunk.ts` | local | **chunk LoRA (e4b chunk-300, exists)** |
233
- | classify | `src/memory/cluster.ts` | local + embeddings | classify LoRA (TODO) |
234
- | synthesize (create/update) | `src/memory/synthesize.ts` | local | synth LoRA (TODO) |
235
- | normalize | `src/memory/wikify.ts` (rename) | **deterministic code** | — |
236
- | wikify (LLM) | **new node** | local | wikify LoRA (TODO) |
237
-
238
- Section-routing (the new intra-article step) is embeddings-shaped: embed the
239
- chunk (or its label) and the article's section headings/lead (from `parseToc` /
240
- `extractSection`, already in `vault.ts`), route to the nearest section(s) over a
241
- threshold. The local Qwen3-Embedding backbone (bit-exact, served, `/v1/embeddings`)
242
- is exactly the "vector search over articles, not conversations" the vision calls
243
- for — now applied at section granularity.
244
-
245
- ## What changes in the scaffold
246
-
247
- The M1 stubs are wired (`pipeline.ts` orchestrates ingest→chunk→cluster→
248
- synthesize→wikify→changelog; stage bodies throw "not implemented"). Two
249
- corrections vs the stubs:
250
-
251
- 1. **`synthesize.ts` is whole-article today.** Make it `create-or-update`, with
252
- update = section-route + section-patch (not whole-article regeneration).
253
- 2. **The LLM wikify node is missing.** The current `wikify.ts` is *only*
254
- deterministic normalize. Keep that (rename to `normalize.ts`), and add a
255
- distinct **LLM wikify** node for the periodic "better version" pass.
256
-
257
- ## Build sequence
258
-
259
- Cold-start first, because the vault is empty and you can't patch what doesn't exist:
260
-
261
- 1. **Wire CHUNK** to the e4b chunk adapter (`chunk.ts`) — the one stage with an
262
- adapter in hand. Verify single-topic chunks + labels on real conversations.
263
- 2. **CLASSIFY from zero** (`cluster.ts`) — emergent bucket taxonomy
264
- (`Meta/Buckets.md`); assign chunks to buckets, propose new ones; filter no-fit.
265
- 3. **CREATE flow** (`synthesize.ts`) — sub-cluster → outline → per-section draft
266
- for buckets crossing the chunk threshold. Behind the conservative gate. This
267
- is what gets us from zero to a first set of articles.
268
- 4. **NORMALIZE** (`normalize.ts`) — wire the deterministic footnote/wikilink
269
- repair (`vault.ts` already has the resolver).
270
- 5. **UPDATE flow** — section-route + patch, once articles exist to update.
271
- 6. **WIKIFY (LLM)** + Talk-page split/merge signals — once articles have
272
- accumulated enough cruft/drift to need them.
273
-
274
- Steps 1–4 are the cold-start path (zero → first articles); 5–6 are steady state.
275
-
276
- ## Open questions
277
-
278
- - **Article granularity / when to CREATE** — chunk threshold per bucket; when a
279
- bucket should become one article vs several (the vision's "soft size caps").
280
- - **Section-route confidence** — threshold for "fits an existing section" vs
281
- "new section needed" vs "route to a different article."
282
- - **Provisional facts** — representing "work set to begin July" so the next pass
283
- cleanly updates it to "began / completed" (temporal/trajectory tracking).
284
- - **Create vs strong-model** — is first-creation good enough on the local model,
285
- or is bootstrap the one place a stronger model is worth it (vision: bootstrap is
286
- heavier but the same code path)?
287
- - **The purity check** — what non-embedding signal guarantees clean buckets.
@@ -1,237 +0,0 @@
1
- # Memory system
2
-
3
- Status: **M0/M0.5 landed (2026-06-19)**. The vault, read tools, CLI, Obsidian open flow, and launchd scheduling are implemented. The actual synthesis stage bodies are still **M1 TODO**; `mlx-bun memory synthesize` is currently a safe no-op stub. The planned M1/M2 synthesis engine uses the same local models the user chats with, plus stage-specific LoRA adapters trained by Josh from the existing Lucien-scale memory corpus and distributed from Hugging Face.
4
-
5
- ## Contract
6
-
7
- The memory contract is ported from `../lucien`:
8
-
9
- > **Chat-time agents read memory. The synthesis pipeline writes memory.**
10
-
11
- Memory articles are durable priors. Conversations are evidence. Synthesis is the deliberate, auditable process that turns evidence into updated articles. Normal chat must not mutate articles.
12
-
13
- This gives both terminal and web the full pi agent experience without turning memory into an unsafe scratchpad:
14
-
15
- - Terminal and web expose the same read-only memory tools through one shared pi surface factory.
16
- - Memory tools/skill are exposed only when the user has enabled the vault.
17
- - When enabled, memory is scoped to user-specific continuity: explicit recall, named personal projects/people/preferences/decisions/history, or missing personal context.
18
- - Memory is **not** the default first step for weather, current public facts, generic web research, or ordinary coding/file tasks where the current files are sufficient.
19
- - Mutating/coding tools remain full-power and approval-gated by pi/web as usual.
20
- - Memory article writes happen only through `mlx-bun memory synthesize` once M1 lands.
21
- - Users can always browse/edit their own Markdown vault directly, especially via Obsidian.
22
-
23
- ## User-facing model
24
-
25
- - User-facing capability: **memory**.
26
- - Store on disk: `~/.mlx-bun/wiki/` (override: `MLX_BUN_WIKI`).
27
- - User articles: `~/.mlx-bun/wiki/articles/*.md`.
28
- - Read-only reference residents: `~/.mlx-bun/wiki/Reference/*.md` symlinked to mlx-bun's own docs.
29
- - Operational pages: `~/.mlx-bun/wiki/Meta/*.md`.
30
- - Talk pages: `~/.mlx-bun/wiki/Talk/`.
31
- - Synthesis DB: `~/.cache/mlx-bun/memory.sqlite`.
32
-
33
- The vault is plain Markdown and git-tracked. It is intentionally usable as an Obsidian vault. `Reference/` is a separate read-only namespace: chat tools may search/read it, but synthesis must skip it and never write through those symlinks. The SQLite DB is derived state and lives in the rebuildable cache, not in the user-owned Markdown vault.
34
-
35
- Stage-specific memory LoRAs are product assets, not user-authored vault content. The creator trains them from the existing memory-pipeline data, publishes them to Hugging Face, and `memory init` can offer to download/cache them for local synthesis.
36
-
37
- ## What is implemented now
38
-
39
- ### Vault and article helpers
40
-
41
- `src/memory/vault.ts` implements:
42
-
43
- - `vaultRoot()` → `~/.mlx-bun/wiki` or `MLX_BUN_WIKI`.
44
- - `setupVault()` — idempotent directory/Meta/README/git setup plus `Reference/` symlinks.
45
- - `listArticles()` / `listReferenceDocs()` / `listMemoryDocuments()`.
46
- - `readArticle()` / `searchArticles()` over both user articles and read-only references.
47
- - `parseToc()` / `extractSection()`.
48
- - `getArticleLinks()` with resolved inbound/outbound wikilinks.
49
- - `importArticlesFrom()` for seeding from an existing vault such as `~/Dreaming`.
50
- - `vaultStatus()` with article/reference counts and recent user article mtimes.
51
-
52
- The read/search/link logic is ported from Lucien's pure filesystem helpers, not from MCP.
53
-
54
- ### CLI
55
-
56
- `mlx-bun memory` supports:
57
-
58
- ```bash
59
- mlx-bun memory init # create vault, optionally import + schedule
60
- mlx-bun memory setup # alias for init
61
- mlx-bun memory status # path, article count, git, schedule, recent articles
62
- mlx-bun memory open # open the vault in Obsidian, fallback Finder
63
- mlx-bun memory open <article> # open one article in Obsidian/default Markdown app
64
- mlx-bun memory list # list article stems + Reference/* docs
65
- mlx-bun memory search <query> # search articles
66
- mlx-bun memory toc <article> # headings + anchors
67
- mlx-bun memory section <article> <anchor>
68
- mlx-bun memory links <article> # inbound/outbound wikilinks
69
- mlx-bun memory read <article> # print full article
70
- mlx-bun memory synthesize [--dry-run] [--model <q>] [--since <cursor>]
71
- mlx-bun memory schedule [--at HH:MM]
72
- mlx-bun memory unschedule
73
- ```
74
-
75
- `memory synthesize` currently reports the M1 stub and writes nothing. Scheduling is real; the scheduled job is harmless until synthesis lands. In the full flow, `memory init` should also offer to download the memory pipeline adapter pack from Hugging Face so synthesis is ready to run locally.
76
-
77
- ### pi/web tools
78
-
79
- `src/memory/tools.ts` defines native pi custom tools:
80
-
81
- - `memory_search`
82
- - `memory_read`
83
- - `memory_toc`
84
- - `memory_section`
85
- - `memory_links`
86
- - `memory_list` (user articles plus read-only `Reference/*` docs)
87
- - `memory_status` (vault path, setup state, article count, git state, last-synthesis placeholder, schedule state, recent changed articles)
88
-
89
- These tools are registered by the shared pi surface in `src/pi-session.ts` and consumed by both front doors:
90
-
91
- - `src/pi-terminal.ts`
92
- - `src/pi-web.ts`
93
-
94
- If the vault does not exist, memory tools and the memory skill are not exposed at all, avoiding prompt fixation on unavailable memory. If the vault exists, `memoryIndexHint()` adds a short scoped presence hint. Detailed usage lives in the memory skill rather than dumping article titles into the prompt.
95
-
96
- Read-only mlx-bun docs are now a separate lookup surface (`reference_search`, `reference_read`, `reference_list`) rather than being mixed into personal-memory search. Personal memory answers “what does the user think / what did we decide”; reference tools answer “what do mlx-bun docs say.”
97
-
98
- ### Bundled memory skill
99
-
100
- `src/web/skills/memory/SKILL.md` is bundled through `src/web/skills.ts` and materialized under `~/.mlx-bun/skills` for pi to load.
101
-
102
- The skill tells the agent to:
103
-
104
- - consult memory quietly for personal context;
105
- - use `memory_search` then `memory_read`, or `memory_toc` + `memory_section` for focused reads;
106
- - use `memory_links` for nearby concepts/backlinks;
107
- - use `memory_status` for setup/location/schedule questions;
108
- - never announce retrieval as the user's experience;
109
- - never edit memory articles during chat;
110
- - open the vault/article for the user if asked via `mlx-bun memory open [article]`.
111
-
112
- ### Session capture substrate
113
-
114
- The synthesis pipeline will ingest mlx-bun's own pi sessions only:
115
-
116
- - web sessions: `~/.mlx-bun/sessions/...` / `~/.mlx-bun/pi-sessions/...` depending on the web `SessionManager` path;
117
- - terminal sessions: `~/.mlx-bun/pi/sessions/...`.
118
-
119
- No Playwright, scraping, cloud transcript import, or Lucien runtime dependency is planned for mlx-bun memory.
120
-
121
- ### Scheduling
122
-
123
- `src/memory/schedule.ts` installs a launchd agent:
124
-
125
- - label: `com.mlx-bun.memory`
126
- - plist: `~/Library/LaunchAgents/com.mlx-bun.memory.plist`
127
- - command: `mlx-bun memory synthesize`
128
- - logs: `~/.mlx-bun/logs/memory-synthesis.{out,err}.log`
129
-
130
- `mlx-bun memory schedule --at 03:00` installs/loads it. `unschedule` unloads/removes it. `status` and `memory_status` report it.
131
-
132
- ## Synthesis pipeline design (M1/M2)
133
-
134
- The M1/M2 pipeline mirrors Lucien's proven stages while running on the same local model stack the user chats with. The difference is execution context and authority: chat uses the model conversationally and read-only; synthesis runs the model as a constrained editor behind deterministic gates.
135
-
136
- ```text
137
- ingest deterministic: pi session JSONL -> memory.sqlite conversations
138
- chunk base model + memory-chunk LoRA -> topic chunks
139
- cluster base model + memory-bucket LoRA -> buckets / target articles
140
- synthesize base model + memory-synthesis LoRA -> candidate article updates
141
- wikify base model + memory-editor LoRA + deterministic normalization
142
- changelog deterministic: run summary + git commit
143
- ```
144
-
145
- The chunking LoRA has already been trained as a WIP artifact. The remaining stage adapters are planned product assets trained by Josh from the existing Lucien/pipeline data and published to Hugging Face. mlx-bun should download/cache them during `memory init` (with user consent) or lazily on first `memory synthesize`.
146
-
147
- Important nouns must stay distinct:
148
-
149
- - **Conversation** — source transcript/evidence.
150
- - **Chunk** — topical segment from a conversation.
151
- - **Bucket** — staging group that collects related chunks.
152
- - **Article** — durable Markdown memory page.
153
-
154
- ### Bookkeeping DB
155
-
156
- `src/memory/db.ts` defines `MemoryStore` over `~/.cache/mlx-bun/memory.sqlite` with tables for:
157
-
158
- - `conversations`
159
- - `chunks`
160
- - `buckets`
161
- - `watermarks`
162
- - `synthesized_bucket_chunks`
163
-
164
- The DB is derived and rebuildable from sessions + articles. It should not be committed to the vault.
165
-
166
- ### Stage-specific adapters
167
-
168
- The pipeline deliberately uses **four specialized LoRA adapters** rather than one generic memory adapter:
169
-
170
- | Stage | Adapter | Job | Primary quality signal |
171
- | --- | --- | --- | --- |
172
- | Chunk | memory-chunk | Conversation transcript → topic-coherent chunks | Boundary/label accuracy vs gold chunks |
173
- | Bucket | memory-bucket | Chunk → existing bucket or new bucket proposal | Stable routing, low duplicate topics, good article target |
174
- | Synthesize | memory-synthesis | New chunks + existing article → conservative candidate update | Citation preservation, faithful integration, no hallucinated claims |
175
- | Edit/wikify | memory-editor | Candidate article → normalized wiki Markdown | Style, wikilinks, references, deterministic format compliance |
176
-
177
- These adapters do **not** get direct write authority. They produce candidates. The pipeline validates, normalizes, and decides whether to write/commit.
178
-
179
- Implementation notes:
180
-
181
- - Adapters should be cached with the rest of mlx-bun's HF/downloaded artifacts, not stored in the wiki vault.
182
- - `memory init` should describe the adapter pack plainly and ask before downloading multi-MB/GB assets.
183
- - `memory synthesize --dry-run` must work without downloading adapters when it only builds the deterministic manifest.
184
- - If a required adapter is missing for a real synthesis stage, the command should offer the download or fail cleanly; it should not silently fall back to an untrained prompt path unless explicitly requested.
185
- - Future routing should use the existing adapter-scoped generation path: one resident base model, stage LoRA mounted per pipeline call.
186
-
187
- ### Current stage modules
188
-
189
- These files exist as typed stubs and currently throw if called directly:
190
-
191
- - `src/memory/ingest.ts`
192
- - `src/memory/chunk.ts`
193
- - `src/memory/cluster.ts`
194
- - `src/memory/synthesize.ts`
195
- - `src/memory/wikify.ts`
196
- - `src/memory/prompts.ts`
197
-
198
- `src/memory/pipeline.ts` intentionally does **not** call them yet. It emits a no-op M1-stub plan so manual and scheduled synthesis cannot accidentally corrupt the vault before gates exist.
199
-
200
- ## Synthesis quality gates to port from Lucien
201
-
202
- M1 should preserve these Lucien properties:
203
-
204
- - deterministic manifest / dry-run before writes;
205
- - per-bucket/per-article workers so failures are isolated;
206
- - idempotency via `synthesized_bucket_chunks`;
207
- - backfill behavior for existing imported articles;
208
- - orphan detection when ledger and files disagree;
209
- - conservative update prompt: integrate, do not rewrite wholesale;
210
- - minimum word-count/truncation guard, e.g. Lucien's 70% floor;
211
- - citation preservation: every original `conv:` reference survives;
212
- - deterministic footnote repair;
213
- - deterministic wikilink normalization;
214
- - git commit for article changes;
215
- - changelog / run summary.
216
-
217
- A weak local-model synthesis pass should no-op, not damage the vault. This remains true even with trained adapters: LoRAs propose; deterministic gates dispose. Synthesis must operate only on `articles/` and must treat `Reference/` as immutable read-only context.
218
-
219
- ## Consent and safety
220
-
221
- - Local session capture is local-only and part of pi/web session persistence.
222
- - Creating the vault is explicit: `mlx-bun memory init`.
223
- - Scheduling is explicit: `mlx-bun memory schedule` or the init wizard prompt.
224
- - Chat-time memory tools are read-only and auto-allowed.
225
- - Opening Obsidian/Finder is user-directed browsing/editing; it is not agent mutation.
226
- - Article mutation by the agent during chat is out of bounds.
227
-
228
- ## Next implementation steps
229
-
230
- 1. Implement `memory synthesize --dry-run` manifest generation without model calls.
231
- 2. Add memory adapter-pack metadata and `memory init` download prompt (HF-hosted LoRAs; chunk adapter exists as WIP, others follow).
232
- 3. Implement ingest from saved pi session JSONL into `MemoryStore`.
233
- 4. Wire the chunk stage to the memory-chunk LoRA and evaluate with chunk boundary/label accuracy.
234
- 5. Implement bucket assignment with the memory-bucket LoRA and article manifest create/update/backfill/orphan modes.
235
- 6. Implement per-article synthesis workers with the memory-synthesis LoRA and conservative gates.
236
- 7. Implement editor/wikify adapter pass plus deterministic footnote/wikilink normalization and git commits.
237
- 8. Move synthesis execution onto the jobs runner with SSE progress once manual synthesis is reliable.
@@ -1,81 +0,0 @@
1
- # mlx-lm serving execution seam
2
-
3
- ## Question
4
-
5
- What should mlx-bun borrow from the pinned mlx-lm oracle when deepening Completion execution around this flow?
6
-
7
- ```text
8
- prepared prompt -> semantic events -> terminal summary
9
- ```
10
-
11
- This note reads the local mlx-lm 0.31.3 source installed in the reference venv. The comparison uses the serving term defined in `CONTEXT.md`: a **Completion execution** includes output, resource lifetime, usage, and scheduling placement.
12
-
13
- mlx-lm is the correctness oracle only for behavior and numeric schemes it implements. It is not mlx-bun's architecture oracle or capability ceiling. mlx-bun also implements explicitly selected features such as mixed-precision KV, TurboQuant, and native draft methods. The execution path must preserve those resolved settings exactly.
14
-
15
- ## Implementation status
16
-
17
- The first consolidation slice landed on 2026-08-21. `prepareCompletion()` performs admission before a streaming response starts and returns an opaque, single-use `PreparedCompletion`. `CompletionExecutor.execute()` then owns placement reporting, `CompletionSink`, logprobs, semantic event delivery, finish reason, usage, and pre-generation cleanup. [`completion-executor.ts:75`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:75) [`completion-executor.ts:219`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:219)
18
-
19
- Chat and raw-text adapters still declare their semantic components and format their own wire responses. Their streaming and non-streaming branches now call the same executor. `GenerationGateway` still owns placement and model execution. The change does not add or remove flags, alter defaults, or substitute one inference method for another.
20
-
21
- S3 completed the scheduling declaration at the same seam. A
22
- `GenerationPlacement` now names `serial` or `continuous`; it no longer calls a
23
- lone scheduler request "batched." The continuous scheduler chooses its B=1
24
- fast path or B=N step from active rows. The strict serial executor remains for
25
- `--batch 1` and for declared compositions the continuous scheduler does not yet
26
- implement. Existing parity evidence covers both the default scheduler's B=1
27
- path and strict serial. The recorded scheduler/serial decode ratios are
28
- 0.992–0.996, and a fresh main-vs-branch serial gate after the sampler
29
- consolidation measured a 1.000 median-best ratio (about 265.0 tok/s on both
30
- sides, MiniCPM5, two interleaved 256-token repeats).
31
-
32
- Final acceptance after the GPQA pause exercised the seam through the complete
33
- two-shard suite and a real two-turn browser conversation. The suite passed
34
- 2,064 tests with zero failures. The browser run verified streaming, tool
35
- events, context carryover, metrics, and turn recovery. A mainline-only queued
36
- DOM render race found by that run was fixed at the UI lifecycle boundary; no
37
- decode-loop work was added. The architecture changes likewise keep accounting
38
- and capability decisions outside numerical kernels. The fresh serial A/B plus
39
- the established scheduler B=1 parity and latency evidence are the performance
40
- gate.
41
-
42
- ## What the oracle actually does
43
-
44
- The HTTP adapter creates a small `CompletionRequest` that still contains protocol-shaped chat messages or a raw text prompt. It separately builds `GenerationArguments`. Prompt preparation has not happened yet. [`server.py:182`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:182) [`server.py:198`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:198) [`server.py:1368`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1368)
45
-
46
- `ResponseGenerator.generate()` submits that pair to one worker thread through a queue. The worker applies the chat template, tokenizes, finds cache segments, chooses the initial reasoning state, constructs stop/tool/reasoning transitions, selects a lane, owns cache work, and emits per-token `Response` records. [`server.py:516`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:516) [`server.py:626`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:626) [`server.py:688`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:688) [`server.py:1026`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1026)
47
-
48
- That organization can be summarized as:
49
-
50
- ```text
51
- HTTP request
52
- -> CompletionRequest + GenerationArguments
53
- -> ResponseGenerator queue
54
- -> tokenize + state machine + lane + cache
55
- -> token Response { text, token, state, match, logprob, finish_reason }
56
- -> HTTP handler accumulates semantics and formats the protocol response
57
- ```
58
-
59
- The model loader is separate. `utils.load()` returns the model and a tokenizer wrapper, while tokenizer loading chooses the streaming detokenizer and tool parser. This keeps model construction out of per-request execution. [`utils.py:453`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/utils.py:453) [`tokenizer_utils.py:578`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/tokenizer_utils.py:578)
60
-
61
- ## Comparison by concern
62
-
63
- | Concern | Oracle organization | Consequence for the mlx-bun seam |
64
- | --- | --- | --- |
65
- | Prepared prompt | The worker owns chat templating, tokenization, initial reasoning state, and cache-oriented prompt segmentation. The HTTP adapter does not know those details. [`server.py:530`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:530) [`server.py:565`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:565) | A prepared-prompt value is a sound seam, but it should be richer than token ids. It must carry the generation inputs and owned media or grammar state needed by either lane. Protocol adapters should not assemble `RequestShape` or transfer resources piecemeal. |
66
- | Semantic events | The state machine classifies tokens as `normal`, `reasoning`, or `tool`. `_process_control_tokens` withholds matched control sequences. The HTTP handler then accumulates reasoning, tool text, visible text, and parses completed tool calls. [`server.py:236`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:236) [`server.py:654`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:654) [`server.py:1442`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1442) | Do not copy this split. mlx-bun's `CompletionSink` already emits content, reasoning, and tool-call events through one interface. [`completion-sink.ts:7`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-sink.ts:7) [`completion-sink.ts:90`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-sink.ts:90) The deepened module should own that semantic work so all protocol adapters consume the same events. |
67
- | Terminal summary | `generate.stream_generate()` puts timing, token counts, memory, and finish reason on every low-level response, but the server discards most of it. The HTTP handler counts emitted tokens, reads prompt and cache counts from `GenerationContext`, derives tool-call finish, and builds usage. [`generate.py:269`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/generate.py:269) [`generate.py:728`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/generate.py:728) [`server.py:1495`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1495) [`server.py:1517`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1517) | The oracle has no single terminal summary at the server seam. mlx-bun should add one. It should be the sole source of finish reason, prompt/generated/cached counts, final lane, speculation facts, and collected result. |
68
- | Streaming and non-streaming | Both modes consume the same response iterator and semantic accumulation loop. Streaming flushes deltas and optionally emits a final usage packet; non-streaming sends one accumulated response. [`server.py:1454`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1454) [`server.py:1507`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1507) [`server.py:1529`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1529) | Keep one Completion execution interface. Streaming and non-streaming are protocol adapters over the same semantic events and terminal summary, not separate execution paths. |
69
- | Scheduling placement | Model loading marks a model batchable only when no draft model exists and every cache supports merge. Per-request placement also excludes a fixed seed. The worker joins the active batch, creates a batch, runs serially, or drains an incompatible batch. [`server.py:370`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:370) [`server.py:685`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:685) [`server.py:731`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:731) [`server.py:801`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:801) [`server.py:831`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:831) | `RequestShape` describes settings already resolved from flags, request fields, model metadata, and defaults. `place()` asks only whether the continuous scheduler implements that exact composition; it never replaces MTP, a KV scheme, or another requested method. The frozen declaration names the `serial` or `continuous` mechanism, and both reporting and `run()` consume it. Active-row count selects B=1 or B=N inside the continuous mechanism. |
70
- | Cancellation and flow | Cancellation is cooperative. The handler's `finally` sets a flag; serial execution checks it after tokens, while batched execution checks it during prompt and generation work and removes the row. [`server.py:1008`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1008) [`server.py:861`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:861) [`server.py:911`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:911) [`server.py:1551`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1551) The response queue is unbounded, and socket writes block only the HTTP thread, so there is no end-to-end demand signal from the client to generation. [`server.py:444`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:444) [`server.py:1032`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1032) [`server.py:1489`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1489) | Do not regress to the oracle here. mlx-bun's token callback accepts a promise or `false`, and `GenerationGateway.run()` accepts an `AbortSignal`. [`generation-gateway.ts:94`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/generation-gateway.ts:94) [`generation-gateway.ts:354`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/generation-gateway.ts:354) Cancellation and async flow control are part of the interface, not HTTP details. |
71
- | Cache and resource lifetime | The worker fetches or creates the serial cache, generates, then inserts it. Batched execution fetches before admission, snapshots segment caches, inserts the final cache, and removes cancelled rows. [`server.py:963`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:963) [`server.py:1018`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1018) [`server.py:752`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:752) [`server.py:864`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:864) [`server.py:901`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:901) `LRUPromptCache` hides prefix matching, copying, trimming, and count/byte eviction behind a small interface. [`cache.py:1623`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1623) [`cache.py:1674`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1674) [`cache.py:1696`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/models/cache.py:1696) | `prepareCompletion()` now disposes owned media and grammar state on admission rejection. `execute()` disposes the same plan on placement or pre-generation failure, then transfers ownership exactly once before `GenerationGateway.run()`. Cache and in-generation disposal remain in the gateway and generation path. [`completion-executor.ts:75`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:75) [`completion-executor.ts:219`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:219) |
72
- | Errors | Errors before the response iterator exists become a JSON error, although the oracle uses status 404 for that whole class. Errors delivered later through the worker queue are raised by the iterator. The handler guarantees `ctx.stop()` but has no matching mid-stream error packet in this loop. [`server.py:1417`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1417) [`server.py:1424`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1424) [`server.py:1035`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1035) [`server.py:1454`](/Users/joshrossi/Code/mlx-lm/.venv/lib/python3.14/site-packages/mlx_lm/server.py:1454) | Preserve a typed distinction between rejection before execution and failure after events begin. Both must run the same ownership cleanup. Protocol adapters decide how to encode the failure after headers have been sent. |
73
-
74
- ## Strongest conclusions
75
-
76
- 1. **Keep resolved inference settings authoritative.** Serial and continuous execution are scheduling mechanisms for the already-selected composition. Consolidating placement may shrink the HTTP adapter, but it must not turn explicit features or opinionated defaults into inferred choices.
77
- 2. **Do not borrow the oracle's semantic split.** Its worker emits state-tagged token records, then the HTTP handler performs semantic accumulation and tool parsing. mlx-bun already has a better starting point in `CompletionSink`. Move that module behind the Completion execution seam so protocol adapters see semantic events only.
78
- 3. **Keep the terminal summary as the only completion result.** It now settles finish reason, usage, cached-token count, final lane, speculation, logprobs, and collected output once. The four HTTP branches only format that summary. [`completion-executor.ts:103`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/serve/completion-executor.ts:103) [`server.ts:3104`](/Users/joshrossi/.codex/worktrees/e408/mlx-bun/src/server.ts:3104)
79
- 4. **Treat cancellation, async flow control, and ownership as interface requirements.** The oracle's queue makes cancellation and socket pressure indirect. mlx-bun has stronger mechanisms already. The deepening should hide their implementation without weakening their behavior.
80
-
81
- The deletion test is positive. If this Completion execution module disappeared, scheduling policy, cache participation, semantic parsing, finish rules, usage, and cleanup would spread back across four protocol branches. Concentrating those rules gives callers leverage and gives maintainers locality. Feature selection and fidelity policy remain outside this seam as resolved inputs.