mlx-bun 0.0.13 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (427) hide show
  1. package/README.md +71 -578
  2. package/bin/mlx-bun.mjs +1 -1
  3. package/docs/README.md +91 -0
  4. package/docs/{design → archive}/hlg-sampling.md +3 -3
  5. package/docs/{design → archive/investigations}/audio-input-plan.md +4 -4
  6. package/docs/{design → archive/investigations}/colibri-glm52-port.md +1 -1
  7. package/docs/{design → archive/investigations}/diffusion-gemma-port.md +3 -3
  8. package/docs/{design → archive/investigations}/faithful-l1-consolidation.md +4 -4
  9. package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
  10. package/docs/{design → archive/investigations}/minicpm5-decode-megakernel.md +11 -11
  11. package/docs/{design → archive/investigations}/optimization_plan.md +1 -1
  12. package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
  13. package/docs/{design → archive/investigations}/pre-colibri-stabilization.md +5 -5
  14. package/docs/{design → archive/investigations}/the-dreaming-handoff.md +2 -2
  15. package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
  16. package/docs/{planning → archive/planning}/chunk-task-roadmap.md +1 -1
  17. package/docs/{planning → archive/planning}/curve-sampler-research-plan.md +4 -4
  18. package/docs/{planning → archive/planning}/memory-docs-and-dag-plan.md +1 -1
  19. package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
  20. package/docs/archive/planning/release-notes-v0.2.0.md +49 -0
  21. package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
  22. package/docs/design/batching.md +569 -0
  23. package/docs/design/decode-speed-program.md +3178 -169
  24. package/docs/design/dreaming-nightly-pipeline.md +675 -282
  25. package/docs/design/generic-model-support.md +579 -334
  26. package/docs/design/kv-cache.md +680 -0
  27. package/docs/design/orpo-training.md +673 -1239
  28. package/docs/design/speculative-decoding.md +1627 -0
  29. package/docs/design/turboquant.md +2102 -0
  30. package/docs/design/unified-engine-frontier-plan.md +1831 -727
  31. package/docs/design/web-chat-redesign.md +666 -1083
  32. package/docs/planning/PRODUCT_ROADMAP.md +34 -1
  33. package/docs/planning/release-notes-v0.3.0.md +35 -0
  34. package/docs/planning/video-series.md +421 -0
  35. package/docs/reference/benchmarks.md +1162 -0
  36. package/docs/reference/cli.md +395 -149
  37. package/docs/reference/distribution.md +321 -181
  38. package/docs/reference/environment.md +348 -0
  39. package/docs/reference/glossary.md +39 -0
  40. package/docs/reference/library-api.md +580 -142
  41. package/docs/reference/memory.md +227 -64
  42. package/docs/reference/models.md +137 -6
  43. package/docs/reference/server-api.md +938 -422
  44. package/docs/reference/server-config.md +652 -320
  45. package/docs/reference/training.md +393 -254
  46. package/docs/reference/troubleshooting.md +166 -0
  47. package/package.json +10 -5
  48. package/src/admission-plan.ts +18 -0
  49. package/src/anthropic.ts +92 -3
  50. package/src/audio/decode.ts +2 -2
  51. package/src/audio/features.ts +2 -2
  52. package/src/backends/mlx/autoregressive.ts +108 -0
  53. package/src/backends/mlx/batch-group.ts +1646 -0
  54. package/src/backends/mlx/diffusion.ts +39 -0
  55. package/src/backends/mlx/draft-target.ts +47 -0
  56. package/src/backends/mlx/evaluation.ts +105 -0
  57. package/src/backends/mlx/fill-append.ts +45 -0
  58. package/src/backends/mlx/gateway-binding.ts +71 -0
  59. package/src/backends/mlx/graph.ts +38 -0
  60. package/src/backends/mlx/memory-client.ts +189 -0
  61. package/src/backends/mlx/memory-guard.ts +40 -0
  62. package/src/backends/mlx/methods.ts +90 -0
  63. package/src/backends/mlx/model-prompt.ts +164 -0
  64. package/src/backends/mlx/model-serving.ts +79 -0
  65. package/src/backends/mlx/prefill.ts +33 -0
  66. package/src/backends/mlx/request-policy.ts +20 -0
  67. package/src/backends/mlx/rollback.ts +51 -0
  68. package/src/backends/mlx/serial-executor.ts +273 -0
  69. package/src/backends/mlx/speculative.ts +114 -0
  70. package/src/backends/mlx/state-views.ts +26 -0
  71. package/src/backends/mlx/text-engine.ts +73 -0
  72. package/src/cli.ts +189 -61
  73. package/src/client.ts +66 -0
  74. package/src/config.ts +21 -4
  75. package/src/contracts/completion.ts +16 -0
  76. package/src/contracts/execution.ts +49 -0
  77. package/src/contracts/generation.ts +103 -0
  78. package/src/contracts/host.ts +7 -0
  79. package/src/contracts/jobs.ts +66 -0
  80. package/src/contracts/pi-provider.ts +30 -0
  81. package/src/contracts/pi.ts +259 -0
  82. package/src/contracts/resources.ts +18 -0
  83. package/src/contracts/scheduling.ts +27 -0
  84. package/src/contracts/tsconfig.json +14 -0
  85. package/src/diffusion/diffusion-generate.ts +218 -153
  86. package/src/embed.ts +1 -1
  87. package/src/engine/admission.ts +59 -0
  88. package/src/engine/cancellation.ts +38 -0
  89. package/src/engine/engine.ts +56 -0
  90. package/src/engine/execution-coordinator.ts +70 -0
  91. package/src/engine/execution-plan.ts +51 -0
  92. package/src/engine/resources.ts +42 -0
  93. package/src/engine/scheduler.ts +67 -0
  94. package/src/engine/session.ts +247 -0
  95. package/src/eval/README.md +44 -1
  96. package/src/eval/kl.ts +263 -23
  97. package/src/eval/reference-logits.ts +207 -0
  98. package/src/eval/runner.ts +10 -79
  99. package/src/eval/tasks/bfcl.ts +2 -1
  100. package/src/eval/tasks/gsm8k.ts +2 -1
  101. package/src/eval/tasks/hashhop.ts +2 -1
  102. package/src/eval/tasks/humaneval.ts +5 -4
  103. package/src/eval/tasks/ifeval.ts +2 -1
  104. package/src/eval/tasks/mmlu.ts +2 -1
  105. package/src/expert-io.ts +3 -1
  106. package/src/expert-offload.ts +3 -1
  107. package/src/fill/echo-index.ts +188 -0
  108. package/src/fill/fill-session.ts +452 -0
  109. package/src/fill/proposal.ts +68 -0
  110. package/src/fill/schema-rows.ts +506 -0
  111. package/src/fill/tool-boundary.ts +103 -0
  112. package/src/fit.ts +24 -43
  113. package/src/generate.ts +740 -337
  114. package/src/grammar.ts +14 -8
  115. package/src/harness-pi.ts +15 -34
  116. package/src/hub-rest.ts +4 -4
  117. package/src/index.ts +27 -0
  118. package/src/inference/denoising.ts +17 -0
  119. package/src/inference/graph.ts +33 -0
  120. package/src/inference/prefill.ts +39 -0
  121. package/src/inference/rollback.ts +7 -0
  122. package/src/jobs/db.ts +4 -0
  123. package/src/jobs/index.ts +2 -0
  124. package/src/jobs/job-entry.ts +15 -14
  125. package/src/jobs/runner.ts +98 -13
  126. package/src/jobs/task-client.ts +19 -0
  127. package/src/jobs/types.ts +2 -58
  128. package/src/kv-scheme.ts +199 -0
  129. package/src/kv-store.ts +459 -234
  130. package/src/lab/README.md +18 -0
  131. package/src/{assets → lab/curve}/curve-designer.html +2 -2
  132. package/src/{curve-sampler.ts → lab/curve/curve-sampler.ts} +2 -2
  133. package/src/{expert-trace.ts → lab/expert-trace/expert-trace.ts} +7 -5
  134. package/src/{model → lab/paged-kv}/paged-kv.ts +9 -6
  135. package/src/library.ts +40 -0
  136. package/src/lora.ts +18 -0
  137. package/src/media-fetch.ts +20 -4
  138. package/src/memory/article.ts +1 -1
  139. package/src/memory/chunk.ts +1 -1
  140. package/src/memory/model.ts +32 -170
  141. package/src/memory/prompts.ts +1 -1
  142. package/src/memory/rest.ts +1 -1
  143. package/src/memory/schedule.ts +1 -1
  144. package/src/memory/stages.ts +4 -1
  145. package/src/memory/vault.ts +3 -4
  146. package/src/mlx/array.ts +9 -10
  147. package/src/mlx/compile.ts +12 -2
  148. package/src/mlx/ffi.ts +66 -22
  149. package/src/mlx/materialize.ts +23 -0
  150. package/src/mlx/metal-kernel.ts +10 -11
  151. package/src/mlx/ops.ts +64 -19
  152. package/src/mlx/quantized-rows.ts +36 -0
  153. package/src/mlx/token-bitmask.ts +52 -0
  154. package/src/mlx/turboquant-kv-decode.ts +82 -0
  155. package/src/mlx/turboquant-kv-inverse.ts +122 -0
  156. package/src/mlx/turboquant-ops.ts +33 -3
  157. package/src/mlx/turboquant-tables.ts +2 -2
  158. package/src/model/batched-mask.ts +9 -3
  159. package/src/model/batched-quant.ts +2 -2
  160. package/src/model/batched-rotating-quant.ts +45 -99
  161. package/src/model/batched-rotating-state.ts +73 -0
  162. package/src/model/batched-rotating.ts +57 -106
  163. package/src/model/batched-row-storage.ts +127 -0
  164. package/src/model/compiled-decode.ts +4 -3
  165. package/src/model/diffusion-gemma.ts +8 -8
  166. package/src/model/factory.ts +87 -49
  167. package/src/model/fingerprint.ts +1 -1
  168. package/src/model/flash-attention.ts +3 -3
  169. package/src/model/gemma4-base.ts +187 -17
  170. package/src/model/gemma4.ts +6 -6
  171. package/src/model/generated/gemma4-12b.ts +52 -148
  172. package/src/model/generated/gemma4-26b.ts +34 -94
  173. package/src/model/generated/gemma4-e4b.ts +28 -76
  174. package/src/model/glm52-cache.ts +19 -9
  175. package/src/model/glm52-dsa.ts +13 -9
  176. package/src/model/glm52-memory.ts +28 -1
  177. package/src/model/implementation.ts +69 -0
  178. package/src/model/minicpm5.ts +7 -8
  179. package/src/model/profile.ts +443 -0
  180. package/src/model/qwen-append.ts +12 -0
  181. package/src/model/qwen-conv.ts +52 -0
  182. package/src/model/qwen3-delta.ts +98 -2
  183. package/src/model/qwen3-mrope.ts +252 -0
  184. package/src/model/qwen3_5-checkpoint.ts +164 -0
  185. package/src/model/qwen3_5.ts +336 -60
  186. package/src/model/support.ts +1 -1
  187. package/src/model/trellis-balanced-scatter.ts +51 -0
  188. package/src/model/trellis-linear.ts +672 -0
  189. package/src/model/trellis-shared-m.ts +151 -0
  190. package/src/model/trellis-shared-scatter.ts +144 -0
  191. package/src/model/trellis-splitk-prefill.ts +158 -0
  192. package/src/model/trellis-tiled-prefill.ts +136 -0
  193. package/src/model/trellis-vector-expand.ts +62 -0
  194. package/src/model/trellis-wide-prefill.ts +94 -0
  195. package/src/model/universal/dense.ts +1 -1
  196. package/src/model/universal/modules.ts +8 -1
  197. package/src/native/frame_extract.swift +140 -0
  198. package/src/native-pack.ts +15 -7
  199. package/src/pi-provider.ts +6 -64
  200. package/src/pi-web.ts +14 -320
  201. package/src/prompt-cache.ts +97 -54
  202. package/src/quantize/allocator.ts +1 -1
  203. package/src/quantize/atomic-output.ts +38 -0
  204. package/src/quantize/calibration.ts +2 -1
  205. package/src/quantize/config-writer.ts +16 -3
  206. package/src/quantize/index.ts +28 -1
  207. package/src/quantize/job.ts +11 -0
  208. package/src/quantize/quantizer.ts +265 -100
  209. package/src/quantize/rotate.ts +603 -0
  210. package/src/quantize/safetensors-writer.ts +79 -1
  211. package/src/quantize/sensitivity.ts +41 -59
  212. package/src/quantize/trellis.ts +586 -0
  213. package/src/quantize/weight-transform.ts +292 -0
  214. package/src/responses.ts +130 -3
  215. package/src/runtime-config.ts +81 -0
  216. package/src/sampler.ts +276 -4
  217. package/src/serve/admin-routes.ts +184 -0
  218. package/src/serve/aux-routes.ts +132 -0
  219. package/src/serve/batch-scheduler.ts +8 -1558
  220. package/src/serve/chat-request.ts +391 -0
  221. package/src/serve/chat-stage.ts +195 -0
  222. package/src/serve/checkpoint-identity.ts +64 -0
  223. package/src/serve/completion-executor.ts +354 -0
  224. package/src/serve/completion-sink.ts +157 -0
  225. package/src/serve/discovery-routes.ts +204 -0
  226. package/src/serve/generation-gateway.ts +211 -243
  227. package/src/serve/http.ts +159 -0
  228. package/src/serve/inference-request.ts +79 -0
  229. package/src/serve/isolate.ts +297 -105
  230. package/src/serve/kv-budget.ts +14 -0
  231. package/src/serve/lab-routes.ts +341 -0
  232. package/src/serve/lane-registry.ts +2 -1
  233. package/src/serve/model-admin-routes.ts +155 -0
  234. package/src/serve/model-binding.ts +43 -0
  235. package/src/serve/model-host.ts +512 -0
  236. package/src/serve/openai-wire.ts +103 -0
  237. package/src/serve/parent-application.ts +56 -0
  238. package/src/serve/pipeline.ts +33 -0
  239. package/src/serve/preparation.ts +33 -0
  240. package/src/serve/prompt-response-trace.ts +147 -0
  241. package/src/serve/request-plan.ts +162 -0
  242. package/src/serve/request-prep.ts +346 -0
  243. package/src/serve/response-lease.ts +24 -0
  244. package/src/serve/responses-client.ts +69 -0
  245. package/src/serve/session-completion-engine.ts +110 -0
  246. package/src/serve/session-search.ts +1 -1
  247. package/src/serve/static-routes.ts +101 -0
  248. package/src/serve/text-completion-stage.ts +104 -0
  249. package/src/serve/token-streams.ts +519 -0
  250. package/src/server.ts +523 -3551
  251. package/src/spec/assistant-source.ts +10 -44
  252. package/src/spec/deepspec-source.ts +6 -6
  253. package/src/spec/dflash-source.ts +9 -8
  254. package/src/spec/dspark/ab-stats.ts +3 -3
  255. package/src/spec/dspark/calibration.ts +2 -2
  256. package/src/spec/dspark/deepspec-module.ts +2 -2
  257. package/src/spec/dspark/generate-dflash.ts +2 -2
  258. package/src/spec/dspark/generate.ts +2 -2
  259. package/src/spec/dspark/loader.ts +1 -1
  260. package/src/spec/dspark/module-dflash.ts +5 -4
  261. package/src/spec/dspark/module.ts +3 -3
  262. package/src/spec/dspark/quantize-drafter.ts +1 -1
  263. package/src/spec/generate.ts +1 -1
  264. package/src/spec/glm52-mtp-source.ts +9 -1
  265. package/src/spec/ngram-source.ts +1 -1
  266. package/src/spec/prefix-state.ts +45 -0
  267. package/src/spec/qwen-mtp-source.ts +528 -0
  268. package/src/spec/serve-loop.ts +179 -213
  269. package/src/spec/source.ts +42 -10
  270. package/src/spec/two-model.ts +1 -1
  271. package/src/ssd-cache.ts +95 -24
  272. package/src/ssd-durability.ts +207 -0
  273. package/src/tool-call.ts +51 -14
  274. package/src/train/flash-cce.ts +14 -13
  275. package/src/train/forward.ts +38 -1
  276. package/src/train/loss.ts +3 -2
  277. package/src/train/prefix-shared.ts +5 -1
  278. package/src/train/segmented.ts +9 -6
  279. package/src/train/trainer.ts +9 -8
  280. package/src/vision/preprocess.ts +1 -1
  281. package/src/vision/prompt.ts +48 -2
  282. package/src/vision/qwen3vl-preprocess.ts +409 -0
  283. package/src/vision/qwen3vl-prompt.ts +196 -0
  284. package/src/vision/qwen3vl-tower.ts +555 -0
  285. package/src/vision/video-frames.ts +148 -0
  286. package/src/web/app.html +1 -1
  287. package/src/web/app.js +15 -6
  288. package/src/web/src/adapters-panel.ts +3 -3
  289. package/src/web/src/assistant.ts +2 -36
  290. package/src/web/src/chat.ts +16 -9
  291. package/src/web/src/composer.ts +4 -4
  292. package/src/web/src/hub.ts +1 -1
  293. package/src/web/src/markdown.ts +0 -0
  294. package/src/web/src/memory-panel.ts +1 -1
  295. package/src/web/src/model-picker.ts +1 -1
  296. package/src/web/src/palette.ts +1 -1
  297. package/src/web/src/protocol.ts +3 -39
  298. package/src/web/src/sessions.ts +1 -1
  299. package/src/web/src/ui-catalog.ts +4 -18
  300. package/src/web-assets.ts +47 -0
  301. package/src/weights.ts +134 -33
  302. package/docs/archive/mlx-bun-lab-report.html +0 -275
  303. package/docs/archive/wwdc-mlx-bun.html +0 -848
  304. package/docs/design/adapters-end-to-end.md +0 -205
  305. package/docs/design/batching-perf-path.md +0 -255
  306. package/docs/design/batching-v2-plan.md +0 -529
  307. package/docs/design/bucketing-stage.md +0 -197
  308. package/docs/design/compat-cli-surface-design.md +0 -230
  309. package/docs/design/docs-reorg-plan.md +0 -165
  310. package/docs/design/dspark-serving-program.md +0 -371
  311. package/docs/design/dspark-speculative-decoding.md +0 -268
  312. package/docs/design/grammar-spec-batching-integration.md +0 -301
  313. package/docs/design/memory-inference-path.md +0 -422
  314. package/docs/design/memory-synthesis.md +0 -287
  315. package/docs/design/memory-system.md +0 -237
  316. package/docs/design/mlx-lm-tool-parity-plan.md +0 -545
  317. package/docs/design/omlx-adoption-map.md +0 -98
  318. package/docs/design/orpo-dynamic-lambda.md +0 -220
  319. package/docs/design/orpo-future-enhancements.md +0 -340
  320. package/docs/design/paged-kv-cache.md +0 -214
  321. package/docs/design/parallel-slots.md +0 -567
  322. package/docs/design/parity-tier-dag.md +0 -161
  323. package/docs/design/repo-cleanup-plan.md +0 -189
  324. package/docs/design/runtime-isolation.md +0 -263
  325. package/docs/design/segmented-backward-training.md +0 -543
  326. package/docs/design/spec-decode-larger-targets.md +0 -229
  327. package/docs/design/ssd-kv-cold-tier.md +0 -288
  328. package/docs/design/structured-output.md +0 -484
  329. package/docs/design/tauri-desktop-app.md +0 -127
  330. package/docs/design/the-dreaming-master-plan.md +0 -445
  331. package/docs/design/turboquant-kv.md +0 -235
  332. package/docs/design/w4a16-compute-precision-spike.md +0 -232
  333. package/docs/design/web-chat-beat-matrix.md +0 -315
  334. package/docs/design/write-pipeline-entity.md +0 -468
  335. package/docs/investigations/curve-runs/bisector-route.json +0 -98
  336. package/docs/investigations/curve-runs/bisector-trace.json +0 -1393
  337. package/docs/investigations/curve-runs/curve-terrain.json +0 -1179
  338. package/docs/investigations/curve-runs/curve-terrain.svg +0 -42
  339. package/docs/investigations/hlg-ab.html +0 -34
  340. package/docs/investigations/hlg-explorer.html +0 -238
  341. package/docs/investigations/hlg-figs/cliff.svg +0 -1
  342. package/docs/investigations/hlg-figs/cross.svg +0 -1
  343. package/docs/investigations/hlg-figs/edges.svg +0 -1
  344. package/docs/investigations/hlg-figs/k20-grids.svg +0 -1
  345. package/docs/investigations/hlg-figs/k20-peaks.svg +0 -1
  346. package/docs/investigations/hlg-figs/lw-curve.svg +0 -1
  347. package/docs/investigations/hlg-figs/terrain.svg +0 -1
  348. package/docs/investigations/hlg-report.html +0 -262
  349. package/docs/investigations/hlg-runs/hlg-ab.json +0 -149
  350. package/docs/investigations/hlg-runs/hlg-blind-prompts.md +0 -87
  351. package/docs/investigations/hlg-runs/hlg-blind.json +0 -107
  352. package/docs/investigations/hlg-runs/hlg-cliff.json +0 -197
  353. package/docs/investigations/hlg-runs/hlg-cross.json +0 -505
  354. package/docs/investigations/hlg-runs/hlg-edge.json +0 -388
  355. package/docs/investigations/hlg-runs/hlg-eval1.json +0 -25
  356. package/docs/investigations/hlg-runs/hlg-frontier.json +0 -86
  357. package/docs/investigations/hlg-runs/hlg-grid.json +0 -242
  358. package/docs/investigations/hlg-runs/hlg-grid2.json +0 -343
  359. package/docs/investigations/hlg-runs/hlg-lw-coarse.json +0 -110
  360. package/docs/investigations/hlg-runs/hlg-map.json +0 -383
  361. package/docs/investigations/hlg-runs/run0-original.log +0 -159
  362. package/docs/investigations/hlg-runs/runA-recommended.log +0 -131
  363. package/docs/investigations/hlg-runs/runAA-cliff-cpm5.log +0 -26
  364. package/docs/investigations/hlg-runs/runAB-grid2-e4b.log +0 -18
  365. package/docs/investigations/hlg-runs/runAC-peak-e4b-partial.log +0 -25
  366. package/docs/investigations/hlg-runs/runAD-ab-samples.log +0 -8
  367. package/docs/investigations/hlg-runs/runAE-edge-e4b.log +0 -51
  368. package/docs/investigations/hlg-runs/runAF-logit-calibration.log +0 -10
  369. package/docs/investigations/hlg-runs/runAG-eval-config2.log +0 -16
  370. package/docs/investigations/hlg-runs/runB-gain-variants.log +0 -192
  371. package/docs/investigations/hlg-runs/runC-pivots.log +0 -162
  372. package/docs/investigations/hlg-runs/runD-oetf.log +0 -132
  373. package/docs/investigations/hlg-runs/runE-eotf.log +0 -162
  374. package/docs/investigations/hlg-runs/runF-shaper-working.log +0 -86
  375. package/docs/investigations/hlg-runs/runG-shaper-sweep.log +0 -101
  376. package/docs/investigations/hlg-runs/runH-wsweep.log +0 -176
  377. package/docs/investigations/hlg-runs/runI-asweep.log +0 -176
  378. package/docs/investigations/hlg-runs/runJ-knobmap.log +0 -49
  379. package/docs/investigations/hlg-runs/runK-frontier.log +0 -19
  380. package/docs/investigations/hlg-runs/runL-widemap.log +0 -65
  381. package/docs/investigations/hlg-runs/runM-frontier-emb.log +0 -15
  382. package/docs/investigations/hlg-runs/runN-verify.log +0 -116
  383. package/docs/investigations/hlg-runs/runO-frontier-seed5000.log +0 -15
  384. package/docs/investigations/hlg-runs/runP-grid-AxSm.log +0 -15
  385. package/docs/investigations/hlg-runs/runQ-grid-tgW.log +0 -15
  386. package/docs/investigations/hlg-runs/runR-blind-transcript.log +0 -79
  387. package/docs/investigations/hlg-runs/runS-cross-coherence.log +0 -33
  388. package/docs/investigations/hlg-runs/runT-cross-cpm5.log +0 -33
  389. package/docs/investigations/hlg-runs/runU-cross-12b.log +0 -33
  390. package/docs/investigations/hlg-runs/runV-lw-e4b.log +0 -22
  391. package/docs/investigations/hlg-runs/runW-lw-12b.log +0 -22
  392. package/docs/investigations/hlg-runs/runX-lw-cpm5.log +0 -22
  393. package/docs/investigations/hlg-runs/runY-cliff-e4b.log +0 -26
  394. package/docs/investigations/hlg-runs/runZ-cliff-12b.log +0 -26
  395. package/docs/planning/IDEAS.md +0 -69
  396. package/docs/reference/embedding.md +0 -197
  397. package/docs/reference/features-matrix.md +0 -100
  398. package/docs/reference/orpo-quickstart.md +0 -135
  399. package/src/flags.ts +0 -13
  400. /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
  401. /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
  402. /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
  403. /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
  404. /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
  405. /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
  406. /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
  407. /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
  408. /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
  409. /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
  410. /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
  411. /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
  412. /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
  413. /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
  414. /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
  415. /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
  416. /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
  417. /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
  418. /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
  419. /package/docs/{planning → archive/planning}/journal.md +0 -0
  420. /package/docs/{planning → archive/planning}/pi-integration-review.md +0 -0
  421. /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
  422. /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
  423. /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
  424. /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
  425. /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
  426. /package/{docs/investigations → src/serve/assets}/curve-terrain.html +0 -0
  427. /package/{docs/dag → src/serve/assets}/training-inference-map.html +0 -0
