mlx-bun 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +362 -0
  3. package/THIRD_PARTY_LICENSES.md +41 -0
  4. package/bin/mlx-bun.mjs +32 -0
  5. package/docs/curve-designer.html +303 -0
  6. package/docs/design/adapters-end-to-end.md +201 -0
  7. package/docs/design/compat-cli-surface-design.md +227 -0
  8. package/docs/design/docs-reorg-plan.md +152 -0
  9. package/docs/design/hlg-sampling.md +340 -0
  10. package/docs/design/memory-system.md +339 -0
  11. package/docs/design/optimization_plan.md +344 -0
  12. package/docs/design/parallel-slots.md +515 -0
  13. package/docs/design/runtime-isolation.md +247 -0
  14. package/docs/design/segmented-backward-training.md +508 -0
  15. package/docs/investigations/chunk-finetune-experiment.md +84 -0
  16. package/docs/investigations/curve-bisector-routing.md +123 -0
  17. package/docs/investigations/curve-runs/bisector-route.json +98 -0
  18. package/docs/investigations/curve-runs/bisector-trace.json +1393 -0
  19. package/docs/investigations/curve-runs/curve-terrain.json +1179 -0
  20. package/docs/investigations/curve-runs/curve-terrain.svg +42 -0
  21. package/docs/investigations/curve-terrain.html +105 -0
  22. package/docs/investigations/expert-offload-single-user-moe.md +292 -0
  23. package/docs/investigations/hlg-ab.html +34 -0
  24. package/docs/investigations/hlg-explorer.html +238 -0
  25. package/docs/investigations/hlg-figs/cliff.svg +1 -0
  26. package/docs/investigations/hlg-figs/cross.svg +1 -0
  27. package/docs/investigations/hlg-figs/edges.svg +1 -0
  28. package/docs/investigations/hlg-figs/k20-grids.svg +1 -0
  29. package/docs/investigations/hlg-figs/k20-peaks.svg +1 -0
  30. package/docs/investigations/hlg-figs/lw-curve.svg +1 -0
  31. package/docs/investigations/hlg-figs/terrain.svg +1 -0
  32. package/docs/investigations/hlg-report.html +262 -0
  33. package/docs/investigations/hlg-runs/hlg-ab.json +149 -0
  34. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +87 -0
  35. package/docs/investigations/hlg-runs/hlg-blind.json +107 -0
  36. package/docs/investigations/hlg-runs/hlg-cliff.json +197 -0
  37. package/docs/investigations/hlg-runs/hlg-cross.json +505 -0
  38. package/docs/investigations/hlg-runs/hlg-edge.json +388 -0
  39. package/docs/investigations/hlg-runs/hlg-eval1.json +25 -0
  40. package/docs/investigations/hlg-runs/hlg-frontier.json +86 -0
  41. package/docs/investigations/hlg-runs/hlg-grid.json +242 -0
  42. package/docs/investigations/hlg-runs/hlg-grid2.json +343 -0
  43. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +110 -0
  44. package/docs/investigations/hlg-runs/hlg-map.json +383 -0
  45. package/docs/investigations/hlg-runs/run0-original.log +159 -0
  46. package/docs/investigations/hlg-runs/runA-recommended.log +131 -0
  47. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +26 -0
  48. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +18 -0
  49. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +25 -0
  50. package/docs/investigations/hlg-runs/runAD-ab-samples.log +8 -0
  51. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +51 -0
  52. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +10 -0
  53. package/docs/investigations/hlg-runs/runAG-eval-config2.log +16 -0
  54. package/docs/investigations/hlg-runs/runB-gain-variants.log +192 -0
  55. package/docs/investigations/hlg-runs/runC-pivots.log +162 -0
  56. package/docs/investigations/hlg-runs/runD-oetf.log +132 -0
  57. package/docs/investigations/hlg-runs/runE-eotf.log +162 -0
  58. package/docs/investigations/hlg-runs/runF-shaper-working.log +86 -0
  59. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +101 -0
  60. package/docs/investigations/hlg-runs/runH-wsweep.log +176 -0
  61. package/docs/investigations/hlg-runs/runI-asweep.log +176 -0
  62. package/docs/investigations/hlg-runs/runJ-knobmap.log +49 -0
  63. package/docs/investigations/hlg-runs/runK-frontier.log +19 -0
  64. package/docs/investigations/hlg-runs/runL-widemap.log +65 -0
  65. package/docs/investigations/hlg-runs/runM-frontier-emb.log +15 -0
  66. package/docs/investigations/hlg-runs/runN-verify.log +116 -0
  67. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +15 -0
  68. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +15 -0
  69. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +15 -0
  70. package/docs/investigations/hlg-runs/runR-blind-transcript.log +79 -0
  71. package/docs/investigations/hlg-runs/runS-cross-coherence.log +33 -0
  72. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +33 -0
  73. package/docs/investigations/hlg-runs/runU-cross-12b.log +33 -0
  74. package/docs/investigations/hlg-runs/runV-lw-e4b.log +22 -0
  75. package/docs/investigations/hlg-runs/runW-lw-12b.log +22 -0
  76. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +22 -0
  77. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +26 -0
  78. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +26 -0
  79. package/docs/investigations/hlg-sampling-investigation.md +970 -0
  80. package/docs/investigations/lab-build-journal.md +157 -0
  81. package/docs/investigations/pi-builtin-investigation.md +308 -0
  82. package/docs/investigations/starter-model-port-handoff.md +323 -0
  83. package/docs/planning/IDEAS.md +26 -0
  84. package/docs/planning/PRODUCT_ROADMAP.md +426 -0
  85. package/docs/planning/ResearchTopics.md +119 -0
  86. package/docs/planning/chunk-task-roadmap.md +77 -0
  87. package/docs/planning/journal.md +155 -0
  88. package/docs/reference/distribution.md +121 -0
  89. package/docs/reference/embedding.md +168 -0
  90. package/docs/reference/library-api.md +153 -0
  91. package/docs/reference/server-api.md +224 -0
  92. package/docs/reference/server-config.md +243 -0
  93. package/docs/segmented-backward-handoff.md +148 -0
  94. package/package.json +68 -0
  95. package/src/anthropic.ts +491 -0
  96. package/src/chat-template.ts +186 -0
  97. package/src/cli.ts +1075 -0
  98. package/src/config.ts +229 -0
  99. package/src/curve-sampler.ts +122 -0
  100. package/src/dataset/generators.ts +1087 -0
  101. package/src/dataset/index.ts +12 -0
  102. package/src/dataset/job.ts +81 -0
  103. package/src/dataset/llm.ts +71 -0
  104. package/src/dataset/registry.ts +528 -0
  105. package/src/download.ts +283 -0
  106. package/src/eval/README.md +86 -0
  107. package/src/eval/kl-prompts.ts +29 -0
  108. package/src/eval/kl.ts +294 -0
  109. package/src/eval/quality-db.ts +92 -0
  110. package/src/eval/runner.ts +102 -0
  111. package/src/eval/score.ts +49 -0
  112. package/src/eval/tasks/bfcl.ts +500 -0
  113. package/src/eval/tasks/gsm8k.ts +85 -0
  114. package/src/eval/tasks/hashhop.ts +109 -0
  115. package/src/eval/tasks/humaneval.ts +252 -0
  116. package/src/eval/tasks/ifeval.ts +354 -0
  117. package/src/eval/tasks/mmlu.ts +145 -0
  118. package/src/evaldb.ts +199 -0
  119. package/src/expert-offload-build.ts +77 -0
  120. package/src/expert-offload.ts +61 -0
  121. package/src/expert-trace.ts +67 -0
  122. package/src/fit.ts +254 -0
  123. package/src/generate.ts +451 -0
  124. package/src/harness-pi.ts +177 -0
  125. package/src/hf-push.ts +628 -0
  126. package/src/index.ts +22 -0
  127. package/src/jobs/db.ts +139 -0
  128. package/src/jobs/index.ts +29 -0
  129. package/src/jobs/job-entry.ts +106 -0
  130. package/src/jobs/runner.ts +304 -0
  131. package/src/jobs/sse.ts +114 -0
  132. package/src/jobs/types.ts +58 -0
  133. package/src/kv-store.ts +185 -0
  134. package/src/lora.ts +314 -0
  135. package/src/md-modules.d.ts +7 -0
  136. package/src/mlx/array.ts +237 -0
  137. package/src/mlx/autograd.ts +267 -0
  138. package/src/mlx/checkpoint.ts +116 -0
  139. package/src/mlx/compile.ts +158 -0
  140. package/src/mlx/custom-vjp.ts +140 -0
  141. package/src/mlx/ffi.ts +433 -0
  142. package/src/mlx/metal-kernel.ts +130 -0
  143. package/src/mlx/ops.ts +707 -0
  144. package/src/mmap.ts +90 -0
  145. package/src/model/batched-mask.ts +204 -0
  146. package/src/model/batched-rotating.ts +300 -0
  147. package/src/model/compiled-decode.ts +681 -0
  148. package/src/model/factory.ts +27 -0
  149. package/src/model/fingerprint.ts +33 -0
  150. package/src/model/flash-attention.ts +674 -0
  151. package/src/model/fused-decode-kernel.ts +305 -0
  152. package/src/model/fused-geglu-kernel.ts +87 -0
  153. package/src/model/gemma4-base.ts +1616 -0
  154. package/src/model/gemma4.ts +1012 -0
  155. package/src/model/generated/gemma4-12b.ts +526 -0
  156. package/src/model/generated/gemma4-26b.ts +500 -0
  157. package/src/model/generated/gemma4-e4b.ts +757 -0
  158. package/src/model/generated/index.ts +18 -0
  159. package/src/model/minicpm5.ts +278 -0
  160. package/src/model/qwen3-delta.ts +224 -0
  161. package/src/model/qwen3_5.ts +429 -0
  162. package/src/model/support.ts +46 -0
  163. package/src/native-pack.ts +152 -0
  164. package/src/pi-provider.ts +95 -0
  165. package/src/pi-terminal.ts +264 -0
  166. package/src/pi-web.ts +924 -0
  167. package/src/preflight.ts +123 -0
  168. package/src/prompt-cache.ts +113 -0
  169. package/src/quantize/allocator.ts +627 -0
  170. package/src/quantize/calibration.ts +180 -0
  171. package/src/quantize/config-writer.ts +132 -0
  172. package/src/quantize/index.ts +57 -0
  173. package/src/quantize/job.ts +136 -0
  174. package/src/quantize/quantizer.ts +462 -0
  175. package/src/quantize/safetensors-writer.ts +171 -0
  176. package/src/quantize/sensitivity.ts +234 -0
  177. package/src/registry.ts +336 -0
  178. package/src/responses.ts +774 -0
  179. package/src/safetensors.ts +158 -0
  180. package/src/sampler.ts +517 -0
  181. package/src/serve/batch-scheduler.ts +362 -0
  182. package/src/serve/generation-gateway.ts +160 -0
  183. package/src/server.ts +1891 -0
  184. package/src/spec/drafter.ts +261 -0
  185. package/src/spec/generate.ts +221 -0
  186. package/src/status-page.html +497 -0
  187. package/src/tokenizer.ts +38 -0
  188. package/src/tool-call.ts +242 -0
  189. package/src/train/dataset.ts +461 -0
  190. package/src/train/export.ts +32 -0
  191. package/src/train/forward.ts +229 -0
  192. package/src/train/index.ts +43 -0
  193. package/src/train/job.ts +148 -0
  194. package/src/train/lora-params.ts +194 -0
  195. package/src/train/loss.ts +342 -0
  196. package/src/train/merge.ts +195 -0
  197. package/src/train/optimizer.ts +176 -0
  198. package/src/train/rank.ts +101 -0
  199. package/src/train/segmented.ts +520 -0
  200. package/src/train/trainer.ts +600 -0
  201. package/src/tui.ts +161 -0
  202. package/src/vision/embedder.ts +168 -0
  203. package/src/vision/preprocess.ts +247 -0
  204. package/src/vision/prompt.ts +158 -0
  205. package/src/vision/siglip.ts +599 -0
  206. package/src/web/app.html +2471 -0
  207. package/src/web/skills/web-research/SKILL.md +44 -0
  208. package/src/web/skills.ts +59 -0
  209. package/src/web-tools.ts +426 -0
  210. package/src/weights.ts +91 -0
