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
package/README.md CHANGED
@@ -1,626 +1,109 @@
1
1
  # mlx-bun
2
2
 
3
- **One command, chatting in under a minute** — a fully local AI on your
4
- Apple Silicon Mac's GPU, no Python, no API key:
5
-
6
- ```sh
7
- curl -fsSL https://mlx-bun.dev/install.sh | sh
8
- mlx-bun
9
- ```
3
+ A Bun/TypeScript native inference engine and OpenAI-compatible HTTP server
4
+ for MLX on Apple Silicon — no Python, no sidecar process. `mlx-bun serve` is
5
+ a drop-in for `mlx_lm.server` (same port, endpoints, request fields, and
6
+ flags); the correctness contract is logit parity with mlx-lm as the oracle,
7
+ verified bit-exact by the test suite. Ships as one signed, notarized binary,
8
+ plus a library-first TypeScript API for embedding generation directly in
9
+ Bun, Tauri, or Electron apps.
10
10
 
11
11
  Docs: **[mlx-bun.dev](https://mlx-bun.dev)**
12
12
 
13
- Native MLX inference for Bun, and the beginning of a one-command local AI
14
- product for Apple Silicon Macs. `mlx-bun` detects the machine, starts a useful
15
- local assistant, exposes OpenAI/Anthropic-compatible APIs, and gives
16
- TypeScript apps direct access to MLX without Python or a sidecar server.
17
-
18
- Six goals, in one binary:
19
-
20
- 1. **A drop-in replacement for `mlx_lm.server`** — same port, endpoints,
21
- request fields, and flags; stop the Python server, start `mlx-bun serve`,
22
- the same curl works ([site guide](https://mlx-bun.dev/guides/drop-in-mlx-lm/)).
23
- 2. **A TypeScript library** — embed MLX generation in Bun/Tauri/Electron apps,
24
- or ship it as a signed single-binary sidecar
25
- ([library](./docs/reference/library-api.md), [embedding](./docs/reference/embedding.md)).
26
- 3. **Bit-exact, fast, and memory-honest** — logit parity with the Python
27
- reference as the correctness oracle, measured speed wins, and a
28
- deterministic `fit` memory contract ([benchmarks](#benchmarks),
29
- [correctness](#correctness)).
30
- 4. **One command, under a minute** — the appliance path above; the default
31
- experience needs zero configuration ([getting started](#getting-started)).
32
- 5. **A personal memory** — a local, git-tracked wiki your assistant reads and
33
- (via local synthesis) writes ([memory](#personal-memory)).
34
- 6. **An AI lab** — training, speculative decoding, and sampling research kept
35
- next to the runtime that serves them ([the lab](#the-lab)).
36
-
37
- The product bet is that local AI on Mac is a finite optimization problem, not
38
- an infinite configuration maze: Apple ships a known set of chip/RAM/bandwidth
39
- SKUs, the supported model list is curated, and the task mode is explicit. That
40
- means defaults can be chosen from measured device × model × mode profiles
41
- instead of asking every user to become an ML systems engineer.
13
+ ## Scope
42
14
 
43
- Measured head-to-head on an M4 Pro (24 GB), same models, same machine
44
- state: logits **bit-exact** against the Python reference; served over
45
- HTTP the **fastest stack on every model tested** — fastest decode, plus
46
- TTFT **34–85 ms** vs python's 218–326 ms at **~0% server overhead**
47
- (mlx-lm pays −5–6%); server start to ready in **0.17–0.47 s**, 2–5×
48
- faster than the Python servers. Full table: [benchmarks](#benchmarks).
15
+ Apple Silicon only — MLX is a Metal framework, so this runs on macOS on M-series
16
+ chips by design, nothing else. Serving is single-user: one process serves one
17
+ loaded model to one caller at a time (`--isolate --model-pool N` pools
18
+ multiple single-model children behind a router; it isn't a multi-tenant
19
+ scheduler). Model support is a curated, oracle-backed list, not a generic
20
+ "any HF repo" loader — see the roster for what's validated.
49
21
 
50
- ## Getting started
22
+ ## Install
51
23
 
52
- You need an Apple Silicon Mac (MLX is Metal-only, so macOS only by
53
- design). Four ways in.
54
-
55
- ### Direct download (recommended)
56
-
57
- No Homebrew, Bun, or git — just curl the install script. It downloads the
58
- signed, notarized self-contained binary from the latest release and puts
59
- `mlx-bun` on your PATH:
24
+ Four ways in; all need an Apple Silicon Mac running macOS.
60
25
 
61
26
  ```sh
27
+ # Direct download — signed, notarized, no toolchain
62
28
  curl -fsSL https://mlx-bun.dev/install.sh | sh
63
- mlx-bun
64
- ```
65
-
66
- Self-contained (binary + MLX runtime) and notarized, so it runs without a
67
- Gatekeeper prompt. Installs to `~/.mlx-bun` by default — override with
68
- `MLX_BUN_INSTALL_DIR`, or pin a release with `MLX_BUN_VERSION=<tag>`
69
- (see [releases](https://github.com/joshuarossi/mlx-bun/releases)).
70
-
71
- ### Homebrew
72
-
73
- A self-contained, signed + notarized binary — no toolchain to install by
74
- hand:
75
29
 
76
- ```sh
30
+ # Homebrew
77
31
  brew install joshuarossi/tap/mlx-bun
78
- mlx-bun
79
- ```
80
-
81
- That's the whole thing. The bottle already bundles the MLX native
82
- runtime, so the only thing the first run fetches is the model.
83
32
 
84
- ### bunx (no install)
85
-
86
- Already have [Bun](https://bun.sh) ≥ 1.4.0? Run it straight from npm,
87
- nothing to install:
88
-
89
- ```sh
33
+ # bunx — no install, needs Bun >= 1.4.0
90
34
  bunx mlx-bun
91
- ```
92
-
93
- First run fetches the MLX native runtime plus the streamed-expert helper
94
- (~52 MB) and the model into your caches, then serves. (Bun only — `npx
95
- mlx-bun` under Node exits with a
96
- "requires Bun" notice by design.)
97
-
98
- ### From source
99
-
100
- Needs [Bun](https://bun.sh) ≥ 1.4.0 — no Python, no native library to
101
- install by hand:
102
-
103
- ```sh
104
- # 1. Install Bun
105
- curl -fsSL https://bun.sh/install | bash
106
- exec $SHELL -l
107
35
 
108
- # 2. Clone, install, link the CLI
36
+ # From source
109
37
  git clone https://github.com/joshuarossi/mlx-bun.git && cd mlx-bun
110
- bun install
111
- bun run link-cli # adds the `mlx-bun` command — or run `bun src/cli.ts <verb>`
112
-
113
- # 3. Run it — that's the whole thing
114
- mlx-bun
38
+ bun install && bun run link-cli
115
39
  ```
116
40
 
117
- Bare `mlx-bun` is an alias for `mlx-bun serve`. On its first run, with no
118
- model named, it does everything for you:
119
-
120
- 1. pulls the MLX native runtime plus streamed-expert helper (~52 MB) into
121
- `~/Library/Caches/mlx-bun/`
122
- (skipped on the Homebrew install — the runtime ships in the bottle);
123
- 2. downloads the sub-GB `MiniCPM5-1B` starter and serves it, so you're
124
- chatting in well under a minute;
125
- 3. starts downloading `gemma-4-e4b` (the stronger 4B model) in the
126
- background — it becomes the default on your next `mlx-bun serve`;
127
- 4. opens the chat UI in your browser at
128
- [`http://localhost:8080/#/chat`](http://localhost:8080/#/chat)
129
- (pass `--no-open` to skip).
41
+ Every channel builds from the same bundle. Details, signing, and the native
42
+ runtime resolution order: [docs/reference/distribution.md](./docs/reference/distribution.md).
130
43
 
131
- Want a specific model instead? Name it — `mlx-bun serve e4b` (substring
132
- match against your downloaded models), grabbing it first with
133
- `mlx-bun get <repo-id>` if you don't have it. See
134
- [Supported models](#supported-models) for the full list and what fits
135
- your machine.
44
+ ## Quickstart
136
45
 
137
- **Prefer the API?** It's OpenAI-compatible — any OpenAI client works:
46
+ Bare `mlx-bun` aliases to `mlx-bun serve`; with no model named it downloads a
47
+ sub-GB starter and opens a chat UI. To pick a model explicitly:
138
48
 
139
49
  ```sh
140
- curl http://localhost:8080/v1/chat/completions \
141
- -H 'Content-Type: application/json' \
142
- -d '{
143
- "messages": [{"role": "user", "content": "Hello!"}],
144
- "max_tokens": 128, "temperature": 0.7
145
- }'
50
+ mlx-bun serve e4b --port 8080
146
51
  ```
147
52
 
148
- That's it. The server serves the one model it was started with (the
149
- request's `model` field is ignored and the loaded model id is echoed
150
- back in responses). Run `serve --isolate --model-pool N` instead and
151
- the parent proxy pools per-model engine children, routing each request
152
- by its `model` field and spawning on demand — see
153
- [docs/reference/server-config.md](./docs/reference/server-config.md)
154
- and [docs/design/runtime-isolation.md](./docs/design/runtime-isolation.md).
155
-
156
- Longer walkthrough on the site:
157
- [Installation](https://mlx-bun.dev/getting-started/installation/) and
158
- [Quickstart](https://mlx-bun.dev/getting-started/quickstart/).
159
-
160
- ## What mlx-bun is
161
-
162
- `mlx-bun` has several faces, all sharing one native runtime:
163
-
164
- - **The local AI product** — run `mlx-bun` or `bunx mlx-bun` and get a
165
- working local chat UI plus a local server. The default path should feel like
166
- an appliance: download the starter model, start chatting quickly, then move
167
- to the stronger recommended model as it becomes available.
168
- - **The app developer library** — embed local MLX inference inside Bun,
169
- Tauri, Electron, and other TypeScript applications without running Python in
170
- the background.
171
- - **The background agent runtime** — leave a local OpenAI-compatible endpoint
172
- available for scripts, recurring jobs, app integrations, and per-request
173
- adapter routing.
174
- - **The local memory layer** and **the AI lab** — each gets its own section
175
- below.
176
-
177
- The default experience is intentionally opinionated. Power users can override
178
- models, budgets, KV modes, adapters, and flags; the average user should not
179
- need to know those knobs exist.
180
-
181
- ## Personal memory
182
-
183
- `mlx-bun memory init` creates a git-tracked Markdown wiki at
184
- `~/.mlx-bun/wiki`; `Reference/` is seeded with read-only symlinks to
185
- mlx-bun's own docs, and the built-in pi agents read both quietly through two
186
- separate tool families — `reference_search`/`reference_read` for the seeded
187
- Reference docs, `memory_search`/`memory_section`/`memory_read` for your own
188
- articles — and can open it in Obsidian for you (`mlx-bun memory open
189
- [article]`). Chat-time memory is
190
- read-only; synthesis is the separate writer path: `mlx-bun memory synthesize`
191
- runs the built-in local pipeline (segment → extract → route → create/patch →
192
- reconcile → link → wikify) that turns your conversations into cross-linked
193
- subject articles, using the same local models with a fine-tuned chunking LoRA
194
- adapter.
195
-
196
- It's your data in your format: plain Markdown, git history, editable in any
197
- tool, never leaves the machine. Reference:
198
- [docs/reference/memory.md](./docs/reference/memory.md); synthesis design:
199
- [docs/design/memory-synthesis.md](./docs/design/memory-synthesis.md); on the
200
- site: [Personal memory](https://mlx-bun.dev/guides/memory/).
201
-
202
- ## The lab
203
-
204
- Parity, evals, kernels, training, and sampling research live next to the
205
- runtime that serves them:
206
-
207
- - **LoRA fine-tuning on your Mac** (SFT / DPO / ORPO) — `mlx-bun train
208
- <model> --data <dir>`, with a flash-CCE Metal head, segmented backward, and
209
- prefix-sharing so long-context preference training fits laptop memory;
210
- watch runs live with `mlx-bun train-watch`
211
- ([training](./docs/reference/training.md),
212
- [quickstart](./docs/reference/orpo-quickstart.md)).
213
- - **The curve designer** — HLG tone-curve sampling with an interactive
214
- designer in the server UI at `/curves`
215
- ([design](./docs/archive/hlg-sampling.md)).
216
- - **Speculative decoding research (DSpark)** — a KV-injection drafter
217
- ([design](./docs/design/dspark-speculative-decoding.md)).
218
- - The full research trail — including dead ends — is tracked in
219
- [docs/design/](./docs/design/) and
220
- [docs/archive/investigations/](./docs/archive/investigations/).
221
-
222
- On the site: [The lab](https://mlx-bun.dev/about/lab/).
223
-
224
- ## Supported models
225
-
226
- Scope is deliberate: a few model families held to explicit oracle contracts,
227
- rather than dozens held to none. Currently MiniCPM5, the Gemma-4 OptiQ quants,
228
- the Qwen 3.x family, and the direct-container GLM-5.2 path:
229
-
230
- | Model | Download | Fits on | Vision | Notes |
231
- |---|---|---|---|---|
232
- | [`mlx-community/MiniCPM5-1B-OptiQ-4bit`](https://huggingface.co/mlx-community/MiniCPM5-1B-OptiQ-4bit) | 0.92 GB | 8 GB | — | Sub-GB option for 8 GB machines; bit-exact 100-step oracle parity (bf16 + mixed KV), tool calling + agent loop verified |
233
- | [`mlx-community/Qwen3.5-4B-OptiQ-4bit`](https://huggingface.co/mlx-community/Qwen3.5-4B-OptiQ-4bit) | 3.1 GB | 8 GB | — | bf16-KV bit-exact parity (vs mlx-lm); thinking + tool calling; ~74 tok/s predicted |
234
- | [`mlx-community/gemma-4-e4b-it-OptiQ-4bit`](https://huggingface.co/mlx-community/gemma-4-e4b-it-OptiQ-4bit) | 7.0 GB | 16 GB | ✓ | **Recommended starter** (16 GB+); ~56 tok/s |
235
- | [`mlx-community/gemma-4-12B-it-OptiQ-4bit`](https://huggingface.co/mlx-community/gemma-4-12B-it-OptiQ-4bit) | 8.4 GB | 16 GB | ✓ | Vision + tool calling, both verified end-to-end |
236
- | [`mlx-community/gemma-4-26B-A4B-it-OptiQ-4bit`](https://huggingface.co/mlx-community/gemma-4-26B-A4B-it-OptiQ-4bit) | 18 GB | 24 GB | — | MoE (top-8 of 128 experts); ~54 tok/s |
237
- | [`mlx-community/Qwen3.8-27B-OptiQ-4bit`](https://huggingface.co/mlx-community/Qwen3.8-27B-OptiQ-4bit) | 20.4 GB | 32 GB (24 GB with `--memory-budget`) | image + video | Current-gen Qwen; bf16-KV bit-exact parity (vs mlx-lm); thinking with `reasoning_effort` (xhigh/medium/low) + `preserve_thinking` + tool calling; native MTP head mounts as a `--draft-model` (lossless-by-verify, recurrent-cache rollback built in); **image AND video input serve** (`image_url` / `video_url` content parts — dedicated vision tower + mRoPE; video decodes via macOS-native AVFoundation, 2 fps ≤768 frames) |
238
- | [`mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp`](https://huggingface.co/mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp) | ~384 GB / 357 GiB | 32 GB + fast disk | — | Direct streamed Colibri container; true top-8, native MTP, bounded 25 GiB process plan; warm single-stream performance is disk-bound and below the aspirational 2 tok/s target |
239
-
240
- Not sure what fits your machine? `bun src/cli.ts fit <model> --ctx 8192`
241
- gives a deterministic answer (see below). Downloading, cache layout, and
242
- reclaiming disk: [docs/reference/models.md](./docs/reference/models.md);
243
- on the site: [Choosing a model](https://mlx-bun.dev/getting-started/models/).
244
-
245
- ### GLM-5.2: 32 GB quickstart
246
-
247
- Choose a volume with at least the artifact remainder plus 1 GiB free before
248
- starting; mlx-bun checks this before the first payload and credits resumable
249
- partials. The validated artifact revision and exact 25 GiB serving command are
250
- documented in the [model-management guide](./docs/reference/models.md#glm-52-on-a-32-gb-mac):
251
-
252
53
  ```sh
253
- export HF_HUB_CACHE=/Volumes/FastSSD/huggingface/hub # optional large fast volume
254
- mlx-bun get mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp \
255
- --revision 3cc8db99b1b13fc79325d987ba3c1c430766b3b8
256
- mlx-bun scan
257
- mlx-bun serve GLM-5.2-colibri --memory-budget 26.8435456 \
258
- --context-length 4096 --max-tokens 128 --mtp on
259
- ```
260
-
261
- Rerun `get` after interruption; partial files resume and every completed blob
262
- is checksum-verified. The model remains in the standard Hugging Face cache—no
263
- Python environment and no second converted copy inside this repository.
264
-
265
- ## Why
266
-
267
- MLX is Apple's ML framework: hand-tuned Metal kernels for Apple Silicon,
268
- with official bindings for Python, C++, Swift, and C — but no JavaScript
269
- story. Today, a JS/TS app that wants local MLX inference must shell out to
270
- a Python server (mlx-lm, optiq) and accept that stack's fragility: venv
271
- setup, brittle download tooling, segfaults on exit, monkey-patched HTTP
272
- layers.
273
-
274
- The performance-critical work — every matmul, every attention pass — lives
275
- in MLX's C++/Metal core and is exposed through `mlx-c`. The Python layer on
276
- top is pure orchestration: model loading, tokenization, the sampling loop,
277
- serving. That layer is performance-neutral (the GPU dominates), so it can
278
- be rewritten in any runtime without losing speed — and Bun is the right
279
- one:
280
-
281
- - **`bun:ffi`** — lowest-overhead FFI of any JS runtime; binds `mlx-c`
282
- directly, no node-gyp, no binding compilation.
283
- - **Lazy native weight loading** — mlx's loader materializes tensors on
284
- first use; opening an 8.4 GB model takes milliseconds, and warm
285
- restarts are near-instant on cached pages.
286
- - **`Bun.Image`** — native OS image codecs (HEIC, AVIF, WebP, JPEG, …)
287
- for the vision path, EXIF auto-orientation included.
288
- - **`bun:sqlite`** — built-in storage for the model registry and eval DB.
289
- - **One binary, one toolchain** — runtime, package manager, test runner.
290
-
291
- ## CLI
292
-
293
- Commands are shown as `bun src/cli.ts <verb>` (runs straight from a
294
- clone). Once installed/linked, `mlx-bun <verb>` is the identical command.
295
-
296
- ```sh
297
- bun src/cli.ts get mlx-community/gemma-4-12B-it-OptiQ-4bit # resumable, verified download
298
- bun src/cli.ts scan # index your HF cache into the registry
299
- bun src/cli.ts ls # list models (size, params, quant, capabilities)
300
- bun src/cli.ts ls --vision --max-size 10GB
301
- bun src/cli.ts fit gemma --ctx 32768 # memory contract: fits? max context? predicted tok/s
302
- bun src/cli.ts fit gemma --ctx 8192 --skus # ...same, across the Apple Silicon lineup
303
- bun src/cli.ts fit GLM-5.2 # streamed plan: disk vs resident slabs + measured speed
304
- bun src/cli.ts serve gemma --port 8080 # OpenAI-compatible server
305
- bun src/cli.ts serve gemma --memory-budget 18 # ...with admission control (GB)
306
- bun src/cli.ts generate gemma "a haiku about metal shaders" # raw one-shot generation
307
- bun src/cli.ts train e4b --data ./pref-data --method orpo # LoRA fine-tune (SFT/DPO/ORPO)
308
- bun src/cli.ts memory init # git-tracked Markdown wiki at ~/.mlx-bun/wiki
309
- bun src/cli.ts memory synthesize # conversations -> cross-linked wiki articles, all local
310
- bun src/cli.ts pi # built-in agentic coding CLI (pi's TUI, in-process)
311
- bun src/cli.ts evals # recorded benchmark runs
312
- bun src/cli.ts harness pi # connect your own pi install to the local server
313
- ./benchmark.sh # head-to-head matrix vs mlx-lm/optiq (reboot first;
314
- # preflight-gated, resumable, writes benchmarks-h2h-<date>-<host>.md)
54
+ curl http://localhost:8080/v1/chat/completions \
55
+ -H 'Content-Type: application/json' \
56
+ -d '{"messages": [{"role": "user", "content": "Hello!"}], "max_tokens": 128}'
315
57
  ```
316
58
 
317
- Model arguments are substring queries against the registry (`e4b`,
318
- `26B`, `12B-it`); a query matching more than one model errors out
319
- listing the candidates — just make it more specific.
320
-
321
- `fit` is deterministic, not vibes: weights bytes from safetensors
322
- headers, KV bytes/token from the config (sliding-window layers capped,
323
- MoE active-expert bytes for decode), calibrated prefill transient, and
324
- the machine's wired-memory ceiling. Predictions are recorded next to
325
- measured peaks in the eval DB. The direct Colibri GLM-5.2 path uses its exact
326
- streamed plan instead: full artifact-on-disk size is separated from bounded
327
- resident weights, main/MTP expert slabs, KV, and reserves, and measured warm
328
- decode is separated from the direct oracle and the 2 tok/s aspiration.
329
-
330
- Every verb, with flags: [docs/reference/cli.md](./docs/reference/cli.md);
331
- on the site: [CLI reference](https://mlx-bun.dev/reference/cli/).
332
-
333
- ## HTTP API
334
-
335
- `serve` exposes an OpenAI-compatible API. Anything that speaks the
336
- OpenAI protocol can point at it — the OpenAI SDK
337
- (`baseURL: "http://localhost:8080/v1"`, any non-empty `apiKey`), or
338
- agent CLIs like pi/OpenClaw via their provider config.
339
-
340
- - **`POST /v1/chat/completions`** — streaming (SSE) and non-streaming;
341
- `temperature`, `top_p`, `top_k`, `max_tokens`, `seed`,
342
- `repetition_penalty`, `stop` (string or array, matched on decoded
343
- text with streaming hold-back), `reasoning_effort` (thinking on/off for
344
- Qwen3.5/3.8 / MiniCPM5 — `none` disables, any level enables; on Qwen3.8
345
- the level also sets reasoning depth: `low`/`medium`/`xhigh`), a Qwen3.8
346
- `chat_template_kwargs.preserve_thinking` toggle (keep think blocks from
347
- history; default on), and an `hlg` tone-curve sampling override;
348
- omitted sampling fields default to the model's own
349
- `generation_config.json` recipe; usage includes `cached_tokens`.
350
- Full schemas in
351
- [docs/reference/server-api.md](./docs/reference/server-api.md); start
352
- flags and the `--batch N` compatibility matrix in
353
- [docs/reference/server-config.md](./docs/reference/server-config.md).
354
- - **Tool calling** — pass OpenAI `tools`; each family's native format
355
- is parsed into `tool_calls` JSON with `finish_reason: "tool_calls"`
356
- (Gemma 4 `<|tool_call>` sentinel tokens; MiniCPM5 / Qwen3.5
357
- `<function name=…>` XML with schema-aware argument decoding);
358
- `role: "tool"` round-trips, including multi-turn agent loops.
359
- The built-in `web_fetch` tool accepts public HTTP(S) destinations only,
360
- revalidates DNS and every redirect, and streams into a 1 MiB response cap.
361
- - **Structured output** — `response_format` (JSON mode / JSON schema),
362
- plus the vLLM/oMLX aliases `guided_grammar`, `guided_regex`,
363
- `guided_choice`, and `structured_outputs`, enforced by
364
- grammar-constrained decoding (xgrammar) on chat and raw completions,
365
- serial and batched lanes alike; a grammar that fails to compile
366
- degrades to a string-valued constraint-specific prompt injection
367
- (oMLX parity) instead of an error
368
- (`MLX_BUN_GRAMMAR=0` disables mask compilation server-wide and routes
369
- requested constraints through that same warning-bearing degrade path).
370
- - **Vision** — `image_url` content parts (data: URLs or http/s), on
371
- models with the vision sidecar. PNG, JPEG, HEIC, AVIF, WebP, TIFF,
372
- GIF, BMP via native OS codecs. Remote fetches are SSRF-guarded by
373
- default (private/loopback/LAN destinations refused); opt out with
374
- `--allow-private-media` / `MLX_BUN_ALLOW_PRIVATE_MEDIA=1`.
375
- - **Audio input** — `input_audio` content parts (base64 WAV, plus
376
- `audio` / `audio_url` aliases), on models whose sidecar ships the
377
- audio tower (gemma-4 e4b). WAV decoded natively; mp3, m4a, FLAC, ogg,
378
- AIFF via CoreAudio. Up to 30 s per clip; images and audio mix in one
379
- message — a capability neither mlx-lm nor optiq serves. Same SSRF
380
- guard and opt-out as `image_url` applies to `audio_url`.
381
- - **Prompt caching** — a byte-capped LRU KV cache reuses the longest
382
- common token prefix across requests (multi-turn conversations
383
- re-prefill only the new turn) — automatic, no client changes.
384
- Entries are adapter-specific when LoRA adapters are in play. With
385
- `--ssd-cache`, pending snapshots are flushed durably on `SIGINT`/`SIGTERM`;
386
- `POST /admin/cache/flush` exposes the same boundary for automation.
387
- - **LoRA hot-swap** — mount adapters at runtime (`POST /v1/adapters`)
388
- and discover on-disk ones (`GET /v1/adapters/available`), select per
389
- request with the `adapter` body field (`"id"`, stacked `"a+b"`, or
390
- `"none"`). The base model never reloads; an unselected adapter costs
391
- nothing.
392
- - **Mixed-precision KV** — opt in with `--kv-quant config` when the model
393
- repo ships `kv_config.json` (every Gemma-4 OptiQ repo does): per-layer
394
- KV quantization with bits set per layer for both full-attention and
395
- sliding-window (rotating) layers (Phase 9). It trades decode speed
396
- (measured 5–20% at ≤16k, on mlx-lm's uniform scheme too) for KV bytes
397
- ÷4 on the quantized layers — reach for it when context, not speed, is
398
- the constraint. The default KV cache is bf16 (the mlx-lm-parity L1
399
- route); `--kv-quant 4|8` selects uniform bits instead, and
400
- `--kv-quant turbo[:kXvY]` opts into TurboQuant rotation-based KV
401
- (affine keys + FWHT/Lloyd-Max values, full-attention layers, serial
402
- lane — [design](./docs/design/turboquant-kv.md)). Long prefills
403
- over quantized caches run a fused FlashAttention-2 tiling that never
404
- materializes the full scores matrix (bounded transient;
405
- `MLX_BUN_NO_FUSED_SDPA=1` to disable).
406
- - **Speculative decoding** — `serve --draft-model <path|query>`
407
- (mlx_lm.server parity; `--num-draft-tokens`): the drafter KIND is
408
- auto-detected from the artifact (`--draft-kind` overrides) — a full
409
- smaller same-tokenizer model (mlx-lm parity), a Gemma `-assistant`
410
- KV-borrowing drafter (optiq parity), a DeepSpec/DSpark
411
- hidden-tapping drafter (e.g. DeepSeek's released
412
- `dspark_gemma4_12b_block7`), or **model-free prompt-lookup drafting**
413
- (`--draft-kind ngram`, no draft artifact at all — drafts are copied
414
- from the request's own prompt/generation; free wins on echo-heavy
415
- workloads like extraction and code edits, lossless at any
416
- temperature). The main model verifies every draft —
417
- exact results, faster decode when drafts land; pays on 12B-class
418
- targets, not small fast models. Serial lane only — with `--batch N` a
419
- mounted draft routes every request serial, like mlx_lm.server.
420
- - **Memory admission control** — `--memory-budget <GB>` refuses to load
421
- a model that can't serve within the budget. For requests, `max_tokens`
422
- is a ceiling, not a promise: a broad client value is capped to the room
423
- remaining under the safe context, and only a prompt that leaves no
424
- generation slot at all is rejected with a 400
425
- (`type: "memory_admission"`) *before* generating. The GPU
426
- out-of-memory crash it prevents is uncatchable by design — rejection
427
- up front is the only defense. Ceiling visible at `GET /stats`.
428
- - **Anthropic Messages API** (`POST /v1/messages`, on by default) —
429
- point any Anthropic-SDK tool at the server
430
- (`ANTHROPIC_BASE_URL=http://localhost:8080`); Claude Code runs
431
- against it as a fully local backend. Streaming event grammar, native
432
- tool_use/tool_result mapping, image blocks via the vision path.
433
- - **OpenAI Responses API** (`POST /v1/responses`) — the protocol
434
- Codex/Cursor/Continue speak; includes `previous_response_id`
435
- resumption backed by a TTL + byte-capped store (visible in /stats).
436
- - **OpenAI Embeddings API** (`POST /v1/embeddings`) — when the served
437
- model is an embedding model (`mlx-bun serve Qwen3-Embedding-4B-4bit-DWQ`):
438
- last-token pooled, L2-normalized vectors, bit-exact vs mlx-lm. Also a
439
- one-shot CLI: `mlx-bun embed <model> --text "…"`.
440
- - **`GET /v1/models`**, **`GET /stats`** (cache hit rates, bytes,
441
- active KV scheme, response store), **`GET/POST/DELETE /v1/adapters`**,
442
- plus **`GET /library`**, **`GET /fit`**, **`GET /downloads`**, and
443
- **`GET /v1`** (a self-describing index of every endpoint).
444
-
445
- Guide with examples on the site:
446
- [The HTTP API](https://mlx-bun.dev/guides/http-api/); coming from
447
- `mlx_lm.server`:
448
- [Drop-in for mlx-lm](https://mlx-bun.dev/guides/drop-in-mlx-lm/).
449
-
450
- ## Library
451
-
452
- The server is one consumer of a library-first API. Published to npm as
453
- `mlx-bun` — import from the package (`from "mlx-bun"`)
454
- or `./src/index` in a clone; `bunx mlx-bun` runs the CLI without
455
- installing. Full reference:
456
- [docs/reference/library-api.md](./docs/reference/library-api.md). For shipping inside a
457
- Mac app (Tauri/Electron sidecar), `./scripts/build-binary.sh` produces
458
- a relocatable single-binary bundle — recipe incl. signing/notarization
459
- in [docs/reference/embedding.md](./docs/reference/embedding.md).
460
-
461
59
  ```ts
462
- import {
463
- openModel, // artifact-aware, incl. bounded streamed GLM-5.2
464
- loadTokenizer, ChatTemplate, generate,
465
- } from "mlx-bun"; // or "./src/index" in a clone
466
-
467
- const dir = "/path/to/hf/snapshot";
468
- const model = await openModel(dir); // RuntimeModel
469
- const tok = await loadTokenizer(dir);
470
- const template = await ChatTemplate.load(dir);
471
-
472
- const ids = tok.encode(template.render([{ role: "user", content: "Hi!" }]));
473
- const gen = generate(model, ids, {
474
- maxTokens: 256,
475
- temperature: 0.7, topP: 0.95, seed: 42, // reproducible sampling
476
- kvBits: 8, quantizedKvStart: 4096, // optional: quantized KV past 4k
60
+ import OpenAI from "openai";
61
+ const client = new OpenAI({ baseURL: "http://localhost:8080/v1", apiKey: "local" });
62
+ const res = await client.chat.completions.create({
63
+ model: "local",
64
+ messages: [{ role: "user", content: "Hello!" }],
477
65
  });
478
- for await (const t of gen) process.stdout.write(tok.decode([t.token], true));
479
- console.log(gen.stats); // prompt/decode tok/s, cached tokens, ...
480
66
  ```
481
67
 
482
- `openModel()` first resolves a declared model profile: exact immutable artifact
483
- profiles outrank dedicated family paths, which outrank the generic fallback.
484
- Profiles select the loader/model graph/generation loop and carry their fidelity
485
- contract; they never rewrite explicit or default-resolved KV, MTP, adapter,
486
- grammar, or sampling choices. `loadContext()` exposes the resolved declaration
487
- as `ctx.profile`, and direct library users can call `resolveModelProfile()`.
488
-
489
- KV caches can be persisted to disk (page-aligned files that reload as
490
- zero-copy GPU-safe mmaps — see `src/kv-store.ts`) so a standard agent
491
- preamble prefills once, ever.
492
-
493
- On the site: [Using the library](https://mlx-bun.dev/guides/library/) and
494
- [Embedding in a Mac app](https://mlx-bun.dev/guides/embedding/).
495
-
496
- ## Benchmarks
497
-
498
- Head-to-head against the Python stacks (mlx-lm 0.31.3, mlx-optiq 0.2.1),
499
- same machine (M4 Pro 24 GB), same HF snapshots, the 2026-06-14
500
- cleared-machine run, preflight-gated, median-of-N with warmups
501
- discarded. Full curated table (parity / performance / quality) with
502
- per-row provenance: [benchmarks/RESULTS.md](./benchmarks/RESULTS.md).
503
-
504
- **Served (warm)** — how agents actually use a local model.
505
- decode tok/s · TTFT ms · start s:
506
-
507
- | model | mlx-bun | mlx-lm | optiq |
508
- |---|---|---|---|
509
- | MiniCPM5-1B | **252.9** · 34 · 0.17 | — | 223.6 · 64 · 0.84 |
510
- | gemma-4-e4b | **55.7** · 44 · 0.36 | 53.5 · 218 · 0.98 | 53.4 · 221 · 0.78 |
511
- | gemma-4-12B | **25.9** · 85 · 0.38 | — | 25.5 · 326 · 1.24 |
512
- | gemma-4-26B | **54.2** · 45 · 0.47 | 52.3 · 228 · 0.77 | — |
513
-
514
- Across every served model mlx-bun has the fastest decode and the fastest
515
- TTFT/startup (2–5×), at **~0% server tax** vs its own direct engine —
516
- mlx-lm pays −5–6%, optiq −1 to −10%.
517
-
518
- **Direct (engine only).** Decode is at parity-to-slightly-behind mlx-lm
519
- (e4b +1.1%, 12B +0.4%, 26B −1.1%, MiniCPM5 −0.9% — within the per-step
520
- host-overhead residual), and prefill leads on the larger models (12B
521
- 1.2×, 26B 1.1×, MiniCPM5 2.3×; e4b trails at 0.8×). The earlier decode
522
- deficit was root-caused and fixed (2026-06-11) — a prefill→decode
523
- allocator-reclaim stall mlx-lm clears with `mx.clear_cache` and bills to
524
- prompt time; see PLAN.md "Decode gap RESOLVED".
525
-
526
- **Long context (12B).** At 16k and 64k mlx-bun holds decode parity with
527
- mlx-lm on bf16 (16k 23.9 = 23.9; 64k 20.9 = 20.9) while optiq drops to
528
- 21.6 then collapses to 12.3 at 64k; mixed-KV trades ~2 tok/s for ~5 GB
529
- lower peak.
530
-
531
- Two cross-stack served cells are absent: no mlx-lm 12B row, and optiq
532
- produced no output on the 26B (the Metal-OOM class from python's
533
- non-lazy load transient — reproduced in isolation; mlx-bun and mlx-lm
534
- both served it from the same machine state). One further optiq cell
535
- (12B/kv=config) is blocked on an upstream `quantized_matmul` bug. Both
536
- are documented in the results file.
537
-
538
- On the site (with the honest negatives spelled out):
539
- [Benchmarks](https://mlx-bun.dev/about/benchmarks/).
540
-
541
- ## Correctness
542
-
543
- Logit parity with mlx-lm (same weights, Python reference) is the
544
- project's oracle. The test suite holds the forward pass **bit-exact**
545
- against it — including every quantized-KV configuration (kv8, kv4, and
546
- the 26B's mixed per-layer scheme) and the fused quantized-attention
547
- prefill, which is bit-exact against optiq's reference implementation.
548
- Every ported helper follows the reference implementation's exact op
549
- composition, down to constants built at load time (the one latent
550
- divergence ever found — rope frequencies computed host-side instead of
551
- on-device — was root-caused and fixed in Phase 10; see PLAN.md
552
- findings). Golden files are regenerated only by explicit scripts
553
- (`scripts/regen-*.ts`) running the Python oracle.
554
-
555
- ```sh
556
- bun test # fast tier runs everywhere; model-loaded tests run only
557
- # when the reference snapshot is in your HF cache
558
- ```
559
-
560
- On the site: [Correctness](https://mlx-bun.dev/about/correctness/) and
561
- [How it compares](https://mlx-bun.dev/about/comparison/).
562
-
563
- ## Troubleshooting
564
-
565
- - **`dlopen` / `libmlxc.dylib` not found** — the MLX runtime
566
- auto-downloads on first `serve` into `~/Library/Caches/mlx-bun/`; if a
567
- download was interrupted, just rerun `serve` (it resumes). To point at
568
- your own copy instead, set `MLX_BUN_LIBMLXC=/path/to/libmlxc.dylib`.
569
- - **`no models match`** — run `bun src/cli.ts scan` after downloading;
570
- models must be in the standard HF cache (`~/.cache/huggingface/hub`).
571
- - **HF download stalls at 0%** — use `bun src/cli.ts get <org/repo>`
572
- (plain HTTPS, no Xet, resumes where it left off); for the Python CLI,
573
- `HF_HUB_DISABLE_XET=1` before the download command.
574
- - **Slow decode on a model near your RAM ceiling** — close memory-heavy
575
- apps; a model that doesn't fit the wired-memory budget pages weights
576
- every token (check with `fit`).
577
- - **Bun version** — requires ≥ 1.4.0 (`bun upgrade`); pinned for
578
- `Bun.Image` and verified FFI behavior.
579
-
580
- ## Status
581
-
582
- Pre-alpha, moving fast. See [PLAN.md](./PLAN.md) for phases, exit
583
- criteria, measured numbers, and the findings log.
584
-
585
- **Complete** — load path; bit-exact model port (MiniCPM5, Qwen3.5-4B,
586
- Qwen3.8-27B, e4b per-layer-input, 12B dense, 26B MoE); sampling + serving (tools, vision,
587
- prompt cache); registry / fit / KV persistence; quantized +
588
- mixed-precision KV serving (rotating-cache KV-quant, Phase 9) with fused
589
- quantized prefill (Phase 10); LoRA hot-swap with per-request selection;
590
- segmented-backward LoRA training (SFT / DPO / ORPO, with an `[M,vocab]`-free
591
- flash-CCE head + prefix-sharing for long-context preference data — `mlx-bun
592
- train <model> --data <dir>`, see [training guide](docs/reference/training.md));
593
- resumable
594
- verified downloads (`mlx-bun get`); memory admission control; the
595
- head-to-head benchmark harness; the decode-gap root-cause fix
596
- (2026-06-11); Anthropic Messages + Responses API (`/v1/messages` and
597
- `/v1/responses`, Phase 11); SigLIP vision sidecar for e4b
598
- (commit 4625fe5); the embeddable single-binary build (signed +
599
- notarized — Homebrew, direct-download, and npm/bunx).
68
+ Longer walkthroughs on the site:
69
+ [Installation](https://mlx-bun.dev/getting-started/installation/) and
70
+ [Quickstart](https://mlx-bun.dev/getting-started/quickstart/).
600
71
 
601
- **In progress** — `Qwen3.8-27B` full support (Phase 14 retarget): text
602
- parity is bit-exact, thinking controls (`reasoning_effort` depths,
603
- `preserve_thinking`) + tool calling are wired, and native MTP speculation
604
- (the Qwen-trained head as a `--draft-model`) mounts through the serve
605
- loop's recurrent-cache rollback contract; vision and video input are in
606
- bring-up.
72
+ ## Reference docs
73
+
74
+ Each fact about the project has exactly one home:
75
+
76
+ | Topic | Doc |
77
+ |---|---|
78
+ | Current state, what's next | [STATUS.md](./STATUS.md) |
79
+ | Benchmark numbers (parity / performance / quality) | [docs/reference/benchmarks.md](./docs/reference/benchmarks.md) |
80
+ | Supported models roster | [docs/reference/models.md](./docs/reference/models.md) |
81
+ | Server start flags, `MLX_BUN_*` env, defaults | [docs/reference/server-config.md](./docs/reference/server-config.md) |
82
+ | HTTP API routes and request/response schemas | [docs/reference/server-api.md](./docs/reference/server-api.md) |
83
+ | CLI verbs | [docs/reference/cli.md](./docs/reference/cli.md) |
84
+ | TypeScript library API | [docs/reference/library-api.md](./docs/reference/library-api.md) |
85
+ | LoRA fine-tuning (SFT / DPO / ORPO) | [docs/reference/training.md](./docs/reference/training.md) |
86
+ | Build, sign, notarize, publish | [docs/reference/distribution.md](./docs/reference/distribution.md) |
87
+ | Troubleshooting | [docs/reference/troubleshooting.md](./docs/reference/troubleshooting.md) |
88
+ | Personal memory (local wiki) | [docs/reference/memory.md](./docs/reference/memory.md) |
89
+ | Reference environment / oracle setup | [docs/reference/environment.md](./docs/reference/environment.md) |
90
+ | Active engineering design docs | [docs/design/](./docs/README.md) |
91
+ | Contributing / repo rules | [CONTRIBUTING.md](./CONTRIBUTING.md) |
92
+
93
+ Correctness is verified bit-exact against the Python mlx-lm reference as the
94
+ project's oracle: [benchmarks.md § Parity](./docs/reference/benchmarks.md#1-parity-porting-correctness--bit-exact-vs-the-oracle).
607
95
 
608
- **Experimental** — opt-in, default-off, still being hardened: transparent
609
- expert offload for MoE models (`serve --expert-offload`, Phase 20:
610
- page-aligned mmap-backed experts, bit-exact — 26B-A4B 17.1→4.2 GB
611
- resident, decode unregressed); continuous serving (`--batch N`, default 8
612
- since 2026-07-05 — the scheduler's B=1 fast path uses serial-class caches and
613
- the parity-gated single-row graph, while the cap permits B=N under real
614
- concurrency such as coding sub-agents; `--batch 1` pins the preserved strict
615
- serial executor; Phase 18: bf16 decode at mlx-lm B=N parity,
616
- B=2 bit-parity verified for MiniCPM5/12B/e4b/26B; sampler extras,
617
- repetition penalty, and grammar-constrained requests batch; Qwen3.5's
618
- SSM caches batch, as do plain full-attention Tier-0 archs (e.g. Llama) —
619
- gemma2-family / sliding-window universal archs and DiffusionGemma route
620
- serial).
96
+ ## Why
621
97
 
622
- **Open** — e4b's ~5% per-step host-overhead decode residual (Phase 7);
623
- SigLIP vision for 26B.
98
+ MLX is Apple's ML framework — hand-tuned Metal kernels with official
99
+ bindings for Python, C++, Swift, and C, but no JavaScript story. The
100
+ performance-critical work (every matmul, every attention pass) lives in
101
+ MLX's C++/Metal core, exposed through `mlx-c`; the layer on top — model
102
+ loading, tokenization, sampling, serving — is pure orchestration and
103
+ performance-neutral, so it can move to a better runtime without losing
104
+ speed. Bun fits: `bun:ffi` binds `mlx-c` directly with no node-gyp step,
105
+ `Bun.Image` gives native OS image codecs for vision input, and the result
106
+ ships as one binary with no Python venv.
624
107
 
625
108
  ## License
626
109