@@ -1,208 +1,348 @@
1
- # Distributing mlx-bun via Homebrew (signed + notarized)
2
-
3
- The end-to-end runbook for shipping a `brew install`-able, Developer-ID
4
- signed and notarized mlx-bun. Companion to [embedding.md](./embedding.md)
5
- (which covers the Tauri/Electron *sidecar* layout); this doc is the
6
- *standalone CLI* distribution.
7
-
8
- ## What ships
9
-
10
- A single **self-contained** bundle — the whole `dist/` directory in one
11
- tarball (~73 MB compressed, ~228 MB installed):
12
-
13
- | file | what |
14
- |---|---|
15
- | `mlx-bun` | the CLI/server (`bun build --compile`), ~61 MB |
16
- | `libmlxc.dylib`, `libmlx.dylib`, `libjaccl.dylib` | MLX native runtime |
17
- | `libmlx_bun_expert_io.dylib` | bounded native expert-streaming helper required by direct Colibri GLM-5.2 |
18
- | `mlx.metallib` | Metal kernels (~150 MB — the bulk) |
19
- | pi assets | `photon_rs_bg.wasm`, `theme/`, `assets/`, `export-html/`, `native/`, `package.json`, `CHANGELOG.md` |
20
-
21
- We ship everything in the bottle (rather than the npm/sidecar approach of
22
- a tiny binary that downloads the native pack on first run) so that
23
- `brew install` is the *only* network step and the entire bundle is signed
24
- and notarized as one artifact.
25
-
26
- ## One-time Apple setup
27
-
28
- 1. **Developer ID Application certificate** — Xcode → Settings → Accounts →
1
+ # Distributing mlx-bun — build, sign, notarize, publish
2
+
3
+ The canonical ship doc. Everything here is what the scripts do, not a
4
+ recipe to type by hand: [scripts/build-binary.sh](../../scripts/build-binary.sh)
5
+ builds the bundle, [scripts/release-binary.sh](../../scripts/release-binary.sh)
6
+ signs and notarizes it, [scripts/publish-release.sh](../../scripts/publish-release.sh)
7
+ pushes it to every channel. If this doc and a script disagree, the script
8
+ is right and this doc has drifted.
9
+
10
+ Three install channels ship from one release:
11
+
12
+ | channel | what the user gets | network step |
13
+ |---|---|---|
14
+ | Homebrew (`brew install joshuarossi/tap/mlx-bun`) | the signed + notarized self-contained bundle | one tarball, via brew |
15
+ | Direct download (`curl -fsSL https://mlx-bun.dev/install.sh \| sh`) | the same bundle, into `~/.mlx-bun` | one tarball, via curl |
16
+ | npm / bunx (`bunx mlx-bun`, `bun install -g mlx-bun`) | a launcher + the TypeScript source, run under the user's Bun | the package, then the native runtime pack on first run |
17
+
18
+ [docs/reference/distribution.md](./distribution.md) covers the *sidecar* use of the same bundle
19
+ inside a Tauri/Electron app; the build and signing facts it relies on are
20
+ documented here.
21
+
22
+ ## What ships in the bundle
23
+
24
+ `scripts/build-binary.sh [outdir]` (default `dist/`) produces one relocatable
25
+ directory. The release tarball is the directory's *contents* (no parent
26
+ dir), ~80 MB compressed; `mlx.metallib` is the bulk of the installed size.
27
+
28
+ | file | what | built from |
29
+ |---|---|---|
30
+ | `mlx-bun` | the CLI/server, `bun build --compile src/cli.ts` | our code + Bun |
31
+ | `libmlxc.dylib` | mlx-c; load command rewritten to `@loader_path/libmlx.dylib` | `/opt/homebrew/lib/libmlxc.dylib` (override `MLXC_DYLIB`) |
32
+ | `libmlx.dylib`, `libjaccl.dylib`, `mlx.metallib` | MLX core, its distributed-comm dependency, the Metal kernels (libmlx loads the metallib from its own directory) | `/opt/homebrew/opt/mlx/lib` (override `MLX_LIB_DIR`) |
33
+ | `libmlx_bun_expert_io.dylib` | bounded streamed-expert I/O for GLM-5.2 MoE serving | [scripts/build-expert-io.sh](../../scripts/build-expert-io.sh) |
34
+ | `mlx-bun-frame-extract` | AVFoundation frame-extraction helper for video input (a Mach-O *executable*, not a dylib) | [scripts/build-frame-extract.sh](../../scripts/build-frame-extract.sh) → `swiftc -O src/native/frame_extract.swift` |
35
+ | `photon_rs_bg.wasm` | pi's image codec, resolved next to the executable by the web chat's `read`-on-image path (best-effort; pi degrades to a text note without it) | `node_modules/@silvia-odwyer/photon-node` (override `PHOTON_WASM`) |
36
+ | `theme/*.json`, `assets/*.png`, `export-html/`, `package.json`, `CHANGELOG.md`, `native/darwin/prebuilds/<arch>/darwin-modifiers.node` | assets the embedded pi **terminal** (`mlx-bun pi`) resolves by path: themes, startup art, `/export` template, version banner + changelog, native modifier-key helper (degrades if absent) | `node_modules/@earendil-works/pi-coding-agent/dist`, `pi-tui` |
37
+
38
+ pi's JavaScript itself is bundled into the executable by `bun build
39
+ --compile`; only what pi resolves *by path* rides along. For a Bun
40
+ single-file executable pi computes its package dir as
41
+ `dirname(process.execPath)`, so every asset sits flat next to `mlx-bun`.
42
+
43
+ After copying, the script runs `install_name_tool` (`libmlxc` →
44
+ `@loader_path/libmlx.dylib`; `@loader_path` rpath on `libmlx` for `libjaccl`)
45
+ and **ad-hoc signs** every Mach-O it touched — arm64 requires a valid
46
+ signature after any load-command rewrite. Ad-hoc is only for local runs; the
47
+ release script replaces it (below).
48
+
49
+ The C and Swift helpers target macOS 14.0 by default, matching the package's
50
+ minimum macOS version. `MACOSX_DEPLOYMENT_TARGET` can override that build
51
+ target. Verify the MLX libraries' deployment targets as well when replacing
52
+ the bundled runtime; compiling our helpers for 14.0 cannot lower a dependency's
53
+ minimum OS version.
54
+
55
+ **Build-time smoke.** The script then runs `mlx-bun --version`, `--help`, and
56
+ `ls`, and compiles [scripts/verify-binary-pi.ts](../../scripts/verify-binary-pi.ts)
57
+ into a *sibling* binary inside the same directory so `process.execPath` points
58
+ at the bundle exactly as it does for the real binary. That smoke builds the
59
+ same headless pi session `src/pi-web.ts` builds (against an unreachable
60
+ provider — a provider error is the success signal), exercises the photon
61
+ image path, calls `initTheme` (load-bearing for `mlx-bun pi`; a failure here
62
+ fails the smoke), and loads the native modifier helper. No model, no server.
63
+ A live streaming turn is the one thing it cannot cover.
64
+
65
+ **Runtime resolution.** The binary finds its native runtime in this order
66
+ (`src/mlx/ffi.ts`, mirrored by `nativeRuntimeDir()` in `src/native-pack.ts`):
67
+ `MLX_BUN_LIBMLXC` env → `libmlxc.dylib` beside the executable → the
68
+ native-pack cache (`~/Library/Caches/mlx-bun/native-v<ver>-<arch>/`) →
69
+ `/opt/homebrew/lib` → `/usr/local/lib`. The expert helper resolves
70
+ `MLX_BUN_EXPERT_IO_DYLIB` → beside the executable → the cache
71
+ (`src/expert-io.ts`); the frame extractor resolves `MLX_BUN_FRAME_EXTRACT` →
72
+ beside the executable → the cache → `dist-native/` → compile-on-demand from
73
+ `src/native/` via the Xcode CLT (`src/vision/video-frames.ts`). The whole
74
+ directory can be moved or renamed; nothing references an absolute path after
75
+ the fixups. Bun realpaths `execPath`, so a symlink to `mlx-bun` (Homebrew's
76
+ `bin/`, the installer's `~/.local/bin`) resolves back to the bundle.
77
+
78
+ ## One-time machine setup
79
+
80
+ Releases are inherently local: signing and notarization need the Developer
81
+ ID certificate and Apple credentials on this Mac, so the publish step is
82
+ local too (no cross-repo CI token, nothing for the tap to drift from). The
83
+ release machine needs:
84
+
85
+ 1. **Build inputs** — Homebrew `mlx` + `mlx-c` (the bundle copies the dylibs
86
+ and metallib from the brew prefixes above), the Xcode command-line tools
87
+ (`swiftc` for the frame extractor, the C toolchain for the expert helper),
88
+ and Bun at or above the floor in `package.json` `engines.bun`.
89
+ 2. **Developer ID Application certificate** — Xcode → Settings → Accounts →
29
90
  your Apple ID → *Manage Certificates…* → **+** → **Developer ID
30
- Application**. Verify:
31
- ```sh
32
- security find-identity -v -p codesigning # shows "Developer ID Application: NAME (TEAMID)"
33
- ```
34
- 2. **Notary credentials** — an App Store Connect **API key** (not the
35
- Developer-portal "Keys" page; not your Apple ID password). Create at
36
- **App Store Connect → Users and Access → Integrations → App Store
37
- Connect API → Team Keys → +** (role: Developer). Download the
38
- `AuthKey_<KEYID>.p8` (one-time download), note the **Key ID** and the
39
- **Issuer ID** (UUID at the top of the page), then:
91
+ Application**. The release script picks the first such identity from
92
+ `security find-identity -v -p codesigning`; override with
93
+ `MLX_BUN_SIGN_IDENTITY`.
94
+ 3. **Notary credentials** — an App Store Connect **API key** (not your Apple
95
+ ID password): App Store Connect → Users and Access → Integrations → App
96
+ Store Connect API → Team Keys → **+** (role: Developer). Download the
97
+ `AuthKey_<KEYID>.p8` (one-time download), note the Key ID and Issuer ID,
98
+ then store them under the profile name the script expects:
40
99
  ```sh
