mlx-bun 0.3.0 → 0.5.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 (231) hide show
  1. package/README.md +57 -32
  2. package/docs/README.md +58 -42
  3. package/docs/archive/investigations/benchmark-ledger-through-v0.4.0.md +3617 -0
  4. package/docs/archive/investigations/openjarvis-fit.md +198 -0
  5. package/docs/archive/investigations/qwen38-27b-campaign-log.md +1092 -0
  6. package/docs/archive/planning/release-notes-v0.4.0.md +45 -0
  7. package/docs/archive/planning/release-notes-v0.5.0.md +37 -0
  8. package/docs/design/batching.md +1535 -50
  9. package/docs/design/decode-speed-program.md +394 -1171
  10. package/docs/design/generic-model-support.md +195 -3
  11. package/docs/design/kv-cache.md +538 -225
  12. package/docs/design/speculative-decoding.md +552 -50
  13. package/docs/design/turboquant.md +140 -17
  14. package/docs/design/unified-engine-frontier-plan.md +259 -150
  15. package/docs/planning/PRODUCT_ROADMAP.md +21 -6
  16. package/docs/planning/public-readiness-handoff.md +244 -0
  17. package/docs/planning/public-readiness.md +149 -0
  18. package/docs/reference/benchmarks.md +3537 -1112
  19. package/docs/reference/cli.md +102 -2
  20. package/docs/reference/distribution.md +45 -13
  21. package/docs/reference/environment.md +159 -13
  22. package/docs/reference/library-api.md +18 -4
  23. package/docs/reference/memory.md +1 -1
  24. package/docs/reference/models.md +28 -7
  25. package/docs/reference/server-api.md +257 -33
  26. package/docs/reference/server-config.md +372 -151
  27. package/docs/reference/troubleshooting.md +13 -21
  28. package/package.json +2 -2
  29. package/src/audio/audiotoolbox.ts +112 -0
  30. package/src/audio/conformer.ts +8 -0
  31. package/src/audio/mic-capture.ts +98 -0
  32. package/src/audio/silero-vad.ts +379 -0
  33. package/src/audio/whisper-decode.ts +774 -0
  34. package/src/audio/whisper-fast.ts +732 -0
  35. package/src/audio/whisper-format.ts +73 -0
  36. package/src/audio/whisper-mel.ts +185 -0
  37. package/src/audio/whisper-timing.ts +274 -0
  38. package/src/audio/whisper-tokenizer.ts +239 -0
  39. package/src/audio/whisper-transcribe.ts +410 -0
  40. package/src/backends/mlx/assistant-target.ts +46 -0
  41. package/src/backends/mlx/autoregressive-draft-rows.ts +120 -0
  42. package/src/backends/mlx/autoregressive.ts +22 -1
  43. package/src/backends/mlx/batch-group.ts +464 -236
  44. package/src/backends/mlx/cache-attachment.ts +67 -0
  45. package/src/backends/mlx/cache-layout.ts +31 -0
  46. package/src/backends/mlx/checkpoint-state.ts +53 -0
  47. package/src/backends/mlx/continuation-persistence.ts +107 -0
  48. package/src/backends/mlx/continuation-request.ts +43 -0
  49. package/src/backends/mlx/continuation.ts +77 -0
  50. package/src/backends/mlx/draft-target.ts +7 -22
  51. package/src/backends/mlx/encoder-cache.ts +25 -0
  52. package/src/backends/mlx/fill-append.ts +21 -8
  53. package/src/backends/mlx/fill-group.ts +497 -0
  54. package/src/backends/mlx/full-kv-row-append.ts +32 -0
  55. package/src/backends/mlx/full-kv-row-donor.ts +54 -0
  56. package/src/backends/mlx/full-transitioning-kv-rows.ts +65 -0
  57. package/src/backends/mlx/gateway-binding.ts +122 -19
  58. package/src/backends/mlx/kv-codec.ts +9 -0
  59. package/src/backends/mlx/kv-maintenance.ts +161 -0
  60. package/src/backends/mlx/kv-tensor-rows.ts +212 -0
  61. package/src/backends/mlx/mixed-iteration.ts +62 -0
  62. package/src/backends/mlx/model-prompt.ts +46 -32
  63. package/src/backends/mlx/model-serving.ts +5 -4
  64. package/src/backends/mlx/paged-cache-codec.ts +27 -0
  65. package/src/backends/mlx/prefill-cohort.ts +100 -0
  66. package/src/backends/mlx/prefill-policy.ts +26 -0
  67. package/src/backends/mlx/prefill-rows.ts +244 -0
  68. package/src/backends/mlx/prefill.ts +1 -1
  69. package/src/backends/mlx/projected-context-rows.ts +72 -0
  70. package/src/backends/mlx/prompt-input.ts +29 -0
  71. package/src/backends/mlx/qwen-prompt-input.ts +40 -0
  72. package/src/backends/mlx/request-state-policy.ts +54 -0
  73. package/src/backends/mlx/rollback.ts +45 -4
  74. package/src/backends/mlx/row-sampling.ts +49 -0
  75. package/src/backends/mlx/serial-executor.ts +51 -73
  76. package/src/backends/mlx/speculative-group.ts +438 -0
  77. package/src/backends/mlx/speculative-round.ts +161 -0
  78. package/src/backends/mlx/speculative.ts +24 -7
  79. package/src/backends/mlx/state-rows.ts +104 -0
  80. package/src/backends/mlx/state-views.ts +21 -1
  81. package/src/backends/mlx/target-layout-capability.ts +35 -0
  82. package/src/backends/mlx/transitioning-kv-rows.ts +173 -0
  83. package/src/cli.ts +333 -36
  84. package/src/contracts/execution.ts +21 -0
  85. package/src/contracts/object-cache.ts +8 -0
  86. package/src/contracts/pi-provider.ts +1 -1
  87. package/src/contracts/pi.ts +3 -1
  88. package/src/contracts/prefix-cache.ts +33 -0
  89. package/src/contracts/resources.ts +7 -0
  90. package/src/contracts/sampling.ts +23 -0
  91. package/src/contracts/scheduling.ts +27 -0
  92. package/src/engine/execution-plan.ts +38 -25
  93. package/src/engine/execution-tasks.ts +44 -0
  94. package/src/engine/namespaced-cache.ts +13 -0
  95. package/src/engine/resources.ts +12 -1
  96. package/src/engine/scheduler.ts +32 -7
  97. package/src/fill/fill-session.ts +14 -3
  98. package/src/fit.ts +29 -15
  99. package/src/generate.ts +105 -195
  100. package/src/grammar.ts +13 -0
  101. package/src/inference/draft-acceptance.ts +41 -0
  102. package/src/inference/draft-output.ts +49 -0
  103. package/src/inference/prefill.ts +6 -0
  104. package/src/inference/rollback.ts +2 -2
  105. package/src/kv-scheme.ts +92 -12
  106. package/src/kv-store.ts +183 -93
  107. package/src/lab/README.md +5 -1
  108. package/src/lab/paged-kv/paged-attention.ts +117 -0
  109. package/src/lab/paged-kv/paged-kv-rows.ts +111 -0
  110. package/src/lab/paged-kv/paged-kv.ts +126 -46
  111. package/src/md-modules.d.ts +5 -0
  112. package/src/mlx/array.ts +39 -1
  113. package/src/mlx/ffi.ts +19 -0
  114. package/src/mlx/normalized-argmax.ts +116 -0
  115. package/src/mlx/ops.ts +97 -10
  116. package/src/model/artifact-identity.ts +73 -0
  117. package/src/model/batched-kv.ts +235 -0
  118. package/src/model/batched-mask.ts +12 -4
  119. package/src/model/batched-quant.ts +8 -2
  120. package/src/model/batched-quantized-kv.ts +144 -0
  121. package/src/model/batched-rotating-quant.ts +76 -15
  122. package/src/model/batched-rotating-state.ts +76 -0
  123. package/src/model/batched-rotating.ts +64 -22
  124. package/src/model/batched-row-storage.ts +52 -0
  125. package/src/model/batched-ssm.ts +52 -0
  126. package/src/model/batched-turboquant-kv.ts +94 -0
  127. package/src/model/compiled-decode.ts +7 -1
  128. package/src/model/decoded-kv-donor.ts +12 -0
  129. package/src/model/delayed-quantized-kv.ts +72 -0
  130. package/src/model/delayed-rotating-quantized-kv.ts +93 -0
  131. package/src/model/delayed-turboquant-kv.ts +57 -0
  132. package/src/model/factory.ts +26 -0
  133. package/src/model/fingerprint.ts +12 -0
  134. package/src/model/full-prefill-padding.ts +56 -0
  135. package/src/model/full-prefill-row.ts +105 -0
  136. package/src/model/gemma4-base.ts +183 -82
  137. package/src/model/gemma4.ts +116 -28
  138. package/src/model/generated/gemma4-12b.ts +4 -1
  139. package/src/model/generated/gemma4-26b.ts +4 -1
  140. package/src/model/generated/gemma4-e4b.ts +4 -1
  141. package/src/model/glm52-cache.ts +80 -4
  142. package/src/model/glm52-mla.ts +12 -6
  143. package/src/model/glm52.ts +19 -40
  144. package/src/model/kv-attention-view.ts +70 -0
  145. package/src/model/minicpm5.ts +11 -7
  146. package/src/model/profile.ts +29 -4
  147. package/src/model/quantized-append-attention.ts +31 -0
  148. package/src/model/qwen3-delta-state.ts +74 -0
  149. package/src/model/qwen3-delta.ts +59 -36
  150. package/src/model/qwen3-mrope.ts +7 -9
  151. package/src/model/qwen3_5.ts +177 -75
  152. package/src/model/rotating-kv-donor.ts +35 -0
  153. package/src/model/rotating-kv-layout.ts +262 -0
  154. package/src/model/rotating-row-transaction.ts +35 -0
  155. package/src/model/speculative-rotating-kv.ts +101 -0
  156. package/src/model/ssm-prefill-padding.ts +39 -0
  157. package/src/model/support.ts +8 -0
  158. package/src/model/token-groups.ts +66 -0
  159. package/src/model/trellis-linear.ts +4 -4
  160. package/src/model/turboquant-codec.ts +89 -0
  161. package/src/model/universal/dense.ts +14 -13
  162. package/src/model/whisper.ts +435 -0
  163. package/src/native/mic_capture.swift +92 -0
  164. package/src/native-pack.ts +6 -5
  165. package/src/pi-web.ts +9 -1
  166. package/src/preflight.ts +31 -15
  167. package/src/prompt-cache.ts +306 -86
  168. package/src/runtime-config.ts +1 -5
  169. package/src/safetensors.ts +9 -2
  170. package/src/sampler.ts +37 -25
  171. package/src/serve/audio-routes.ts +323 -0
  172. package/src/serve/chat-request.ts +2 -0
  173. package/src/serve/chat-stage.ts +19 -14
  174. package/src/serve/completion-executor.ts +9 -1
  175. package/src/serve/discovery-routes.ts +17 -1
  176. package/src/serve/generated-token-history.ts +57 -0
  177. package/src/serve/generation-gateway.ts +88 -38
  178. package/src/serve/model-binding.ts +7 -1
  179. package/src/serve/model-host.ts +3 -4
  180. package/src/serve/preparation.ts +3 -3
  181. package/src/serve/prompt-response-trace.ts +14 -0
  182. package/src/serve/request-plan.ts +6 -3
  183. package/src/serve/request-prep.ts +40 -25
  184. package/src/serve/text-completion-stage.ts +2 -2
  185. package/src/serve/transcription-server.ts +64 -0
  186. package/src/serve/transcription-service.ts +502 -0
  187. package/src/server.ts +185 -261
  188. package/src/spec/assistant-rows.ts +93 -0
  189. package/src/spec/assistant-source.ts +28 -18
  190. package/src/spec/cache-identity.ts +22 -0
  191. package/src/spec/deepspec-rows.ts +29 -0
  192. package/src/spec/deepspec-source.ts +12 -10
  193. package/src/spec/dflash-source.ts +28 -4
  194. package/src/spec/drafter.ts +153 -142
  195. package/src/spec/dspark/deepspec-module.ts +95 -120
  196. package/src/spec/dspark/module-dflash.ts +126 -170
  197. package/src/spec/glm52-mtp-graph.ts +29 -0
  198. package/src/spec/glm52-mtp-rows.ts +132 -0
  199. package/src/spec/glm52-mtp-source.ts +54 -136
  200. package/src/spec/glm52-mtp-state.ts +33 -0
  201. package/src/spec/ngram-source.ts +115 -21
  202. package/src/spec/projected-draft-rows.ts +73 -0
  203. package/src/spec/qwen-mtp-module.ts +171 -0
  204. package/src/spec/qwen-mtp-rows.ts +230 -0
  205. package/src/spec/qwen-mtp-source.ts +84 -226
  206. package/src/spec/qwen-mtp-state.ts +30 -0
  207. package/src/spec/serve-loop.ts +73 -69
  208. package/src/spec/source.ts +93 -15
  209. package/src/spec/two-model-rows.ts +62 -0
  210. package/src/spec/two-model.ts +45 -103
  211. package/src/ssd-cache.ts +107 -36
  212. package/src/ssd-durability.ts +29 -27
  213. package/src/storage/host-buffer.ts +24 -0
  214. package/src/storage/kv-writer.ts +83 -0
  215. package/src/storage/kv-writer.worker.js +264 -0
  216. package/src/storage/retention-policy.ts +37 -0
  217. package/src/tiered-prompt-cache.ts +45 -0
  218. package/src/vision/embedder.ts +8 -0
  219. package/src/vision/prompt.ts +101 -65
  220. package/src/vision/qwen3vl-prompt.ts +101 -64
  221. package/src/vision/qwen3vl-tower.ts +11 -0
  222. package/src/vision/siglip.ts +8 -0
  223. package/src/web/app.html +12 -0
  224. package/src/web/app.js +217 -57
  225. package/src/web/src/chat.ts +4 -1
  226. package/src/web/src/composer.ts +3 -0
  227. package/src/web/src/voice.ts +141 -0
  228. package/src/web/sw.js +1 -1
  229. package/src/backends/mlx/memory-guard.ts +0 -40
  230. package/src/spec/prefix-state.ts +0 -45
  231. /package/docs/{planning → archive/planning}/release-notes-v0.3.0.md +0 -0
