mlx-bun 0.5.0 → 1.0.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 (640) hide show
  1. package/README.md +1449 -109
  2. package/THIRD_PARTY_NOTICES.md +882 -0
  3. package/bin/mlx-bun.convert.mjs +4 -0
  4. package/bin/mlx-bun.fuse.mjs +4 -0
  5. package/bin/mlx-bun.generate.mjs +4 -0
  6. package/bin/mlx-bun.lora.mjs +4 -0
  7. package/bin/mlx-bun.mjs +13 -21
  8. package/bin/mlx-bun.server.mjs +4 -0
  9. package/bin/mlx-bun.upload.mjs +4 -0
  10. package/dist/web/app.js +9584 -0
  11. package/package.json +50 -53
  12. package/src/cli/ane-install.ts +76 -0
  13. package/src/cli/args.ts +179 -0
  14. package/src/cli/engine-entry.ts +68 -0
  15. package/src/cli/inference.ts +214 -0
  16. package/src/cli/job-entry.ts +97 -0
  17. package/src/cli/library-host.ts +117 -0
  18. package/src/cli/main.ts +57 -0
  19. package/src/cli/memory-engine.ts +163 -0
  20. package/src/cli/memory.ts +36 -0
  21. package/src/cli/mlx-lm-aliases.ts +309 -0
  22. package/src/cli/model-choice.ts +33 -0
  23. package/src/cli/model-selection.ts +84 -0
  24. package/src/cli/module-host.ts +11 -0
  25. package/src/cli/module-verbs.ts +50 -0
  26. package/src/cli/numerical-policy.ts +12 -0
  27. package/src/cli/perplexity.ts +89 -0
  28. package/src/cli/serve-host.ts +423 -0
  29. package/src/cli/serve-isolated.ts +217 -0
  30. package/src/cli/serve-options.ts +106 -0
  31. package/src/cli/serve-state.ts +205 -0
  32. package/src/cli/serve.ts +500 -0
  33. package/src/cli/served-model-host.ts +102 -0
  34. package/src/cli/server-entry.ts +148 -0
  35. package/src/cli/serving-unit.ts +177 -0
  36. package/src/{tui.ts → cli/terminal.ts} +13 -8
  37. package/src/cli/worker-adapters.ts +34 -0
  38. package/src/cli/worker-entry.ts +272 -0
  39. package/src/cli/worker-unit.ts +179 -0
  40. package/src/engine/adapter-operation.ts +26 -0
  41. package/src/engine/cache-services.ts +114 -0
  42. package/src/engine/completion.ts +39 -0
  43. package/src/engine/generation-gateway.ts +358 -0
  44. package/src/engine/index.ts +59 -0
  45. package/src/engine/kv-budget.ts +120 -0
  46. package/src/engine/media-preparation.ts +232 -0
  47. package/src/engine/model-binding.ts +24 -0
  48. package/src/engine/model-host.ts +513 -0
  49. package/src/engine/model-serving.ts +89 -0
  50. package/src/{serve → engine}/preparation.ts +7 -5
  51. package/src/{serve → engine}/session-completion-engine.ts +6 -6
  52. package/src/engine/telemetry.ts +109 -0
  53. package/src/hub/downloads.ts +116 -0
  54. package/src/jobs/db.ts +16 -7
  55. package/src/jobs/events.ts +29 -0
  56. package/src/jobs/executable.ts +5 -0
  57. package/src/jobs/host.ts +51 -0
  58. package/src/jobs/in-process.ts +55 -0
  59. package/src/{contracts/jobs.ts → jobs/protocol.ts} +7 -9
  60. package/src/jobs/runner.ts +150 -231
  61. package/src/jobs/service.ts +75 -0
  62. package/src/jobs/sse.ts +59 -23
  63. package/src/jobs/worker-memory.ts +46 -0
  64. package/src/jobs/worker-process.ts +163 -0
  65. package/src/jobs/worker-supervisor.ts +258 -0
  66. package/src/modules.ts +58 -0
  67. package/src/publishing/catalog-hub.ts +18 -0
  68. package/src/publishing/credentials.ts +31 -0
  69. package/src/publishing/upload.ts +37 -0
  70. package/src/residency/leased-adapters.ts +21 -0
  71. package/src/residency/local-records.ts +16 -0
  72. package/src/residency/model-residency.ts +405 -0
  73. package/src/residency/record-index.ts +28 -0
  74. package/src/residency/resident-estimate.ts +50 -0
  75. package/src/{anthropic.ts → server/anthropic.ts} +3 -81
  76. package/src/server/cache-routes.ts +36 -0
  77. package/src/{serve → server}/chat-request.ts +10 -10
  78. package/src/{serve → server}/chat-stage.ts +14 -14
  79. package/src/{client.ts → server/client.ts} +28 -2
  80. package/src/{serve → server}/completion-executor.ts +33 -41
  81. package/src/server/decision-body.ts +55 -0
  82. package/src/server/decision-routes.ts +134 -0
  83. package/src/server/decision-wire.ts +228 -0
  84. package/src/{serve → server}/discovery-routes.ts +25 -82
  85. package/src/{serve → server}/http.ts +25 -13
  86. package/src/{serve → server}/inference-request.ts +5 -5
  87. package/src/server/job-routes.ts +20 -0
  88. package/src/server/media-prompt.ts +63 -0
  89. package/src/server/memory-completion-client.ts +46 -0
  90. package/src/server/model-routes.ts +192 -0
  91. package/src/{serve → server}/openai-wire.ts +3 -2
  92. package/src/{serve → server}/pipeline.ts +1 -1
  93. package/src/server/prompt-builder.ts +13 -0
  94. package/src/server/prompt-contracts.ts +17 -0
  95. package/src/server/proxy-routes.ts +187 -0
  96. package/src/server/publishing-routes.ts +41 -0
  97. package/src/{serve → server}/request-plan.ts +6 -8
  98. package/src/{serve → server}/request-prep.ts +47 -50
  99. package/src/{serve → server}/responses-client.ts +30 -13
  100. package/src/{responses.ts → server/responses.ts} +12 -93
  101. package/src/server/routes.ts +205 -0
  102. package/src/server/start.ts +72 -0
  103. package/src/server/status-routes.ts +108 -0
  104. package/src/{serve → server}/text-completion-stage.ts +25 -4
  105. package/src/server/text-prompt.ts +12 -0
  106. package/src/{serve → server}/token-streams.ts +36 -38
  107. package/src/server/worker-routes.ts +311 -0
  108. package/src/storage/paths.ts +61 -0
  109. package/src/web/assets.ts +37 -0
  110. package/src/web/{src → browser}/api.ts +5 -23
  111. package/src/web/browser/chat-host.ts +17 -0
  112. package/src/web/browser/installed-panels.ts +6 -0
  113. package/src/web/browser/main.ts +55 -0
  114. package/src/web/browser/markdown.ts +279 -0
  115. package/src/web/browser/memory-panel.ts +9 -0
  116. package/src/web/browser/palette.ts +64 -0
  117. package/src/web/browser/protocol.ts +13 -0
  118. package/src/web/browser/shell.ts +467 -0
  119. package/src/web/{src → browser}/status.ts +32 -36
  120. package/src/web/build.ts +51 -0
  121. package/src/web/public/app.html +1054 -0
  122. package/src/web/{sw.js → public/sw.js} +4 -3
  123. package/src/web/{vendor → public/vendor}/hljs-theme.css +2 -2
  124. package/src/web/{vendor → public/vendor}/hljs.js +2 -2
  125. package/THIRD_PARTY_LICENSES.md +0 -51
  126. package/docs/README.md +0 -107
  127. package/docs/archive/hlg-sampling.md +0 -350
  128. package/docs/archive/investigations/audio-input-plan.md +0 -356
  129. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +0 -3617
  130. package/docs/archive/investigations/chunk-finetune-experiment.md +0 -84
  131. package/docs/archive/investigations/colibri-glm52-port.md +0 -1486
  132. package/docs/archive/investigations/colibri-oracle-pin.md +0 -1284
  133. package/docs/archive/investigations/curve-bisector-routing.md +0 -123
  134. package/docs/archive/investigations/decode-roofline-lookagain.md +0 -348
  135. package/docs/archive/investigations/diffusion-gemma-port.md +0 -602
  136. package/docs/archive/investigations/dspark-handoff.md +0 -224
  137. package/docs/archive/investigations/expert-offload-single-user-moe.md +0 -292
  138. package/docs/archive/investigations/faithful-l1-consolidation.md +0 -310
  139. package/docs/archive/investigations/hlg-sampling-investigation.md +0 -970
  140. package/docs/archive/investigations/indexshare-performance-spike.md +0 -357
  141. package/docs/archive/investigations/kernel-perf-review-2026-07.md +0 -171
  142. package/docs/archive/investigations/lab-build-journal.md +0 -157
  143. package/docs/archive/investigations/minicpm5-decode-megakernel.md +0 -489
  144. package/docs/archive/investigations/openjarvis-fit.md +0 -198
  145. package/docs/archive/investigations/openwiki-evaluation.md +0 -249
  146. package/docs/archive/investigations/optimization_plan.md +0 -346
  147. package/docs/archive/investigations/orpo-base-uf-experiment-and-directions.md +0 -120
  148. package/docs/archive/investigations/orpo-flash-cce-pin-leak.md +0 -167
  149. package/docs/archive/investigations/orpo-uf-testing-handoff.md +0 -126
  150. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +0 -92
  151. package/docs/archive/investigations/pi-builtin-investigation.md +0 -308
  152. package/docs/archive/investigations/pre-colibri-stabilization.md +0 -329
  153. package/docs/archive/investigations/qwen38-27b-campaign-log.md +0 -1092
  154. package/docs/archive/investigations/segmented-backward-handoff.md +0 -148
  155. package/docs/archive/investigations/starter-model-port-handoff.md +0 -342
  156. package/docs/archive/investigations/steel-flash-cce-handoff.md +0 -489
  157. package/docs/archive/investigations/the-dreaming-handoff.md +0 -141
  158. package/docs/archive/investigations/trainer-validation-experiment.md +0 -173
  159. package/docs/archive/planning/chat-ui-vision-memory-first.md +0 -199
  160. package/docs/archive/planning/chat-ui-vision.md +0 -50
  161. package/docs/archive/planning/chunk-task-roadmap.md +0 -77
  162. package/docs/archive/planning/curve-sampler-research-plan.md +0 -331
  163. package/docs/archive/planning/journal.md +0 -316
  164. package/docs/archive/planning/memory-docs-and-dag-plan.md +0 -194
  165. package/docs/archive/planning/pi-integration-review.md +0 -178
  166. package/docs/archive/planning/release-notes-v0.0.10.md +0 -57
  167. package/docs/archive/planning/release-notes-v0.0.11.md +0 -239
  168. package/docs/archive/planning/release-notes-v0.0.12.md +0 -80
  169. package/docs/archive/planning/release-notes-v0.0.13.md +0 -77
  170. package/docs/archive/planning/release-notes-v0.0.9.md +0 -122
  171. package/docs/archive/planning/release-notes-v0.2.0.md +0 -49
  172. package/docs/archive/planning/release-notes-v0.3.0.md +0 -35
  173. package/docs/archive/planning/release-notes-v0.4.0.md +0 -45
  174. package/docs/archive/planning/release-notes-v0.5.0.md +0 -37
  175. package/docs/archive/planning/web-ui-pass-plan.md +0 -213
  176. package/docs/archive/planning/website-readme-pass-plan.md +0 -224
  177. package/docs/design/batching.md +0 -2054
  178. package/docs/design/decode-speed-program.md +0 -2404
  179. package/docs/design/dreaming-nightly-pipeline.md +0 -684
  180. package/docs/design/generic-model-support.md +0 -821
  181. package/docs/design/kv-cache.md +0 -993
  182. package/docs/design/orpo-training.md +0 -680
  183. package/docs/design/speculative-decoding.md +0 -2129
  184. package/docs/design/turboquant.md +0 -2225
  185. package/docs/design/unified-engine-frontier-plan.md +0 -1987
  186. package/docs/design/web-chat-redesign.md +0 -695
  187. package/docs/planning/PRODUCT_ROADMAP.md +0 -593
  188. package/docs/planning/ResearchTopics.md +0 -119
  189. package/docs/planning/public-readiness-handoff.md +0 -244
  190. package/docs/planning/public-readiness.md +0 -149
  191. package/docs/planning/video-series.md +0 -421
  192. package/docs/reference/benchmarks.md +0 -3587
  193. package/docs/reference/cli.md +0 -646
  194. package/docs/reference/distribution.md +0 -380
  195. package/docs/reference/environment.md +0 -494
  196. package/docs/reference/glossary.md +0 -39
  197. package/docs/reference/library-api.md +0 -688
  198. package/docs/reference/memory.md +0 -260
  199. package/docs/reference/models.md +0 -346
  200. package/docs/reference/server-api.md +0 -1945
  201. package/docs/reference/server-config.md +0 -973
  202. package/docs/reference/training.md +0 -462
  203. package/docs/reference/troubleshooting.md +0 -158
  204. package/src/admission-plan.ts +0 -18
  205. package/src/audio/audiotoolbox.ts +0 -112
  206. package/src/audio/conformer.ts +0 -655
  207. package/src/audio/decode.ts +0 -133
  208. package/src/audio/features.ts +0 -202
  209. package/src/audio/mic-capture.ts +0 -98
  210. package/src/audio/silero-vad.ts +0 -379
  211. package/src/audio/transcode.ts +0 -67
  212. package/src/audio/whisper-decode.ts +0 -774
  213. package/src/audio/whisper-fast.ts +0 -732
  214. package/src/audio/whisper-format.ts +0 -73
  215. package/src/audio/whisper-mel.ts +0 -185
  216. package/src/audio/whisper-timing.ts +0 -274
  217. package/src/audio/whisper-tokenizer.ts +0 -239
  218. package/src/audio/whisper-transcribe.ts +0 -410
  219. package/src/backends/mlx/assistant-target.ts +0 -46
  220. package/src/backends/mlx/autoregressive-draft-rows.ts +0 -120
  221. package/src/backends/mlx/autoregressive.ts +0 -129
  222. package/src/backends/mlx/batch-group.ts +0 -1874
  223. package/src/backends/mlx/cache-attachment.ts +0 -67
  224. package/src/backends/mlx/cache-layout.ts +0 -31
  225. package/src/backends/mlx/checkpoint-state.ts +0 -53
  226. package/src/backends/mlx/continuation-persistence.ts +0 -107
  227. package/src/backends/mlx/continuation-request.ts +0 -43
  228. package/src/backends/mlx/continuation.ts +0 -77
  229. package/src/backends/mlx/diffusion.ts +0 -39
  230. package/src/backends/mlx/draft-target.ts +0 -32
  231. package/src/backends/mlx/encoder-cache.ts +0 -25
  232. package/src/backends/mlx/evaluation.ts +0 -105
  233. package/src/backends/mlx/fill-append.ts +0 -58
  234. package/src/backends/mlx/fill-group.ts +0 -497
  235. package/src/backends/mlx/full-kv-row-append.ts +0 -32
  236. package/src/backends/mlx/full-kv-row-donor.ts +0 -54
  237. package/src/backends/mlx/full-transitioning-kv-rows.ts +0 -65
  238. package/src/backends/mlx/gateway-binding.ts +0 -174
  239. package/src/backends/mlx/graph.ts +0 -38
  240. package/src/backends/mlx/kv-codec.ts +0 -9
  241. package/src/backends/mlx/kv-maintenance.ts +0 -161
  242. package/src/backends/mlx/kv-tensor-rows.ts +0 -212
  243. package/src/backends/mlx/memory-client.ts +0 -189
  244. package/src/backends/mlx/methods.ts +0 -90
  245. package/src/backends/mlx/mixed-iteration.ts +0 -62
  246. package/src/backends/mlx/model-prompt.ts +0 -178
  247. package/src/backends/mlx/model-serving.ts +0 -80
  248. package/src/backends/mlx/paged-cache-codec.ts +0 -27
  249. package/src/backends/mlx/prefill-cohort.ts +0 -100
  250. package/src/backends/mlx/prefill-policy.ts +0 -26
  251. package/src/backends/mlx/prefill-rows.ts +0 -244
  252. package/src/backends/mlx/prefill.ts +0 -33
  253. package/src/backends/mlx/projected-context-rows.ts +0 -72
  254. package/src/backends/mlx/prompt-input.ts +0 -29
  255. package/src/backends/mlx/qwen-prompt-input.ts +0 -40
  256. package/src/backends/mlx/request-policy.ts +0 -20
  257. package/src/backends/mlx/request-state-policy.ts +0 -54
  258. package/src/backends/mlx/rollback.ts +0 -92
  259. package/src/backends/mlx/row-sampling.ts +0 -49
  260. package/src/backends/mlx/serial-executor.ts +0 -251
  261. package/src/backends/mlx/speculative-group.ts +0 -438
  262. package/src/backends/mlx/speculative-round.ts +0 -161
  263. package/src/backends/mlx/speculative.ts +0 -131
  264. package/src/backends/mlx/state-rows.ts +0 -104
  265. package/src/backends/mlx/state-views.ts +0 -46
  266. package/src/backends/mlx/target-layout-capability.ts +0 -35
  267. package/src/backends/mlx/text-engine.ts +0 -73
  268. package/src/backends/mlx/transitioning-kv-rows.ts +0 -173
  269. package/src/chat-template.ts +0 -382
  270. package/src/cli.ts +0 -3490
  271. package/src/config.ts +0 -399
  272. package/src/contracts/completion.ts +0 -16
  273. package/src/contracts/execution.ts +0 -70
  274. package/src/contracts/generation.ts +0 -103
  275. package/src/contracts/host.ts +0 -7
  276. package/src/contracts/object-cache.ts +0 -8
  277. package/src/contracts/pi-provider.ts +0 -30
  278. package/src/contracts/pi.ts +0 -261
  279. package/src/contracts/prefix-cache.ts +0 -33
  280. package/src/contracts/resources.ts +0 -25
  281. package/src/contracts/sampling.ts +0 -23
  282. package/src/contracts/scheduling.ts +0 -54
  283. package/src/contracts/tsconfig.json +0 -14
  284. package/src/dataset/generators.ts +0 -1087
  285. package/src/dataset/index.ts +0 -12
  286. package/src/dataset/job.ts +0 -81
  287. package/src/dataset/llm.ts +0 -71
  288. package/src/dataset/registry.ts +0 -528
  289. package/src/diffusion/diffusion-generate.ts +0 -507
  290. package/src/download.ts +0 -505
  291. package/src/embed.ts +0 -77
  292. package/src/engine/admission.ts +0 -59
  293. package/src/engine/cancellation.ts +0 -38
  294. package/src/engine/engine.ts +0 -56
  295. package/src/engine/execution-coordinator.ts +0 -70
  296. package/src/engine/execution-plan.ts +0 -64
  297. package/src/engine/execution-tasks.ts +0 -44
  298. package/src/engine/namespaced-cache.ts +0 -13
  299. package/src/engine/resources.ts +0 -53
  300. package/src/engine/scheduler.ts +0 -92
  301. package/src/engine/session.ts +0 -247
  302. package/src/eval/README.md +0 -130
  303. package/src/eval/ifeval.ts +0 -81
  304. package/src/eval/kl-prompts.ts +0 -29
  305. package/src/eval/kl.ts +0 -590
  306. package/src/eval/perplexity.ts +0 -164
  307. package/src/eval/quality-db.ts +0 -92
  308. package/src/eval/reference-logits.ts +0 -207
  309. package/src/eval/runner.ts +0 -124
  310. package/src/eval/score.ts +0 -49
  311. package/src/eval/tasks/bfcl.ts +0 -535
  312. package/src/eval/tasks/gsm8k.ts +0 -98
  313. package/src/eval/tasks/hashhop.ts +0 -139
  314. package/src/eval/tasks/humaneval.ts +0 -275
  315. package/src/eval/tasks/ifeval.ts +0 -525
  316. package/src/eval/tasks/mmlu.ts +0 -157
  317. package/src/eval/ultrafeedback.ts +0 -60
  318. package/src/evaldb.ts +0 -199
  319. package/src/expert-io.ts +0 -393
  320. package/src/expert-offload-build.ts +0 -77
  321. package/src/expert-offload.ts +0 -76
  322. package/src/expert-residency.ts +0 -1134
  323. package/src/expert-usage.ts +0 -415
  324. package/src/fill/echo-index.ts +0 -188
  325. package/src/fill/fill-session.ts +0 -463
  326. package/src/fill/proposal.ts +0 -68
  327. package/src/fill/schema-rows.ts +0 -506
  328. package/src/fill/tool-boundary.ts +0 -103
  329. package/src/fit.ts +0 -249
  330. package/src/generate.ts +0 -1352
  331. package/src/grammar.ts +0 -604
  332. package/src/harness-pi.ts +0 -184
  333. package/src/hf-push.ts +0 -628
  334. package/src/hub-rest.ts +0 -242
  335. package/src/index.ts +0 -63
  336. package/src/inference/denoising.ts +0 -17
  337. package/src/inference/draft-acceptance.ts +0 -41
  338. package/src/inference/draft-output.ts +0 -49
  339. package/src/inference/graph.ts +0 -33
  340. package/src/inference/prefill.ts +0 -45
  341. package/src/inference/rollback.ts +0 -7
  342. package/src/jobs/index.ts +0 -31
  343. package/src/jobs/job-entry.ts +0 -107
  344. package/src/jobs/task-client.ts +0 -19
  345. package/src/jobs/types.ts +0 -2
  346. package/src/kv-scheme.ts +0 -279
  347. package/src/kv-store.ts +0 -1135
  348. package/src/lab/README.md +0 -22
  349. package/src/lab/curve/curve-designer.html +0 -303
  350. package/src/lab/curve/curve-sampler.ts +0 -122
  351. package/src/lab/expert-trace/expert-trace.ts +0 -69
  352. package/src/lab/paged-kv/paged-attention.ts +0 -117
  353. package/src/lab/paged-kv/paged-kv-rows.ts +0 -111
  354. package/src/lab/paged-kv/paged-kv.ts +0 -336
  355. package/src/library.ts +0 -40
  356. package/src/lora.ts +0 -408
  357. package/src/md-modules.d.ts +0 -54
  358. package/src/media-fetch.ts +0 -442
  359. package/src/memory/article.ts +0 -558
  360. package/src/memory/chunk-validation.ts +0 -150
  361. package/src/memory/chunk.ts +0 -318
  362. package/src/memory/cluster.ts +0 -351
  363. package/src/memory/coverage.ts +0 -134
  364. package/src/memory/crosslink.ts +0 -0
  365. package/src/memory/db.ts +0 -253
  366. package/src/memory/entity.ts +0 -203
  367. package/src/memory/gate.ts +0 -187
  368. package/src/memory/history.ts +0 -152
  369. package/src/memory/ingest.ts +0 -335
  370. package/src/memory/model.ts +0 -183
  371. package/src/memory/normalize.ts +0 -671
  372. package/src/memory/parse.ts +0 -22
  373. package/src/memory/pipeline.ts +0 -275
  374. package/src/memory/prompts.ts +0 -65
  375. package/src/memory/query.ts +0 -334
  376. package/src/memory/reconcile.ts +0 -734
  377. package/src/memory/redirect.ts +0 -108
  378. package/src/memory/reindex.ts +0 -325
  379. package/src/memory/resolve.ts +0 -307
  380. package/src/memory/rest.ts +0 -245
  381. package/src/memory/route.ts +0 -272
  382. package/src/memory/schedule.ts +0 -165
  383. package/src/memory/stages.ts +0 -777
  384. package/src/memory/synthesize.ts +0 -1638
  385. package/src/memory/tools.ts +0 -749
  386. package/src/memory/vault.ts +0 -1194
  387. package/src/memory/wikify.ts +0 -1064
  388. package/src/mlx/array.ts +0 -425
  389. package/src/mlx/autograd.ts +0 -304
  390. package/src/mlx/checkpoint.ts +0 -149
  391. package/src/mlx/compile.ts +0 -168
  392. package/src/mlx/custom-vjp.ts +0 -188
  393. package/src/mlx/ffi.ts +0 -531
  394. package/src/mlx/materialize.ts +0 -23
  395. package/src/mlx/metal-kernel.ts +0 -159
  396. package/src/mlx/normalized-argmax.ts +0 -116
  397. package/src/mlx/ops.ts +0 -1108
  398. package/src/mlx/quantized-rows.ts +0 -36
  399. package/src/mlx/token-bitmask.ts +0 -52
  400. package/src/mlx/turboquant-kv-decode.ts +0 -82
  401. package/src/mlx/turboquant-kv-inverse.ts +0 -122
  402. package/src/mlx/turboquant-ops.ts +0 -861
  403. package/src/mlx/turboquant-tables.ts +0 -237
  404. package/src/mmap.ts +0 -90
  405. package/src/model/artifact-identity.ts +0 -73
  406. package/src/model/batched-kv.ts +0 -235
  407. package/src/model/batched-mask.ts +0 -279
  408. package/src/model/batched-quant.ts +0 -212
  409. package/src/model/batched-quantized-kv.ts +0 -144
  410. package/src/model/batched-rotating-quant.ts +0 -353
  411. package/src/model/batched-rotating-state.ts +0 -149
  412. package/src/model/batched-rotating.ts +0 -338
  413. package/src/model/batched-row-storage.ts +0 -179
  414. package/src/model/batched-ssm.ts +0 -52
  415. package/src/model/batched-turboquant-kv.ts +0 -94
  416. package/src/model/compiled-decode.ts +0 -712
  417. package/src/model/decoded-kv-donor.ts +0 -12
  418. package/src/model/delayed-quantized-kv.ts +0 -72
  419. package/src/model/delayed-rotating-quantized-kv.ts +0 -93
  420. package/src/model/delayed-turboquant-kv.ts +0 -57
  421. package/src/model/diffusion-gemma.ts +0 -1026
  422. package/src/model/factory.ts +0 -215
  423. package/src/model/fingerprint.ts +0 -45
  424. package/src/model/flash-attention.ts +0 -694
  425. package/src/model/full-prefill-padding.ts +0 -56
  426. package/src/model/full-prefill-row.ts +0 -105
  427. package/src/model/gemma4-base.ts +0 -2370
  428. package/src/model/gemma4.ts +0 -1395
  429. package/src/model/generated/gemma4-12b.ts +0 -429
  430. package/src/model/generated/gemma4-26b.ts +0 -448
  431. package/src/model/generated/gemma4-e4b.ts +0 -717
  432. package/src/model/generated/index.ts +0 -18
  433. package/src/model/glm52-atlas.ts +0 -511
  434. package/src/model/glm52-cache.ts +0 -792
  435. package/src/model/glm52-config.ts +0 -262
  436. package/src/model/glm52-container.ts +0 -305
  437. package/src/model/glm52-coupling.ts +0 -388
  438. package/src/model/glm52-dsa.ts +0 -606
  439. package/src/model/glm52-expert-layout.ts +0 -253
  440. package/src/model/glm52-layout.ts +0 -152
  441. package/src/model/glm52-memory.ts +0 -500
  442. package/src/model/glm52-mla.ts +0 -792
  443. package/src/model/glm52-moe.ts +0 -223
  444. package/src/model/glm52-pilot.ts +0 -537
  445. package/src/model/glm52-reference.ts +0 -445
  446. package/src/model/glm52-residency.ts +0 -557
  447. package/src/model/glm52-resident-weights.ts +0 -135
  448. package/src/model/glm52-streamed-experts.ts +0 -453
  449. package/src/model/glm52-streamed-metal.ts +0 -610
  450. package/src/model/glm52-weights.ts +0 -503
  451. package/src/model/glm52.ts +0 -1132
  452. package/src/model/implementation.ts +0 -69
  453. package/src/model/kv-attention-view.ts +0 -70
  454. package/src/model/minicpm5.ts +0 -376
  455. package/src/model/profile.ts +0 -468
  456. package/src/model/quantized-append-attention.ts +0 -31
  457. package/src/model/qwen-append.ts +0 -12
  458. package/src/model/qwen-conv.ts +0 -52
  459. package/src/model/qwen3-delta-state.ts +0 -74
  460. package/src/model/qwen3-delta.ts +0 -451
  461. package/src/model/qwen3-moe.ts +0 -404
  462. package/src/model/qwen3-mrope.ts +0 -250
  463. package/src/model/qwen3.ts +0 -277
  464. package/src/model/qwen3_5-checkpoint.ts +0 -164
  465. package/src/model/qwen3_5.ts +0 -881
  466. package/src/model/rotating-kv-donor.ts +0 -35
  467. package/src/model/rotating-kv-layout.ts +0 -262
  468. package/src/model/rotating-row-transaction.ts +0 -35
  469. package/src/model/speculative-rotating-kv.ts +0 -101
  470. package/src/model/ssm-prefill-padding.ts +0 -39
  471. package/src/model/support.ts +0 -110
  472. package/src/model/token-groups.ts +0 -66
  473. package/src/model/trellis-balanced-scatter.ts +0 -51
  474. package/src/model/trellis-linear.ts +0 -672
  475. package/src/model/trellis-shared-m.ts +0 -151
  476. package/src/model/trellis-shared-scatter.ts +0 -144
  477. package/src/model/trellis-splitk-prefill.ts +0 -158
  478. package/src/model/trellis-tiled-prefill.ts +0 -136
  479. package/src/model/trellis-vector-expand.ts +0 -62
  480. package/src/model/trellis-wide-prefill.ts +0 -94
  481. package/src/model/turboquant-codec.ts +0 -89
  482. package/src/model/universal/archs.ts +0 -332
  483. package/src/model/universal/dense.ts +0 -612
  484. package/src/model/universal/modules.ts +0 -170
  485. package/src/model/universal/rope.ts +0 -381
  486. package/src/model/whisper.ts +0 -435
  487. package/src/native/expert_io.c +0 -523
  488. package/src/native/frame_extract.swift +0 -140
  489. package/src/native/mic_capture.swift +0 -92
  490. package/src/native-pack.ts +0 -163
  491. package/src/pi-provider.ts +0 -53
  492. package/src/pi-session.ts +0 -81
  493. package/src/pi-terminal.ts +0 -274
  494. package/src/pi-web.ts +0 -1940
  495. package/src/preflight.ts +0 -158
  496. package/src/prompt-cache.ts +0 -682
  497. package/src/quantize/allocator.ts +0 -627
  498. package/src/quantize/atomic-output.ts +0 -38
  499. package/src/quantize/calibration.ts +0 -181
  500. package/src/quantize/config-writer.ts +0 -145
  501. package/src/quantize/index.ts +0 -84
  502. package/src/quantize/job.ts +0 -162
  503. package/src/quantize/quantizer.ts +0 -666
  504. package/src/quantize/rotate.ts +0 -603
  505. package/src/quantize/safetensors-writer.ts +0 -249
  506. package/src/quantize/sensitivity.ts +0 -216
  507. package/src/quantize/trellis.ts +0 -586
  508. package/src/quantize/weight-transform.ts +0 -292
  509. package/src/registry.ts +0 -602
  510. package/src/runtime-config.ts +0 -77
  511. package/src/safetensors.ts +0 -165
  512. package/src/sampler.ts +0 -1012
  513. package/src/serve/admin-routes.ts +0 -184
  514. package/src/serve/assets/curve-terrain.html +0 -105
  515. package/src/serve/assets/training-inference-map.html +0 -575
  516. package/src/serve/audio-routes.ts +0 -323
  517. package/src/serve/aux-routes.ts +0 -132
  518. package/src/serve/batch-scheduler.ts +0 -8
  519. package/src/serve/checkpoint-identity.ts +0 -64
  520. package/src/serve/generation-gateway.ts +0 -537
  521. package/src/serve/isolate.ts +0 -609
  522. package/src/serve/kv-budget.ts +0 -14
  523. package/src/serve/lab-routes.ts +0 -341
  524. package/src/serve/lane-registry.ts +0 -45
  525. package/src/serve/model-admin-routes.ts +0 -155
  526. package/src/serve/model-binding.ts +0 -49
  527. package/src/serve/model-host.ts +0 -511
  528. package/src/serve/parent-application.ts +0 -56
  529. package/src/serve/prompt-response-trace.ts +0 -161
  530. package/src/serve/response-lease.ts +0 -24
  531. package/src/serve/session-search.ts +0 -326
  532. package/src/serve/static-routes.ts +0 -101
  533. package/src/serve/transcription-server.ts +0 -64
  534. package/src/serve/transcription-service.ts +0 -502
  535. package/src/server.ts +0 -1282
  536. package/src/spec/assistant-rows.ts +0 -93
  537. package/src/spec/assistant-source.ts +0 -126
  538. package/src/spec/cache-identity.ts +0 -22
  539. package/src/spec/deepspec-rows.ts +0 -29
  540. package/src/spec/deepspec-source.ts +0 -145
  541. package/src/spec/dflash-source.ts +0 -149
  542. package/src/spec/drafter.ts +0 -304
  543. package/src/spec/dspark/ab-stats.ts +0 -136
  544. package/src/spec/dspark/calibration.ts +0 -112
  545. package/src/spec/dspark/data-dflash.ts +0 -156
  546. package/src/spec/dspark/data.ts +0 -201
  547. package/src/spec/dspark/deepspec-module.ts +0 -776
  548. package/src/spec/dspark/generate-dflash.ts +0 -245
  549. package/src/spec/dspark/generate.ts +0 -290
  550. package/src/spec/dspark/loader.ts +0 -23
  551. package/src/spec/dspark/loss.ts +0 -213
  552. package/src/spec/dspark/module-dflash.ts +0 -560
  553. package/src/spec/dspark/module.ts +0 -540
  554. package/src/spec/dspark/quantize-drafter.ts +0 -91
  555. package/src/spec/dspark/sample.ts +0 -112
  556. package/src/spec/generate.ts +0 -276
  557. package/src/spec/glm52-mtp-graph.ts +0 -29
  558. package/src/spec/glm52-mtp-rows.ts +0 -132
  559. package/src/spec/glm52-mtp-source.ts +0 -318
  560. package/src/spec/glm52-mtp-state.ts +0 -33
  561. package/src/spec/ngram-source.ts +0 -226
  562. package/src/spec/projected-draft-rows.ts +0 -73
  563. package/src/spec/qwen-mtp-module.ts +0 -171
  564. package/src/spec/qwen-mtp-rows.ts +0 -230
  565. package/src/spec/qwen-mtp-source.ts +0 -386
  566. package/src/spec/qwen-mtp-state.ts +0 -30
  567. package/src/spec/serve-loop.ts +0 -587
  568. package/src/spec/source.ts +0 -228
  569. package/src/spec/two-model-rows.ts +0 -62
  570. package/src/spec/two-model.ts +0 -113
  571. package/src/ssd-cache.ts +0 -431
  572. package/src/ssd-durability.ts +0 -209
  573. package/src/storage/host-buffer.ts +0 -24
  574. package/src/storage/kv-writer.ts +0 -83
  575. package/src/storage/kv-writer.worker.js +0 -264
  576. package/src/storage/retention-policy.ts +0 -37
  577. package/src/tiered-prompt-cache.ts +0 -45
  578. package/src/tokenizer.ts +0 -335
  579. package/src/tool-approvals.ts +0 -131
  580. package/src/tool-call.ts +0 -695
  581. package/src/train/dataset.ts +0 -484
  582. package/src/train/diffusion-lora.ts +0 -216
  583. package/src/train/export.ts +0 -32
  584. package/src/train/flash-cce.ts +0 -1234
  585. package/src/train/forward.ts +0 -266
  586. package/src/train/fuse.ts +0 -243
  587. package/src/train/index.ts +0 -46
  588. package/src/train/job.ts +0 -205
  589. package/src/train/lora-params.ts +0 -254
  590. package/src/train/loss.ts +0 -1591
  591. package/src/train/merge.ts +0 -195
  592. package/src/train/optimizer.ts +0 -183
  593. package/src/train/prefix-shared.ts +0 -490
  594. package/src/train/rank.ts +0 -137
  595. package/src/train/segmented.ts +0 -1828
  596. package/src/train/steel-qmm-header.ts +0 -1461
  597. package/src/train/trainer.ts +0 -1221
  598. package/src/train/watch.ts +0 -542
  599. package/src/vision/diffusion-vision.ts +0 -620
  600. package/src/vision/embedder.ts +0 -176
  601. package/src/vision/preprocess.ts +0 -247
  602. package/src/vision/prompt.ts +0 -409
  603. package/src/vision/qwen3vl-preprocess.ts +0 -409
  604. package/src/vision/qwen3vl-prompt.ts +0 -233
  605. package/src/vision/qwen3vl-tower.ts +0 -566
  606. package/src/vision/siglip.ts +0 -607
  607. package/src/vision/video-frames.ts +0 -148
  608. package/src/web/app.html +0 -2155
  609. package/src/web/app.js +0 -5863
  610. package/src/web/skills/memory/SKILL.md +0 -120
  611. package/src/web/skills/web-research/SKILL.md +0 -46
  612. package/src/web/skills.ts +0 -97
  613. package/src/web/src/adapters-panel.ts +0 -288
  614. package/src/web/src/assistant.ts +0 -451
  615. package/src/web/src/chat.ts +0 -1060
  616. package/src/web/src/composer.ts +0 -962
  617. package/src/web/src/dataset.ts +0 -132
  618. package/src/web/src/finetune.ts +0 -267
  619. package/src/web/src/hub.ts +0 -428
  620. package/src/web/src/main.ts +0 -98
  621. package/src/web/src/markdown.ts +0 -0
  622. package/src/web/src/memory-panel.ts +0 -572
  623. package/src/web/src/model-picker.ts +0 -159
  624. package/src/web/src/palette.ts +0 -346
  625. package/src/web/src/protocol.ts +0 -26
  626. package/src/web/src/quantize.ts +0 -167
  627. package/src/web/src/rag.ts +0 -274
  628. package/src/web/src/sessions.ts +0 -469
  629. package/src/web/src/shell.ts +0 -804
  630. package/src/web/src/ui-catalog.ts +0 -78
  631. package/src/web/src/voice.ts +0 -141
  632. package/src/web/vendor/README.md +0 -61
  633. package/src/web-assets.ts +0 -47
  634. package/src/web-tools.ts +0 -478
  635. package/src/weights.ts +0 -255
  636. /package/src/{serve → server}/completion-sink.ts +0 -0
  637. /package/src/{serve → server}/generated-token-history.ts +0 -0
  638. /package/src/web/{icon.svg → public/icon.svg} +0 -0
  639. /package/src/web/{manifest.webmanifest → public/manifest.webmanifest} +0 -0
  640. /package/src/web/{vendor → public/vendor}/hljs-LICENSE +0 -0