41
100
  xcrun notarytool store-credentials AC_PROFILE \
42
101
  --key ~/.private_keys/AuthKey_<KEYID>.p8 \
43
102
  --key-id "<KEYID>" --issuer "<ISSUER-UUID>"
44
103
  ```
45
- `store-credentials` validates against Apple before saving — success
46
- means notarization auth works.
47
-
48
- ## Release a build
49
-
50
- ```sh
51
- ./scripts/release-binary.sh # version from package.json
52
- # or: ./scripts/release-binary.sh 0.0.4
53
- ```
54
-
55
- This runs [build-binary.sh](../../scripts/build-binary.sh), then:
56
- - signs every nested Mach-O (dylibs, any `.node`) with the hardened
57
- runtime, then the executable with the JIT
58
- [entitlements](../../packaging/entitlements.plist) (JavaScriptCore JITs —
59
- without `allow-jit` the binary is killed on launch);
60
- - notarizes the zipped bundle via `AC_PROFILE` and waits;
61
- - emits `dist-release/mlx-bun-v<ver>-arm64.tar.gz` (+ `.sha256`) and
62
- prints the `version`/`url`/`sha256` for the formula.
63
-
64
- > A flat CLI bundle **cannot be stapled** (`stapler` only handles
65
- > `.app`/`.dmg`/`.pkg`); the notarization ticket lives on Apple's servers.
66
- > Gatekeeper checks it online only when a copy is *quarantined*. brew
67
- > formula installs are **not** quarantined (brew downloads via curl), so
68
- > the binary runs prompt-free regardless — notarization is load-bearing
69
- > only for a direct browser download or a Cask.
70
-
71
- Publish the artifact as a GitHub release whose tag matches the formula url:
72
- ```sh
73
- gh release create v0.0.4 dist-release/mlx-bun-v0.0.4-arm64.tar.gz \
74
- --title "mlx-bun v0.0.4" --notes "..."
75
- ```
76
-
77
- ## The tap
78
-
79
- Homebrew taps must be a repo named `homebrew-<name>`. The canonical tap is
80
- **`joshuarossi/homebrew-tap`** (Homebrew shorthand: `joshuarossi/tap`).
81
-
82
- 1. Create a public repo **`joshuarossi/homebrew-tap`** (one-time).
83
- 2. Copy [packaging/homebrew/mlx-bun.rb](../../packaging/homebrew/mlx-bun.rb)
84
- to `Formula/mlx-bun.rb` in it, updating `version`/`url`/`sha256` from
85
- the release-script output. Commit and push.
86
- 3. Install:
87
- ```sh
88
- brew install joshuarossi/tap/mlx-bun
89
- mlx-bun --version
90
- ```
91
-
92
- `brew audit --strict --new joshuarossi/tap/mlx-bun` before pushing
93
- catches most formula issues; `brew install --build-from-source` +
94
- `brew test` runs the formula's `test do` locally.
95
-
96
- ## Updating (one command)
97
-
98
- Releases must originate on this Mac (signing + notarization need the
99
- Developer ID cert + Apple creds), so the publish step is local too — no
100
- cross-repo CI token to manage, and the tap can't drift out of sync.
101
-
102
- Per release:
103
-
104
- 1. bump `version` in `package.json` and commit;
105
- 2. one shot:
106
- ```sh
107
- PUBLISH=1 ./scripts/release-binary.sh
108
- ```
109
- This builds → signs → notarizes → creates the `v<ver>` GitHub release →
110
- rewrites `version`/`url`/`sha256` in the tap's `Formula/mlx-bun.rb` and
111
- pushes it → mirrors the same fields into
112
- [packaging/homebrew/mlx-bun.rb](../../packaging/homebrew/mlx-bun.rb)
113
- (left staged — commit it).
114
-
115
- Prefer two steps? Run `./scripts/release-binary.sh` to build, eyeball the
116
- artifact, then `./scripts/publish-release.sh` to publish + sync the tap.
117
- Both are idempotent: re-running `publish-release.sh` clobbers the release
118
- asset and no-ops the tap push if nothing changed.
119
-
120
- Users then upgrade with:
121
- ```sh
122
- brew upgrade joshuarossi/tap/mlx-bun
123
- ```
124
-
125
- ## Direct download (stable URL)
104
+ `store-credentials` validates against Apple before saving. Override the
105
+ profile name with `NOTARY_PROFILE`.
106
+ 4. **GitHub** — `gh auth login` with push access to `joshuarossi/mlx-bun`
107
+ (releases) and `joshuarossi/homebrew-tap` (the tap is cloned over https
108
+ and pushed).
109
+ 5. **npm** — a publish token for `mlx-bun` (`.npmrc`; `npm whoami` must
110
+ answer).
111
+ 6. **The tap repo** — `joshuarossi/homebrew-tap` (Homebrew shorthand
112
+ `joshuarossi/tap`) must already contain `Formula/mlx-bun.rb`; the publish
113
+ script rewrites three fields in it and refuses to run if the file is
114
+ missing.
115
+
116
+ ## Per-release flow
117
+
118
+ Exactly what `bun run release` (= `PUBLISH=1 sh scripts/release-binary.sh`)
119
+ does, in order. Steps 1–3 are yours; the rest is the scripts.
120
+
121
+ 1. **Write the notes** at `docs/planning/release-notes-v<ver>.md`. The
122
+ publish script uses it as the GitHub release body (`--notes-file`); if it
123
+ is missing the release is created with a bare title and a warning. After
124
+ the release the file is archived to `docs/archive/planning/` (the
125
+ planning directory holds living docs only).
126
+ 2. **Bump `version` in `package.json`** and commit.
127
+ 3. **Push** so `HEAD == origin/main`. The publish preflight refuses a dirty
128
+ tree or a local HEAD that differs from `origin/main`: the site deploys from
129
+ the push while the binaries are built from the local tree, and the two
130
+ must tell the same story. `RELEASE_SKIP_GIT_CHECK=1` bypasses this for an
131
+ assets-only re-run.
132
+ 4. **Build** — `scripts/build-binary.sh dist` as described above
133
+ (`BUILD_DIR` overrides `dist`). Release builds are arm64-only; the script
134
+ exits on any other host arch.
135
+ 5. **Sign nested code first** — every `*.dylib`, `*.node`, and the
136
+ `mlx-bun-frame-extract` helper, matched by name under the build dir, gets
137
+ `codesign --force --timestamp --options runtime -s "<identity>"`.
138
+ Nested-before-container is required. The metallib, wasm, JSON, and PNG
139
+ assets are data, not code, and are skipped.
140
+ 6. **Sign the executable** with the hardened runtime and
141
+ [scripts/packaging/entitlements.plist](../../scripts/packaging/entitlements.plist):
142
+ - `allow-jit` + `allow-unsigned-executable-memory` — JavaScriptCore JITs;
143
+ under the hardened runtime the binary is killed on launch without them;
144
+ - `disable-library-validation` — required for the Homebrew install.
145
+ brew ad-hoc re-signs bundled dylibs during its relocation pass,
146
+ stripping our team ID off them while leaving the executable
147
+ Developer-ID signed; library validation would then reject the team-ID
148
+ mismatch at `dlopen`. Notarization still passes with it.
149
+ 7. **Verify + smoke** — `codesign --verify --strict`, then
150
+ `dist/mlx-bun --version`. A missing entitlement kills the binary here, not
151
+ in a user's `brew install`.
152
+ 8. **Notarize** — `ditto` the bundle into a zip, `xcrun notarytool submit
153
+ --wait` under the notary profile (Apple's automated scan, typically 1–5
154
+ min), delete the zip. The script greps the output for
155
+ `status: Accepted` and **exits non-zero on anything else**, printing the
156
+ `xcrun notarytool log <submission-id>` command to inspect the rejection.
157
+ `notarytool` itself exits 0 on `Invalid`, so without this gate a rejected
158
+ bundle would reach PUBLISH.
159
+ 9. **Package** — `tar -czf dist-release/mlx-bun-v<ver>-arm64.tar.gz` of the
160
+ bundle contents (only the files that exist from the fixed manifest:
161
+ binary, four dylibs, helper, metallib, wasm, pi assets), plus a `.sha256`
162
+ sidecar. The script prints the `version` / `url` / `sha256` triple for
163
+ the formula. (`OUT_DIR` overrides `dist-release`.) Without `PUBLISH=1` it
164
+ stops here and tells you to run `scripts/publish-release.sh`.
165
+ 10. **GitHub release** (`publish-release.sh`, step 1) — copies the tarball to
166
+ a versionless `mlx-bun-arm64.tar.gz`, then `gh release create v<ver>`
167
+ with both assets and the notes file; if the release already exists the
168
+ assets are re-uploaded with `--clobber` instead.
169
+ 11. **Tap push** (step 2) — clones `joshuarossi/homebrew-tap`, rewrites
170
+ `version` / `url` / `sha256` in `Formula/mlx-bun.rb` with `sed`, commits
171
+ and pushes only if the diff is non-empty.
172
+ 12. **Mirror the formula** (step 3) — the same three fields are rewritten in
173
+ the in-repo source of truth,
174
+ [scripts/packaging/homebrew/mlx-bun.rb](../../scripts/packaging/homebrew/mlx-bun.rb),
175
+ and left **uncommitted** for you.
176
+ 13. **npm publish** (step 4) — `npm view mlx-bun@<ver>`; if that version is
177
+ already live the step is skipped, otherwise `bun publish`. On failure the
178
+ script exits with the retry hint `bun run publish:npm`.
179
+ 14. **Commit the mirrored formula** — the script's closing line:
180
+ `git commit -am "chore(dist): mlx-bun <ver>"`.
181
+
182
+ Two-step variant: run `./scripts/release-binary.sh` alone, eyeball
183
+ `dist-release/`, then `./scripts/publish-release.sh`. Both are idempotent —
184
+ re-running publish clobbers the release assets, no-ops the tap push, and skips
185
+ npm if the version is live. Env overrides: `MLX_BUN_SIGN_IDENTITY`,
186
+ `NOTARY_PROFILE`, `BUILD_DIR`, `OUT_DIR` (release); `OUT_DIR`, `REPO`,
187
+ `TAP_REPO` (publish).
188
+
189
+ ### The notarization lesson (v0.2.0, 2026-08-24)
190
+
191
+ The first v0.2.0 submission came back **Invalid**. The release added
192
+ `mlx-bun-frame-extract`, a Swift executable, to the bundle; the signing step
193
+ matched only `*.dylib` and `*.node`, so the helper reached Apple with the
194
+ build script's ad-hoc signature — no Developer ID, no hardened runtime, no
195
+ timestamp — and notarization rejects any nested Mach-O signed that way. The
196
+ old script also treated `notarytool`'s exit 0 as success, which would have
197
+ let the rejected bundle go on to publish.
198
+
199
+ Two changes, both in `scripts/release-binary.sh`: helper executables are
200
+ matched **by name** in the nested-signing pass (add every new helper there
201
+ when it lands — the manifest in the packaging step is the checklist), and
202
+ the script fails on any status other than `Accepted`. The resubmission was
203
+ accepted and the release shipped the same day.
204
+
205
+ ### Stapling, quarantine, and where notarization matters
206
+
207
+ A flat CLI bundle **cannot be stapled** (`stapler` only handles `.app` /
208
+ `.dmg` / `.pkg`); the notarization ticket lives on Apple's servers, and
209
+ Gatekeeper consults it online only when a copy carries the
210
+ `com.apple.quarantine` xattr. Homebrew's download and the installer's
211
+ `curl` do not set that xattr, so both run prompt-free regardless;
212
+ notarization is load-bearing for a browser-downloaded copy (or a future
213
+ Cask). `xattr -d com.apple.quarantine <file>` is the manual escape hatch for
214
+ a quarantined copy on an offline machine.
215
+
216
+ ## Channel: Homebrew
217
+
218
+ `brew install joshuarossi/tap/mlx-bun`; upgrades with
219
+ `brew upgrade joshuarossi/tap/mlx-bun`. The formula
220
+ ([scripts/packaging/homebrew/mlx-bun.rb](../../scripts/packaging/homebrew/mlx-bun.rb),
221
+ mirrored to the tap by the publish script):
222
+
223
+ - `depends_on arch: :arm64`, `depends_on macos: :sonoma` — bump the macOS
224
+ floor if MLX needs newer;
225
+ - `libexec.install Dir["*"]` then `bin.install_symlink libexec/"mlx-bun"` —
226
+ the whole bundle lands in `libexec`, and the dylibs and pi assets resolve
227
+ next to the executable through Bun's realpath of `execPath`;
228
+ - `test do` asserts `mlx-bun --version` prints the formula version.
229
+
230
+ The formula deliberately ships everything in one tarball rather than the
231
+ npm approach of a small package plus a first-run download, so `brew install`
232
+ is the only network step and the entire bundle is one signed, notarized
233
+ artifact. Before pushing a formula change by hand, `brew audit --strict --new
234
+ joshuarossi/tap/mlx-bun` catches most issues and `brew install
235
+ --build-from-source` + `brew test` runs the `test do` block locally.
236
+
237
+ ## Channel: direct download
126
238
 
127
239
  `publish-release.sh` uploads two assets per release: the versioned tarball
128
- (`mlx-bun-v<ver>-arm64.tar.gz`) **and** a versionless stable copy
129
- (`mlx-bun-arm64.tar.gz`) pinned to `releases/latest`. This lets the
130
- install script target a URL that never changes:
240
+ and a versionless `mlx-bun-arm64.tar.gz`, so `releases/latest` has a URL
241
+ that never changes:
131
242
 
132
243
  ```