@@ -215,6 +215,17 @@ fusedSdpaRuntimeOk(q, mask)` in `src/model/generated/gemma4-*.ts`) that are
215
215
  per-generation-decidable and should be hoisted out of the token path; compiled
216
216
  decode already achieves the debranched line dynamically (trace once, replay).
217
217
 
218
+ The shared greedy operation uses native logsumexp followed by tiled normalized
219
+ score/index reductions in `src/mlx/normalized-argmax.ts`. It preserves rounding
220
+ and lowest-ID ties without materializing the normalized vocabulary array.
221
+ The step sampler applies processors and grammar first, and selects this operation
222
+ only for built-in greedy requests that do not require metadata. Independent
223
+ verification calls the same operation. Fixed-shape compilation caches each
224
+ geometry; enclosing shapeless graphs retain native operations. No scheduler,
225
+ model-family branch or separate sampling setting selects this optimization.
226
+ Actual-model and operation comparisons, plus both-machine serving measurements,
227
+ are recorded in benchmarks.md under fused normalized greedy selection.
228
+
218
229
  ### Layer 0 — the SSD spill substrate
219
230
 
220
231
  It is almost always faster to cache to SSD and mmap it back than to
@@ -414,12 +425,12 @@ satisfy, with the state of `GenerationGateway.#supportsContinuous` as read on
414
425
  | layer | today (src) | end state |