@@ -1,973 +0,0 @@
1
- # Server configuration
2
-
3
- The canonical reference for **every start flag, every `MLX_BUN_*`
4
- environment variable, and every serving feature** of `mlx-bun serve` (and
5
- `mlx-bun pi`, which shares the flag set). Each default here is read from
6
- the code, not from memory: flags are parsed by `serverRuntimeFlags()` /
7
- `applyDecodeRoute()` in [src/cli.ts](../../src/cli.ts) (the `SERVER_FLAGS`
8
- help block is the same list), runtime knobs land in `ServerOptions`
9
- ([src/server.ts](../../src/server.ts)), environment reads go through
10
- [src/runtime-config.ts](../../src/runtime-config.ts), and the `--isolate`
11
- proxy lives in [src/serve/isolate.ts](../../src/serve/isolate.ts). For the
12
- request/response wire format see [server-api.md](./server-api.md); for
13
- CLI verbs see [cli.md](./cli.md).
14
-
15
- The server runs generation through method-neutral sessions. A model binding
16
- supplies execution planning, its supported methods, media preparation and
17
- diagnostics. Stop/tool parsing runs directly in session delivery, so it can stop
18
- generation before another token is produced. This adds no architecture flag.
19
-
20
- Sections: [Start flags](#start-flags) · [`--isolate` semantics](#--isolate-semantics)
21
- · [Per-request overrides](#per-request-overrides) · [Environment variables](#environment-variables)
22
- · [Execution modes](#execution-modes-serial-vs---batch-n) · [Compatibility matrix](#compatibility-matrix)
23
- · [Fidelity tiers](#fidelity-tiers-and-the-decode-route---l1----l2) · [Feature matrix](#feature-matrix)
24
- · [Performance & recipes](#performance-characteristics--recipes) · [`GET /stats`](#observability--get-stats).
25
-
26
- ## Configuration ownership
27
-
28
- CLI presets and explicit flags resolve before model loading. Request preparation
29
- combines server defaults with request overrides once; explicit request values
30
- win. A bound execution keeps its immutable runtime snapshot across awaits.
31
- The tables below own the individual defaults and effective-value rules; this
32
- map identifies who consumes them.
33
-
34
- | Settings | Owning interface / implementation | Binding and use |
35
- |---|---|---|
36
- | Model selection, host/port, isolation, native paths, shutdown | CLI and server host | Startup and process lifecycle; no model-forward policy |
37
- | Batch capacity, queue/KV budget, prefill cohort budget, `MIXED_PREFILL`, `MIXED_TOKEN_BUDGET` | Scheduling policy and execution group | Choose admission and work size; never choose a codec or sample |
38
- | Draft kind/model/depth, `DSPARK_MINCONF`, `GRAMMAR_DRAFT_TOKENS` | Draft provider and inference method | Bind provider policy; propose tokens through the shared verifier |
39
- | `GRAMMAR_BATCH`, `BATCH_SSM`, `QWEN_SPEC_KV4`, compiled/grammar/fill eligibility | Model gateway and execution planner | Resolve supported composition before placement |
40
- | Temperature, seed, penalties, probability filters, logprobs, `BATCH_VEC_SAMPLE` | Sampling session | Request-owned policy and RNG; selected-token output remains device-backed where supported |
41
- | Thinking/template defaults, grammar schema, `GRAMMAR`, `TOKEN_MASK` | Chat renderer and grammar controller | Render and compile per request; no scheduling decisions |
42
- | KV scheme/start/group size, `PAGED_KV`, `PAGED_ATTN`, `TURBOQUANT_FUSED_DECODE` | KV scheme, request-state policy and codec | Capture layout/kernel choice; preserve it through deferred construction and RAM copies |
43
- | Prompt/SSD budgets, demotion, `SSD_*`, `CACHE_RETENTION`, `SESSION_CACHE`, `MTP_PROMPT_CACHE` | Prefix cache and persistence service | Cache owns residency and session lookup; persistence owns queued storage work |
44
- | `COMPILED_DECODE`, `COMPILED_GEGLU`, `COMPILED_SWIGLU`, `NO_FUSED_SDPA`, `TRELLIS*`, `MIXED_PACKED_MLP` | Model backend and numerical kernels | Read bound execution policy; select implementations by supported tensor geometry |
45
- | `RD_PREFILL_CHUNK`, `PREFILL_TAIL_SPLIT`, `EARLY_FIRST_TOKEN`, `BATCH_NO_PIPELINE`, `BATCH_EXTEND` | Prefill/step execution and row state | Preserve method boundaries, output ordering and state ownership; the batch-prefixed names remain compatibility controls |
46
- | `FILL*`, `GRAMMAR_JUMP` | Fill session or grammar proposal provider | Capture request policy; supported methods consume proposals/appends independently of scheduling |
47
- | Context limits, checkpoints, media access, trace/debug settings | Request preparation, checkpoint service, media adapter and diagnostics | Each service applies its own options; evaluation-only settings stay in the evaluation adapter |
48
-
49
- Environment names in this map omit the `MLX_BUN_` prefix. Historical A/B switches
50
- remain available while their control paths are supported. They are not alternate
51
- configuration systems. Internal boolean reads use the same `runtimeFlag` port;
52
- the old `flagOn` wrapper has been removed. CLI aliases remain compatible.
53
-
54
- Paged request state captures both its cache namespace and its direct-attention
55
- choice. Changing host settings after binding cannot change later prefetch, lookup,
56
- publication or cache construction for that request. The same rule applies to
57
- TurboQuant's fused codec across copies and delayed precision conversion.
58
-
59
- ## Start flags
60
-
61
- How flags are parsed (`src/cli.ts` `opt`/`flag`/`positional`):
62
-
63
- - A value flag is `--name value` (space-separated; `--name=value` is not
64
- recognized). A value flag with no following token takes its default.
65
- - **Unknown flags are silently ignored** — there is no unknown-flag error.
66
- mlx_lm.server's `--kv-group-size` and `--quantized-kv-start` are in this
67
- class: `src/serve/isolate.ts` lists them as value-taking so the engine
68
- argv builder does not mistake their value for a model positional, but
69
- `serve` never reads them (uniform `--kv-quant 4|8` is fixed at group
70
- size 64, start 0).
71
- - Aliases: `--adapter-path` = `--adapter`; `--temp` = `--temperature`
72
- (explicit `--temperature` wins); `--decode-concurrency` = `--batch`
73
- (`--batch` wins); `--query`/`-q` = the positional model query.
74
- - `mlx-bun pi` consumes the same flag set; when it attaches to an
75
- already-running server every server-shaping flag except `--port` is
76
- reported as ignored (the running server keeps its configuration).
77
-
78
- **Lane/tier column:** `serial` = the strict single-queue executor;
79
- `batch` = the continuous scheduler (`--batch N`); `both` = lane-independent.
80
- L1 = bit-exact vs mlx-lm, L2 = bit-exact vs mlx-optiq, Lab = no external
81
- oracle. See [Fidelity tiers](#fidelity-tiers-and-the-decode-route---l1----l2).
82
-
83
- ### Model selection
84
-
85
- | Flag | Arg | Default | Lane/tier | What it does |
86
- | --- | --- | --- | --- | --- |
87
- | `[query]` (positional) | registry query | auto-pick | both | First non-flag token after `serve`: a registry query (`"12B"`, `"e4b"`, a repo substring). Omitted: serves e4b when downloaded, else the largest downloaded model that fits; a fresh install downloads a small starter model first, then e4b in the background. |
88
- | `--model` | path \| query | none | both | mlx_lm.server's spelling, and the **highest-precedence** selector: a directory containing `config.json` loads straight from that path (`scanSnapshot`, no registry lookup — the bench/CI shape; an HF-cache path recovers its repo id from `models--org--name/snapshots/`); anything else resolves like the positional query. Precedence: `--model` > positional > `--query` > auto-pick. Under `--isolate`, the parent resolves the model and pins `--model <path>` on the engine child. |
89
- | `--query` / `-q` | registry query | none | both | Same as the positional query (lowest-precedence explicit selector). `-q` is the `mlx-bun pi` spelling. |
90
-
91
- ### Network
92
-
93
- | Flag | Arg | Default | Lane/tier | What it does |
94
- | --- | --- | --- | --- | --- |
95
- | `--host` | addr | `127.0.0.1` | both | Interface to bind. Loopback-only by default (mlx_lm.server parity); `--host 0.0.0.0` exposes the server on your network. The browser-open uses `localhost` when the bind is `0.0.0.0`/`::`. |
96
- | `--port` | n | `8080` | both | Listen port. Before loading weights the CLI probes `http://localhost:<port>/v1` and refuses to start if something is already serving there (skipped under `--unix`). |
97
- | `--unix` | socket path | none | both | **Internal.** Listen on a unix domain socket instead of TCP — the engine half of `--isolate` (`ServerOptions.unixSocket`; `hostname`/port are ignored, stale socket files are unlinked before bind). Usable directly for socket-level integration. |
98
-
99
- ### Memory, admission, and caches
100
-
101
- Memory estimates are advisory by default. The server attempts requests without
102
- rejecting a prompt or shortening `max_tokens` based on predicted GPU headroom.
103
- `fit` and `/stats.admission.max_safe_context` remain estimates; they do not
104
- set the default execution limit. Explicit `--memory-budget`, `--kv-budget`,
105
- and context caps remain opt-in restrictions. GLM-5.2's allocated context
106
- layout retains its configured capacity.
107
-
108
- When batch rows finish, full-attention caches drop padding shared by every
109
- surviving row, matching MLX-LM while preserving each row's absolute position.
110
-
111
- Qwen prefills longer than four tokens materialize each layer and its cache
112
- state before continuing, bounding deferred buffer lifetimes. Cache maintenance
113
- demotes least recently used snapshots under allocator pressure without
114
- refusing the request. With SSD enabled, an unwritten victim stays in RAM until
115
- its queued write completes. The RAM target can be exceeded while writes are
116
- pending or failing;
117
- it does not promise that every workload fits.
118
- Actual allocation failures use the ordinary error path when recoverable;
119
- a native Metal allocation failure can terminate the process.
120
- Recurrent-cache hits lend independently owned views before any donor is
121
- reclaimed. The request can advance those views while the original boundary
122
- remains in RAM or in a completed SSD snapshot. Persistence stays asynchronous.
123
-
124
- | Flag | Arg | Default | Lane/tier | What it does |
125
- | --- | --- | --- | --- | --- |
126
- | `--memory-budget` | GB (decimal, ×10⁹) | unset; memory estimates are advisory | both (per request) | Explicit opt-in budget. Sets the allocator limit and enforces the fit estimate: a prompt leaving no generation slot gets **400** (`type: memory_admission`); a broader completion cap is reduced to the remaining context. Estimates account for active KV quantization and prefill temporaries. Not an aggregate batch cap — see `--kv-budget`. GLM-5.2 also uses this value in its resource plan before loading. |
127
- | `--kv-budget` | GB (decimal) | off | batch | Aggregate KV budget across concurrently admitted batch rows: a joiner whose projected KV (prompt + `max_tokens`, window-capped) would exceed it **queues** until rows finish; a request over the budget alone is rejected. Without it, N large-context rows can collectively exceed memory. Reported in `/stats.batch.kv_budget_bytes`. |
128
- | `--prompt-cache` | GB (binary GiB) | `8` | both | RAM prefix-KV residency target, managed by LRU. `--prompt-cache 0` disables it. RAM hits lend zero-copy views, including recurrent Qwen and method state. With SSD enabled, eviction persists an unwritten donor before removing it from RAM; pending writes can temporarily exceed the target. A successful write alone does not evict RAM. The target does not reserve that much memory. SSD persistence runs in the background; RAM reuse never waits for a write. Explicit cache flush and graceful shutdown report durability, including snapshots lost before persistence. Batch-lane joiners `take()` the longest usable prefix at admission; completed decode publishes reusable processed-token state through the same interface. |
129
- | `--ssd-cache` | dir | off | both | SSD cold tier under the prompt cache ([docs/design/kv-cache.md](../design/kv-cache.md)): prefix KV spills to disk on RAM eviction and idle demotion, is also persisted after publication by a dedicated CPU worker while inference continues (`MLX_BUN_SSD_WRITEBEHIND=0` disables proactive writes), and **survives restarts**. Entries are keyed by model fingerprint + effective KV scheme + backend numerical identity + tokenizer hash + adapter namespace. MLX includes its runtime version and GPU architecture; older numerical identities use separate directories. `SIGINT`/`SIGTERM` drains active requests and flushes dirty snapshots before exit (`MLX_BUN_SHUTDOWN_TIMEOUT_MS`); `POST /admin/cache/flush` is the explicit boundary. Requires the RAM cache. |
130
- | `--ssd-cache-max` | GB (binary GiB; `0` = unlimited) | unlimited | both | Optional SSD tier byte cap; oldest-mtime entries are evicted only when a positive cap is configured. Warns and is ignored without `--ssd-cache`. |
131
- | `--ssd-cache-verify` | (bool) | off | both | Verify every tensor hash on restore (reads all bytes eagerly, defeating lazy fault-in) — integrity paranoia only; the header hash is always verified. Warns and is ignored without `--ssd-cache`. |
132
- | `--ssd-demote-idle` | seconds | `300` with `--ssd-cache`, else off | both | Prompt-cache entries unused this long spill to the SSD tier and free their GPU memory; the next hit restores them. The cache sweeps by entry age independently of scheduler activity; RAM remains resident until SSD coverage exists. `0` disables. Warns and is ignored without `--ssd-cache`. |
133
- | `--generation-checkpoint` | output tokens | off | qualified requests | Queues an owned in-flight generation snapshot every N emitted tokens. Repeating the identical request after a restart replays the saved assistant prefix and continues from its already-sampled next token. Requires `--ssd-cache`. Shared execution qualifies ordinary requests with supported row-cache layouts, including Qwen, Llama, MiniCPM and Gemma4, with or without adapters, excluding media, grammar, fill, paging, logprobs or speculative methods; existing serial qualification remains available. Explicit cache flush drains queued writes. Completed generations remove their checkpoint, while client cancellation preserves the latest checkpoint. |
134
-
135
- Generation checkpoint identity includes stop strings, sampling/KV policy, the
136
- resolved execution method, compiled/grammar policy, and artifact/implementation
137
- identity. Changing any of these starts a new completion. Version-2/3 generation keys are not
138
- selected for automatic resume. Prefix-cache files retain their state codec
139
- format, but automatic reuse also requires the model binding's numerical
140
- identity. MLX runtime or GPU architecture changes select a fresh cache
141
- directory and leave the previous directory intact. A different backend codec
142
- identity refuses incompatible files. Adapter namespaces include the mounted weight contents and
143
- scale, so a changed adapter starts with a fresh prefix and checkpoint.
144
- Native media and grammar preparation uses the backend execution lease between
145
- decode iterations when the backend supports queued preparation. Exclusive model
146
- changes retain drain priority. Media downloads and container transcoding run
147
- outside that lease; a slow remote URL does not hold up decode. Preparations
148
- retain a reservation through request
149
- completion. Gemma4 and Qwen shared serving can retain up to `--batch` media preparations;
150
- other media bindings retain one. Grammar preparation retains up to `--batch`. Generation and preparation
151
- queues each allow 64 waiting requests; overflow returns `429` before a response
152
- stream opens, or a terminal stream error after it opens. Disconnects release
153
- queued reservations and completed preparation resources.
154
-
155
- Ordinary requests in the continuous scheduler can join an ongoing prefill
156
- between chunks when their execution context is compatible and batch capacity
157
- is available. Scheduling also budgets the initial prefill work in a cohort, so
158
- long prompts can be prepared one at a time through the continuous executor
159
- while decode remains batched. Subsequent forwards process real-token chunks from admitted requests
160
- together. Each request keeps its own cache-maintenance and checkpoint boundaries.
161
- Arrival timing can change batch geometry and near-tie generated text. Qwen MTP,
162
- prompt lookup and standalone drafting use the same target prefill driver.
163
- Their providers prepare companion state through a separate interface;
164
- scheduling determines admission and work budgets.
165
-
166
- Disconnected serial requests leave the admission queue immediately. Active AR
167
- requests check cancellation between prefill chunks and decode steps; a native
168
- operation already running completes before that boundary.
169
-
170
-
171
- Qwen image/video and Gemma image/audio encoder features use the existing
172
- prompt-cache RAM budget and, when configured, its SSD persistence layer.
173
- Exact encoder-weight, computation-setting and input hashes identify reusable
174
- features; each request still renders its own tokens, timestamps, masks and
175
- positions. Qwen hashes prepared pixels and grids; Gemma hashes image/WAV bytes
176
- within each encoder's versioned schema. No separate media-cache capacity is
177
- allocated. `--prompt-cache 0` disables retention. CPU preprocessing and media
178
- extraction still run before feature lookup, outside the native execution queue.
179
- Encoder reuse is independent of batch/method selection. Experimental Gemma
180
- media KV reuse is controlled by `MLX_BUN_MEDIA_PREFIX_CACHE` below. Cache counters
181
- are documented in [server-api.md](server-api.md).
182
-
183
-
184
- ### Runtime isolation
185
-
186
- | Flag | Arg | Default | Lane/tier | What it does |
187
- | --- | --- | --- | --- | --- |
188
- | `--isolate` | (bool) | off | both | Run the inference engine as a **child process** on a unix socket while this process owns CPU application routes and proxies inference — instant under any GPU load, survives engine crashes (auto-respawn). Full semantics in [`--isolate` semantics](#--isolate-semantics). |
189
- | `--whisper-model` | path \| query | first downloaded `whisper` checkpoint, resolved on the first `/v1/audio/*` request | both | Whisper checkpoint served beside the chat model for [audio transcription](server-api.md#post-v1audiotranscriptions--post-v1audiotranslations-speech-to-text). Serving a Whisper checkpoint as the MAIN model (`serve mlx-community/whisper-large-v3-turbo`) starts a **transcription-only server** (audio routes, `/v1/models`, `/health`, `/stats`; no chat model, no prompt cache). |
190
- | `--whisper-idle-unload` | seconds | `0` | both | How long the Whisper weights (and MLX's allocator cache) stay after a take. Default `0`: released right after every take, so the chat model has the memory back before it prefills the dictated prompt; the process drops by ≈1.4 GB and the next take pages them back in from the OS file cache (a cold 11 s take is ≈520 ms vs 365 warm on the M1 Max, `TranscriptionService`). Reported per response in `mlx_bun.timings.load_ms`. |
191
- | `--whisper-resident` | flag | off | both | Never dispose the Whisper weights (sotto's always-loaded behaviour). |
192
- | `--preload` | flag | off | both | Transcription-only server: load the Whisper weights before listening instead of on the first request. |
193
- | `--model-pool` | n (≥1) | `1` | both | With `--isolate`: max **resident** model engines. A request whose `model` field is an **exact** `/v1/models` id spawns/routes to that model's own engine child (spawn-overlap: the new model loads while the old keeps serving). Over the cap the least-recently-used engine is drained (`POST /admin/drain` over its socket), demotes its prompt cache to the SSD tier, and exits; switching back respawns it with state restored from disk. Without `--isolate` the flag warns and is ignored. |
194
-
195
- ### Scheduling
196
-
197
- | Flag | Arg | Default | Lane/tier | What it does |
198
- | --- | --- | --- | --- | --- |
199
- | `--batch` | n (integer ≥ 1) | `8` | batch / L1 | Max concurrent requests decoded together. A lone admitted request uses the B=1 fast path (adopted serial-class caches, compiled decode, prompt cache + SSD restore — byte-identical to serial); a batch layout only exists once a second request arrives. `--batch 1` pins the strict serial executor (arrival-independent numerics — use it for golden regeneration). `--decode-concurrency` is accepted as the mlx_lm.server alias, but its semantics differ there (per-`BatchGenerator` decode parallelism, default 32). See [Execution modes](#execution-modes-serial-vs---batch-n). |
200
-
201
- ### KV cache
202
-
203
- | Flag | Arg | Default | Lane/tier | What it does |
204
- | --- | --- | --- | --- | --- |
205
- | `--kv-quant` | `config` \| `off` \| `4` \| `8` \| `turbo[:k<bits>v<bits>]` | `off` (bf16) | see row | KV-cache quantization. `off` = bf16 (the L1 default: quantized KV measured 5–20% slower decode than bf16 at ≤16k on both stacks, so it is an opt-in that buys **memory headroom**). `4`/`8` = **uniform** bits (group 64, start 0 — mlx-lm's `--kv-bits` scheme); with fused-sdpa off (the default for uniform) our unfused quantized SDPA is op-for-op mlx-lm's `quantized_scaled_dot_product_attention`, so uniform is **bit-exact L1**; uniform requests use shared B=1/B>1 execution where the loaded cache layout supports affine conversion. `config` = **per-layer mixed precision** from the model's `kv_config.json` — optiq-only → **L2**; per-layer configs **batch** on every shipped model (full-attention and rotating layers; gated bit-exact per row vs the serial composition). `turbo[:k<bits>v<bits>]` = **TurboQuant** ([docs/design/turboquant.md](../design/turboquant.md)): rotation-based KV quantization, default `k8v3`; `kBits` ∈ {2,4,5,8}, `vBits` ∈ {2,3,4,5,8}; a separate axis (mutually exclusive with `config`/`4`/`8`), uses the existing decoded or deferred rotated-value attention path, **full-attention layers only** (sliding-window layers stay bf16 with a one-time warning), refuses head dims outside `TURBOQUANT_HEAD_DIMS`, and supports shared ordinary and grouped drafting execution at B=1/B>1 including positive library conversion thresholds when the cache layout qualifies. Any explicit `--kv-quant` overrides the tier preset. |
206
- | `--paged-kv` | (bool) | off | shared / optional | Full-attention block pools through the common cache-layout and attention interfaces. Supports bf16 and uniform affine `--kv-quant 4|8`; affine pages encode from their first token. Default attention gathers into stock SDPA; `MLX_BUN_PAGED_ATTN=1` selects the experimental direct Metal reader. RAM/SSD reuse uses a separate numerical namespace. Gemma4-family only; draft models, per-layer KV schemes and TurboQuant pages remain unsupported. Media/adapter requests retain their existing non-paged behavior. Env mirror `MLX_BUN_PAGED_KV=1`. |
207
- | `--paged-kv-block-size` | n | `256` | shared | Tokens per KV block (`--paged-kv` only); 256 = the plain cache's growth step. |
208
-
209
- ### Adapters and speculative decoding
210
-
211
- In v0.4.0, Qwen MTP publishes aligned target/draft
212
- prefill snapshots through the shared prompt cache by default. The RAM budget
213
- includes the draft KV and pending hidden row; configured SSD persistence
214
- queues those tensors with the target state and supports reuse after restart.
215
- RAM hits retain immutable snapshots for later requests. Target, draft-weight,
216
- adapter-revision and KV-policy identities separate incompatible state.
217
- `usage.cached_tokens` reports the reused target prefix.
218
- `MLX_BUN_MTP_PROMPT_CACHE=0` disables this reuse. Completed decode also
219
- publishes checkpoints for processed tokens through the same cache.
220
- Long-conversation performance acceptance remains open.
221
-
222
- Uniform KV4 attention automatically groups three query heads for the key
223
- multiplication on M4 Pro when B≤2, L=3, GQA6/D256, N≥8192 and bf16/f32
224
- match the qualified shape. Masking, softmax and value multiplication retain
225
- their existing geometry. This internal selection needs no additional flag;
226
- other shapes and machines keep the existing implementation. Exactness and
227
- timing evidence are in [benchmarks.md](benchmarks.md#three-query-affine-attention-head-grouping).
228
-
229
- In v0.4.0, Qwen uniform affine KV4 with
230
- `quantizedKvStart=0` supports configured speculative execution by default.
231
- `MLX_BUN_QWEN_SPEC_KV4=0` restores the ordinary-decode compatibility control. Recurrent state and draft KV keep their original precision. Shared Qwen MTP
232
- also supports bf16, uniform KV8 and TurboQuant at start zero; per-layer mixed
233
- KV remains incompatible. Strict legacy serial speculation retains bf16/KV4.
234
- The KV4 control does not disable bf16, KV8 or TQ shared speculation. Six paired M4 Pro combined suites and two completed Kanban tasks support
235
- this default. Configuring a drafter and selecting KV4 remain explicit choices.
236
-
237
- The shared prefill policy selects a chunk once per request. The usual size is
238
- 2,048 tokens. For recurrent-attention models with materialized SDPA scores,
239
- it halves that size until the estimated per-layer score workspace is at most
240
- 1 GiB (minimum eight queries, where native fused decode attention applies).
241
- Qwen3.8-27B therefore uses 2,048 at 10,398 prompt tokens and 256 at 78,678.
242
- This changes the work size; it does not reject or shorten the request.
243
- Ordinary and speculative execution consume the same bound policy.
244
-
245
- `MLX_BUN_RD_PREFILL_CHUNK` selects an explicit fixed chunk. A group option
246
- supersedes the environment, and a library request's `prefillChunkSize`
247
- supersedes either. Explicit values bypass the automatic choice.
248
- `MLX_BUN_RD_CONTEXT_LIMIT` sets an explicit request context cap
249
- without enlarging it. Both controls require positive integers; the context
250
- cap is unset by default. Sampling and the published model context remain
251
- independent of prefill chunk selection. To reproduce a seeded response, keep
252
- the prefill chunk policy fixed along with the model, runtime, machine and
253
- sampling settings. Changing chunk boundaries can change numerical results
254
- and the sampled continuation. The [Kanban comparison](benchmarks.md#full-kanban-after-decode-integration)
255
- records this effect on the same M4 Pro with identical initial request JSON.
256
-
257
- | Flag | Arg | Default | Lane/tier | What it does |
258
- | --- | --- | --- | --- | --- |
259
- | `--adapter` | dir | none | compatible adapter groups | Mount a LoRA adapter at startup (same machinery as `POST /v1/adapters`; the id is the directory basename) and make it the default for requests without an `adapter` field. A request's explicit `adapter` — including `"none"` — wins; hot-swap via `/v1/adapters` is unchanged. A bad adapter fails startup. Alias `--adapter-path`. |
260
- | `--draft-model` | path \| query | none | shared Qwen methods; full-attention/rotating lookup/standalone and Gemma assistant/DeepSpec/DSpark; other combinations serial | **Speculative decoding**: a drafter proposes tokens the target verifies in one forward — exact results, faster decode when drafts land. Resolves like the main model. Kind is auto-detected: a full same-tokenizer model (mlx_lm.server parity, L1 token-for-token; tokenizer-family mismatch fails startup), a Gemma `-assistant` KV-borrowing drafter (L2 vs optiq `spec_generate`), a locally trained **DSpark** checkpoint (`dspark.json`), or a released DeepSpec `Gemma4DSparkModel` drafter. Qwen MTP, prompt lookup and standalone drafting use the shared executor at one or several active rows, including logprobs. Supported full-attention and rotating targets, including Llama, MiniCPM and Gemma, also share bf16, uniform KV4/KV8 or per-layer affine KV or TurboQuant prompt lookup and standalone drafting. Rotating target transactions retain different accepted lengths across the sliding window and publish paired RAM/SSD state. Gemma assistant drafting shares the same execution at B1/B>1 with bf16, uniform KV4/KV8 or per-layer affine KV or TurboQuant target storage. Its hidden-state companion and target KV use the RAM/SSD cache; donor attention owns row validity while the assistant graph stays independent of storage. DeepSpec and DSpark share bf16, uniform KV4/KV8 or per-layer affine KV or TurboQuant target execution and projected-context RAM/SSD companions. DeepSpec supports bf16 or affine-quantized draft weights; DSpark supports its Markov/RNN heads. Confidence selects each row's proposal length independently. Other provider/target combinations still run serial. Unsupported speculative compositions use ordinary execution when their own features support it. Composes with structured output; Qwen MTP, prompt lookup, standalone, Gemma assistant, DeepSpec and DSpark drafting use the shared RAM/SSD prefix cache by default (`MLX_BUN_MTP_PROMPT_CACHE=0` disables); other speculative sources start fresh. Telemetry: `usage.speculation`. |
261
- | `--draft-kind` | `two-model` \| `assistant` \| `dspark` \| `deepspec` \| `mtp` \| `ngram` | auto | shared Qwen methods; full-attention/rotating lookup/standalone and Gemma assistant/DeepSpec/DSpark; other combinations serial | Override drafter detection. `mtp` = a native multi-token-prediction head split from the target's release (`*_mtp` model_type; shares the target's embeddings/lm-head, defaults `--num-draft-tokens` to its trained `block_size − 1`, rolls DeltaNet caches back by snapshot/replay on partial rejects); `mtp` alone mounts the companion bundled at `<model>/mtp/` when present. Qwen MTP companions accept dense or affine-quantized projections using their checkpoint metadata; changing the draft can change acceptance and speed. `ngram` = **model-free prompt lookup** (drafts copied from the request's own prompt+generation; port of prompt-lookup decoding / vLLM's `ngram` proposer) — mount it **alone** (`--draft-kind ngram` with a `--draft-model` is refused, as is any other kind without one); lossless by the same verify, a no-match round degrades to one plain target step. Any other value fails startup. |
262
- | `--num-draft-tokens` | n (integer ≥ 1) | `3` (`ngram`: `10`; DSpark: pinned ≤ its trained `gamma`) | method-dependent | Drafts per verify round (mlx_lm.server's default; `mlx_lm.generate`'s is 2). |
263
- | `--ngram-max` / `--ngram-min` | k (integer ≥ 1) | `3` / `1` | Qwen and full-attention targets shared / other models serial | `--draft-kind ngram` only: longest/shortest trailing k-gram searched (longest first, first occurrence wins). `--ngram-min` > `--ngram-max` fails startup; either flag without `ngram` warns and is ignored. |
264
- | `--mtp` | `on` \| `off` | `on` for GLM-5.2 | serial+spec | GLM-5.2 checkpoint-native MTP row as the server's drafter, using the bounded auxiliary expert tier and the exact serial verify loop (`usage.lane: "serial+spec"`). `off` removes the draft so ordinary GLM requests can use continuous batching. Other model families ignore it. |
265
- | `--context-length` | tokens (integer ≥ 1) | `4096` (GLM-5.2) | both | Context reserved by GLM-5.2's header-only resource equation; also the request-admission ceiling, reported in `/stats.glm52`. An impossible plan fails before committing model memory. Ignored by other families. |
266
-
267
- ### Sampling and template defaults
268
-
269
- | Flag | Arg | Default | Lane/tier | What it does |
270
- | --- | --- | --- | --- | --- |
271
- | `--thinking` | `true`\|`false` (also `on`/`off`/`1`/`0`) | model's own (`false` for MiniCPM5) | both | Server-wide default for the chat template's `enable_thinking`. Precedence (`resolveEnableThinking`): explicit request `chat_template_kwargs.enable_thinking` → request `reasoning_effort` (`"none"` = off, any other level = on) → this flag → the model's default. With no explicit temperature, a no-think turn is capped at 0.7 while a think turn keeps the model's configured temperature. |
272
- | `--temperature` | n ∈ [0, 5] | `generation_config.json`, else `0.7` | both | Server-wide sampling default; a per-request `temperature` wins; the browser chat (sends none) inherits it. Alias `--temp` (mlx_lm.server spelling — note its *default* there is `0.0`; pass `--temp 0` for that behavior). |
273
- | `--top-p` | n ∈ [0, 1] | `generation_config.json`, else `0` (off) | both | Server-wide top-p default (per-request `top_p` wins). |
274
- | `--top-k` | n ∈ [0, 1e6] | `generation_config.json`, else `0` (off) | both | Server-wide top-k default (per-request `top_k` wins). |
275
- | `--max-tokens` | n ∈ [1, 1e7] | GLM-5.2: `128` (memory-plan reservation); otherwise none — an omitted cap generates until EOS/stop or an explicitly configured limit | both | Completion cap when a request omits `max_tokens` (mlx_lm.server flag). DEVIATION when unset: `mlx_lm.server` stops a defaulted request at 512 — `--max-tokens 512` reproduces it. For GLM-5.2 the value is also reserved by the pre-open resource equation and must fit inside `--context-length`. Note: `max_tokens` also feeds `--kv-budget` row projections (prompt + cap), so an uncapped request cannot fit a finite explicit KV budget; set `--max-tokens` or send a request cap when using that budget. |
276
- | `--hlg-sampling` | `on`\|`off` | off | serial / Lab | Piecewise tone-curve (HLG) sampling: rolls off the top-token region, boosts the mids, gentles the tail; the gain folds from `--temperature`. Design: [docs/archive/hlg-sampling.md](../archive/hlg-sampling.md). |
277
- | `--hlg-width` | nats ∈ [0, 100] | `4` | serial | HLG mid-region half-width. Only with `--hlg-sampling on`. |
278
- | `--hlg-shoulder` | nats ∈ [0, 100] | `4` | serial | HLG highlight rolloff scale. Only with `--hlg-sampling on`. |
279
- | `--hlg-toe` | nats ∈ [0, 100] | `6` | serial | HLG shadow rolloff scale. Only with `--hlg-sampling on`. |
280
- | `--hlg-pivot-offset` | nats ∈ [0, 100] | `6` | serial | HLG pivot: nats below the top token. Only with `--hlg-sampling on`. |
281
-
282
- Greedy sampling without requested logprobs uses a shared normalized-selection
283
- kernel after applying penalties and grammar masks. It preserves dtype-rounded
284
- scores and lowest-ID ties while avoiding a full normalized vocabulary output.
285
- Independent speculative verification uses the same operation. Requests needing
286
- logprobs, stochastic sampling or a custom sampler keep their existing operations;
287
- no new flag is required. Measurements are in [benchmarks](benchmarks.md#fused-normalized-greedy-selection).
288
-
289
- ### Media and UX
290
-
291
- | Flag | Arg | Default | Lane/tier | What it does |
292
- | --- | --- | --- | --- | --- |
293
- | `--allow-private-media` | (bool) | off | both (model-qualified media) | Let `image_url`/`audio_url`/`video_url` parts fetch from **private/loopback/link-local** hosts. Off by default: a request's URL is attacker-controlled, so `src/media-fetch.ts` refuses non-http(s) schemes and private/loopback/link-local/CGNAT destinations — including hosts that *resolve* there and every redirect hop (SSRF guard). Independent of the flag, every remote fetch has a 10 s timeout and a 64 MB streaming-enforced cap; violations are clean `400`s. `data:` URLs are never policy-checked. Env mirror `MLX_BUN_ALLOW_PRIVATE_MEDIA=1`. |
294
- | `--no-open` | (bool) | off | both | Skip the automatic browser open. By default an interactive TTY opens `http://<host>:<port>/#/chat` once the server is ready; non-TTY runs never open. Parent-only under `--isolate`. |
295
-
296
- ### Parity tier and kill switches
297
-
298
- | Flag | Arg | Default | Lane/tier | What it does |
299
- | --- | --- | --- | --- | --- |
300
- | `--l1` | (bool) | **the default** | serial route / L1 | Tier alias: bit-for-bit identical to mlx-lm — bf16 KV, compiled decode, compiled activations, fused-sdpa off. No tier flag ⇒ `--l1` (decision 2026-07-05). Any per-fork flag below overrides one preset value. |
301
- | `--l2` | (bool) | — | serial route / L2 | Tier alias: bit-for-bit identical to mlx-optiq — `--kv-quant config` + fused N-tiled prefill SDPA + stock unfused decode (the composition the optiq goldens track). |
302
- | `--l3` | — | — | — | **Removed 2026-07-05.** Passing it exits with a pointer to `--l2` / the Lab. |
303
- | `--compiled-decode` | `on`\|`off` | on | serial, and batch at B=1 / L1 | Replay the per-step decode graph in C++ (`MLX_BUN_COMPILED_DECODE`). Bit-exact A/B lever. Gemma4-dense only; LoRA, MoE, and other families run eager, and an unsupported step falls back to eager for the rest of that generation. |
304
- | `--compiled-activations` | `on`\|`off` | on | both / L1 | Route geglu/swiglu through mlx-lm's `@mx.compile` closure (`MLX_BUN_COMPILED_GEGLU` + `MLX_BUN_COMPILED_SWIGLU`). MiniCPM5 uses compiled SwiGLU for decode and prefill. `off` selects the uncompiled composition and can change prefill numerics on MLX 0.32.2. Toggles gemma geglu + MiniCPM5 swiglu; qwen3/qwen3.5/universal compile unconditionally. |
305
- | `--fused-sdpa` | `on`\|`off` | follows `--kv-quant`: on for `config`, off for `4`/`8` and bf16 | serial / L2 | Fused SDPA for quantized-KV prefill/continuation (inverted env `MLX_BUN_NO_FUSED_SDPA`). Defaults to the composition its oracle uses. No-op on bf16. |
306
- | `--force-wire` | (bool) | off | serial | Wire weights into memory for the whole generation (`MLX_BUN_FORCE_WIRE=1`). Near-ceiling models need it. The batch scheduler bypasses `generate()`'s wired scope. |
307
- | `--expert-offload` | (bool) | off | serial / Lab | **MoE only.** Serve experts from a page-aligned file mmap (`<model>/.mlx-bun-offload`, built on first use) — physical footprint ≈ active params. Dense models log "ignored". Bit-exact with the resident path. Env mirror: `MLX_BUN_EXPERT_OFFLOAD=<dir>`. |
308
-
309
- The default host/port (`127.0.0.1:8080`) match `mlx_lm.server`, so running
310
- mlx-bun alongside the Python reference needs an explicit `--port`.
311
-
312
- ## Reproducing mlx_lm.server
313
-
314
- Numeric parity (same tokens in → same logits, bit-for-bit) is unconditional
315
- — no flag buys it back and none is needed. **Behavior policy** (defaults,
316
- caps, sampling fallbacks) is mlx-bun's own; mlx_lm.server's policy is one
317
- configuration of it:
318
-
319
- ```sh
320
- mlx-bun serve <model> --temp 0 --top-p 0 --top-k 0 --max-tokens 512 --batch 1
321
- ```
322
-
323
- - `--temp 0 --top-p 0 --top-k 0` — mlx_lm.server does not read
324
- `generation_config.json` (we inject its sampling defaults, optiq-style);
325
- its unset-request defaults are temperature 0.0, top-p/top-k off.
326
- - `--max-tokens 512` — its cap when a request omits `max_tokens` (ours is
327
- none: run to EOS/stop or an explicit operator limit). The cap changes the stopping
328
- point and `finish_reason`.
329
- - `--batch 1` — strict serial, arrival-independent numerics. (`--batch N`
330
- is itself bit-parity with mlx-lm at B=N; pin 1 for golden regeneration.)
331
- - Already matching without flags: host/port, bf16 KV (`--kv-quant off`),
332
- the L1 kernel preset (`--l1` is the default), logprobs caps, error text.
333
-
334
- These flags align sampling and caps. Exact generated trajectories also need
335
- matching prefill and cache boundaries. Stock MLX-LM HTTP splits system and
336
- thinking segments before reserving the final token. Different forward shapes
337
- can change near-tie greedy choices even inside the same Python model.
338
- The benchmark's explicit `--reference-prefill unsplit` control and the saved
339
- MiniCPM/Qwen investigation are documented in [benchmarks.md](benchmarks.md).
340
-
341
- The kill switches are bit-exact A/B levers; **the naked default is the L1
342
- set** (2026-07-05: an output-changing lever earns a default only by beating
343
- the L1 baseline in a paired A/B, and none did — the losing kernels were
344
- deleted, Phase 1 of
345
- [unified-engine-frontier-plan.md](../design/unified-engine-frontier-plan.md)).
346
- They are installed as `MLX_BUN_*` runtime values before the model loads,
347
- so they apply to `mlx-bun pi` too. They affect the **serial** decode path;
348
- the batch scheduler drives `model.forwardHidden` directly and is unaffected
349
- except by `--compiled-decode` at B=1 — see
350
- [Levers that don't reach the batched lane](#--batch-n-is-compat-mode--perf-flags-dont-apply-by-design).
351
-
352
- ## `--isolate` semantics
353
-
354
- Design and measurements: [docs/reference/server-config.md](./server-config.md)
355
- (P1 single engine and P2 model pool landed). What the flag does, from
356
- `src/serve/isolate.ts` and the `serve` handler in `src/cli.ts`:
357
-
358
- - **Process layout.** The parent binds the TCP `--host`/`--port` and makes
359
- zero MLX calls. It re-execs itself as `serve` with the same argv minus
360
- the **parent-only flags** (`--isolate`, `--port`, `--host`, `--model-pool`,
361
- `--no-open`), the model selectors replaced by a pinned `--model <path>`,
362
- plus `--unix <socket>` (socket under the OS temp dir, named by parent
363
- pid). Every other flag and every exported `MLX_BUN_*` variable reaches
364
- the engine child unchanged (`env: process.env`); the child's stdout/stderr
365
- are inherited, so load progress prints in your terminal.
366
- - **Readiness.** The parent polls the child's `/health` over the socket
367
- (up to 15 minutes — large models take a while) and prints "engine ready
368
- pid N". Requests arriving earlier wait on that readiness.
369
- - **Application state.** The web shell, job submissions, records, progress streams, settings and
370
- Responses conversation history live in the CPU-only parent, so worker death or model eviction does not remove
371
- them. Native inspection/merge/export and generation still execute in workers.
372
- WebSocket chat retains its existing unsupported status under isolation.
373
- - **Proxying.** Remaining HTTP requests are forwarded over the unix
374
- socket (hop-by-hop headers stripped, SSE streams through, a client
375
- abort aborts the proxied fetch so the engine sees the disconnect).
376
- `GET /engine` answers from the parent:
377
- `{ isolated: true, pid, restarts, socket, response_store, pool?: { resident, default } }`.
378
- Worker fields describe the currently resident default worker and are `null`
379
- while it is evicted; inspection does not load a model. A recreated worker has
380
- its own restart count.
381
- `/ws/chat` is **not proxied** — `501` with a pointer to run without
382
- `--isolate` for the web chat UI.
383
- - **Crashes.** A child exit (uncatchable Metal OOM/SIGTRAP included) is
384
- respawned automatically (`restarts` increments), with at most three restarts
385
- in a rolling 60-second window. Exhausting that budget leaves the host
386
- unavailable until restarted. An engine that dies within 10 s of spawning
387
- waits 5 s before the retry. In-flight requests
388
- get `502 { error: { type: "engine_unavailable" } }`; bodyless `GET`/`HEAD`
389
- requests are retried once after the respawn. A request whose client
390
- disconnected answers `499`.
391
- - **Model pool (`--model-pool n`).** `POST` bodies on `/v1/chat/completions`,
392
- `/v1/completions`, `/v1/messages`, `/v1/responses`, `/v1/embeddings` are
393
- buffered to read `model`. An **exact** registry id (`/v1/models` id)
394
- spawns/routes to that model's own child; anything else — empty, fuzzy,
395
- `"gpt-4"`-style — rides the default engine (mlx-lm's ignored-field
396
- semantics). Eviction over the cap: `POST /admin/drain` on the victim's
397
- socket (gateway quiesce + demote its prompt cache to the SSD tier),
398
- then stop; `/admin/drain` is unix-socket-only, never on the TCP
399
- listener. Cold model starts are serialized through a bounded queue while the
400
- resident model keeps serving; concurrent switches cannot evict a newly loaded
401
- worker before its pending request is returned. `--model-pool` is clamped to ≥ 1.
402
- - **Managed GPU jobs.** A FIFO parent coordinator waits for active worker
403
- responses, then holds a native execution lease inside every resident worker
404
- before spawning a quantization/finetuning job. Startup, restart and eviction
405
- participate in admission too. Job exit releases those leases. Dataset jobs use
406
- the same loopback completion API and keep their progress in the parent.
407
- - **Shutdown.** `SIGINT`/`SIGTERM` cancels queued jobs, stops the active GPU job,
408
- waits for in-process task cleanup, then closes workers and unlinks sockets.
409
- Worker close also waits for pending startup admission and failed startup
410
- attempts to release their execution leases, including before a child exists.
411
-
412
- ## Near-ceiling models on small machines (24 GB)
413
-
414
- A model whose weights approach the default macOS GPU wired ceiling (~75%
415
- of RAM) loads and serves short prompts, but a long prefill can exceed the
416
- ceiling and die with an **uncatchable** Metal OOM. `mlx-bun serve` checks
417
- this at startup (model bytes > 80% of `maxRecommendedWorkingSetSize` while
418
- `iogpu.wired_limit_mb` is at its default) and prints the remedy:
419
-
420
- ```
421
- sudo sysctl iogpu.wired_limit_mb=<RAM_MB - ~2500> # resets on reboot
422
- ```
423
-
424
- For very long contexts on such machines, additionally prefer `--kv-quant`
425
- (e.g. `turbo`) — the prefill transient scales with chunk size × context.
426
-
427
- ## Per-request overrides
428
-
429
- Most quality knobs can be set per request in the chat body and override
430
- the server-wide default. Precedence, highest first:
431
-
432
- 1. explicit request field (`temperature`, `top_p`, `top_k`, `seed`,
433
- `min_p`, `xtc_probability`/`xtc_threshold`, `logit_bias`,
434
- `repetition_penalty`, `presence_penalty`/`frequency_penalty` (+ their
435
- `*_context_size` windows), `max_tokens`/`max_completion_tokens`, `stop`,
436
- `chat_template_kwargs.enable_thinking`, `reasoning_effort`, `adapter`,
437
- `tools`)
438
- 2. the matching `--temperature`/`--top-p`/`--top-k`/`--thinking`/`--max-tokens`
439
- server default
440
- 3. the model's `generation_config.json`
441
- 4. the built-in fallback (temperature 0.7, top-p/top-k 0 = off)
442
-
443
- These ride all three protocol surfaces (`/v1/chat/completions`,
444
- `/v1/messages`, `/v1/responses`) because each funnels through one
445
- chat stage (`src/serve/chat-stage.ts`). Full field list: [server-api.md](./server-api.md).
446
-
447
- ## Environment variables
448
-
449
- All `MLX_BUN_*` variables are captured once at process start into an
450
- immutable snapshot (`src/runtime-config.ts`); CLI flags install overrides
451
- into the same snapshot before the model loads. Boolean levers read the
452
- literal strings `"1"`/`"0"` — `runtimeFlag` treats any other value as unset.
453
- Under `--isolate` the whole environment is inherited by the engine child.
454
-
455
- ### Serving levers (flag-backed and lane kill switches)
456
-
457
- | Env var | CLI flag | Default | Effect |
458
- | --- | --- | --- | --- |
459
- | `MLX_BUN_COMPILED_DECODE` | `--compiled-decode` | on (`"0"` disables) | Compiled decode graph replay (serial lane; batch lane at B=1). |
460
- | `MLX_BUN_MEDIA_PREFIX_CACHE` | (env only) | on (`=0` disables) | Reuse prepared Gemma image/audio or Qwen image/video conversation KV in the shared executor. Media contents, encoder identity and preceding tokens scope the ordinary RAM/SSD cache. Generated follow-ups reuse state; rewinds before a delayed-precision boundary recompute. Qwen recurrent layers require an exact retained prefix. Explicit serial retains encoder-only reuse. |
461
- | `MLX_BUN_MIXED_PREFILL` | — | off (`=1`) | Lab mixed prefill/decode execution for Gemma 4 and Qwen3.5/3.8 text groups, including grouped speculative methods. The scheduler reserves running tokens before prompt work; the model packs feed-forward operations across real tokens while attention and KV state retain their original group geometry. Methods supply candidate-token demand and per-group hidden taps; speculative verification preserves its existing matmul geometry. Packed matmuls can select different kernels from solo decode; this does not claim solo-logit identity or a measured serving win. |
462
- | `MLX_BUN_MIXED_PACKED_MLP` | — | on (`=0` disables) | Lab control inside mixed model work: disable feed-forward packing while keeping the same scheduling budget and attention geometry, to measure packing separately from chunk scheduling. No effect when mixed execution is off. |
463
- | `MLX_BUN_MIXED_TOKEN_BUDGET` | — | `256` | Total real tokens in an enabled mixed iteration, including running decode rows. At least one token per participating row progresses. A lone preparation retains its existing chunk setting. Precision transitions and checkpoint endpoints remain method-owned. |
464
- | `MLX_BUN_EARLY_FIRST_TOKEN` | — | on (`=0` disables) | Eligible ordinary generation yields token zero before constructing the next decode step; later decode remains pipelined. The continuous scheduler yields after preparation creates its first active row when no other request is queued, allowing prepared output to flush before decode. It then rechecks cancellation, admission and shutdown; queued short admissions still group together. Serial fill, grammar, checkpoint resume and single-token budgets retain their existing order. If a native consumer stops at the first yield and retains caller-owned caches, a non-aborted return completes that token’s M=1 forward before returning the cache, preserving the ordinary pipeline’s boundary for prefix reuse. Aborted requests do not start another forward; generation-owned caches need no alignment. The setting is captured by generation and the batch runtime. Native M1/M4 state and continuation, HTTP cancellation/overlap and cached/SSD gates pass. Monitored paired chat measurements support earlier visible output; they do not establish higher decode throughput, and an invisible token zero need not improve client latency. See benchmarks.md. |
465
- | `MLX_BUN_TURBOQUANT_FUSED_DECODE` | — | on (`=0` disables) | Packed K/V decode fusion for an existing `--kv-quant turbo:...` cache, captured when each cache is created. A shared Metal operation unpacks keys and values, applies the existing key zero/scale and Lloyd-Max value scale, and preserves the codec's eager or deferred inverse rotation. It accepts supported bit widths, head dimensions 64/128/256/512 and 32/64-element groups with fp16/bf16/f32 metadata. Eager k8v3 with B1/H4, head dimension 256, fp16 metadata, group32 and at least 8192 cached tokens also fuses inverse rotation; other shapes keep the existing rotation path. Unsupported inputs, CPU streams and shapeless traces retain ordinary operations. Quantization, stored cache format and serving eligibility are unchanged. Joint-decoder Qwen native/serial and repeated long-context HTTP gates pass. The inverse operation passes both integrated Qwen model gates and six HTTP pairs per quant. MiniCPM/Gemma deferred-consumer serving gates also pass. The shared codec/layout supports ordinary and supported drafting groups without changing this kernel selection. Gemma now owns pre-write row positions across cache appends; the fix passes native checks on both Macs. The combined fused-k8v3/MTP3 pressure fixture passes on M4 and M1 with exact responses/usage and durable SSD writes. Codec policy is resolved once for ordinary, batched and delayed caches; `=0` retains the unfused control. This does not enable TurboQuant quantization itself: `--kv-quant` remains a separate choice. |
466
- | `MLX_BUN_NO_FUSED_SDPA` | `--fused-sdpa` (inverted) | follows `--kv-quant` | `=1` forces the stock unfused SDPA everywhere. |
467
- | `MLX_BUN_COMPILED_GEGLU` | `--compiled-activations` | on (`"0"` disables) | Gemma geglu via mlx-lm's `@mx.compile` closure. `=0` → uncompiled composition (same parity, slower). |
468
- | `MLX_BUN_COMPILED_SWIGLU` | `--compiled-activations` | on (`!== "0"`) | Compiled SwiGLU on MiniCPM5 decode and prefill, matching mlx-lm. An enclosing compiled graph owns its own fusion. qwen3/qwen3.5/universal compile unconditionally. |
469
- | `MLX_BUN_FORCE_WIRE` | `--force-wire` | off (`=1`) | Wire weights for the generation. |
470
- | `MLX_BUN_TRELLIS` | — | `kernel` (`=expand`) | Packed trellis-coded weights (`mode: "trellis"` modules, Q2b — design: `docs/design/turboquant.md`). `kernel` serves them through the Metal decode kernels (M≤4 matvec; larger M expands one tensor to bf16 and runs a stock matmul). `=expand` decodes every trellis tensor at LOAD into 8-bit g64 affine (+~4 GiB at 27B, the eval-carrier numerics) and serves it through the stock quantized path — the fallback for a machine where the kernels lose. |
471
- | `MLX_BUN_TRELLIS_VARIANT` | — | `13` | Trellis kernel variant (see [Q2b experiments](../design/turboquant.md)): `6` = code computed inline × reciprocal, weight served as f32 code×scale; `1` adds a residual step and bf16 rounding to reproduce the fake-quant artifact's weights. `0`/`2`/`3`/`4`/`5` are bench-only decoder variants. Variants `7`–`13` retain variant-6 decode values; `13` is the measured default. These variants tune work assignment; `11` tiles eligible short axis-1 prefills, `12` adds split-K axis-0 prefill at M=5..8, and `13` also vectorizes remaining bf16 expansion for k2/k3/k4, T=256, L=12. On MLX 0.32.2/M3+ the axis-1 M5..15 path instead uses direct packed decoding with native wide-matvec arithmetic when Qwen's RMSNorm establishes aligned row-contiguous inputs; callers without that layout proof use native expansion/matmul. Qwen27B additionally selects an integer codebook for its interleaved k3 down projection at M=3/4 with bf16 activations; other calls retain the computed decoder. Prefill rounds weights to the activation dtype. |
472
- | `MLX_BUN_TRELLIS_ASYNC_EXPAND` | — | off (`=1`) | Experimental variant-13 expansion scheduling. Submit an expanded projection asynchronously while MLX active allocation is below 75% of the device's recommended working set; retain blocking evaluation above it. Other variants are unchanged. Uses the execution's runtime-policy snapshot and preserves the caller's layer barriers. The threshold is not a total-memory cap. Qwen27B integrated native, repeated serial/continuous HTTP and both saved-agent pressure gates pass on M4 Pro 24 GB. Broader-model, combined-optimization and quiet M4 Pro acceptance remain. |
473
- | `MLX_BUN_PAGED_KV` | `--paged-kv` | off (`=1`) | Paged KV cache; the same eligibility and separate RAM/SSD namespace as the flag. |
474
- | `MLX_BUN_ALLOW_PRIVATE_MEDIA` | `--allow-private-media` | off (`=1`) | Permit media fetches to private/loopback/link-local hosts (timeout + size cap still apply). |
475
- | `MLX_BUN_EXPERT_OFFLOAD` | `--expert-offload` | off | `=<dir>` — the path of a built expert-offload file, activated at module load (`src/expert-offload.ts`) for scripts and library runs that never parse serve flags. The CLI flag builds the file and activates it itself. |
476
- | `MLX_BUN_PREFILL_TAIL_SPLIT` | — | on (`"0"` disables) | Oracle prefill convention: drain the prompt to len−1, then compute step-0 logits from a separate L=1 forward of the last prompt token (mlx-lm `generate_step` and its batched engine). Both lanes. The spec lane follows its own oracle's shape under the same flag (mlx-lm `speculative_generate_step`: target and draft drain to len−1, no separate step 0). `=0` restores the full-final-chunk convention everywhere — ulp-different at step 0, flips near-tie greedy streams vs mlx-lm. |
477
- | `MLX_BUN_GRAMMAR` | — | on (`"0"` disables) | `=0` disables structured-output mask compilation; requested constraints take the graceful-degrade route (chat prompt injection + a `Warning` header; raw completions header only). |
478
- | `MLX_BUN_TOKEN_MASK` | `host` \| `metal` | `host` | Experimental grammar-mask implementation. `metal` uploads packed bits and applies the same additive mask in a compiled shared Metal kernel. Captured when the grammar controller is created; serving performance gates remain open. |
479
- | `MLX_BUN_GRAMMAR_JUMP` | — | **off** (`=1`) | Grammar-supplied continuations. Eligible shared requests without a configured drafter propose xgrammar's forced string to the existing target verifier; the sampler validates every emitted token, including requested logprobs. Candidates leave the matcher unchanged until sampling. Affine/TurboQuant layouts compose through their speculative capabilities; paged requests keep ordinary grammar sampling. Explicit serial execution retains direct jump-forward: it emits retokenized forced spans with one multi-token forward, skips jumping with logprobs, and can choose different tokens than ordinary sampling. A configured drafter retains its own proposal policy. This remains opt-in; tokenization/verification width can change numerical trajectories. |
480
- | `MLX_BUN_GRAMMAR_DRAFT_TOKENS` | — | `3` | Maximum grammar candidates per shared verification round when `MLX_BUN_GRAMMAR_JUMP=1`. Changes proposal depth, independently of scheduler capacity. |
481
- | `MLX_BUN_FILL` | — | **off** (`=strict` \| `=echo`) | **Token fast-forwarding.** Strict mode appends tool-call spans determined by the request's schema and chat template, then resumes sampling. Request-local parsing excludes ambiguous literals and incomplete delimiters; closed, single-required-property schemas qualify for key/call-close assertions. Echo mode additionally proposes text copied from the session and verifies it with the request's sampler. Shared execution supports seeded requests and the qualified bf16/affine/TurboQuant row layouts. Homogeneous echo cohorts use the existing grouped target verifier; mixed proposed/unproposed rows retain one-position sampling. Rejected suffixes are rolled back before reusable state is published. Wider verification can change floating-point rounding relative to sequential decode, so sampled text need not be identical. Explicit serial fill still excludes fixed seeds and uses its existing model/cache eligibility. Fill is disabled for logprobs, structured output, media, a mounted draft model and shared paging. Strict appends bypass sampling and therefore change behavior policy at nonzero temperature. Both modes remain opt-in; see the shared-fill section below and `usage.fill`. |
482
- | `MLX_BUN_FILL_MAX_SPAN` | — | `32` (floor 2) | Hard cap on one injected span. |
483
- | `MLX_BUN_FILL_APPEND_CHUNK_SIZE` | — | `0` (model limit) | Execution chunk cap for assert-policy fill, captured by each FillSession. Zero selects the model's qualified limit; a positive value can lower that limit. The Qwen 27B text path on `applegpu_g16s`, validated on the M4 Pro, supports up to four positions with supported affine projections and optional Trellis MLPs. It rechecks the limit after each chunk and splits at MLX's attention arithmetic boundaries to preserve one-token numerics. Other configurations use one position per forward. The engine commits the complete span before emission and resumes sampling after it, with no intermediate vocabulary heads or verification. Verify-policy proposals keep a single forward for recurrent rollback. The injected-token cap is unchanged. Library callers can set `FillSession`'s `appendChunkSize` option. Held-out, broader-model and quiet M4 Pro acceptance remain. |
484
- | `MLX_BUN_FILL_K` | — | `8` (floor 2) | Echo anchor length: the k-gram that must match before a copied span is proposed (the corpus study's token-level threshold). |
485
- | `MLX_BUN_FILL_CANDIDATES` | — | `24` | Echo bucket-scan cap — the NEAREST occurrences of the anchor win. A span extends only while every one of them agrees; the first disagreement (a **branch point**) ends it. |
486
- | `MLX_BUN_FILL_INDEX_MAX` | — | `131072` (floor 1024) | Token cap on the growing echo index; past it the index freezes rather than growing. |
487
- | `MLX_BUN_FILL_TRACE` | — | off (`=1` \| `=<file.jsonl>`) | `=1`: assert the fill cache-alignment invariant (`cache offset == prompt + forwarded`) on both sides of every append, and log each event. `=<file.jsonl>`: additionally append one record per proposal — proposed ids/text next to what the model's own logits said at every span position (position 0 = the in-flight sample, then argmax), for both policies; under `assert` that readback is trace-only. `bun scripts/fill.ts trace <file>` prints the list and per-position agreement. |
488
- | `MLX_BUN_GRAMMAR_BATCH` | — | on (`"0"` forces serial) | `=0` routes grammar requests to the serial lane instead of per-row batch matchers (A/B + kill switch). |
489
- | `MLX_BUN_BATCH_SSM` | — | on (`"0"` forces serial) | `=0` excludes SSMCache (Qwen3.5 gated-DeltaNet hybrids) from the batch capability gate → those models route serial. |
490
- | `MLX_BUN_BATCH_EXTEND` | — | on (`"0"` reverts) | Joining rows append to the running batch's KV in one pad+concat (mlx-lm `BatchKVCache.extend`). `=0` reverts to whole-batch re-merge (numerically equivalent, O(B·S)). |
491
- | `MLX_BUN_BATCH_VEC_SAMPLE` | — | on (`"0"` reverts) | Vectorized greedy batch sampling; `=0` falls back to per-row sampling (bit-equal A/B). |
492
- | `MLX_BUN_BATCH_NO_PIPELINE` | — | off (`=1`) | Read each batch step's tokens synchronously instead of pipelined (A/B lever; numerically equivalent, slower). Captured when the execution group is constructed. |
493
- | `MLX_BUN_SSD_WRITEBEHIND` | — | on (`"0"` disables) | Proactive persistence after cache publication. A CPU worker packs, hashes and writes immutable state without a generation lock. Writing does not evict RAM. `=0` keeps eviction-triggered persistence; RAM victims remain resident until their SSD copy commits. |
494
- | `MLX_BUN_SSD_LAYOUT` | — | `whole` | `blocks` writes immutable content-addressed blocks with atomic checkpoint manifests (format 5). Existing whole files remain readable. Shared blocks count once toward an explicit SSD cap and survive deletion of other referencing checkpoints. Experimental space/time tradeoff; see benchmarks. |
495
- | `MLX_BUN_SSD_SEGMENTED` | — | on (`"0"` disables) | With block storage, read contiguous spans directly and pack arbitrary strides in at most 1 MiB scratch. `=0` retains whole-tensor CPU packing for paired measurements. |
496
- | `MLX_BUN_SSD_PREFETCH` | — | on (`"0"` disables) | Prepare cold prefixes before execution, using a separate CPU read queue and owned page-aligned allocations. Concurrent identical reads coalesce. Cancellation releases request interest; the cache chooses residency. `=0` retains synchronous restore for comparison. |
497
- | `MLX_BUN_SESSION_CACHE` | — | on (`"0"` disables) | Honor application session affinity for checkpoint lookup and soft RAM retention. `=0` ignores session metadata for paired HTTP measurements. Full input is still required; see server-api.md for body/header fields and session closure. |
498
- | `MLX_BUN_CACHE_RETENTION` | — | `lru` | `cost-size` selects GreedyDual-style reuse/size retention, with reused prefix tokens as the processing-cost proxy. This changes RAM residency only; SSD durability remains independent. |
499
- | `MLX_BUN_PAGED_ATTN` | — | off | With paged KV, `1` selects direct Metal reads for short causal queries (≤8 tokens), bf16 or affine KV4/KV8. Longer prefill and explicit masks use the established SDPA shape dispatch. Lab numerical contract: tolerance-tested against the same stored values, not an L1 bit-exact claim. |
500
- | `MLX_BUN_SSD_SPILL_QUEUE_GB` | — | `2` (GiB; any finite value ≥ 0) | Pending snapshot cap for optional interrupted-generation checkpoints. Older queued intervals may be superseded; `=0` retains the newest plus any in-flight interval. Normal prompt-history persistence does not use this drop policy; its cache owns RAM residency and SSD demotion. Counters in `/stats.ssd_cache`. |
501
- | `MLX_BUN_SHUTDOWN_TIMEOUT_MS` | — | `120000` (any finite value > 0) | Maximum time `serve` gives active requests plus the SSD durability flush after `SIGINT`/`SIGTERM`; on timeout it logs the remaining snapshot/spill counters and exits. |
502
- | `MLX_BUN_DSPARK_MINCONF` | — | checkpoint-driven | Overrides the DSpark/DeepSpec draft scheduler's minimum-confidence threshold (draft-length pruning). Spec lane only ([docs/design/speculative-decoding.md](../design/speculative-decoding.md)). |
503
- | `MLX_BUN_MEMORY_BATCH` | — | `1` (integer ≥ 1) | Row width for `mlx-bun memory` model calls. 1 = serial (batching measured 1.7–1.9× slower on the heterogeneous extract/chunk workload — [docs/design/dreaming-nightly-pipeline.md](../design/dreaming-nightly-pipeline.md)). |
504
-
505
- ### Paths and tooling
506
-
507
- | Env var | Default | Effect |
508
- | --- | --- | --- |
509
- | `MLX_BUN_LIBMLXC` | resolved: beside the executable → native-pack cache (`~/Library/Caches/mlx-bun/native-v<ver>-<arch>/`) → Homebrew | Explicit path to `libmlxc.dylib`; its directory is then the native runtime dir (`src/mlx/ffi.ts`, `src/native-pack.ts`). |
510
- | `MLX_BUN_NATIVE_PACK_URL` | the GitHub release asset for `NATIVE_PACK_VERSION` | Override the native runtime pack download URL (first-run fetch, sha256-verified). |
511
- | `MLX_BUN_FRAME_EXTRACT` | resolved: beside the executable → native-pack cache → `dist-native/` → compile from `src/native` | Explicit path to the `mlx-bun-frame-extract` AVFoundation sidecar used for video input. |
512
- | `MLX_BUN_EXPERT_IO_DYLIB` | resolved: beside the executable → native-pack cache → `dist-native/` | Explicit path to `libmlx_bun_expert_io.dylib` (GLM-5.2 streamed expert I/O). |
513
- | `MLX_BUN_WIKI` | `~/.mlx-bun/wiki` | Root of the memory vault (`~` expands). |
514
- | `MLX_BUN_JOBS_DB` / `MLX_BUN_JOBS_DIR` | the `JobStore` defaults | Job-store SQLite path and logs dir. The job runner sets both on the subprocess it spawns so the child opens the same store; override for tests. |
515
- | `MLX_BUN_CALIBRATION_JSONL` | bundled optiq mix in the oracle venv | Explicit calibration corpus for `mlx-bun convert`/quantize. |
516
- | `MLX_BUN_ORACLE_PYTHON` | `/Users/joshrossi/Code/mlx-lm/.venv/bin/python` (the reference box; machine-specific, never re-commit) | Oracle venv interpreter for evals that shell out to Python (HumanEval). |
517
- | `MLX_BUN_EVAL_DATA` | `~/.cache/mlx-bun/eval-data` | Directory of exported eval `.jsonl` datasets. |
518
-
519
- ### Diagnostics and tracing (off unless set)
520
-
521
- | Env var | Value | Effect |
522
- | --- | --- | --- |
523
- | `MLX_BUN_P2R_TRACE` | `=1` | Per-request prompt→response phase trace (request-slot wait, execution admission wait, cache prefetch/restore, prefill forward/evaluation/maintenance/checkpoints, mixed-forward token counts, token-zero, bounded initial token routing, response writes) for `/v1/chat/completions` and `/v1/completions`; records print to stderr as JSON lines. The trace id is `x-mlx-bun-trace-id` when the request sends it. |
524
- | `MLX_BUN_P2R_SYNC` | `=1` (with `MLX_BUN_P2R_TRACE`) | Token-zero attribution mode: synchronizes hidden/cache state, projection and sampling at the instrumented boundaries. This changes overlap and slows the traced request. Ordinary prefill traces add no synchronization: forward includes any backend evaluation, while evaluate measures the remaining state wait. |
525
- | `MLX_BUN_SPEC_TRACE` | `=1` | Explicit serial speculative-loop round diagnostics, captured once at run setup. |
526
- | `MLX_BUN_LANE_DEBUG` | `=1` | Logs each request's scheduling placement (`mechanism` + shape) to stderr. |
527
- | `MLX_BUN_BATCH_STEP_TRACE` | `=1` | Per-step phase timing in the batch scheduler (build / read / emit / gap), captured when the execution group is constructed; summarized by `stepTraceReport()`. |
528
- | `MLX_BUN_GRAMMAR_DEBUG` | `=1` | Logs per-step grammar row state in the batch scheduler. |
529
- | `MLX_BUN_PREFILL_MEM_LOG` | `=1` | Logs active/peak memory after each serial prefill chunk. |
530
- | `MLX_BUN_EXPERT_TRACE` | `=<path>` | Records every MoE router decision as JSONL to that path (adds a per-call GPU→host sync — a measurement tool, not a serving path). |
531
- | `MLX_BUN_PI_DEBUG` | any non-empty | Extra `[pi-web]` logging (prompt fingerprint, tool/memory surface) for the web-chat pi session. |
532
- | `MLX_BUN_EVAL_DEBUG` | `=1` | HumanEval: pipe the sandbox's stderr and print failures. |
533
-
534
- P2R records include a process-local `startedAtMs` origin to align concurrent
535
- requests. Prefill `workId` attributes identify shared spans recorded on several
536
- rows; these spans and their nested children must not be summed as separate
537
- GPU work. The first eight token-routing spans stop at the first semantic event
538
- and distinguish hidden channel markers from visible output. With tracing
539
- enabled, `bench-serve.ts all` retains complete records by child PID in
540
- `promptResponseTraces`, including records emitted during shutdown. Summarize a
541
- saved report with `bun scripts/bench/prefill-trace.ts report.md.json --out
542
- breakdown.json`. Clocks from different server processes are independent.
543
-
544
- ### Eval and training
545
-
546
- | Env var | Default | Effect |
547
- | --- | --- | --- |
548
- | `MLX_BUN_EVAL_THINK` | off (`=1`) | Evaluate with `enable_thinking` on (default off for parity with optiq's published non-thinking numbers). |
549
- | `MLX_BUN_EVAL_KV_QUANT` | off (`=1`) | Generate through the model's `kv_config.json` quantized KV during evals (default full-precision KV, matching optiq's eval). An explicit `--kv-quant` on `mlx-bun eval` wins. |
550
- | `MLX_BUN_MMLU_FROZEN` / `MLX_BUN_GSM8K_FROZEN` / `MLX_BUN_HUMANEVAL_FROZEN` / `MLX_BUN_IFEVAL_FROZEN` / `MLX_BUN_BFCL_FROZEN` / `MLX_BUN_HASHHOP_FROZEN` | on (`"0"` reverts) | Use the frozen oracle-exported problem sets (parity with the reference numbers); `=0` falls back to our own sampling of the full set. |
551
- | `MLX_BUN_TRAIN_ATTN` | `ops.sdpa` (unset) | `=flash` selects the hand-rolled O(L)-memory flash kernel for training attention (~30× slower). **Refused for Gemma models** (e4b SIGTRAPs at seq ≥ 2048); MiniCPM5 allowed. |
552
- | `MLX_BUN_FLASH_MIN_M` | `1024` | With a flash-CCE head requested, rows shorter than this take the exact fused head instead; `=0` always honors flash. |
553
- | `MLX_BUN_MEM_LOG` | off (`=1`) | Trainer per-step memory logging. |
554
-
555
- `MLX_BUN_CCE_*` (flash-CCE kernel variant selectors and epsilons in
556
- `src/train/flash-cce.ts`) and `MLX_BUN_SEG_*` (segmented-backward head and
557
- memory probes in `src/train/segmented.ts`) are intentionally undocumented
558
- developer knobs; `MLX_BUN_EVAL_KV_ARM_NOOP` is an inert placeholder the KL
559
- harness flips.
560
-
561
- ### Removed
562
-
563
- `MLX_BUN_PERF_KERNEL`, `MLX_BUN_FUSED_GELU`, `MLX_BUN_FUSED_DECODE`,
564
- `MLX_BUN_FUSED_SWIGLU*`, `MLX_BUN_CPM5_FAITHFUL`, and the `--l3` tier were
565
- deleted 2026-07-05 with their kernels
566
- ([unified-engine-frontier-plan.md](../design/unified-engine-frontier-plan.md));
567
- exporting the variables now does nothing, and `--l3` exits with a pointer.
568
-
569
- ## Execution modes: serial vs. `--batch N`
570
-
571
- Scheduling is **concurrency-driven** (default cap 8): a lone scheduler
572
- request uses the B=1 fast path — its caches are adopted serial-class
573
- objects, compiled decode replays, and the prompt cache and SSD tier serve
574
- it. Only a second concurrent request causes a batch layout to exist. The
575
- flag declares the concurrency cap; active rows select B=1 or B=N inside
576
- the scheduler.
577
-
578
- No flag is needed to enable this default. The cap is a maximum, not a minimum
579
- group size: a lone eligible request starts at B=1. The serial executor remains
580
- available through `--batch 1` and for unsupported request compositions.
581
-
582
- `--batch 1` pins the strict serialized single-queue path: one generation
583
- at a time, arrival-independent numerics (a request's bits never depend on
584
- what else was in flight). Pin it for golden regeneration and
585
- reproducibility work. Batched rows carry bf16 left-pad reduction-order
586
- noise vs their solo runs (calibrated per model in the gated suites) — a
587
- request that never shares a step is bit-identical either way.
588
-
589
- The batched engine is **bit-parity with `mlx_lm.server` at `B=N`** per
590
- row for bf16, and per-row oracle-gated for the quantized compositions:
591
-
592
- - **KV quant unset ⇒ bf16** — the batch path engages out of the box.
593
- - **`--kv-quant config`** (per-layer mixed precision) **batches** on
594
- every shipped model — full-attention and rotating layers — applied per
595
- row, gated bit-exact for unpadded rows vs the serial composition.
596
- - **`--kv-quant 4|8`** uses shared affine conversion and batches on supported
597
- full-attention, rotating and hybrid recurrent models.
598
- - **`turbo`** uses encoded shared rows for qualified start-zero full-attention caches; sliding layers stay bf16.
599
-
600
- ### Scheduling declaration (`GenerationGateway.place`)
601
-
602
- With a cap greater than one, `GenerationGateway.place()` freezes one
603
- scheduling mechanism for the exact resolved request shape: `continuous`
604
- admits it to the scheduler (which then picks B=1 or B=N from active rows);
605
- `serial` preserves the strict executor. The support check never removes,
606
- downgrades, or substitutes MTP, KV schemes, TurboQuant, grammar, adapters,
607
- or sampling — a composition the scheduler does not implement drains it and
608
- runs unchanged serially. The two mechanisms are mutually exclusive on the
609
- GPU (one `AsyncMutex`).
610
-
611
- | Request property | Continuous scheduler? |
612
- | --- | --- |
613
- | vision / audio / video parts | Gemma4 image/audio and Qwen image/video use atomic media prefill followed by shared decode; diffusion retains its separate serial method |
614
- | LoRA `adapter` (resolves to ≥1) | ✅ identical ordered adapter sets share a group; different sets wait for the next group |
615
- | `logprobs` / `top_logprobs` | ✅ ordinary and qualified MTP/lookup/standalone-draft groups capture per-request probabilities; other exclusions still apply |
616
- | explicit `seed` | ✅ request-local random stream; reproducibility also depends on model arithmetic and batch composition |
617
- | KV quant active | ✅ batches for per-layer `config` and uniform `4`/`8` schemes on supported cache layouts |
618
- | `--kv-quant turbo` | ✅ qualified TQ layouts; ordinary and supported grouped drafting library requests also support delayed row-local conversion |
619
- | `--draft-model` mounted | ✅ qualified MTP, lookup, standalone, assistant, DeepSpec and DSpark/DFlash groups; provider and request capabilities determine eligibility; supported ordinary requests batch |
620
- | `repetition_penalty` / `min_p` / `xtc_*` / `logit_bias` / presence+frequency penalties | ✅ batches — per-row logits processors over per-row device-side history (Qwen3.5 ships a *default* repetition penalty, so this is load-bearing) |
621
- | structured output (`response_format` / `guided_*`) | ✅ batches — per-row grammar matchers (`MLX_BUN_GRAMMAR_BATCH=0` forces serial) |
622
- | `temperature` / `top_p` / `top_k` | ✅ batches (each row samples with its own seed) |
623
- | `stop` sequences | ✅ batches (per-row `StopMatcher`) |
624
- | `tools` / `tool_choice` | ✅ batches (per-row tool router); opt-in `MLX_BUN_FILL=strict` uses the shared known-token method |
625
- | `--thinking` / `enable_thinking` | ✅ batches (template-render concern) |
626
- | multi-turn / long prompt | ✅ batches with prompt-cache reuse: a joiner restores the longest usable cached prefix and prefills only the suffix (`cached_tokens` reported) |
627
-
628
- **Which models use continuous scheduling** (`#modelCachesBatchable`):
629
- full-attention (CPM), sliding-window (Gemma), hybrid gated-DeltaNet
630
- (Qwen3.5 — `MLX_BUN_BATCH_SSM=0` reverts to serial routing), and plain
631
- full-attention Tier-0 universal archs (Llama etc., gated token-exact vs
632
- mlx-lm B=2). Still serial by the capability gate: gemma2-family
633
- (`maskArray`) and sliding-window *universal* archs (unvalidated cells) and
634
- DiffusionGemma (non-autoregressive).
635
-
636
- A request requiring the serial mechanism **drains** the scheduler: while
637
- it waits, the scheduler stops admitting new rows, finishes the running
638
- ones, and releases the GPU (mlx-lm's `drain_batch`); admission then
639
- resumes, so batchable traffic cannot starve a serial-lane request.
640
- Placement is not load-dependent: a request admitted to the continuous
641
- scheduler stays there whether it is the only row or one of many.
642
-
643
- ## Compatibility matrix
644
-
645
- "serial" = `--batch 1`; `--batch N` permits continuous scheduling, though a
646
- declared composition may still require the serial mechanism as shown above.
647
-
648
- | Option | serial (`--batch 1`) | `--batch N` (N>1) |
649
- | --- | --- | --- |
650
- | `--kv-quant config` | ✅ applied to all requests | ✅ batches where the loaded cache capability supports the per-layer scheme; otherwise routes serial |
651
- | `--kv-quant 4`/`8` | ✅ applied to all requests | ✅ server start=0 converts during prefill and batches on supported cache layouts; delayed library thresholds use qualified shared affine row layouts |
652
- | `--kv-quant turbo[:k<bits>v<bits>]` | ✅ ordinary decode; strict serial speculation remains excluded | ✅ ordinary TQ, including delayed library conversion; supported grouped drafting also supports delayed library conversion |
653
- | `--kv-quant off` / unset | ✅ bf16 (the L1 default) | ✅ bf16 |
654
- | `--paged-kv` | ✅ | ✅ Gemma4 bf16/affine4/8 with separate RAM/SSD namespace; experimental direct attention is opt-in |
655
- | `--memory-budget` | ✅ per-request admission | ✅ per-request admission — not aggregate (use `--kv-budget`) |
656
- | `--kv-budget` | n/a | ✅ aggregate queue/reject across rows |
657
- | `--prompt-cache` / `--ssd-cache` | ✅ prefix/output reuse + SSD restore | ✅ immutable prefill/output checkpoints, session lookup and queued SSD persistence |
658
- | `--temperature`/`--top-p`/`--top-k` | ✅ | ✅ (per-row) |
659
- | `--thinking` | ✅ | ✅ |
660
- | vision / audio / video request | ✅ | Gemma4 image/audio and Qwen image/video shared; diffusion via its serial method |
661
- | LoRA `adapter` | ✅ | ✅ compatible groups on adapter-capable backends |
662
- | `repetition_penalty` / `min_p` / `xtc_*` / `logit_bias` / presence+frequency | ✅ | ✅ (batches — per-row processors) |
663
- | `seed` | ✅ | ✅ request-local sampling |
664
- | `tools` / `stop` | ✅ | ✅ (batches) |
665
- | structured output (`response_format`/`guided_*`) | ✅ (mask in the decode loop) | ✅ (batches; per-row matchers) |
666
- | `--draft-model` / `--draft-kind` | ✅ eligible spec decode | ✅ qualified MTP, lookup, standalone, Gemma assistant/DeepSpec/DSpark groups, including grammar/logprobs |
667
- | GLM `--mtp on` | ✅ native MTP spec decode | ✅ native MTP uses grouped state/verification; tiny-model and oracle tests pass, final Colibri artifact testing is deferred |
668
- | `--compiled-decode` | ✅ | ✅ at **B=1 only**: a lone request's adopted serial-class caches replay the same compiled step; B>1 steps run the plain graph |
669
- | `--fused-sdpa` | ✅ eligible affine attention | ✅ kernel eligibility depends on dtype, quantization and mask geometry |
670
- | `--force-wire` | ✅ serial wired scope | not applied by the shared executor |
671
-
672
- ### Shared execution and kernel settings
673
-
674
- The scheduler selects request work. The inference method advances it through
675
- model-owned numerical operations. Specialized kernels and sampling policies
676
- remain available wherever their backend capabilities qualify; batching does
677
- not disable performance settings as a category.
678
-
679
- - `--compiled-decode` uses the qualified compiled graph for one active,
680
- unpadded request. Multi-row steps use the batched graph.
681
- - `--fused-sdpa` follows affine kernel eligibility. Padded/array masks can
682
- require the ordinary attention operation; this is an attention decision.
683
- - `--force-wire` controls the explicit serial wired scope. The shared executor
684
- does not enter that scope.
685
- - Trellis, compiled activations, affine row reuse and TurboQuant kernel choices
686
- belong to the numerical backend and remain independent of admission policy.
687
-
688
- `MLX_BUN_FILL=strict` uses a grouped method for eligible tool requests. Each
689
- row owns its fill session and sampler history. Known positions bypass sampling;
690
- when all next positions are known, the method omits the vocabulary head.
691
- Shared fill uses the model-qualified multi-position append when all active
692
- rows have known spans and the model permits that geometry. Qualified Qwen B1
693
- uses its specialized append; wider rows currently advance one position per step. The shared method supports
694
- bf16, affine KV4/KV8 and supported TurboQuant layouts, including explicit seeds.
695
- It does not use compiled replay, interrupted-generation checkpoints, paging,
696
- probability metadata, media, grammar or a mounted draft provider.
697
- `MLX_BUN_FILL=echo` uses the same shared method with sampled verification and
698
- row-specific rollback. Ordinary rows can join with empty proposals; eligible
699
- plain-greedy requests reuse independent verification sampling. With a Qwen MTP
700
- companion, echo proposals use the speculative method and the provider consumes
701
- accepted tokens before resuming learned drafting. Asserted template spans remain
702
- sampled in this combination. Other draft providers are not yet qualified. Fill stays off by default;
703
- per-model performance acceptance remains separate from numerical replay.
704
-
705
- Executors capture an immutable runtime configuration. Later host configuration
706
- changes do not change an active request's kernel choices. TurboQuant storage
707
- carries its decode policy through RAM copies, row extraction and delayed
708
- conversion; restored SSD state is opened under the receiving binding's policy.
709
-
710
- ## Known limitations under shared execution
711
-
712
- 1. Gemma4 image/audio uses shared decode after an indivisible embeddings prefill.
713
- Qwen image/video positions stay with each request through shared decode; diffusion retains its separate serial method. Strict tool-call fill
714
- and echo verification have shared methods. Qwen MTP supports verified echo;
715
- asserted fill with a drafter, other providers and shared paging remain unsupported. Grammar has shared masking and opt-in verified
716
- proposals; direct serial jump-forward is a different algorithm.
717
- 2. Aggregate admission is opt-in through `--kv-budget`. Without it, concurrent
718
- contexts can exceed available memory. Default fit estimates remain advisory.
719
- 3. Native GLM MTP has tiny-model/same-B oracle coverage; final Colibri artifact
720
- testing is deferred. DSpark/DFlash execution has fixture coverage, with no
721
- trained checkpoint available for a performance claim.
722
- 4. Paged Gemma storage supports bf16/affine4/8. TurboQuant pages, per-layer
723
- paged KV and paged speculative methods remain unsupported. Qualified
724
- ordinary resume and adapter resume are implemented; exact combinations are
725
- tracked in [batching](../design/batching.md).
726
- 5. Stock bf16, affine mixed-KV and TurboQuant retain separate correctness
727
- contracts. A passing storage test does not qualify an untested model or
728
- numerical geometry. Existing accepted matrices remain in the design and
729
- benchmark references.
730
-
731
- ## Fidelity tiers and the decode route (`--l1` / `--l2`)
732
-
733
- The tiers are **correctness contracts**; each flag is an alias for a
734
- decode-route preset (`applyDecodeRoute()` in `src/cli.ts`), and any
735
- per-fork flag (`--kv-quant`, `--compiled-decode`, `--compiled-activations`,
736
- `--fused-sdpa`) overrides its tier's preset.
737
-
738
- | Tier | Contract | KV | Kernels | Verified against |
739
- | --- | --- | --- | --- | --- |
740
- | `--l1` | mlx-lm **bit-for-bit** | bf16 | compiled decode + compiled activations, fused-sdpa off | mlx-lm goldens (per machine) |
741
- | `--l2` | mlx-optiq **bit-for-bit** | mixed precision (`kv_config.json`) | + fused SDPA (matches optiq exactly) | optiq goldens |
742
- | *(none)* | **= `--l1`** | bf16 | as `--l1` | mlx-lm goldens |
743
- | **Lab** | no external oracle | — | env-flagged experiments with a bench + expiry; graduate only by beating L1 in a paired A/B | validity / KL / eval gates |
744
-
745
- Compiled decode is on in **every** tier (proven bit-exact with uncompiled —
746
- free speed, not a fidelity trade). **There is no `--l3` tier** (removed
747
- 2026-07-05; its role is the Lab).
748
-
749
- **KV precision is a separate axis from the tier's kernels.** `--l1
750
- --kv-quant 8` is a bit-exact L1 config: with fused-sdpa off our quantized
751
- decode runs `quantizedSdpaUnfused`, op-for-op mlx-lm's
752
- `quantized_scaled_dot_product_attention` (`mlx_lm/models/base.py`). Only
753
- the per-layer `config` scheme is optiq-only (→ L2).
754
-
755
- **Where each feature sits:** batching = L1-class (mlx-lm B=N parity);
756
- two-model speculative decoding = L1-class; structured output = L2-class
757
- (oMLX oracle; masking doesn't touch the numerics of valid tokens, so it
758
- composes with any tier); grammar × spec, HLG sampling, expert offload,
759
- TurboQuant's cache class, jump-forward decoding, and batched
760
- uniform/turbo KV are **no-oracle (Lab-gated)**.
761
-
762
- ## Feature matrix
763
-
764
- Everything mlx-bun serves, with its default, lane, fidelity tier, and knob.
765
-
766
- ### Serving & performance
767
-
768
- | Feature | Default | Lane | Tier | Knob |
769
- | --- | --- | --- | --- | --- |
770
- | OpenAI chat completions (`/v1/chat/completions`, SSE) | on | both | — | — |
771
- | Raw text completions (`/v1/completions`) | on | both | — | — |
772
- | Anthropic Messages (`/v1/messages`) | on | both | — | — |
773
- | OpenAI Responses shim (`/v1/responses`) | on | both | — | — |
774
- | Continuous batching (mlx-lm parity at the same B) | on, cap 8 | batch | L1 | `--batch <n>` (`1` pins serial) |
775
- | Prompt cache (prefix KV reuse) | on, 8 GiB | both | — | `--prompt-cache <GB>` (`0` = off) |
776
- | SSD KV cold tier (survives eviction + restarts; GLM compressed MLA/DSA state included) | off | both | — | `--ssd-cache <dir>` (+ `--ssd-cache-max`, `--ssd-cache-verify`, `--ssd-demote-idle`, `--generation-checkpoint`) |
777
- | Runtime isolation (crash-isolated engine child behind a proxy parent) | off | both | — | `--isolate` |
778
- | Model pool (LRU-capped resident engines under `--isolate`) | 1 | both | — | `--model-pool <n>` |
779
- | Mixed-precision KV (`kv_config.json`, optiq's scheme) | off | serial + batch (per-layer configs batch) | L2 | `--kv-quant config`, `--l2` |
780
- | Uniform quantized KV (mlx-lm's `--kv-bits` scheme) | off | serial + batch | L1 | `--kv-quant 4\|8` |
781
- | TurboQuant KV (rotation-based: affine keys + FWHT/Lloyd-Max values) | off | serial + qualified shared ordinary/drafting | Lab (codec oracle-backed; composition gates apply) | `--kv-quant turbo[:k<bits>v<bits>]` (default `k8v3`) |
782
- | Compiled decode (bit-exact graph replay) | on | serial, batch at B=1 | L1/L2 | `--compiled-decode on\|off` |
783
- | Compiled activations (mlx-lm's `@mx.compile` geglu/swiglu) | on | both | L1 | `--compiled-activations on\|off` |
784
- | Fused SDPA (optiq-exact quantized-KV attention) | follows `--kv-quant` | serial | L2 | `--fused-sdpa on\|off` |
785
- | Paged KV (vLLM-style block pool, gather before the stock SDPA) | off | shared B1/B>1 | gated bit-exact vs plain `KVCache` | `--paged-kv`, `--paged-kv-block-size <n>` |
786
- | Speculative decoding (two-model / Gemma `-assistant` / DSpark / DeepSpec / native MTP head) | off | shared Qwen methods; full-attention/rotating lookup/standalone and Gemma assistant/DeepSpec/DSpark; other combinations serial | per-drafter oracle (L1 two-model, L2 assistant, DeepSpec reference, Lab DSpark) | `--draft-model`, `--draft-kind`, `--num-draft-tokens` |
787
- | GLM-5.2 checkpoint-native MTP | on for GLM-5.2 | serial+spec | oracle trajectory + synthetic HTTP gate | `--mtp on\|off` |
788
- | Model-free prompt-lookup speculation (vLLM `ngram` port) | off | Qwen and full-attention targets shared / other models serial | lossless by verify (gated vs non-spec greedy) | `--draft-kind ngram`, `--ngram-max`, `--ngram-min`, `--num-draft-tokens` (default 10) |
789
- | Estimated memory admission | off (advisory) | both | — | `--memory-budget <GB>` opts in |
790
- | Aggregate KV admission for batch rows | off | batch | — | `--kv-budget <GB>` |
791
- | Expert offload (MoE experts on mmap) | off | serial | Lab | `--expert-offload` |
792
- | Extend-join (O(1) batch admission) | on | batch | L1 (mlx-lm `extend`) | `MLX_BUN_BATCH_EXTEND=0` |
793
- | Vectorized greedy batch sampling | on | batch | bit-equal A/B | `MLX_BUN_BATCH_VEC_SAMPLE=0` |
794
- | Pipelined batch token readback | on | batch | numerically equivalent | `MLX_BUN_BATCH_NO_PIPELINE=1` |
795
-
796
- ### Request features
797
-
798
- | Feature | Default | Lane | Tier | Knob |
799
- | --- | --- | --- | --- | --- |
800
- | Structured output (`response_format` json_object/json_schema) | on | both | L2 (oMLX) | request field; `MLX_BUN_GRAMMAR=0` kills |
801
- | Structured-output continuations (shared verified proposals / serial direct jump) | off | shared and serial | Lab | `MLX_BUN_GRAMMAR_JUMP=1` |
802
- | Token fast-forwarding for tool calls (template-determined spans) | off | serial + shared strict method | opt-in; identity tested on covered fixtures, parser/held-out gates remain (`tests/parity/fill-strict.test.ts`) | `MLX_BUN_FILL=strict` |
803
- | Echo injection (session self-copy spans, verified against the same forward's logits) | off | shared bf16/affine/TurboQuant; explicit serial eligibility remains separate | Lab (paired A/B on task success + wall clock before any default) | `MLX_BUN_FILL=echo`, `MLX_BUN_FILL_K`, `MLX_BUN_FILL_CANDIDATES`, `MLX_BUN_FILL_INDEX_MAX` |
804
- | `guided_grammar` (EBNF) / `guided_regex`¹ / `guided_choice` / `structured_outputs` | on | both | L2 | request fields |
805
- | Structured output × speculative decoding | on when both active | Qwen grouped MTP, lookup and standalone drafting / eligible serial methods | Lab | — |
806
- | Quantized KV × speculative decoding | Shared Qwen supports uniform KV4/KV8 and TQ with zero or positive conversion thresholds; strict serial supports qualified KV4; per-layer mixed KV remains excluded | Qwen grouped MTP, lookup and standalone drafting / eligible serial methods | scheme and method gates | `MLX_BUN_QWEN_SPEC_KV4=0` disables the KV4 composition |
807
- | Tool calling (Gemma sentinel / CPM+Qwen XML / GLM `arg_key`+`arg_value`) + `role:"tool"` loops | on | both | — | request `tools` |
808
- | Vision (`image_url`; PNG/JPEG/HEIC/AVIF/WebP/TIFF/GIF/BMP) | on for models with a tower; SSRF guard on remote URLs | Gemma4 shared; other media bindings serial | L1/L2 | `--allow-private-media` |
809
- | Video input (`video_url`/`video`; AVFoundation sidecar, 2 fps, ≤768 frames, 256 MB body cap; never with audio) | on for Qwen3.5-family | serial | mlx-vlm oracle | `--allow-private-media`, `MLX_BUN_FRAME_EXTRACT` |
810
- | Audio input (`input_audio`/`audio`/`audio_url`; WAV native, mp3/m4a/flac/ogg/aiff via CoreAudio; ≤30 s per clip; mixes with images) | on for models with `audio_config` + sidecar tower (e4b) | serial³ | L2 (greedy stream exact vs optiq's internal model) | `--allow-private-media` |
811
- | LoRA adapters (mount at start / hot-swap) | off | compatible groups | — | `--adapter <dir>`, `POST /v1/adapters` |
812
- | Sampling: temperature / top-p / top-k / min-p / XTC / logit_bias / presence+frequency+repetition penalties | per request | both | L1 (mlx-lm-faithful) | request fields / server defaults |
813
- | `logprobs` / `top_logprobs` | off | both | L1 | request fields |
814
- | Fixed `seed` reproducibility | off | both | — | request field; compare the same execution composition |
815
- | Thinking-mode control (hybrid-reasoning models) | model default | both | — | `--thinking`, `chat_template_kwargs`, `reasoning_effort` |
816
- | Stop sequences / streaming / usage accounting | on | both | — | request fields |
817
- | HLG tone-curve sampling | off | serial | Lab | `--hlg-sampling on` |
818
- | Spec-decode telemetry (`usage.speculation`) | on with a draft | Qwen shared MTP, lookup and standalone drafting / eligible serial methods | — | — |
819
- | Token-fast-forwarding telemetry (`usage.fill`) | on with `MLX_BUN_FILL=strict` | serial + shared | — | — |
820
- | Per-turn lane telemetry (`usage.lane`: serial / serial+spec / batched) | on | both | — | — |
821
-
822
- ### Model coverage (per-model validated cells)
823
-
824
- | Family | Serial | Batch | Notes |
825
- | --- | --- | --- | --- |
826
- | MiniCPM5 (cpm5) | ✅ L1/L2 | ✅ | the starter model |
827
- | Gemma 4 (1B/e4b/12B/26B, + vision e4b/12B, + audio e4b) | ✅ L1/L2 | ✅ | sliding+full interleaved; MoE 26B |
828
- | Qwen3.5 (gated-DeltaNet hybrid) | ✅ L1/L2 | ✅ (SSM path) | `MLX_BUN_BATCH_SSM=0` reverts |
829
- | Qwen3.8-27B (same qwen3_5 graph) | ✅ L1 | ✅ (SSM path) | native MTP head via `--draft-model`/`--draft-kind mtp` (lossless-gated; slower on a quiet box — opt-in); images and video serve (mlx-vlm oracle) |
830
- | GLM-5.2 / Colibri | ✅ chat/text, Messages, Responses, SSE, tools, grammar, logprobs | ✅ compressed MLA/DSA scheduler | native MTP shares the executor; final Colibri artifact testing is deferred; embeddings, vision/audio, adapters, training unsupported |
831
- | DiffusionGemma-26B (non-autoregressive) | ✅ (own engine) | — serial always | first bit-exact non-AR port |
832
- | Tier-0 universal (llama/qwen2/qwen3/olmo2/…, 11 archs) | ✅ L1 | ✅ plain full-attention archs² | gemma2-family / sliding-window universal → serial |
833
-
834
- ¹ `guided_regex` accepts the regex∩EBNF subset today (no `\d`/anchors — those degrade to prompt injection).
835
- ² Gated token-exact vs mlx-lm B=2 (static + dynamic join/leave) on Llama-3.2-3B.
836
- ³ Audio is a capability neither ancestor serves (mlx-lm strips the tower; optiq never wires it into its serve frontend). Serial by design; prompt cache skipped.
837
-
838
- Beyond serving, the same binary does training (`mlx-bun train`),
839
- quantization (`convert`, `fuse`), embeddings, local memory (`mlx-bun
840
- memory`), the pi agent (`mlx-bun pi`), the registry/`fit`/`gc`, HF
841
- `upload`, and the web Model Hub — see [cli.md](./cli.md).
842
-
843
- ## Performance characteristics & recipes
844
-
845
- Reference numbers are from this project's dev machines (loaded-machine
846
- numbers are directional only; [benchmarks.md](./benchmarks.md) holds the
847
- quotable set, and `scripts/bench-matrix.ts features` measures the
848
- composition cells in one run).
849
-
850
- - **A lone request is the serial engine** — prompt cache, compiled
851
- decode, and SSD restore all apply at B=1 under the default cap.
852
- - **`--batch N` wins under concurrency** — cpm5 `--batch 4`: ~349 tok/s
853
- aggregate vs ~173 serial-queued, TTFT 2–3× better; Llama-3B at B=2:
854
- 1.7× aggregate, TTFT 765→162 ms.
855
- - **Spec pays only on slow targets.** One accepted draft = one skipped
856
- target forward: 12B ≈ 1.09× at γ=1; fast small targets lose (e4b
857
- 0.78×). Draft for 12B+, skip below.
858
- - **Structured output is ~free** (<1% serial; bounded ~0.1 ms/step class
859
- in the batch lane).
860
- - **`--ssd-cache` has 0% decode overhead** — pure TTFT/restart win.
861
- - **Quantized-KV prefill pays a scheme-intrinsic tax at long context** —
862
- chunked prefill converts each chunk's KV at the boundary, so later
863
- chunks attend against the quantized prefix (the same streaming
864
- conversion optiq serve uses): ~30% prefill throughput vs bf16 at ~16k
865
- where the config quantizes every cache, single-digit % on the
866
- sliding-window gemmas. The lever is upstream (mlx `quantized_matmul`,
867
- [decode-speed-program.md](../design/decode-speed-program.md) lever 2).
868
-
869
- **Recipes:**
870
-
871
- - *Single-user agent/chat (the default use):*
872
- `mlx-bun serve <model> --ssd-cache <dir>` — L1, prompt cache + SSD tier.
873
- On 12B+ add `--draft-model <small-same-tokenizer>`.
874
- - *Several clients at once (throughput):*
875
- `mlx-bun serve <model> --batch 4 --ssd-cache <dir> --kv-budget <GB>` —
876
- supports the qualified grouped methods and cache layouts in the compatibility
877
- matrix. Use the default cap eight unless a workload calls for another cap.
878
- - *UI must never lag / survive engine crashes:* add `--isolate`
879
- (`--model-pool 2` to keep two models resident).
880
- - *Reproducibility:* bare / `--l1` (≡ mlx-lm), `--l1 --batch 1` (strict
881
- serial), `--l2` (≡ optiq).
882
- - *Memory-tight big model:* `--kv-quant config|4|8|turbo` +
883
- `--memory-budget <GB>` + `--ssd-cache <dir>`; MoE adds
884
- `--expert-offload`. Start-zero TurboQuant supports shared execution.
885
-
886
- **Remaining exclusions:** fill combined with media, speculation or paging, and unsupported provider/layout
887
- combinations. Qualified ordinary resume, paged storage and grouped draft
888
- providers are implemented; see the compatibility matrix above.
889
- Qwen ordinary, shared MTP and prompt lookup support positive library thresholds for uniform
890
- affine KV4/KV8 and TurboQuant. Ordinary Gemma supports positive affine KV4/KV8
891
- thresholds, including sliding-window layers. Other-model delayed affine remains
892
- open. Qwen MTP
893
- prefill and completed decode state use the common RAM/SSD cache. Generated
894
- checkpoints contain only processed tokens; persistence uses the existing
895
- queue. Chat preparation preserves generated token IDs when their decoded text
896
- exactly prefixes the next rendered request, including provenance recovered from
897
- SSD headers. This avoids a full prefill when re-encoding identical generated
898
- text would choose a different BPE segmentation. Edited text retains ordinary
899
- tokenization. Input token counts can differ from encoding the full prompt again;
900
- cache state is always matched by exact IDs and execution namespace.
901
- Strict serial deletion is deferred. Remaining feature and performance work
902
- is tracked in Phase 6/18.
903
-
904
- ## Observability — `GET /stats`
905
-
906
- The live config and batch state. The canonical field-by-field snippet
907
- lives in [server-api.md](server-api.md#get-stats); highlights:
908
- `prompt_cache` (cap), `kv_quant.mode` (incl. `turbo kXvY`), the
909
- conditional `ssd_cache` block (pending/dropped/failed spill counters), the
910
- conditional `glm52` block, and `batch`
911
- (`mode`/`active_rows`/`pending_rows`/`submitted_rows`/`kv_bytes`/
912
- `kv_budget_bytes`).
913
-
914
- `batch.mode` is the truthful configured/capability state: `off` for
915
- `--batch 1`, `serial` when a larger configured cap cannot batch the loaded
916
- model's cache layout, and `batch` when the model is admitted.
917
- `batch.batched` is the compatibility boolean for `mode == "batch"`;
918
- `active_rows` is the instantaneous live-row count. Under `--isolate`,
919
- `GET /engine` on the parent reports the child pid, restart count, socket,
920
- and pool residency.
921
-
922
- Managed quantization and finetuning jobs wait for the serving gateway to drain,
923
- then hold its execution lease until their subprocess exits. Generation and native
924
- preparation wait during that job. Shutdown cancels queued jobs and terminates the
925
- host's active job before releasing its lease. Resident model weights remain
926
- loaded. Under isolation, the parent coordinates all of its model-pool workers.
927
- This controls execution, not memory capacity or independently launched servers.
928
-
929
- ### Delayed KV conversion in library requests
930
-
931
- The CLI keeps `quantizedKvStart=0`. A library `KvScheme("turbo", ...)` can
932
- set a positive threshold for ordinary or Qwen MTP shared execution. Every row converts
933
- at its own existing maintenance boundary. During the mixed phase, the
934
- cache retains plain and encoded rows independently while model attention
935
- still runs at the shared batch size. The fetched attention state restores
936
- only the rotated value rows; once all rows convert, the standard packed
937
- batch layout takes over. Shared MTP converts committed history before a
938
- verification round; crossing the threshold inside that round converts at
939
- resolution after rollback and before checkpoint publication. Rejected tokens
940
- cannot set the conversion offset.
941
-
942
- Qwen ordinary, shared MTP and prompt lookup also support positive `quantizedKvStart` with
943
- uniform affine KV4/KV8. Affine and TQ adapters share the same row-transition
944
- lifecycle. During mixed affine precision, each row uses its existing plain or
945
- quantized attention arithmetic; after conversion, the packed batch layout owns
946
- attention. The model binding declares this support; scheduling does not choose
947
- the codec or conversion boundary. Ordinary Gemma also supports delayed affine
948
- conversion in full and sliding-window layers. Rotating rows retain the same
949
- physical columns while converting independently, so shared attention masks stay
950
- aligned. Gemma speculative methods and other-model delayed affine remain open.
951
-
952
- A delayed conversion records the earliest reusable prefix offset. RAM and
953
- SSD reuse preserve earlier plain donors and never trim converted state
954
- below that boundary. Older TQ SSD files without this metadata remain
955
- usable at their stored offset, but cannot serve shorter prefixes. The
956
- start-zero default-group cache keys are unchanged; positive TQ and affine
957
- thresholds, and non-default affine group sizes, have distinct keys.
958
- No memory budget or admission default changes.
959
-
960
-
961
- Supported grouped draft providers also accept TurboQuant with positive library
962
- conversion thresholds. Full-attention layers use the selected codec; sliding
963
- layers stay bf16. Generated target and method-companion snapshots preserve
964
- precision through RAM and queued SSD persistence. Defaults are unchanged.
965
- Composition evidence and remaining gaps: [batching design](../design/batching.md).
966
-
967
- The programmatic `createServer` option `quantizedKvStart` sets the absolute
968
- per-row offset at which the selected KV scheme converts. Omission preserves
969
- the existing start-zero server policy. This option is resolved once with the
970
- KV scheme and shared by request preparation, execution, and checkpoint identity.
971
- Generation checkpoints preserve encoded state and each cache's earliest reusable
972
- offset; restoring a checkpoint does not re-quantize it. TurboQuant retains its
973
- existing full-attention scope, with sliding-window caches in bf16.