133
244
  https://github.com/joshuarossi/mlx-bun/releases/latest/download/mlx-bun-arm64.tar.gz
134
245
  ```
135
246
 
136
- The user-facing install path is the script at
137
- [`website/public/install.sh`](../../website/public/install.sh) (served at
138
- `mlx-bun.dev/install.sh`), which resolves that URL, extracts the bundle, and
139
- links `mlx-bun` onto `PATH`:
140
- ```sh
141
- curl -fsSL https://mlx-bun.dev/install.sh | sh
142
- ```
247
+ The user-facing path is [website/public/install.sh](../../website/public/install.sh)
248
+ (served at `mlx-bun.dev/install.sh`):
143
249
 
144
- Without the script, the same stable URL streams straight to `tar`:
145
250
  ```sh
146
- curl -fsSL https://github.com/joshuarossi/mlx-bun/releases/latest/download/mlx-bun-arm64.tar.gz \
147
- | tar -xz -C /usr/local/bin mlx-bun
251
+ curl -fsSL https://mlx-bun.dev/install.sh | sh
148
252
  ```
149
253
 
150
- Note: **browser downloads and `curl`-to-file** (e.g. `curl -O ...`) are
151
- quarantined by Gatekeeper — macOS sets the `com.apple.quarantine` xattr on
152
- the saved file. The piped one-liner above streams directly to `tar` and
153
- never writes a quarantined file, so it runs without any Gatekeeper prompt.
154
- For the browser/curl-to-file path, the notarization ticket resolves the
155
- Gatekeeper check online; `xattr -d com.apple.quarantine mlx-bun` is the
156
- manual escape hatch if offline.
254
+ It checks for Darwin/arm64, downloads that URL (or a pinned tag via
255
+ `MLX_BUN_VERSION=v<ver>`), extracts the **whole** bundle into
256
+ `MLX_BUN_INSTALL_DIR` (default `~/.mlx-bun`), and symlinks `mlx-bun` into the
257
+ first writable of `~/.local/bin`, `/usr/local/bin`, `/opt/homebrew/bin` —
258
+ or prints the `PATH` line to add. Extract into a directory, never just the
259
+ `mlx-bun` file: the executable alone would fall through to the native-pack
260
+ download on first run and lose the pi terminal's assets.
157
261
 
158
- ## npm / bunx
159
-
160
- mlx-bun is published to npm as `mlx-bun`. Install or run without a
161
- permanent install:
262
+ ## Channel: npm / bunx
162
263
 
163
264
  ```sh
