spb/zyquo-mlx Public MIT
The local MLX foundry for your Mac — run, fine-tune, quantize, and ship models. Nothing leaves your machine.
Swift 93.4%
Python 3.8%
Makefile 2.2%
Shell 0.5%
1<!--2 MLX-RESEARCH.md3 Zyquo MLX45 Author: Simon-Pierre Boucher6 Mail: contact@spboucher.ai7-->89# Zyquo MLX — MLX Framework Research (Ground Truth 2026-07-30)1011> Phase 0.A research document. Every version number and API name below was12> verified against live sources (GitHub releases API, raw source files at13> `main`, PyPI JSON, official docs) on 2026-07-30, plus an empirical build test14> on this machine. Items not verifiable against a primary source are marked15> *UNVERIFIED*.1617**Version snapshot (live-verified):**1819| Component | Version | Date | Source |20|---|---|---|---|21| `mlx` (core, PyPI/GitHub) | **0.32.0** | 2026-07-07 | github.com/ml-explore/mlx |22| `mlx-swift` | **0.31.6** | 2026-07-02 | github.com/ml-explore/mlx-swift |23| `mlx-swift-lm` | **3.31.4** | 2026-06-30 | github.com/ml-explore/mlx-swift-lm |24| `mlx-lm` (PyPI) | **0.31.3** | 2026-04-22 | pypi.org/project/mlx-lm |25| `swift-transformers` | **1.3.3** | 2026-05-16 | github.com/huggingface/swift-transformers |26| `swift-huggingface` (HubClient) | **0.9.0** | — | github.com/huggingface/swift-huggingface |27| `mlx-vlm` (PyPI) | **0.6.8** | 2026-07-27 | github.com/Blaizzy/mlx-vlm |28| `mlx-whisper` (PyPI) | **0.4.3** | 2025-08-29 | ml-explore/mlx-examples/whisper |29| `mlx-audio` (PyPI) | **0.4.6** | 2026-07-25 | github.com/Blaizzy/mlx-audio |3031---3233## 1. What MLX Is — Core Primitives3435- **An array framework for ML on Apple Silicon** from Apple ML research:36 NumPy-like `mlx.core`, NN modules `mlx.nn`, `mlx.optimizers`. C++ core with a37 Metal backend (a CUDA/Linux backend also exists now — visible in mlx-swift's38 `Package.swift`, which conditionally compiles `mlx/backend/cuda` on Linux).39- **Lazy evaluation & `eval()`**: operations record a compute graph; nothing40 executes until `mx.eval(...)` or an implicit eval (printing, `.item()`,41 NumPy conversion, `mx.save`). Laziness enables transformations (`grad`,42 `vmap`, `compile`), dead-output elimination, and loading weights without43 materializing intermediates. Guidance: eval at outer-loop boundaries (after44 an optimizer step); graphs of "tens to thousands of ops" per eval are the45 sweet spot. (ml-explore.github.io/mlx — lazy evaluation guide, fetched.)46- **Unified memory**: arrays live in memory shared by CPU and GPU. There is no47 data placement — only *operation* placement via `stream:`/`device:`48 (`mx.gpu` / `mx.cpu`). The scheduler manages cross-stream dependencies49 automatically. (Unified-memory guide, fetched.)50- **Autodiff**: `mx.grad` / `mx.value_and_grad`, composable with `mx.vmap` and51 `mx.compile`. Module-aware: `nn.value_and_grad(model, loss_fn)`; Swift:52 `MLXNN.valueAndGrad(model:_:)` (3 public overloads, verified in source).53- **Dispatch to Metal**: the core dispatches lazily-built graphs to54 precompiled + runtime-JIT Metal kernels (`backend/metal/kernels`,55 `jit_kernels.cpp`, `default.metallib`); quantized matmul and56 scaled-dot-product-attention are dedicated kernels.5758---5960## 2. Swift vs. Python — The Honest Capability Split (2026-07-30)6162**Major reorg (critical):** `MLXLLM`, `MLXVLM`, `MLXLMCommon`, `MLXEmbedders`63moved out of `mlx-swift-examples` into **`ml-explore/mlx-swift-lm`** (3.x).643.x decoupled downloads/tokenizers into protocols (`Downloader`, `Tokenizer`,65`TokenizerLoader`) with concrete impls supplied by the **`MLXHuggingFace`66macros** (`#hubDownloader()`, `#huggingfaceTokenizerLoader()`,67`#huggingFaceLoadModelContainer(...)`) backed by `swift-huggingface` +68`swift-transformers`. `mlx-swift-examples` (renamed package `mlx-libraries`)69now only ships `StableDiffusion` and `MLXMNIST` + example apps.7071| Capability | Native Swift today | Python | Zyquo MLX strategy |72|---|---|---|---|73| LLM inference (streaming, KV cache, chat) | ✅ MLXLLM/MLXLMCommon (`ChatSession`, `ModelContainer`, speculative decoding, KV-cache quantization) | mlx-lm | **Swift** |74| VLM inference | ✅ MLXVLM (smaller zoo; no omni/audio) | mlx-vlm (broader) | **Swift**; Py optional for exotic/omni |75| Embeddings | ✅ MLXEmbedders | mlx-embeddings (thin, v0.1.0) | **Swift** |76| Speech (STT/TTS) | ❌ no official Swift package | ✅ mlx-whisper / mlx-audio | **Python bridge** |77| Image generation | ✅ `StableDiffusion` (SD 2.1 / SDXL-turbo) in mlx-swift-examples; FLUX ❌ | ✅ mlx-examples flux + SD scripts | Swift for SD; **Python bridge for FLUX** |78| LoRA/DoRA training | ✅ `LoRATrain` (MLXLLM) — real but text-only datasets, no grad-checkpoint/accum, no numbered checkpoints | ✅ mlx_lm.lora (chat/completions datasets, mask_prompt, full/dora, grad checkpoint/accum, checkpoints, schedules) | **Python bridge primary** (see TRAINING-RESEARCH.md §8.3) |79| QLoRA (quantized base) | ✅ `QLoRALinear` | ✅ implicit when base is quantized | Both |80| Adapter interchange | ✅ `LoRAContainer.from(directory:)` — documented mlx-lm-compatible (`adapter_config.json` + `adapters.safetensors`) | native | Interoperable both ways |81| Full fine-tuning | ❌ no packaged pipeline (primitives exist) | ✅ `--fine-tune-type full` | **Python bridge** |82| Quantization + HF→MLX conversion | ✅ **new native Swift**: `LLMModelFactory.convert(from:to:options:)` (safetensors input only, LLMs; affine/mxfp4) | ✅ mlx_lm.convert (+ AWQ/DWQ/GPTQ/dynamic, mixed recipes, `.bin`, GGUF export, VLM convert) | Swift for standard LLM convert/quant; **Python for advanced** |83| Fuse adapter → disk | ✅ in-memory fuse; packaged fuse-to-disk one-liner UNVERIFIED | ✅ mlx_lm.fuse (+ `--dequantize`, GGUF) | **Python safest**; Swift feasible |84| Evaluation (ppl / lm-eval) | partial (`LoRATrain.evaluate` loss) | ✅ mlx_lm.evaluate (lm-eval), mlx_lm.perplexity, `--test` | **Python bridge** |85| OpenAI-compatible server | ❌ | ✅ mlx_lm.server / mlx_vlm.server | out of scope v1 |8687---8889## 3. Model Types & the Current MLX Zoo9091### 3.1 Swift-native architectures (verified from factory registries at main)9293- **LLM** (`LLMTypeRegistry`, keyed by `config.json` `model_type`): llama,94 mistral, mixtral, mistral3, phi, phi3, phimoe, gemma, gemma2,95 gemma3/gemma3_text, gemma3n, gemma4/gemma4_unified/gemma4_text, qwen2, qwen3,96 qwen3_moe, qwen3_next, qwen3_5, qwen3_5_moe, qwen3_5_text, smollm3,97 deepseek_v2, deepseek_v3, glm4, glm4_moe, glm4_moe_lite, gpt_oss, granite,98 granitemoehybrid, cohere, starcoder2, openelm, internlm2, minicpm, mimo,99 minimax, falcon_h1, bitnet, ernie4_5, lfm2, lfm2_moe, exaone4, olmoe, olmo2,100 olmo3, bailing_moe, nemotron_h, jamba, mamba2, apertus, and more101 (Qwen2.5 = `qwen2`; DeepSeek-R1 distills use their base arch).102- **VLM** (`VLMModelFactory`): paligemma, qwen2_vl, qwen2_5_vl, qwen3_vl,103 qwen3_5, qwen3_5_moe, idefics3, gemma3, gemma4, gemma4_unified, smolvlm,104 fastvlm (llava_qwen2), pixtral, mistral3, lfm2_vl, glm_ocr.105- **Embedders** (`EmbedderTypeRegistry`): bert, roberta, xlm-roberta,106 distilbert, nomic_bert, qwen3 (Qwen3-Embedding), lfm2, gemma3/gemma3n107 (EmbeddingGemma). Curated `EmbedderRegistry` includes bge family, MiniLM,108 nomic-embed-text v1/v1.5, e5, mixedbread, Qwen3-Embedding.109- **Image gen**: `StableDiffusion` product (SD 2.1, SDXL-turbo).110- **Bonus (new since 2025, all verified in mlx-swift-lm):** native conversion +111 quantization (`ModelConversion.swift`), LoRA/DoRA adapters + fusing,112 LoRA training, speculative decoding + MTP drafters, KV-cache quantization113 (incl. "TurboQuant"), guided generation (`MLXGuidedGeneration`, JSON114 Schema/EBNF via vendored xgrammar), tool calling with per-family parsers,115 prompt-cache persistence, `MLXFoundationModels` bridge (macOS 27 SDK).116117### 3.2 Python-first packages118119| Package | What | Interface |120|---|---|---|121| mlx-lm 0.31.3 | LLM inference/serve/convert/quant/train | CLIs: `mlx_lm.generate/chat/convert/fuse/lora/server/evaluate/manage/benchmark/cache_prompt/perplexity/upload`; quant CLIs `mlx_lm.awq/dwq/gptq/dynamic_quant`. Python: `load()`, `generate()`, `stream_generate()` (yields `GenerationResponse{text, token, prompt_tps, generation_tps, peak_memory, finish_reason}`), `make_sampler(...)` |122| mlx-vlm 0.6.8 | VLM + omni (audio/video) inference & LoRA | `mlx_vlm.generate/chat/convert/server`; huge zoo (Qwen-VL/3.5, gemma 3/4, DeepSeek-OCR, Moondream, MiniCPM-V/o, Pixtral, LLaVA, Idefics…) |123| mlx-whisper 0.4.3 | STT | `mlx_whisper audio.mp3 [-f fmt --model repo]`; API `mlx_whisper.transcribe()`; needs ffmpeg |124| mlx-audio 0.4.6 | TTS/STT/STS | `mlx_audio.tts.generate`, `mlx_audio.stt.generate`, `mlx_audio.convert`, `mlx_audio.server` |125| mlx-examples (repo) | SD + FLUX image gen (script-based), FLUX LoRA (dreambooth.py) | `stable_diffusion/txt2image.py`, `flux/txt2image.py --model schnell\|dev` |126127---128129## 4. Inference API Specifics (Swift-first, exact names from source)130131### 4.1 Loading (mlx-swift-lm 3.x)132133```swift134// Free functions in MLXLMCommon (ModelFactory.swift):135loadModelContainer(from: any Downloader, using: any TokenizerLoader,136 configuration: ModelConfiguration,137 progressHandler: @Sendable (Progress) -> Void) async throws -> ModelContainer138loadModelContainer(from: any Downloader, using: any TokenizerLoader,139 id: String, revision: String = "main", …) async throws -> ModelContainer140loadModelContainer(from directory: URL, using: any TokenizerLoader)141 async throws -> ModelContainer // pure-local — ideal for our library142// Factory-scoped: LLMModelFactory.shared.loadContainer(...) / VLMModelFactory.shared...143// Macros (MLXHuggingFace): #huggingFaceLoadModelContainer(configuration:), #hubDownloader(), #huggingfaceTokenizerLoader()144```145146`ModelContainer` is a `Sendable final class` wrapping `ModelContext`147(model + tokenizer + processor) with `perform { }` / `update { }` access;148exposes `configuration`, `tokenizer`, `processor`, `modelDirectory`,149`prepare(input:) -> LMInput`, `generate(input:parameters:) ->150AsyncStream<Generation>`, `encode/decode`, `applyChatTemplate(messages:)`.151152High-level chat: `ChatSession(model)` → `respond(to:)` /153`streamResponse(to:)` / `streamDetails(...)`, `clear()`, `saveCache(to:)`;154supports instructions, tools, speculative decoding.155156### 4.2 Streaming generation (core path)157158```swift159generate(input: LMInput, cache: [KVCache]? = nil, parameters: GenerateParameters,160 context: ModelContext, …) throws -> AsyncStream<Generation>161162enum Generation { case chunk(String); case info(GenerateCompletionInfo); case toolCall(ToolCall) }163struct GenerateCompletionInfo {164 promptTokenCount: Int; generationTokenCount: Int165 promptTime: TimeInterval // → TTFT166 generateTime: TimeInterval // → tok/s167 stopReason: GenerateStopReason // .stop / .length / .cancelled168 // + speculative-decoding stats169}170```171172Callback-based `generate` overloads are **deprecated** in favor of173`AsyncStream`. Cancellation = cancel the Task / terminate the stream174(`generateTask` returns `(AsyncStream, Task)`). Token-level:175`generateTokens(...) -> AsyncStream<TokenGeneration>`. Per-run stats for the176Playground (tok/s, TTFT) come from `GenerateCompletionInfo`.177178### 4.3 GenerateParameters (verified fields)179180`prefillStepSize`, `maxTokens`, `maxKVSize` (→ `RotatingKVCache`),181`kvBits` + `kvGroupSize` (default 64) + `quantizedKVStart`,182`kvScheme` ("affine4"/"affine8"/"turbo8v3"…), `temperature`, `topP`, `topK`,183`minP`, `seed: UInt64?` (nil = entropy; global RNG via `MLXRandom.seed`),184`repetitionPenalty` (+ context size).185186### 4.4 Tokenizers & chat templates187188`MLXLMCommon.Tokenizer` protocol: `encode(text:addSpecialTokens:)`,189`decode(tokenIds:skipSpecialTokens:)`, `bosToken/eosToken`,190`applyChatTemplate(messages:tools:additionalContext:) throws -> [Int]`.191Concrete impl from swift-transformers via the MLXHuggingFace macro adapter.192Messages: `Chat.Message` (`.system/.user/.assistant/.tool`, with193`images:/videos:/audios:`) → `UserInput` → `processor.prepare(input:)` →194`LMInput`. VLM: `UserInput(chat: [.user("Describe", images: [.url(fileURL)])],195processing: .init(resize: …))`.196197### 4.5 KV cache198199`KVCache` protocol; `KVCacheSimple`, `RotatingKVCache`, `QuantizedKVCache`,200`ChunkedKVCache`, `MambaCache`, `CacheList`; persistence via201`savePromptCache(...)` / `loadPromptCache(...)`.202203### 4.6 Memory management (RENAMED — important)204205`MLX.GPU.set(cacheLimit:)` & friends are **deprecated**; current API is the206**`MLX.Memory`** enum (`Source/MLX/Memory.swift`):207208```swift209Memory.cacheLimit = 2 * 1024 * 1024 // deprecated alias: GPU.set(cacheLimit:)210Memory.memoryLimit = … // default 1.5× device recommended working set211Memory.activeMemory; Memory.cacheMemory; Memory.peakMemory212let snap = Memory.snapshot() // Snapshot{activeMemory, cacheMemory, peakMemory}, .delta(other)213Memory.clearCache() // free all cached buffers214GPU.deviceInfo() // architecture, maxBufferSize, maxRecommendedWorkingSetSize, memorySize215GPU.resetPeakMemory()216```217218**Unload pattern (drives Playground/Engine):** release all `ModelContainer`219references → `Memory.clearCache()` → verify with `Memory.snapshot()` deltas.220Doc comment (verified): small cache limits (~2 MB) often perform as well as221unconstrained — expose in Settings › Compute.222223### 4.7 Embeddings (MLXEmbedders 3.x)224225```swift226let container = try await EmbedderModelFactory.shared.loadContainer(227 from: #hubDownloader(), using: #huggingfaceTokenizerLoader(),228 configuration: EmbedderRegistry.nomic_text_v1_5)229let vectors: [[Float]] = await container.perform { model, tokenizer, pooling in230 let ids = MLXArray(tokenizer.encode(text: text, addSpecialTokens: true))[.newAxis, 0...]231 let out = model(ids, positionIds: nil, tokenTypeIds: nil, attentionMask: nil)232 return pooling(out, normalize: true).asArray(Float.self)233 // Pooling.Strategy: .mean/.cls/.first/.last/.max/.none234}235```236237### 4.8 Training primitives in Swift238239`MLXNN.valueAndGrad`; `MLXOptimizers`: SGD, RMSprop, AdaGrad, AdaDelta, Adam,240AdamW, Adamax, Lion, Adafactor, Muon, MultiOptimizer; schedulers:241`exponentialDecay`, `stepDecay`, `cosineDecay`, `linearSchedule`,242`joinSchedules`. `MLX.QuantizationMode`: `.affine`, `.mxfp4`.243Details of `LoRATrain` in `docs/TRAINING-RESEARCH.md` §8.244245---246247## 5. Quantization & Conversion248249### 5.1 MLX core quantization (verified docs)250251`mx.quantize(w, group_size=None, bits=None, mode='affine', *, global_scale=None)`252— **affine**: group sizes 32/64/128, bits **2,3,4 (default),5,6,8**,253scale+bias per group. **mxfp4/mxfp8**: E8M0 scales (group 32); **nvfp4**:254E4M3 scale (group 16). **No NF4 mode exists.**255256### 5.2 `mlx_lm.convert` (verified argparse at main)257258```259mlx_lm.convert --hf-path <repo-or-dir> [--mlx-path mlx_model]260 [-q] [--q-bits N] [--q-group-size G]261 [--q-mode affine|mxfp4|nvfp4|mxfp8]262 [--quant-predicate mixed_2_6|mixed_3_4|mixed_3_6|mixed_4_6]263 [--dtype float16|bfloat16|float32] [-d/--dequantize] [--upload-repo] [--trust-remote-code]264```265266Mode defaults: affine → (group 64, 4 bits); mxfp4 → (32, 4); nvfp4 → (16, 4);267mxfp8 → (32, 8). Mixed recipes are llama.cpp-Q4_K_M-style (affine only).268Advanced (beyond round-to-nearest): **`mlx_lm.awq`, `mlx_lm.dwq`,269`mlx_lm.gptq`, `mlx_lm.dynamic_quant`** — first-class CLIs.270`convert()` also exists as a Python API. Swift-native equivalent:271272```swift273let result = try await LLMModelFactory.shared.convert(274 from: directory, to: outputDirectory,275 options: .init(bits: 4, groupSize: 64, mode: .affine),276 progressHandler: { p in /* ModelConversionProgress{stage, fractionCompleted, message} */ })277// safetensors input only; PyTorch .bin explicitly out of scope; LLMs only278```279280### 5.3 On-disk MLX model format (verified `save_model` in utils.py)281282- `config.json` with top-level `"quantization": {"group_size", "bits", "mode"}`283 (+ per-layer overrides for mixed/partial quantization).284- Weights: `model.safetensors` or sharded `model-0000X-of-0000N.safetensors`285 (**max 5 GB/shard**), each with safetensors metadata `{"format": "mlx"}`.286- `model.safetensors.index.json` with `metadata.total_size`,287 `metadata.total_parameters`, `weight_map`.288- Tokenizer files (`tokenizer.save_pretrained`), copied `*.py` +289 `generation_config.json`, and an mlx-tagged `README.md` model card.290291→ `ModelStore` validates a local model dir by checking: `config.json`292(`model_type`, optional `quantization`), weight file(s) + index consistency,293tokenizer files present.294295---296297## 6. Build & Execution Strategy (resolved — details in `docs/BUILD.md`)298299**Build (empirically tested on this Mac, 2026-07-30):** `swift build` with CLT300only compiles all C++/Swift then **fails** at `CompileMetalFile301steel_attention.metal` — `unable to spawn process 'metal'`. The CLT ships no302Metal compiler; no prebuilt-metallib distribution of mlx-swift exists yet303(PR #430 / mlx#3597 / mlx-swift#416 in flight, not landed). The Metal Toolchain304is an Xcode 26+ downloadable component (`xcodebuild -downloadComponent305metalToolchain`) and cannot be installed with CLT alone.306**→ Adapted rule per charter 0.A.6: install full Xcode.app strictly as a307toolchain, drive everything via command-line `xcodebuild`/`swift build`308from the Makefile. No IDE. No hand-authored `.xcodeproj`.**309The app bundle must ship the **`mlx-swift_Cmlx.bundle`** resource bundle310(contains `default.metallib`); existence proof of a signed/notarized311xcodebuild-built mlx-swift app: sfomuseum/Docent (mlx-swift issue #345).312313**Execution model (the 0.A.6 decision):**3143151. **Native Swift (in-process)** — LLM/VLM/embeddings inference, Stable316 Diffusion image gen, standard HF→MLX conversion + affine/mxfp4 quantization317 of safetensors LLMs, adapter load/unload/fuse in memory.3182. **Embedded Python venv (out-of-process via `PythonRunner`)** — fine-tuning319 (LoRA/QLoRA/DoRA/full via `mlx_lm.lora` API with a custom320 `TrainingCallback` → JSON-lines protocol), adapter fuse-to-disk + GGUF321 export, advanced quantization (AWQ/DWQ/GPTQ/mixed), `.bin` conversions,322 Whisper STT, mlx-audio TTS, FLUX image gen, evaluation323 (`--test` ppl, `mlx_lm.evaluate`).324 - Venv: **Python 3.12 pinned** (mlx wheels are cp310–cp314,325 macOS ≥ 14 arm64-only — aligns with the Apple-Silicon gate), provisioned326 with **uv** into `~/Library/Application Support/ZyquoMLX/py/` on first327 run (never inside the signed bundle; never touching system Python).328 Pins: `mlx-lm==0.31.3`, `mlx-vlm==0.6.8`, `mlx-whisper==0.4.3`,329 `mlx-audio==0.4.6` (+ lockfile via `uv pip compile`); uv supports330 `--offline` + local wheel cache for repair-offline behavior.331 - Progress protocol: our own JSON lines on stdout emitted by pinned helper332 scripts (`PyBridge/scripts/`) — **never scrape mlx-lm's stdout**333 (format changed between 0.31.3 and main; see TRAINING-RESEARCH.md §5).334335---336337## 7. Memory & Performance338339- **Inference RAM ≈ weights + KV cache + overhead.** Weights: 4-bit affine340 gs64 ≈ 0.5625 B/param (verified against real repo sizes, see MODELS.md);341 8-bit ≈ 1.07; bf16 ≈ 2.0. KV cache (fp16):342 `2 × layers × kvHeads × headDim × seqLen × 2 bytes` — e.g. Qwen3-8B343 (36L, 8 KV heads, 128 dim) at 8k ctx ≈ 1.2 GB; quantizable via344 `kvBits`/`kvScheme`. (Formula standard practice; per-model numbers345 *UNVERIFIED* against one official doc — `MemoryAdvisor` computes from346 config.json fields and calibrates in Phase 7.)347- **`Memory.memoryLimit` defaults to 1.5× `maxRecommendedWorkingSetSize`**348 (verified doc comment); macOS caps GPU-visible memory ≈ 66–75% of unified349 RAM — query `GPU.deviceInfo().maxRecommendedWorkingSetSize` at runtime for350 exact gating rather than hardcoding.351- **Training memory**: LoRA ≈ 2–4× the inference footprint of the same base352 (optimizer state + activations); QLoRA on a 4-bit base is the 16–32 GB353 path; full FT ≈ 8 B/param + activations. Full tables in354 TRAINING-RESEARCH.md §6 and MODELS.md §3.355- **Throughput** (third-party 2026 benchmarks, *indicative, UNVERIFIED356 first-party*): M4 Max ≈ 62 tok/s on 8B-4bit, ≈ 38 tok/s on 14B-4bit;357 M4 Air 16 GB ≈ 25–35 tok/s on 9B-4bit; generation is358 memory-bandwidth-bound. First-party per-run stats come from359 `GenerateCompletionInfo` / `GenerationResponse`.360- **This Mac (dev machine): M5 Max, 48 GB** → comfortable up to ~35B 4-bit361 inference, QLoRA ≤ 32B, LoRA ≤ 14B, full FT ≤ ~3–4B.362363---364365## 8. Dependency Decision (feeds Phase 1 `Package.swift`)366367```swift368.package(url: "https://github.com/ml-explore/mlx-swift", .upToNextMinor(from: "0.31.6")),369.package(url: "https://github.com/ml-explore/mlx-swift-lm", .upToNextMajor(from: "3.31.4")),370.package(url: "https://github.com/huggingface/swift-huggingface", from: "0.9.0"),371.package(url: "https://github.com/huggingface/swift-transformers", from: "1.3.0"),372// StableDiffusion (image gen) from mlx-swift-examples ("mlx-libraries") — add in Phase 6 if SD ships in v1373```374375Platform floor: macOS 14 (mlx-swift Package.swift) — Zyquo MLX targets376**macOS 14+, arm64 only**. Note: mlx-swift `main` uses377`swift-tools-version: 6.3 (experimentalCGen)` — depend on **released tags378only**, never branch `main`.379380### Primary sources381382github.com/ml-explore/{mlx, mlx-swift, mlx-swift-lm, mlx-swift-examples,383mlx-lm, mlx-examples} (releases API + raw files at main) ·384ml-explore.github.io/mlx (lazy eval, unified memory, quantize docs) ·385pypi.org/pypi/{mlx, mlx-lm, mlx-vlm, mlx-whisper, mlx-audio}/json ·386github.com/huggingface/{swift-transformers, swift-huggingface} ·387github.com/Blaizzy/{mlx-vlm, mlx-audio} · mlx-swift PR #430, issues #345/#349 ·388local empirical build test (this Mac, 2026-07-30).389