415
426
  |---|---|---|
416
427
  | dedicated per-model graph | both mechanisms (profile-routed) | unchanged |
417
- | mixed-precision KV (`affine-config`) | continuous when every configured layer is a plain or rotating KVCache the scheme can convert (`KvScheme.batchable` + the gateway's cache probe); uniform `kvBits`, SSM-layer configs, and TurboQuant route serial | one active scheme per server, any B |
418
- | LoRA adapters | serial only (`shape.hasAdapters`) | per-slot adapter state (vLLM Punica/SGMV pattern: every row runs the adapter math, non-adapter rows at scale 0) |
419
- | speculative decoding (two-model · assistant · dspark · deepspec · native MTP · ngram) | serial only; a mounted draft routes every request serial (`shape.hasDraft`, mlx_lm.server's `is_batchable = draft is None`); GLM-5.2 MTP is on by default and pins the serial verify lane (`--mtp off` restores batching) | per-slot drafting behind the `DraftSource` seam |
428
+ | mixed-precision KV (`affine-config`) | supported per-layer and uniform affine KV use continuous groups; incompatible layouts remain open | one active scheme per server, any B |
429
+ | LoRA adapters | compatible ordered adapter sets share a group; context and cache identity bind under the execution lease | per-slot adapter state (vLLM Punica/SGMV pattern: every row runs the adapter math, non-adapter rows at scale 0) |
430
+ | speculative decoding (two-model · assistant · dspark · deepspec · native MTP · ngram) | actual speculation uses the serial verifier; supported ordinary requests can batch with a mounted draft | per-slot drafting behind the `DraftSource` seam |
420
431
  | structured output (grammar) | both (per-row matchers; `MLX_BUN_GRAMMAR_BATCH=0` forces serial) | unchanged; keep the conformance gate |
421
- | sampling (temp/top-p/top-k/min-p/XTC/penalties/HLG/seed) | per-row `StepSampler` batches, including repetition penalty and logits extras; a user-fixed `seed` forces serial (mlx-lm's `_is_batchable`) | fully per-row, seeds included |
422
- | logprobs capture | serial only (`shape.wantsLogprobs`) | per-row readback in the scheduler |
432
+ | sampling (temp/top-p/top-k/min-p/XTC/penalties/HLG/seed) | per-row sampling sessions, including explicit seeds, repetition penalty and logits extras | fully per-row, seeds included |
433
+ | logprobs capture | shared row sampling and readback in continuous groups | preserve method composition |
423
434
  | vision / audio media prompts | serial only (`shape.hasVision`; embeddings-prefill bypasses the prompt cache) | batched media prefill |
424
435
  | prompt cache / SSD tier | both: scheduler joiners `take()` the longest usable prefix at admission, never-merged rows `put()` back on finish; the cold tier restores inside `take()` | block-granular sharing across rows |
425
436
  | paged KV (`--paged-kv`) | serial only, Gemma4 bf16, refuses `--batch N>1`, `--kv-quant`, `--draft-model`; bypasses the prompt cache | block-level CoW prefix sharing (vLLM oracle) |
@@ -472,132 +483,13 @@ entries so a caller cannot mutate conversion or accounting after resolution.
472
483
  `BatchScheduler.#prefillChunk` in `src/serve/batch-scheduler.ts` (the same
473
484
  conventions re-implemented over `PrefillState` for interleaved admission).
474
485
  Both are gated bit-exact, but a convention change must land in two places.
475
- 2. **Spec eligibility is decided after placement.** `planRequest` only knows
476
- `hasDraft = !!ctx.draft` (server-level), which routes every request serial
477
- while a draft is mounted. The real per-request eligibility — text-only, no
478
- adapters, no logprobs capture, bf16 KV (no `kvBits`/`kvConfig`/`turboQuant`),
479
- not paged — is evaluated inside `runGeneration` after `place()`; ineligible
480
- requests silently fall through to plain serial decode, and the lane label is
481
- corrected from `serial+spec` to `serial` only when `stats.spec` is absent
482
- (`finalLane` in the executor). Resolving this means lifting the eligibility
483
- predicate into `RequestShape` so placement and the lane label are decided
484
- once.
485
-
486
- Other seams worth knowing: `runGeneration` also decides the prompt-cache
487
- bypass (media, paged) and the adapter cache namespace; `--isolate` wraps the
488
- ENTIRE server as an engine child behind a proxy (`src/serve/isolate.ts`,
489
- `ModelPool` for `--model-pool` LRU residency and model switching by the
490
- request's `model` field) — the inter-process API is the /v1 surface itself, no
491
- second protocol.
492
-
493
- ## 7. The flag surface (src truth, grouped by layer)
494
-
495
- Read from `SERVER_FLAGS` and `applyDecodeRoute` in `src/cli.ts`. Every
496
- `MLX_BUN_*` value is read through the immutable runtime snapshot
497
- (`src/runtime-config.ts` `runtimeValue/runtimeFlag`, `src/flags.ts` `flagOn`);
498
- feature code never reads `process.env`, and the CLI installs tier/fork
499
- overrides with `configureRuntime()` before model modules load.
500
-
501
- **Parity tier (aliases):** `--l1` (default) · `--l2`. `--l3` hard-errors with a
502
- pointer to this doc.
503
-
504
- **L2 — quantization:** `--kv-quant config|off|4|8|turbo[:k<bits>v<bits>]`
505
- (default off). An older draft of this doc listed only `config|4|8|off`; the
506
- `turbo` axis is real and mutually exclusive with the affine modes.
507
-
508
- **L3 — scheduler / decode policy:** `--batch <n>` (default 8;
509
- `--decode-concurrency` alias) · `--kv-budget <GB>` · `--draft-model <query>` ·
510
- `--draft-kind two-model|assistant|dspark|deepspec|mtp|ngram` ·
511
- `--num-draft-tokens` · `--ngram-max` / `--ngram-min` · `--mtp on|off`
512
- (GLM-5.2 native MTP, on by default) · `--context-length` (GLM-5.2 reservation)
513
- · `--paged-kv` / `--paged-kv-block-size` (env `MLX_BUN_PAGED_KV=1`).
514
-
515
- **L4 — serving surface:** `--model` · `--host` · `--port` · `--memory-budget`
516
- · `--prompt-cache <GB>` · `--ssd-cache <dir>` · `--ssd-cache-max` ·
517
- `--ssd-demote-idle` · `--ssd-cache-verify` · `--isolate` · `--model-pool` ·
518
- `--unix` (internal) · `--no-open` · `--allow-private-media` · `--adapter`
519
- (`--adapter-path` alias) · `--thinking` · `--temperature`/`--temp` · `--top-p`
520
- · `--top-k` · `--max-tokens` · the HLG sampler family (`--hlg-sampling`,
521
- `--hlg-width`, `--hlg-shoulder`, `--hlg-toe`, `--hlg-pivot-offset`).
522
-
523
- **Kill switches (bit-exact A/B levers, each selects a slower same-parity
524
- path):** `--compiled-decode on|off` (`MLX_BUN_COMPILED_DECODE`) ·
525
- `--compiled-activations on|off` (`MLX_BUN_COMPILED_GEGLU` +
526
- `MLX_BUN_COMPILED_SWIGLU`; only gemma geglu and MiniCPM5 swiglu have an
527
- uncompiled form — qwen3/qwen3.5/universal compile unconditionally) ·
528
- `--fused-sdpa on|off` (`MLX_BUN_NO_FUSED_SDPA`, inverted; default follows
529
- `--kv-quant`) · `--force-wire` (`MLX_BUN_FORCE_WIRE`) · `--expert-offload`
530
- (`MLX_BUN_EXPERT_OFFLOAD`). An older draft said these were env-only; the three
531
- decode kill switches are CLI flags as well.
532
-
533
- **Lab / diagnostic env flags (no CLI flag; live with a bench and an expiry):**
534
- `MLX_BUN_GRAMMAR_JUMP=1` (jump-forward decoding, serial non-spec loop),
535
- `MLX_BUN_GRAMMAR_BATCH=0` (grammar back to serial), `MLX_BUN_BATCH_SSM=0`
536
- (SSM caches back to serial), `MLX_BUN_BATCH_NO_PIPELINE`,
537
- `MLX_BUN_BATCH_STEP_TRACE`, `MLX_BUN_BATCH_VEC_SAMPLE`, `MLX_BUN_BATCH_EXTEND`,
538
- `MLX_BUN_PREFILL_TAIL_SPLIT`, `MLX_BUN_FLASH_MIN_M`, the `MLX_BUN_CCE_*`
539
- training-kernel switches, and the memory/trace loggers. Anything
540
- output-changing is Lab by definition.
541
-
542
- **Deleted (2026-07-05, §11):** `--fused-decode`, `--fused-gelu`,
543
- `--perf-kernel`, `--l3`, and their env twins. None exist in `src/`.
544
-
545
- ## 8. Design invariants proven en route (durable, not changelog)
546
-
547
- - **Readbacks in a pipelined loop must not create ops.** `toFloat32()` on the
548
- int token array enqueued a cast BEHIND the next dispatched step, stalling the
549
- "overlapped" read a full GPU step per token. Use `MlxArray.toIntTokens()`.
550
- - **A lone row keeps bare serial-class caches.** `KVCache.makeMask(1)` is the
551
- empty mask and scalar rope; the batched step then dispatches the same graph
552
- the serial loop builds. The per-layer `BatchedDecodeMaskCache` wrapper is
553
- only for padded batches.
554
- - **Rope-array step-stability contract.** A batched cache's `ropeOffsetArr`
555
- must be stable within a decode step and refresh only at `releaseRopeArr()`;
556
- re-reading it mid-update ropes K and Q one position apart.
557
- - **Generated-file guards accept batched subclasses.** The generated forwards'
558
- per-layer `instanceof` guards pass any batched cache that subclasses a
559
- serial class, so an all-quant gemma batch decodes through the generated
560
- fast path — a feature (B=1 proved bit-exact) but a contract: batched caches
561
- must behave serially under re-reads. Test with FULL configs; one bf16 layer
562
- anywhere fails the guard and drops to the monolith.
563
- - **Quantization packs along HEAD_DIM**, so token-axis batch surgery over
564
- (packed, scales, biases) triples is byte-safe; solo rows convert at serial
565
- chunk boundaries (bit-exact by construction).
566
- - **A scheme-less path must refuse, never silently drop quantization.** The
567
- gateway only threads a `KvScheme` to the scheduler when it is batchable; the
568
- scheduler refuses an unsupported scheme at construction.
569
- - **Prefix sharing is non-consuming.** `PromptCache.take()` serves zero-copy
570
- clones (ref-counted retain so a demoted donor never unmaps pages a clone
571
- reads); the donor stays put; `put()` supersedes same-namespace prefix
572
- ancestors when the new entry is trimmable. Kills the cannibalization flaw
573
- (agent B consuming agent A's entry). v1 shares COMPUTE and durability;
574
- concurrent rows still hold separate physical KV — one shared physical prefix
575
- across rows is the block-KV frontier item, and whole-entry duplication in
576
- the disk tier is the block-granularity revisit trigger.
577
- - **Prompt-boundary snapshot.** The prompt+generation entry is untrimmable
578
- past a wrapped ring or under quantized KV, so every substantial request also
579
- snapshots a strict prompt prefix (cap `len-1`), the mlx-lm
580
- `insert_segments` invariant; a re-rendered next turn always matches.
581
- - **Never a JS callback as an mlx buffer destructor** — last-ref `Data` dtors
582
- run on the Metal completion thread (native `dlsym(free)` dtor, process-pinned
583
- mmaps).
584
- - **Isolation proxies the whole server**, not the gateway: grammar WASM,
585
- vision arrays, and sampler closures don't serialize; the /v1 surface is the
586
- IPC.
587
-
588
- ## 9. The frontier program (order matters)
589
-
590
- Ranked by expected frontier shift (memory ↓ / intelligence ↑ first, then
591
- speed). Each item is a Lab program with its own doc; `decode-speed-program.md`
592
- ranks the speed levers and is the only doc that does.
593
-
594
- 1. **Mixed-precision weights** — knapsack `--target-bpw` (ours; OptiQ-style
595
- sensitivity port in `src/quantize/sensitivity.ts`) and rotation-folded
596
- quantization (`docs/design/turboquant.md`, `--rotate-weights`). Gate:
597
- perplexity + frozen 6-task eval at equal bpw.
598
- 2. **TurboQuant KV** (`docs/design/turboquant.md`, landed v1) — orthogonal to
599
- allocation: mixed precision is the ALLOCATION axis, TurboQuant the
600
- QUANTIZER axis; they compose. Solo-only in v1.
486
+ 2. **Method selection now precedes placement.** `resolveExecution` selects
487
+ speculative or ordinary decoding from the actual request and backend
488
+ capabilities. Configuring a draft no longer forces supported ordinary work
489
+ into the serial executor. The final design has one shared executor; changing
490
+ method must not select a retired execution path. Concurrent speculation is
491
+ still an implementation gap, tracked in batching.md.
492
+
601
493
  3. **Speculative decoding depth** — DFlash/DSpark, native MTP, behind the
602
494
  `DraftSource` seam (`docs/design/speculative-decoding.md`).
603
495
  4. **Per-model graph work from the baseline** — unroll a model's flat DAG,
@@ -767,14 +659,12 @@ implementations throughout migration. New numerical work has separate paired
767
659
  validation, so structural changes cannot conceal a quality or performance
768
660
  tradeoff. §12.11 defines the shared frontier scorecard.
769
661
 
770
- Future design question (2026-09-05): consider a monorepo with the inference
771
- engine kept together as one package, and application modules such as memory
772
- and the web UI in separate packages. CLI/TUI and training boundaries can be
773
- considered in that discussion. This is an unplanned idea, not part of the
774
- current optimization campaign. Before choosing boundaries, map dependencies,
775
- native assets, builds, tests, and releases; preserve in-process execution and
776
- the single-binary distribution. Package boundaries should follow demonstrated
777
- ownership and dependency needs without adding abstractions to the decode path.
662
+ Package organization is now a planned decision in the
663
+ [public-readiness program](../../PLAN.md#public-readiness), separate from
664
+ the optimization campaign. §12.15 records the initial boundary audit and
665
+ remaining evidence needed before choosing a workspace layout. Preserve
666
+ in-process execution and the single-binary distribution; package boundaries
667
+ must follow ownership and dependency needs without adding decode overhead.
778
668
 
779
669
  ### 12.2 Dependency structure
780
670
 
@@ -833,8 +723,11 @@ Small stateless ports may be implemented by functions or object literals.
833
723
  | Interface | Owns | Must not own |
834
724
  |---|---|---|
835
725
  | `CompletionClient` | Semantic completion request, event stream, terminal result, cancellation | Tensor/state handles, model class selection |
836
- | `PromptPreparer` | Template/tokenizer policy, token IDs, validated media descriptors, stable-prefix boundary | GPU scheduling or request-global model mutation |
837
- | `ExecutionPlanner` | Effective immutable policy, implementation selection, capability negotiation, fallback reasons, plan identity | Starting generation or inventing new feature support |
726
+ | `PromptPreparer` | Coordinate renderer, tokenizer and media preparation; produce token IDs and a stable-prefix boundary | Template syntax, tokenizer algorithms, GPU scheduling or request-global model mutation |
727
+ | `RequestPolicyResolver` | Resolve defaults and explicit overrides once into immutable policy | Executing model work or resampling defaults inside a token loop |
728
+ | `ChatTemplateRenderer` | Render messages, tools and reasoning markers; identify stable rendered boundaries | Tokenizer algorithms, scheduling or cache retention |
729
+ | `Tokenizer` | Encode/decode, token metadata and incremental encoding | Chat-template policy, sampling or scheduling |
730
+ | `ExecutionPlanner` | Effective immutable policy, implementation selection, capability negotiation, declared implementation choices, plan identity | Starting generation or inventing new feature support |
838
731
  | `InferenceEngine` | Session creation, runtime coordination, shutdown | Per-family forward math |
839
732
  | `GenerationSession` | Lifecycle, committed output, result, cancellation and close | Token-at-a-time assumption, KV offsets, concrete method branches |
840
733
  | `InferenceMethod` | AR/speculative/diffusion algorithm and private per-run state | HTTP framing or application sessions |
@@ -1010,14 +903,20 @@ inside forward/decode after binding. Experiment commands construct separate
1010
903
  bindings with explicit snapshots. Diagnostics may observe a running request
1011
904
  but cannot change its numeric policy halfway through execution.
1012
905
 
1013
- Admission is two-stage: validate metadata and reserve a conservative preparation
1014
- budget before compiling grammar or running media towers; then refine the
1015
- reservation using prepared sizes before execution. Count shared resident
1016
- weights once, per-run state, draft resources, media/preparation transients,
1017
- compiled state, pending output, and retained snapshot/write-behind buffers.
1018
- Reservation ownership transfers across stages and releases on every failure.
1019
- Keep prompt/context clamping semantics and aggregate KV limits consistent with
1020
- current policy. A rejected prompt must not first allocate its full GPU payload.
906
+ Configuration follows ownership: scheduling owns concurrency and queue policy;
907
+ methods own sampling, speculation and stopping; backends own kernels and state
908
+ layouts; storage owns cache budgets, tiers and persistence. The application
909
+ composition root binds these interfaces. A single-request caller supplies the
910
+ same method configuration as a batched caller. Consolidate duplicate controls
911
+ as implementations migrate, retaining documented CLI aliases where needed.
912
+
913
+ Default memory estimates are advisory by Josh's instruction. Attempt the
914
+ requested work without predicted-memory refusals or automatic token clamping.
915
+ Explicit user limits and actual layout requirements still apply. Account for
916
+ shared weights once, live state, draft resources, preparation transients and
917
+ retained/write-behind buffers. Release actual resources on failure; a
918
+ conservative estimate does not establish that execution is impossible. This
919
+ supersedes the earlier mandatory reservation-before-preparation design.
1021
920
 
1022
921
  ### 12.6 State, ownership, and persistence
1023
922
 
@@ -1074,11 +973,35 @@ and define read-old/write-new compatibility or explicit invalidation per change.
1074
973
  ### 12.7 Scheduling and inference methods
1075
974
 
1076
975
  Keep policy independent from mechanics. Scheduler chooses eligible work,
1077
- fairness, queue bounds, active-row limits, and resource reservations. A method's
976
+ fairness, queue bounds and active-row limits. A method's
1078
977
  scheduling adapter creates execution groups and implements join/leave/advance
1079
978
  over its own state. Native batch merge and filter stay inside the MLX adapter.
1080
979
  Scheduler must not import KV classes or perform a per-layer tensor loop.
1081
980
 
981
+ The consolidation target is single-request execution as a batch of one through
982
+ these same contracts. Methods publish reusable checkpoints through the shared
983
+ cache interface at completed boundaries. The cache owns prefix selection,
984
+ retention and RAM/SSD placement; scheduling does not choose a storage tier, and
985
+ decode does not inspect the request queue. Model/method codecs describe the
986
+ state needed to restore a prefix, including draft state when applicable.
987
+ Prefill and generated tokens populate the same cache. R17 in the decode-speed
988
+ program owns the current implementation and acceptance work.
989
+
990
+ Full batch feature parity is required, including speculation. The current
991
+ serial exclusions are migration work, not the target architecture. Keep an
992
+ explicit feature matrix in the batching design and retire duplicate request
993
+ lifecycles only after the batched implementation covers every serial feature
994
+ and equals or beats serial performance in matched measurements. B=1 latency
995
+ and feature-specific costs must pass independently of aggregate throughput.
996
+ The optimized kernels already built remain behind the backend interface;
997
+ scheduling policy does not choose or reimplement their arithmetic. Continue
998
+ building faster specializations, fusing operations, removing work and avoiding
999
+ materialization. Interfaces must permit complete fused work units rather than
1000
+ force one call or intermediate tensor per logical operation. Measure kernel
1001
+ changes separately from composition refactors so their effects are attributable. Interface
1002
+ extraction must not force tensor copies, materialization, synchronization or
1003
+ additional dispatches; compare B=1 latency and B>1 throughput at fixed settings.
1004
+
1082
1005
  An advancement is a bounded safe unit, not necessarily a token: one prefill
1083
1006
  chunk, a pipelined decode step, one verify round, or one denoising iteration.
1084
1007
  Budgets describe admitted resources and work hints separately. A synchronous
@@ -1876,3 +1799,189 @@ existing placement and numerical defaults. Their independent experiment programs
1876
1799
  still own promotion/deletion decisions. Quiet performance, exact target quants,
1877
1800
  unavailable oracle/drafter fixtures and the second machine remain acceptance
1878
1801
  work, not missing interface code. No frontier advance is claimed by this refactor.
1802
+
1803
+ ### 12.14 Request flow and interface ownership
1804
+
1805
+ This is the target responsibility map for Phase 6/18. A request carries one
1806
+ resolved policy: measured defaults plus explicit user overrides. Each component
1807
+ consumes its own part of that policy. The table below distinguishes existing
1808
+ contracts from implementation and migration work still in progress.
1809
+
1810
+ ```mermaid
1811
+ flowchart TB
1812
+ client["Client: chat, Pi, API or library"]
1813
+ server["Server adapter<br/>receive requests and send responses"]
1814
+ policy["Request policy interface<br/>resolve defaults and user overrides once"]
1815
+ template["Chat template interface<br/>messages and tools → rendered prompt"]
1816
+ tokenizer["Tokenizer interface<br/>rendered prompt → token IDs"]
1817
+ session["InferenceEngine / GenerationSession<br/>own request lifecycle and cancellation"]
1818
+ scheduler["Scheduler / ExecutionGroup<br/>choose when ready work runs"]
1819
+ method["InferenceMethod<br/>ordinary decode or MTP proposal / verification"]
1820
+ graph["Model graph interface<br/>prefill, forward passes and specialized kernels"]
1821
+ sampler["SamplingSession<br/>apply settings and grammar; select tokens"]
1822
+ output["Response interface<br/>decode committed tokens; emit text and tool events"]
1823
+ state["Active state interface<br/>target KV, recurrent state, draft state and positions"]
1824
+ cache["PrefixCache interface<br/>restore and retain aligned token / state checkpoints"]
1825
+ ram["RAM cache<br/>retain reusable checkpoints"]
1826
+ persistence["Persistence interface<br/>queue background writes and restore from SSD"]
1827
+
1828
+ client --> server --> policy --> template --> tokenizer --> session
1829
+ session -->|ready work| scheduler
1830
+ scheduler -->|admit and advance a batch of 1 or more| method
1831
+ method -->|inputs and state| graph
1832
+ graph -->|device logits| sampler
1833
+ sampler -->|selected tokens or proposals| method
1834
+ method -->|committed tokens only| output
1835
+ output -->|response events| server
1836
+ method <-->|borrow, update, snapshot, rollback| state
1837
+ session <-->|restore / publish prefill checkpoint| cache
1838
+ method -->|publish generated checkpoint| cache
1839
+ cache <-->|fast reuse| ram
1840
+ ram <-->|spill and restore when needed| persistence
1841
+ ```
1842
+
1843
+ The scheduler chooses **when** work runs and which requests are active. The
1844
+ inference method chooses **what numerical work** advances them. A batch of one
1845
+ uses the same method and state contracts as a larger batch. The final design
1846
+ has one shared executor and no separate serial executor to fall back to.
1847
+
1848
+ The model graph returns logits to the sampler. The sampler applies temperature,
1849
+ penalties, grammar, sampling filters and RNG policy, and returns selected tokens
1850
+ with requested logprobs. MTP keeps proposals private until verification commits
1851
+ them. The response formatter sees committed tokens only.
1852
+
1853
+ Live KV is working state for the current computation. A reusable checkpoint
1854
+ contains token IDs plus the corresponding target, recurrent and optional draft
1855
+ state. Both prefill and generated output must feed the same cache interface.
1856
+ Only an exact, rendered-stable token boundary can be published for state that
1857
+ cannot be trimmed. RAM retention, eviction, asynchronous SSD writes and restart
1858
+ restore belong behind that interface. Scheduling does not wait for an ordinary
1859
+ SSD spill; an explicit durability flush can wait for persistence.
1860
+
1861
+ | Piece | Current code or contract | Remaining work |
1862
+ |---|---|---|
1863
+ | Server / response adapters | `CompletionEngine`, `CompletionSink`, `GenerationOutput` | Preserve the same semantics through the final shared-executor cutover. |
1864
+ | Request policy | `RequestPlan`, request preparation and execution planning | Consolidate configuration into one resolved policy; choose measured defaults for typical multi-turn use and retain user overrides. |
1865
+ | Chat template | `ChatTemplate.render` | Expose the renderer as its own narrow port instead of requiring a concrete serving context. Record rendered-stable boundaries for generated checkpoint alignment. |
1866
+ | Tokenizer | `LoadedTokenizer` | Reuse the same encode/decode contract across preparation, caching and output. Keep incremental encoding inside this component. |
1867
+ | Session / scheduling | `InferenceEngine`, `GenerationSession`, `ExecutionGroup`, `SchedulingClock` | Close all feature and performance gaps before deleting the remaining serial executor. |
1868
+ | Inference method | `InferenceMethod`; shared ordinary and speculative methods | Complete every shared-method composition and acceptance gate. Draft depth belongs here, independently of queue policy. |
1869
+ | Numerical graph / kernels | `AutoregressiveGraph`, `GraphFactory`, backend bindings | Continue hardware-specific fusion and kernel optimization behind these contracts. |
1870
+ | Sampler | `SamplingSession` | Retain one set of sampling/history/logprob semantics for ordinary and speculative execution. |
1871
+ | Active state / codec | `Cache`, `KvAttentionState` / `KvAttentionView`, row layouts, `SpeculativeTransaction`, checkpoint attachments | Appending and attending are separate operations. One captured view can serve multiple model layers while retaining pre-write positions and tensor ownership. Delayed affine/TurboQuant and rotating layouts are integrated; qualify additional model/layout combinations separately. |
1872
+ | Reusable cache | `PrefixCache.take/put`, shared `PromptCache` | Prefill and processed generated output populate the same immutable RAM/SSD cache. Session lookup and rendered-token alignment are integrated. |
1873
+ | Persistence | `ColdTier`, `SpillSink`, `SsdCacheStore`, `SsdDurabilityCoordinator` | Queued persistence, native/restart checks and full Kanban durability acceptance are complete. RAM/SSD retention remains behind cache operations. |
1874
+
1875
+ An interface boundary does not require copying tensors, downloading logits,
1876
+ or adding an RPC or synchronization per token. Device handles can stay lazy;
1877
+ the backend may fuse compatible graph and sampling operations while preserving
1878
+ policy, ownership and observable results. Each component can improve its own
1879
+ implementation without adding model, cache or sampling decisions to scheduling.
1880
+
1881
+ Contract sources: [generation](../../src/contracts/generation.ts),
1882
+ [scheduling](../../src/contracts/scheduling.ts),
1883
+ [sampling](../../src/contracts/sampling.ts),
1884
+ [prefix cache](../../src/contracts/prefix-cache.ts),
1885
+ [graph](../../src/inference/graph.ts),
1886
+ [tokenizer](../../src/tokenizer.ts),
1887
+ [cache tiers](../../src/prompt-cache.ts).
1888
+ Performance evidence and default selection live in
1889
+ [benchmarks.md](../reference/benchmarks.md); open acceptance remains in Phase 6/18.
1890
+
1891
+ #### Kernel configuration ownership
1892
+
1893
+ Shared and serial bindings execute within one immutable `RuntimeConfig`.
1894
+ Numerical helpers read that scope; they do not read process environment in
1895
+ forward loops. The serial speculative trace switch is captured once per run.
1896
+ Trellis mode resolves through the same configuration port at weight creation.
1897
+
1898
+ TurboQuant caches capture their codec's fused-decode choice at construction.
1899
+ RAM clones, full-prefill row restoration, batch layout factories, extraction
1900
+ and delayed conversion preserve that choice. KV maintenance binds its runtime
1901
+ before conversion, including conversion performed after a host setting changes.
1902
+ SSD formats contain numerical state, not a frozen process configuration; their
1903
+ receiving cache factory selects the destination binding's policy.
1904
+
1905
+ The configuration tests change host settings around scoped construction,
1906
+ copy/extraction and delayed conversion. Existing codec/donor tests now select
1907
+ both fused settings through `configureRuntime`, so they exercise the same
1908
+ configuration contract as serving. Paged request policies also bind the numerical
1909
+ namespace and construction policy before deferred lookup or allocation, including
1910
+ when a gateway outlives later host configuration changes. The serving reference
1911
+ maps flags to their owning interfaces and records supported combinations. The
1912
+ legacy internal `flagOn` wrapper is removed; CLI controls remain compatible.
1913
+ The new paged-policy tests first reproduce both deferred-setting failures, then
1914
+ pass with the captured policy. Paged operation/layout checks pass on both Macs;
1915
+ the full local model-free suite and all typechecks pass.
1916
+
1917
+ ### 12.15 Package boundaries before community outreach
1918
+
1919
+ Initial audit, 2026-09-11. The public-readiness program owns the packaging
1920
+ work; the existing interface and optimization milestones retain their scope.
1921
+ The three published entry points need different treatment:
1922
+
1923
+ | Entry or layer | Verified dependency boundary | Packaging consequence |
1924
+ |---|---|---|
1925
+ | `mlx-bun/client`, `src/client.ts` | Imports only completion/host contracts; uses standard Request, Response, fetch and cancellation APIs | A candidate for independent client installation. The current npm package still has Darwin/arm64 metadata and application dependencies; a portable source file alone does not change that install contract. |
1926
+ | `src/contracts/`, `src/engine/`, `src/inference/` | Separate TypeScript project excludes Bun and DOM types; the AST boundary test limits imports by layer | Keep these interfaces and policies together inside the engine. They do not each need a published package. |
1927
+ | `mlx-bun/engine`, `src/library.ts` | CPU-safe entry exports engine/client APIs, but `initializeMlx()` dynamically imports the broad root API; `openIsolatedHost()` imports serving isolation and locates the CLI | Preserve this compatibility entry. Separate native engine initialization from application/worker assembly before treating it as a standalone engine package. |
1928
+ | `mlx-bun`, `src/index.ts` | Re-exports concrete models, generation, downloads, registry, fit and server construction | Already a published compatibility API. A workspace move needs forwarding exports, not a silent reduction of available functionality. |
1929
+ | Browser application | Own TypeScript project; boundary test allows web code and contracts | A candidate private application workspace. Its assets still participate in the CLI/native bundle. |
1930
+ | Website | Already has its own package manifest and build; generates reference pages from canonical docs | Keep one source for reference facts. A root workspace declaration alone would not improve this ownership. |
1931
+
1932
+ The source audit followed static imports, re-exports, type imports and literal
1933
+ `import()`/`require()` references using TypeScript module resolution. The
1934
+ client closure contained four source files and no external module imports.
1935
+ The high-level engine entry reached the broad root API, including Pi and web
1936
+ assets. This is a dependency inventory, not a claim that importing the
1937
+ CPU-safe entry eagerly loads those modules. Non-code assets and executable
1938
+ paths also need a packaging check; import analysis cannot establish that they
1939
+ ship correctly.
1940
+
1941
+ Recommended direction for the remaining audit: one engine package containing
1942
+ models, native bindings, cache codecs, inference methods and their interfaces;
1943
+ application assembly outside it; a small client package if independent
1944
+ installation is useful. Keep specialized kernels and tensor ownership within
1945
+ that engine. Memory, Pi and training require their own dependency and asset
1946
+ review before deciding whether they become private workspaces. A general MLX
1947
+ array binding is a separate API commitment and is not implied by this split.
1948
+
1949
+ Before choosing and implementing the layout, map the engine-to-application
1950
+ edges through server construction, native bootstrap, worker commands and
1951
+ bundled assets. Verify the package tarball and a consumer installed outside
1952
+ the repository. Public import compatibility and the single-binary release are
1953
+ acceptance requirements. The initial audit does not yet close the package
1954
+ organization milestone.
1955
+
1956
+ The initial `bun pm pack --dry-run --ignore-scripts` also confirms that the
1957
+ package includes the whole `docs/` tree, including archived investigations
1958
+ and active plans. Review that allowlist during packaging work; these are not
1959
+ runtime dependencies. This dry run inventories the candidate but does not
1960
+ replace installation and asset checks against an actual tarball.
1961
+
1962
+
1963
+ ### 12.15 Prefill workspace policy
1964
+
1965
+ `PrefillPolicy` selects a request's chunk size independently of scheduling,
1966
+ cache placement and sampling. The MLX backend captures model geometry and
1967
+ explicit configuration when it binds the policy. Ordinary generation,
1968
+ shared rows and speculative preparation consume the selected size through
1969
+ their existing prefill interfaces. A caller's explicit request value wins.
1970
+ The automatic recurrent-attention policy bounds the temporary materialized
1971
+ SDPA score workspace; it does not inspect live free memory or refuse work.
1972
+ Default values and precedence live in [server configuration](../reference/server-config.md).
1973
+
1974
+ ### 12.16 Committed append cache formats
1975
+
1976
+ `MlxTokenAppend` declares supported affine precisions and TurboQuant K/V
1977
+ formats. Qualified Qwen27B bindings expose KV4/KV8 and K8V3.
1978
+ Request preparation supplies template-derived candidates; placement selects
1979
+ an eligible method without inspecting numerical cache formats. The ordinary
1980
+ method consumes the binding's declaration once and uses its committed-append
1981
+ operation. Qwen shares projection work over known tokens while retaining each
1982
+ query's one-token affine attention calculation and causal KV extent.
1983
+ `KvMaintenance.maxAppendTokens` bounds a committed chunk at a pending
1984
+ precision transition; the method runs maintenance before continuing.
1985
+ Verification remains a separate method capability: enabling committed
1986
+ quantized appends does not enable quantized echo verification. No default fill setting or
1987
+ shared-group support is inferred from that declaration.
@@ -6,6 +6,22 @@ the evolving UI/UX/DX north star.
6
6
 
7
7
  ## Product north star
8
8
 
9
+ Josh's guiding principle for the entire project is "The absolute BEST local
10
+ AI experience on a mac". This governs installation, application development,
11
+ everyday use and inference performance.
12
+
13
+ Offer multiple simple installation methods without asking users to manage
14
+ a Python virtual environment. Let developers import local AI into their
15
+ applications without managing a separate inference sidecar. Make JavaScript
16
+ and TypeScript first-class ways to build with local AI, without requiring
17
+ Python. Make more capable models practical on the same Mac and reduce the
18
+ time users wait for successful results.
19
+
20
+ Every workstream must serve that experience. Evaluate engineering choices
21
+ by the setup, integration and operating burden they remove, as well as the
22
+ quality, reliability, speed and hardware efficiency they deliver. Research
23
+ and publication can support the project; user benefit determines priority.
24
+
9
25
  Make the answer to "what is the best way to use local AI on my Mac?"
10
26
  boringly simple:
11
27
 
@@ -49,12 +65,11 @@ disclosure: appliance defaults at the front, sharp instruments underneath.
49
65
 
50
66
  ## The three modes (the organizing design law)
51
67
 
52
- mlx-bun has not published anything: the entire CLI, command, and flag
53
- surface is still ours to invent, and we are not married to any flag
54
- name. Where a de-facto standard name exists (mlx-lm's), we adopt it
55
- rather than reinvent. The surface is designed once, to serve three
56
- audiences at three depths — progressive disclosure over ONE set of
57
- verbs and one flag vocabulary, not three separate CLIs:
68
+ mlx-bun is published. Existing commands, flags, and package exports are
69
+ compatibility commitments; changes need documented migration behavior.
70
+ Where an mlx-lm flag has matching semantics, prefer its established name.
71
+ The CLI serves three audiences through one set of verbs, with more explicit
72
+ configuration available as users need it:
58
73
 
59
74
  1. **Automatic mode** — first-time local-AI users. `mlx-bun` (and bare
60
75
  verbs) with zero flags. Smart, sane defaults from the device-profile