164
- # one-off (no install)
165
- bunx mlx-bun
166
-
167
- # permanent global install
168
- bun install -g mlx-bun
265
+ bunx mlx-bun # one-off, no install
266
+ bun install -g mlx-bun # permanent
169
267
  mlx-bun --version
170
268
  ```
171
269
 
172
- The npm package is a thin launcher (no postinstall hook): it imports
173
- `src/cli.ts` under Bun, which fetches the small (~52 MB compressed,
174
- sha256-verified) native runtime pack — `libmlxc`/`libmlx`/`libjaccl`/
175
- `mlx.metallib` plus `libmlx_bun_expert_io.dylib` — into
176
- `~/Library/Caches/mlx-bun/` on first invocation if
177
- no copy is already resolvable (env / beside the binary / cache /
178
- Homebrew). This is the same npm/sidecar mechanism described above, not
179
- the signed/notarized Homebrew bundle. `bun publish` is already run
180
- automatically and idempotently as step 4 of `PUBLISH=1
181
- ./scripts/release-binary.sh`; run it standalone only as a manual
182
- fallback/retry:
183
-
184
- ```sh
185
- bun publish # manual retry; package.json version must already be bumped
186
- ```
187
-
188
- ### Publishing the first-run native pack
189
-
190
- The npm/bunx path has an independent, versioned release asset. Whenever its
191
- file manifest changes, build and publish it before shipping code that names the
192
- new `NATIVE_PACK_VERSION`:
270
+ The npm package is **source, not a binary**. `package.json` `files[]` ships
271
+ `bin/`, `src/`, `docs/`, `README.md`, `LICENSE`, `THIRD_PARTY_LICENSES.md`;
272
+ `exports["."]` points at `src/index.ts` (the library API), `bin.mlx-bun` at
273
+ [bin/mlx-bun.mjs](../../bin/mlx-bun.mjs). There is no postinstall hook and
274
+ no build step. `scripts/packaging/` is not in `files[]`, so the pi
275
+ adapter extension
276
+ ([scripts/packaging/pi-extensions/mlx-bun-adapter.ts](../../scripts/packaging/pi-extensions/mlx-bun-adapter.ts))
277
+ is installed by copying it from the repo into `~/.pi/agent/extensions/`.
278
+
279
+ **The launcher** is plain `.mjs` so any runtime can parse it before anything
280
+ touches `bun:ffi` / `bun:sqlite`. It exits with an install hint when `Bun` is
281
+ undefined (Node), when `Bun.version` is below `MIN_BUN` (kept equal to
282
+ `engines.bun`), or when the platform is not darwin/arm64; otherwise it
283
+ imports `src/cli.ts`.
284
+
285
+ **First run: the native runtime pack.** Before importing anything that
286
+ `dlopen`s, `src/cli.ts` calls `ensureNativeRuntime()` (`src/native-pack.ts`).
287
+ If no runtime resolves through the order above, it downloads
288
+ `mlx-bun-native-v<ver>-<arch>.tar.gz` from the GitHub release tagged
289
+ `native-v<ver>` (override the URL with `MLX_BUN_NATIVE_PACK_URL`) through the
290
+ same resumable, sha256- and size-verified `downloadOne` path as model
291
+ downloads, extracts it into a staging directory, checks every file in
292
+ `NATIVE_PACK_FILES` is present, and renames it into
293
+ `~/Library/Caches/mlx-bun/native-v<ver>-<arch>/` — a crashed extract never
294
+ leaves a half-populated cache. Dev trees and embedders resolve via
295
+ Homebrew/env or the sidecar and never hit this path.
296
+
297
+ The pack contains the six native files: `libmlxc.dylib`, `libmlx.dylib`,
298
+ `libjaccl.dylib`, `mlx.metallib`, `libmlx_bun_expert_io.dylib`,
299
+ `mlx-bun-frame-extract`. It is **versioned independently** of the package
300
+ (`NATIVE_PACK_VERSION` in `src/native-pack.ts`, not `package.json`), because
301
+ it changes only when MLX or the helper set changes.
302
+
303
+ ### Publishing a new native pack
304
+
305
+ Whenever the pack's file manifest or the MLX runtime changes, publish the pack
306
+ **before** the package release that depends on it — the download 404s until
307
+ the `native-v<ver>` release exists:
193
308
 
194
309
  ```sh