@@ -0,0 +1,426 @@
1
+ # PRODUCT ROADMAP
2
+
3
+ Working notes for the product shape of mlx-bun. This is intentionally
4
+ less settled than PLAN.md: PLAN is the engineering contract; this file is
5
+ the evolving UI/UX/DX north star.
6
+
7
+ ## Product north star
8
+
9
+ Make the answer to "what is the best way to use local AI on my Mac?"
10
+ boringly simple:
11
+
12
+ ```sh
13
+ mlx-bun
14
+ ```
15
+
16
+ The user should not need to research Hugging Face variants, quantization
17
+ formats, context windows, Python environments, server commands, or agent
18
+ provider config before they can try local AI. They should install one
19
+ binary, run one command, wait for one resumable model download, and get a
20
+ working local chat UI plus a local AI server.
21
+
22
+ The runtime can still expose every advanced knob. The default path should
23
+ not require them.
24
+
25
+ ## The three modes (the organizing design law)
26
+
27
+ mlx-bun has not published anything: the entire CLI, command, and flag
28
+ surface is still ours to invent, and we are not married to any flag
29
+ name. Where a de-facto standard name exists (mlx-lm's), we adopt it
30
+ rather than reinvent. The surface is designed once, to serve three
31
+ audiences at three depths — progressive disclosure over ONE set of
32
+ verbs and one flag vocabulary, not three separate CLIs:
33
+
34
+ 1. **Automatic mode** — first-time local-AI users. `mlx-bun` (and bare
35
+ verbs) with zero flags. Smart, sane defaults from the device-profile
36
+ table (see Core idea). Typing to a chatbot in a web UI in under a
37
+ minute, with no knowledge of HF variants, quant formats, or context
38
+ windows required.
39
+ 2. **Compat mode** — people moving over from mlx-lm. The same verbs,
40
+ plus dotted aliases (`mlx-bun.server` *is* `mlx-bun serve`), using
41
+ mlx-lm's flag vocabulary, so existing muscle memory and scripts port
42
+ with a one-token rename. mlx-lm is canonical because it is the
43
+ default Apple references at WWDC and outweighs the alternative by
44
+ ~425× monthly installs (1.64M vs 3.85k; mlx-lm 5.8k stars / 765
45
+ forks; mlx-optiq has no public repo — measured 2026-06-12).
46
+ 3. **Stick-shift mode** — power users and researchers. The full knob
47
+ surface: every mlx-lm flag, every optiq feature, plus our own
48
+ envelope-pushing ones, all exposed and composable. Build the exact
49
+ system you want.
50
+
51
+ ### Laws that keep the three modes coherent
52
+
53
+ - **One surface, mlx-lm vocabulary.** The dotted form is a pure alias
54
+ of the space form. Adopt mlx-lm's flag names wherever they are the
55
+ standard; only name a flag ourselves where mlx-lm has no concept for
56
+ it (and there we are free to improve on optiq's name, not bound to
57
+ it).
58
+ - **Compatibility = superset, never intersection.** Every documented
59
+ mlx-lm flag/verb behaves faithfully so scripts drop in unchanged. We
60
+ never subtract or gate a capability we already have for free to
61
+ resemble an upstream — e.g. we serve OpenAI + Anthropic + Responses
62
+ from one server, and that stays on: it costs nothing and is invisible
63
+ to a beginner.
64
+ - **Gate only on conflict.** A capability is always on UNLESS leaving
65
+ it on would degrade the automatic or compat experience (it changes
66
+ output determinism, trades quality, or surprises a script). Only then
67
+ does it move behind a stick-shift flag. This is rule 3 yielding to
68
+ rules 1 and 2.
69
+ - **optiq is a feature set to absorb, not a flag dialect to honor.**
70
+ Its distinctive features (sensitivity mixed-precision convert,
71
+ per-layer KV sensitivity profiling, LoRA rank scaling, dual-protocol
72
+ serving, latency prediction, the Lab UI) graft onto the mlx-lm spine
73
+ as additive flags and a few new verbs.
74
+
75
+ ### Status (2026-06-12)
76
+
77
+ The compat layer does not exist yet: today's commands (`serve`, `fit`,
78
+ `benchmark`, `evals`, `get`/`scan`/`ls`, `pi`, `harness`) are ad-hoc,
79
+ not a designed mlx-lm-matching surface — though their flags already
80
+ overlap mlx-lm/optiq heavily, so this is mostly rename-and-confirm, not
81
+ migration. The work: design the full surface against mlx-lm vocabulary,
82
+ reconcile the existing commands into it, and fill the capability matrix
83
+ behind it (convert/quantize, LoRA training, eval/perplexity, fuse,
84
+ cache_prompt, upload/share). Decomposed into phases in PLAN.md.
85
+
86
+ ## Core idea
87
+
88
+ The local-AI problem is not continuous for Mac users. People own a small
89
+ set of real Apple Silicon SKUs: 16 GB, 24 GB, 32 GB, 36 GB, 48 GB,
90
+ 64 GB, and larger workstation tiers. For each profile, we can research
91
+ and preselect the best known model artifact, context target, KV mode,
92
+ memory budget, and runtime flags.
93
+
94
+ That means first-run behavior can be a lookup table, not a wizard or a
95
+ benchmark:
96
+
97
+ ```text
98
+ detect Mac profile
99
+ look up recommended runtime profile
100
+ download/resume the exact model artifact
101
+ start the tuned local server
102
+ open the built-in UI
103
+ show how to connect external tools and harnesses
104
+ ```
105
+
106
+ The research work feeds the table. The table feeds the user.
107
+
108
+ ## Recommended profiles
109
+
110
+ Initial profile work should stay narrow and excellent. Start with the
111
+ Gemma 4 OptiQ family and expand only when the project has a better answer.
112
+
113
+ Candidate shape:
114
+
115
+ | Device profile | Default model | Intent |
116
+ |---|---|---|
117
+ | MacBook Air / 16 GB | `mlx-community/gemma-4-e4b-it-OptiQ-4bit` | Fast first local-AI experience. |
118
+ | MacBook Pro / 24-32 GB | `mlx-community/gemma-4-12B-it-OptiQ-4bit` | Strong default chat/agent model. |
119
+ | Mac Studio / 64 GB | `mlx-community/gemma-4-26B-A4B-it-OptiQ-4bit` | Larger local-agent profile. |
120
+
121
+ Exact model choices, context lengths, and flags are not frozen here. They
122
+ should be updated from benchmarks, evals, fit predictions, and real use.
123
+
124
+ Each profile should eventually carry:
125
+
126
+ ```ts
127
+ {
128
+ id: "macbook-pro-24gb",
129
+ model: "mlx-community/gemma-4-12B-it-OptiQ-4bit",
130
+ context: 65536,
131
+ kv: "mixed",
132
+ memoryBudgetBytes: "...",
133
+ compiledDecode: true,
134
+ perfKernel: false,
135
+ expectedDecodeTps: 30,
136
+ expectedTtftMs: 100,
137
+ label: "Recommended for this Mac",
138
+ }
139
+ ```
140
+
141
+ The important rule: an optimization matters for product defaults when it
142
+ changes a device-tier decision, unlocks a larger useful context window,
143
+ keeps decode above a user-visible threshold, improves quality at the same
144
+ budget, or prevents failure. Saving memory for its own sake is secondary.
145
+
146
+ ## First-run UX
147
+
148
+ The no-args command should be the friendly path:
149
+
150
+ ```sh
151
+ mlx-bun
152
+ ```
153
+
154
+ Likely behavior:
155
+
156
+ 1. Detect the hardware profile.
157
+ 2. Pick the recommended runtime profile.
158
+ 3. Show the selected model and why it was chosen.
159
+ 4. Start or resume the background download.
160
+ 5. Start the local server when ready.
161
+ 6. Open or serve the built-in chat UI.
162
+ 7. Show connection details for OpenAI/Anthropic-compatible clients.
163
+ 8. Offer harness setup actions for Pi, Hermes, OpenClaw, and others.
164
+
165
+ This should feel like an appliance, not a framework tutorial.
166
+
167
+ ## Built-in UI
168
+
169
+ Bun can serve the UI directly from the same executable. The default UI
170
+ does not need to be elaborate at first, but it should work immediately.
171
+
172
+ Expected surfaces:
173
+
174
+ - Chat UI backed by the local model server.
175
+ - Download progress, resume status, and model readiness.
176
+ - Current device profile and selected model.
177
+ - Server URL and API compatibility hints.
178
+ - Simple controls for common settings: context, temperature, max tokens.
179
+ - Advanced panel for explicit model/profile overrides.
180
+ - Integration panel for harnesses and external clients.
181
+
182
+ ### Model hot-swap from the UI (candidate)
183
+
184
+ Let the user switch the served model at runtime — e.g. Gemma e4b →
185
+ MiniCPM5 — from a picker in the web UI, without restarting the server.
186
+ Weight load is cheap (mmap is lazy, load runs on the CPU stream; ~0.5 s
187
+ for a small model), so a swap can feel like changing a setting rather
188
+ than a relaunch. `/library` already enumerates every model on disk with
189
+ a per-machine fit assessment and flags the active one (`serving`), so the
190
+ menu and the "does it fit" data already exist — the missing pieces are a
191
+ swap action and a mutable served context.
192
+
193
+ Sketch:
194
+ - Today the server is single-model-per-process: `serve()` captures one
195
+ `ServerContext` as a const in the `Bun.serve` closure. Hot-swap needs a
196
+ mutable "current context" ref that all handlers and the generation
197
+ gateway read through.
198
+ - A swap endpoint (e.g. `POST /library/activate`) drains in-flight
199
+ generations, frees the old model's GPU buffers + KV/prompt caches,
200
+ `loadContext()`s the target, rebuilds the gateway, then atomically
201
+ swaps the ref. `/v1/models`, `/status`, and the Pi probe report the new
202
+ id afterward.
203
+
204
+ Constraints to honor:
205
+ - On a memory-bound Mac you can't hold two models at once — unload before
206
+ load. There is an unavoidable brief "swapping…" gap, not an instant
207
+ switch. Validate fit() before unloading the current model.
208
+ - Load time scales with model size; don't promise instant for large ones.
209
+ - Decide adapter behavior on swap (dropped vs. model-scoped) and surface
210
+ it. Active LoRA adapters are tied to the base model.
211
+
212
+ The UI should not hide that this is local. It should make "local" feel
213
+ easy: predictable memory, transparent downloads, offline-capable serving,
214
+ and clear integration instructions.
215
+
216
+ ### The UI must never lag while the AI is busy (candidate, 2026-06-16)
217
+
218
+ A product guarantee: **the AI may crash, the UI never may** — and the UI
219
+ must stay responsive no matter how hard the model is working. Waiting for
220
+ a *chat reply* is fine and expected (local inference takes time). A laggy
221
+ web UI — slow refreshes, stalled `/status`, a frozen page while an agentic
222
+ pipeline hammers the GPU — is not.
223
+
224
+ One `mlx-bun` process plays three roles on one event-loop thread: it
225
+ serves the UI, serves the API, and runs the AI. The AI work is synchronous
226
+ blocking GPU/FFI (each `mlx_eval` is atomic and uninterruptible), so it
227
+ starves the loop — worst in the non-streaming path and during prefill,
228
+ where nothing hands a macrotask back. Yielding between tokens helps the
229
+ common case but cannot isolate the UI under sustained load.
230
+
231
+ Direction (decided: **subprocess**, not worker thread — only address-space
232
+ isolation survives the uncatchable GPU OOM): move the inference runtime
233
+ into its own persistent child process behind the existing
234
+ `GenerationGateway` seam. The main process becomes a pure reactor (UI +
235
+ API + routing, zero MLX calls); one GPU lease serializes all GPU consumers
236
+ (chat, API, quantize, finetune) — reusing the spawn/lease pattern jobs
237
+ already prove. Converges with model hot-swap (model lives off the main
238
+ thread either way). Full design + phasing: `docs/design/runtime-isolation.md`.
239
+
240
+ ## Harness UX
241
+
242
+ Harness setup should be executable, not just documented.
243
+
244
+ ```sh
245
+ mlx-bun harness
246
+ mlx-bun harness pi
247
+ mlx-bun harness hermes
248
+ mlx-bun harness openclaw
249
+ ```
250
+
251
+ `mlx-bun harness` should open an interactive picker. Direct subcommands
252
+ should configure a specific harness.
253
+
254
+ Each harness adapter can:
255
+
256
+ - Detect whether the harness is installed.
257
+ - Preserve existing user config.
258
+ - Add or update the local mlx-bun provider entry.
259
+ - Point it at the local server.
260
+ - Select the right API protocol.
261
+ - Validate the connection with a tiny request.
262
+ - Show the command to launch the harness.
263
+
264
+ Pi deserves a first-class path because it can be embedded through its SDK:
265
+
266
+ ```sh
267
+ mlx-bun harness pi
268
+ mlx-bun pi
269
+ ```
270
+
271
+ `mlx-bun harness pi` configures the user's existing Pi install. `mlx-bun
272
+ pi` should start the local mlx-bun runtime and launch Pi itself against
273
+ that runtime. If the Pi TUI is the right surface, use it. If an embedded
274
+ SDK session is the right surface, use that.
275
+
276
+ Other harnesses should follow the same adapter pattern.
277
+
278
+ Sketch:
279
+
280
+ ```ts
281
+ interface HarnessAdapter {
282
+ id: "pi" | "hermes" | "openclaw";
283
+ label: string;
284
+ detect(): Promise<Detection>;
285
+ configure(profile: RuntimeProfile): Promise<ConfigureResult>;
286
+ validate(profile: RuntimeProfile): Promise<ValidationResult>;
287
+ launch?(profile: RuntimeProfile): Promise<void>;
288
+ }
289
+ ```
290
+
291
+ ## CLI shape
292
+
293
+ Possible command map:
294
+
295
+ ```sh
296
+ mlx-bun # recommended model + server + UI
297
+ mlx-bun serve # server only
298
+ mlx-bun ui # UI only, connect to local/running server
299
+ mlx-bun repl # Bun REPL with a local AI client preloaded
300
+ mlx-bun pi # launch embedded Pi against mlx-bun
301
+ mlx-bun harness # interactive harness setup
302
+ mlx-bun harness pi # configure existing Pi
303
+ mlx-bun harness hermes # configure Hermes
304
+ mlx-bun harness openclaw # configure OpenClaw
305
+ mlx-bun models # installed and recommended models
306
+ mlx-bun fit # device/model fit information
307
+ mlx-bun doctor # diagnostics
308
+ ```
309
+
310
+ Flags should compose with these modes. The default is opinionated, not
311
+ restrictive.
312
+
313
+ Examples:
314
+
315
+ ```sh
316
+ mlx-bun --model gemma-4-12b --context 65536
317
+ mlx-bun serve --no-ui --port 8090
318
+ mlx-bun pi --model qwen-profile
319
+ mlx-bun harness pi --base-url http://localhost:8090/v1
320
+ ```
321
+
322
+ ## Research loop behind the product
323
+
324
+ The product table should be backed by the same research discipline as
325
+ PLAN.md:
326
+
327
+ 1. Pick a small set of real target devices.
328
+ 2. Pick a small set of candidate model artifacts.
329
+ 3. Measure fit, context, decode speed, TTFT, memory, and quality.
330
+ 4. Specialize the runtime for winning artifacts.
331
+ 5. Promote only defaults that pass clean-machine measurements.
332
+ 6. Keep fallback and explicit override paths for research and power users.
333
+
334
+ The first family is Gemma 4 OptiQ. Qwen is the next obvious family to
335
+ evaluate. The default model should be whichever gives the best experience
336
+ for a device profile and use case, not whichever family arrived first.
337
+
338
+ ## Artifact design
339
+
340
+ Longer term, mlx-bun may not only choose among existing model artifacts.
341
+ It may create artifacts for exact device/use-case targets.
342
+
343
+ The useful question is not "can we save 1% RAM?" It is:
344
+
345
+ ```text
346
+ Can this model fit on this device,
347
+ with this context window,
348
+ above this decode-speed floor,
349
+ while preserving enough quality for this use case?
350
+ ```
351
+
352
+ TurboQuant plus sensitivity analysis fits this direction. The quantizer
353
+ can target concrete SKU boundaries and context tiers:
354
+
355
+ - Make a specific model fit on 16 GB with useful context.
356
+ - Make a 12B-class model hit 64k context on 24-32 GB.
357
+ - Keep decode above 30 tok/s on the recommended profile.
358
+ - Preserve tool/agent behavior under the chosen quantization.
359
+
360
+ This turns quantization from generic compression into product-driven
361
+ artifact design.
362
+
363
+ ## Runtime specialization
364
+
365
+ When a user asks to run a specific model, there is no ambiguity in the hot
366
+ path. The artifact, config, tensor shapes, KV config, quantization layout,
367
+ chat template, and architectural quirks are known.
368
+
369
+ The generic runtime is scaffolding for research, portability, and
370
+ fallback. The served instance can be specialized:
371
+
372
+ - Generated per-model execution paths.
373
+ - Branches and loops removed where the model shape is fixed.
374
+ - Per-layer quant bits/group sizes baked in.
375
+ - Known cache layouts and attention patterns used directly.
376
+ - Custom kernels generated or selected for exact dispatch sites.
377
+
378
+ Compatibility paths remain the oracle. Specialized paths are promoted
379
+ only when they are correct, measured, and useful.
380
+
381
+ ## Lucien / memory-system direction (candidate, 2026-06-12)
382
+
383
+ A second product direction under debate alongside the UI/harness work:
384
+ make mlx-bun the local-model engine for Lucien (the Dreaming memory
385
+ system), in two stages.
386
+
387
+ 1. **Prove the models do real work.** Run Lucien's pipeline tasks
388
+ (session ingestion, synthesis into articles, recall-grounded chat)
389
+ against mlx-bun-served models. Measure quality and performance per
390
+ task — this is a real-workload eval, not a benchmark row, and it
391
+ feeds the profile table (which model tier can sustain synthesis
392
+ work? what context does recall actually need?).
393
+ 2. **Package it.** If the models hold up: mlx-bun as a Lucien backend
394
+ option — one executable that creates the memory store, gathers
395
+ session transcripts, synthesizes them into articles, and serves
396
+ conversations grounded on those articles. Same appliance principle
397
+ as the chat default: one binary, one command, a working memory
398
+ system.
399
+
400
+ This stresses exactly the things the runtime is good at measuring:
401
+ long-context prefill, sustained batch-ish generation, prompt-cache
402
+ reuse across pipeline stages.
403
+
404
+ ## Non-goals for the default UX
405
+
406
+ - Do not make the user choose from thousands of Hugging Face variants on
407
+ first run.
408
+ - Do not benchmark their machine before giving a recommendation.
409
+ - Do not require Python, a venv, or manual server setup.
410
+ - Do not require hand-editing harness config files.
411
+ - Do not expose every research flag before the user has a working local
412
+ AI experience.
413
+
414
+ ## Open questions
415
+
416
+ - What exact profile table should ship first?
417
+ - Should no-args open the UI automatically, print a local URL, or both?
418
+ - Which UI stack should be embedded?
419
+ - How much of Pi should be bundled, embedded, or configured externally?
420
+ - What is the minimum first-run UI that feels good enough?
421
+ - What is the right install path: Homebrew, curl installer, GitHub
422
+ release, or all of the above?
423
+ - How should background downloads interact with server startup and UI
424
+ readiness?
425
+ - How should profile recommendations be versioned as benchmarks improve?
426
+ - When Qwen lands, what evals decide whether it replaces a Gemma default?
@@ -0,0 +1,119 @@
1
+ # Research Topics
2
+
3
+ Speculative, exploratory directions for mlx-bun — theses worth prototyping, not
4
+ committed work. Each entry carries enough detail to pick up cold. PLAN.md is for
5
+ work in flight; this is for ideas waiting their turn.
6
+
7
+ ---
8
+
9
+ ## 1. Tonal Grading for Token Distributions ("HDR Sampling")
10
+
11
+ > Replace the global scalar sampling knobs (temperature, top-k, top-p) with a
12
+ > region-aware **transfer function** applied to logits before softmax — the
13
+ > color-grading move, ported to token distributions.
14
+
15
+ **Framing — the Wes Anderson point.** A film's symmetrical pastel look isn't a
16
+ colorist failing to neutralize; it's a *target*. Grade Marvel that way and it's
17
+ "wrong" only against Marvel's acceptance function, not against any absolute.
18
+ Different films, different targets — and you have a lot of films. The
19
+ Lucien-synthesis agent and the test-writing agent want different *looks*, and
20
+ "temperature + a system-prompt vibe word" is the crude contrast slider standing
21
+ in for a real grade.
22
+
23
+ **Core thesis.** Current LLM sampling is "SDR": the available controls
24
+ (temperature, top-k, top-p) are crude *global* knobs — the equivalent of a single
25
+ contrast slider. Color grading abandoned "just turn the contrast knob" long ago
26
+ in favor of transfer functions with region-specific behavior. The same move is
27
+ available for sampling: replace global scalar knobs with a region-aware transfer
28
+ function applied to the logits before softmax.
29
+
30
+ **The reframe that makes it work.** Signal vs. noise is defined by *intent*, not
31
+ by magnitude — exactly as on a camera sensor, where the noise floor is "noise"
32
+ because it doesn't represent what's wanted, not because it's small. The full
33
+ logit vector is the model's signal, but it is not the signal *I* care about. My
34
+ acceptance criterion defines which part is signal. The low-logit tail is
35
+ therefore legitimately treatable as a noise floor to roll off.
36
+
37
+ **The three regions** — one curve, three treatments. This is precisely what
38
+ temperature *cannot* do, since it scales everywhere uniformly:
39
+
40
+ - **Shoulder** (head / confident tokens): soft rolloff instead of hard
41
+ truncation. Top-k/top-p slam into the ceiling and clip; a shoulder eases the
42
+ top tokens toward co-equality while *preserving their ordering* — it tames
43
+ single-token dominance without destroying the relationships among the spared
44
+ tokens.
45
+ - **Midtones** (the plausible-but-distinct band): steepen for local contrast.
46
+ Push apart the tokens that matter so detail comes out sharp. This has no name
47
+ in current sampling because sampling has no concept of distributional
48
+ midtones — and it's the most novel piece.
49
+ - **Toe** (tail / unwanted tokens): roll into the floor. Defines them as noise
50
+ relative to intent.
51
+
52
+ **Curve vocabulary, ported from grading:**
53
+
54
+ - **Pivot/cut** placed *relative* to the distribution (by rank or percentile),
55
+ recomputed every step — never an absolute logit value, because logits are only
56
+ meaningful up to an additive constant (softmax shift-invariance). HLG's
57
+ relative / scene-referred design is the right philosophical match; LogC3 is
58
+ more absolute / exposure-locked.
59
+ - **Slope-matched splices** between regions (C1 continuity — no kink in how
60
+ adjacent-ranked tokens get treated).
61
+ - **Curve family:** signed / `log1p`-style forms to stay finite on negative
62
+ logits. An HLG-style architecture (gamma toe + log shoulder, slope-matched) is
63
+ the leading candidate because its two-regime structure happens to match the
64
+ two-regime structure of a real logit distribution — temperature-style shaping
65
+ on the uncertain tail, log-style compression on the overconfident head.
66
+
67
+ **Why it's not overclaiming.** I am *not* claiming buried capability that a curve
68
+ "unclips" — the logits aren't a compressed encoding of something richer. The
69
+ honest claim: there is an acceptable manifold the model can't articulate and the
70
+ default transform doesn't reliably land on; the curve encodes my
71
+ *observer-relative acceptance function* onto a distribution that has no opinion
72
+ of its own. This is why sampling knobs exist at all — "friendly / neutral /
73
+ professional" are crude gestures at exactly this, and a grade is the
74
+ high-resolution version.
75
+
76
+ **The per-agent-target insight (the payoff).** "Correctly transformed to display"
77
+ is not universally acceptable — it's unacceptable for an Oscar-buzz feature and
78
+ fine for a sports broadcast, because they have different acceptance functions.
79
+ Grading Marvel like Wes Anderson isn't incompetence; it's the wrong *target*. My
80
+ agents are different films:
81
+
82
+ - A **conversation→article synthesis** agent wants range, texture, and
83
+ surprising-but-apt word choices — "cinematic."
84
+ - An **acceptance-criteria→tests** agent wants tight, predictable, low-variance
85
+ determinism — "broadcast neutral."
86
+
87
+ They want different *grades*, not different *temperatures*. Per-task tonal
88
+ curves, not per-task scalar knobs.
89
+
90
+ **Open engineering question — build this first.** The colorist works in a tight
91
+ perceptual loop against a calibrated reference monitor; a sampler's curve is
92
+ chosen *upstream* of seeing output, with a slower, noisier judgment loop. So the
93
+ gating question isn't "is the curve good" — it's **"what is the monitor?"** What
94
+ readout tells me the midtones got crisper and the highlights rolled off well, per
95
+ target? Candidates: held-out preference, diversity-at-fixed-quality, task-specific
96
+ pass rates (for the test agent) vs. human preference (for the synthesis agent).
97
+ Define the per-target reference monitor first; the curve design follows from it
98
+ the way a grade follows from a trustworthy display.
99
+
100
+ **Implementation.** A pure elementwise function on the logits tensor inside
101
+ mlx-bun's per-step logits-processor hook: sort once for the rank-relative pivot,
102
+ apply the slope-matched toe/mid/shoulder curve, renormalize, sample. The hook
103
+ already exists — logits processors run at
104
+ [`generate.ts:236`](../../src/generate.ts:236)
105
+ (`for (const p of processors) logits = disposing(logits, p(history, logits))`),
106
+ built by `makeLogitsProcessors` in [`src/sampler.ts`](../../src/sampler.ts) as pure
107
+ `(history, logits) => logits` functions applied before `toLogprobs` and the
108
+ sampler — so the curve drops in as one more processor in that loop.
109
+
110
+ Given dispatch dominates decode wall time (~90–96%), the curve's arithmetic cost
111
+ rides inside work already dispatched — wall-time-negligible. Parameterize: pivot
112
+ rank, toe exponent, midtone slope, shoulder compression. A/B against plain
113
+ temperature **at matched effective entropy**, judged on the per-target monitor —
114
+ looking for outputs that land in the target region *unreachably* by
115
+ temperature-plus-top-p at any setting, not merely "different."
116
+
117
+ *Relation to current code:* the `--temperature` / `--top-p` / `--top-k` server
118
+ defaults (and `generation_config.json`) are the SDR knobs this topic proposes to
119
+ supersede — useful as the A/B baseline, not the destination.
@@ -0,0 +1,77 @@
1
+ # Chunk-task quality roadmap (2026-06-17)
2
+
3
+ Where the MiniCPM5 chunking adapter stands and what raises real segmentation
4
+ quality. Companion to [[chunk-eval-metric-vs-accuracy]] and
5
+ [`docs/investigations/chunk-finetune-experiment.md`](../investigations/chunk-finetune-experiment.md).
6
+
7
+ ## Where we are
8
+
9
+ - Adapter **solved the output contract**: 0/25 invalid JSON (base model: 22/25
10
+ invalid — unusable). That's the entire 95.10 well-formedness score.
11
+ - Adapter is **mediocre at the actual task**: vs-gold boundary ~35.6, label ~52.0,
12
+ all 25 cases in disagreement (`reports/chunk-eval-cpm-2026-06-17.html`).
13
+ - Dominant failures: `under_split` 17/25, TAIL GAP / `missed_content` 9,
14
+ hallucinated anchors 4 — explained by the training-data bias below.
15
+
16
+ ## Step 1 (the lever): fix the training data
17
+
18
+ The data (`chunk-data-le4000`) is **86% single-chunk** (626/730 examples = 1 chunk,
19
+ mean 1.16, max 4). The model learned a strong "one short chunk" prior → it
20
+ under-splits and truncates coverage. A 1B model on this diet isn't at its capacity
21
+ ceiling, it's mimicking its data.
22
+
23
+ - Rebuild the dataset so the **chunk-count distribution matches real operational
24
+ segmentation**, not a single-topic majority.
25
+ - Teach **full-transcript coverage** (spans that reach the end — kill the tail gaps).
26
+ - This is the #1 lever. Do it before touching capacity or iters.
27
+
28
+ ## Eval methodology: do NOT judge against codex's gold
29
+
30
+ **Codex over-segments — it splits articles ~2× what we actually do in operations.**
31
+ So the current gold is inflated: judging the adapter as `under_split` is partly an
32
+ artifact of a gold that over-splits. The under-split signal is real but smaller than
33
+ the verdict count suggests.
34
+
35
+ - Recalibrate the gold to **operational granularity** (use real-ops segmentations as
36
+ the reference, or down-weight codex's extra splits) before trusting `bs`/`ls`.
37
+ - Until the gold matches ops, the report **understates** the adapter.
38
+ - Going forward, optimize against operational gold, not codex, and not the saturated
39
+ well-formedness score.
40
+
41
+ ## rank / scale: tune for a single narrow task
42
+
43
+ We are telling CPM to do exactly **one** thing: take a sequence of messages and find
44
+ the topic seams. That narrowness should drive the LoRA capacity knobs deliberately —
45
+ revisit the inherited rank 16 / scale 1 rather than carrying old defaults. Folds into
46
+ the "configurable training params with mlx-lm defaults" task (rank / scale / num_layers
47
+ / LR / dropout selectable at run start). The question to answer empirically: how little
48
+ rank does this one transformation need, and what scale/LR pairs with it.
49
+
50
+ ## Streaming / windowed segmentation mode
51
+
52
+ Whole-transcript-at-once is one framing; it likely isn't the operational one. Explore:
53
+
54
+ - A **sliding message window** — segment incrementally as messages arrive, over a
55
+ bounded window, rather than ingesting the entire conversation.
56
+ - "Lots of different ways to segment these conversations" — try multiple task
57
+ formulations (whole-transcript vs windowed vs streaming/online) and measure which
58
+ matches operations and trains best on a small model.
59
+ - Implications for training data shape (windowed targets) and for serving (a streaming
60
+ endpoint / incremental decode).
61
+
62
+ ## Evaluate other base models
63
+
64
+ CPM5-1B is tiny and was a memory-driven pick. Run a **bake-off**: score other base
65
+ models on the chunk task (same gold, same harness) to find the best base for the
66
+ chunking adapter. Capacity is the second lever after data — and the e4b +
67
+ segmented-backward work exists precisely to train bigger models at long context. See
68
+ [[e4b-lora-training-seqlen-ceiling]], [[segmented-backward-landed]].
69
+
70
+ ## Ordered plan
71
+
72
+ 1. **Fix the training data** (multi-chunk + full coverage, operational granularity).
73
+ 2. **Recalibrate the eval gold** off codex toward operational segmentation.
74
+ 3. **Tune rank/scale** for the single narrow task (with configurable params).
75
+ 4. **Prototype streaming/windowed** segmentation; pick the framing that fits ops.
76
+ 5. **Model bake-off**; move up in capacity (e4b via segmented backward) if data alone
77
+ plateaus.