195
- sh scripts/build-native-pack.sh 0.2.0 dist-native
196
- gh release create native-v0.2.0 \
197
- dist-native/mlx-bun-native-v0.2.0-arm64.tar.gz \
198
- dist-native/mlx-bun-native-v0.2.0-arm64.tar.gz.sha256 \
199
- --title "mlx-bun native runtime v0.2.0" \
200
- --notes "Adds the bounded native expert-I/O helper required by direct Colibri GLM-5.2."
310
+ sh scripts/build-native-pack.sh <ver> dist-native
311
+ gh release create native-v<ver> \
312
+ dist-native/mlx-bun-native-v<ver>-arm64.tar.gz \
313
+ dist-native/mlx-bun-native-v<ver>-arm64.tar.gz.sha256 \
314
+ --title "mlx-bun native runtime v<ver>" --notes "<what changed>"
201
315
  ```
202
316
 
203
- For v0.2.0 the arm64 archive is 52,307,647 bytes with SHA-256
204
- `9bd3795c5ea8f52b18413501f2d68c32c264a20751302300a08dc04cd67df97c`.
205
- It contains `libmlxc.dylib`, `libmlx.dylib`, `libjaccl.dylib`,
206
- `mlx.metallib`, and `libmlx_bun_expert_io.dylib`. These values must match
207
- `src/native-pack.ts`; a fresh-cache extraction plus real MLX dlopen and native
208
- expert read is the pre-publish smoke.
317
+ `build-native-pack.sh` stages the same six files with the same
318
+ `install_name_tool` fixups and ad-hoc signatures as the bundle, tars them,
319
+ and prints the three constants to bake into `src/native-pack.ts`:
320
+ `NATIVE_PACK_VERSION`, the arm64 `SHA256`, and the arm64 `SIZE`. Paste them,
321
+ add any new file to `NATIVE_PACK_FILES`, and commit before bumping the
322
+ package. Pre-publish smoke: a fresh-cache extraction plus a real MLX
323
+ `dlopen` (and, when the helpers changed, an expert read or a video decode).
324
+ The pack is ad-hoc signed only — `build-native-pack.sh` never touches a
325
+ Developer ID and nothing notarizes it; it is `dlopen`ed by the user's own Bun
326
+ process, not by our signed executable. The most recent pack
327
+ (`native-v0.3.0`, published 2026-08-22) added `mlx-bun-frame-extract`.
328
+
329
+ The working tree targets native pack 0.4.0 with MLX 0.32.2 and MLX-C
330
+ `c74db5307cc8ce122f48d97ef951b30578674e7f`. Its six-file macOS 14 candidate
331
+ has been built and verified locally. It is not published. Release the native
332
+ asset before publishing any package that uses this manifest. Runtime bindings
333
+ match this one C API, and startup checks the linked core version. The old
334
+ runtime and source controls remain separate for benchmark comparisons.
335
+
336
+ CI builds that pinned C wrapper with
337
+ `sh scripts/packaging/build-native-runtime.sh <new-output-directory>` and sets
338
+ `MLX_BUN_LIBMLXC` to its `lib/libmlxc.dylib`. The script verifies the official
339
+ macOS 14 MLX-Metal archive hash and checks out the exact MLX-C commit. It
340
+ extracts native libraries and headers without running Python or compiling
341
+ Metal sources. This also reproduces local native-pack build inputs before
342
+ the candidate is published; Homebrew's C wrapper is not the CI runtime.
343
+
344
+ Managed jobs in the compiled binary re-exec that binary through a private job
345
+ entry, with the database/log paths passed in the environment. They do not depend
346
+ on a Bun executable or a TypeScript source tree. The build runs
347
+ `scripts/packaging/verify-jobs.ts` as a compiled smoke: subprocess completion,
348
+ progress persistence and the CLI entry must pass before the bundle is accepted.