SPB Git

spb/zyquo-mlx

Public MIT

The local MLX foundry for your Mac — run, fine-tune, quantize, and ship models. Nothing leaves your machine.

phase1: SPM manifest (pinned MLX deps), app entry + Apple-Silicon gate, Info.plist, Makefile, README

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
simon-pierre boucher committed (Jul 30, 2026) parent 35d453d Browse files

8 changed files +474 −1

added Makefile +75 −0
@@ -0,0 +1,75 @@
1+#
2+# Makefile
3+# Zyquo MLX
4+#
5+# Author: Simon-Pierre Boucher
6+# Mail: contact@spboucher.ai
7+#
8+# Command-line-only builds (no Xcode IDE, no .xcodeproj) per docs/BUILD.md.
9+# Requires full Xcode installed as a toolchain + Metal toolchain component:
10+# sudo xcode-select -s /Applications/Xcode.app
11+# xcodebuild -downloadComponent metalToolchain
12+#
13+
14+APP_NAME := Zyquo MLX
15+EXEC_NAME := ZyquoMLX
16+BUNDLE_ID := com.zyquo.mlx
17+DIST := dist
18+APP := $(DIST)/$(APP_NAME).app
19+CONFIG ?= release
20+
21+# Use Xcode's toolchain per-command; the machine default (CLT) is untouched.
22+XCODE_DEV_DIR := /Applications/Xcode.app/Contents/Developer
23+DEV := DEVELOPER_DIR=$(XCODE_DEV_DIR)
24+
25+# Build backend per docs/BUILD.md §3.1: try SwiftPM first (Swift 6.4 issues
26+# CompileMetalFile itself); fall back to xcodebuild if metallib is missing.
27+BUILD_DIR := .build
28+BIN_DIR = $(BUILD_DIR)/$(CONFIG)
29+
30+.PHONY: build build-xcodebuild app dev run icon clean release check-toolchain
31+
32+check-toolchain:
33+ @test -d $(XCODE_DEV_DIR) || { echo "error: Xcode toolchain not found at /Applications/Xcode.app — see docs/BUILD.md §2"; exit 1; }
34+
35+build: check-toolchain
36+ $(DEV) swift build -c $(CONFIG)
37+
38+build-xcodebuild: check-toolchain
39+ $(DEV) xcodebuild build \
40+ -scheme $(EXEC_NAME) \
41+ -destination 'platform=OS X,arch=arm64' \
42+ -configuration Release \
43+ -derivedDataPath $(BUILD_DIR)/xcode \
44+ -skipMacroValidation
45+
46+app: build
47+ rm -rf "$(APP)"
48+ mkdir -p "$(APP)/Contents/MacOS" "$(APP)/Contents/Resources"
49+ cp Support/Info.plist "$(APP)/Contents/Info.plist"
50+ cp "$(BIN_DIR)/$(EXEC_NAME)" "$(APP)/Contents/MacOS/$(EXEC_NAME)"
51+ @# Ship every SPM resource bundle — mlx-swift_Cmlx.bundle carries
52+ @# default.metallib; omitting it crashes GPU ops (docs/BUILD.md §3.2).
53+ @for b in "$(BIN_DIR)"/*.bundle; do \
54+ [ -e "$$b" ] && cp -R "$$b" "$(APP)/Contents/Resources/" && echo "bundled $$(basename $$b)"; \
55+ done; true
56+ @if [ -f assets/icon/AppIcon.icns ]; then cp assets/icon/AppIcon.icns "$(APP)/Contents/Resources/AppIcon.icns"; fi
57+ codesign --force --deep --sign - "$(APP)"
58+ @echo "→ $(APP) (ad-hoc signed)"
59+
60+dev: app
61+ open "$(APP)"
62+
63+run: app
64+ "$(APP)/Contents/MacOS/$(EXEC_NAME)"
65+
66+icon:
67+ @# Phase 5: SVG → PNGs → .iconset → .icns (rsvg-convert + iconutil)
68+ bash scripts/make-icon.sh
69+
70+release: app
71+ @# Phase 8: Developer ID signing + notarization + stapling (docs/BUILD.md §4)
72+ @echo "release target completed in Phase 8 — currently ad-hoc only"; exit 1
73+
74+clean:
75+ rm -rf $(BUILD_DIR) $(DIST)
added Package.resolved +149 −0
@@ -0,0 +1,149 @@
1+{
2+ "pins" : [
3+ {
4+ "identity" : "eventsource",
5+ "kind" : "remoteSourceControl",
6+ "location" : "https://github.com/mattt/EventSource.git",
7+ "state" : {
8+ "revision" : "a3a85a85214caf642abaa96ae664e4c772a59f6e",
9+ "version" : "1.4.1"
10+ }
11+ },
12+ {
13+ "identity" : "mlx-swift",
14+ "kind" : "remoteSourceControl",
15+ "location" : "https://github.com/ml-explore/mlx-swift",
16+ "state" : {
17+ "revision" : "0bb916c67f4b9e5c682cbe02a42c701c93ab5021",
18+ "version" : "0.31.6"
19+ }
20+ },
21+ {
22+ "identity" : "mlx-swift-lm",
23+ "kind" : "remoteSourceControl",
24+ "location" : "https://github.com/ml-explore/mlx-swift-lm",
25+ "state" : {
26+ "revision" : "bd4b7434e6bdb588c7ef55706ff8904cb7fd4c57",
27+ "version" : "3.31.4"
28+ }
29+ },
30+ {
31+ "identity" : "swift-argument-parser",
32+ "kind" : "remoteSourceControl",
33+ "location" : "https://github.com/apple/swift-argument-parser",
34+ "state" : {
35+ "revision" : "6a52f3251125d74daf04fcbd5e6f08a75d074382",
36+ "version" : "1.8.2"
37+ }
38+ },
39+ {
40+ "identity" : "swift-asn1",
41+ "kind" : "remoteSourceControl",
42+ "location" : "https://github.com/apple/swift-asn1.git",
43+ "state" : {
44+ "revision" : "a9a5efd40eaf558a2bcd48d64b1d1646be686008",
45+ "version" : "1.7.1"
46+ }
47+ },
48+ {
49+ "identity" : "swift-atomics",
50+ "kind" : "remoteSourceControl",
51+ "location" : "https://github.com/apple/swift-atomics.git",
52+ "state" : {
53+ "revision" : "0442cb5a3f98ab802acb777929fdb446bda11a34",
54+ "version" : "1.3.1"
55+ }
56+ },
57+ {
58+ "identity" : "swift-collections",
59+ "kind" : "remoteSourceControl",
60+ "location" : "https://github.com/apple/swift-collections.git",
61+ "state" : {
62+ "revision" : "a0cb0954ecb21e4e31b0070e6ed5674e8556685a",
63+ "version" : "1.6.0"
64+ }
65+ },
66+ {
67+ "identity" : "swift-crypto",
68+ "kind" : "remoteSourceControl",
69+ "location" : "https://github.com/apple/swift-crypto.git",
70+ "state" : {
71+ "revision" : "47d3869a7291f085c1fb9fb1e6d3b97a793f45c6",
72+ "version" : "4.5.1"
73+ }
74+ },
75+ {
76+ "identity" : "swift-huggingface",
77+ "kind" : "remoteSourceControl",
78+ "location" : "https://github.com/huggingface/swift-huggingface",
79+ "state" : {
80+ "revision" : "b721959445b617d0bf03910b2b4aced345fd93bf",
81+ "version" : "0.9.0"
82+ }
83+ },
84+ {
85+ "identity" : "swift-jinja",
86+ "kind" : "remoteSourceControl",
87+ "location" : "https://github.com/huggingface/swift-jinja.git",
88+ "state" : {
89+ "revision" : "7d0b8880ef8e567dd4e0089f8b99fb354129017c",
90+ "version" : "2.4.2"
91+ }
92+ },
93+ {
94+ "identity" : "swift-nio",
95+ "kind" : "remoteSourceControl",
96+ "location" : "https://github.com/apple/swift-nio.git",
97+ "state" : {
98+ "revision" : "0b18836bd8b0162e7e17a995a3fbee20ed8f3b2b",
99+ "version" : "2.101.3"
100+ }
101+ },
102+ {
103+ "identity" : "swift-numerics",
104+ "kind" : "remoteSourceControl",
105+ "location" : "https://github.com/apple/swift-numerics",
106+ "state" : {
107+ "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2",
108+ "version" : "1.1.1"
109+ }
110+ },
111+ {
112+ "identity" : "swift-syntax",
113+ "kind" : "remoteSourceControl",
114+ "location" : "https://github.com/swiftlang/swift-syntax.git",
115+ "state" : {
116+ "revision" : "79e4b74a295b6eb74a8b585e3a39d29e70c1dbd1",
117+ "version" : "603.0.2"
118+ }
119+ },
120+ {
121+ "identity" : "swift-system",
122+ "kind" : "remoteSourceControl",
123+ "location" : "https://github.com/apple/swift-system.git",
124+ "state" : {
125+ "revision" : "50688cacbd41d547e9eb9f7a213542340b7c442b",
126+ "version" : "1.7.5"
127+ }
128+ },
129+ {
130+ "identity" : "swift-transformers",
131+ "kind" : "remoteSourceControl",
132+ "location" : "https://github.com/huggingface/swift-transformers",
133+ "state" : {
134+ "revision" : "2fa33e1f5e7131a7fc64c28e6d161dcec0d24820",
135+ "version" : "1.3.3"
136+ }
137+ },
138+ {
139+ "identity" : "yyjson",
140+ "kind" : "remoteSourceControl",
141+ "location" : "https://github.com/ibireme/yyjson.git",
142+ "state" : {
143+ "revision" : "8b4a38dc994a110abaec8a400615567bd996105f",
144+ "version" : "0.12.0"
145+ }
146+ }
147+ ],
148+ "version" : 2
149+}
added Package.swift +44 −0
@@ -0,0 +1,44 @@
1+// swift-tools-version: 5.9
2+//
3+// Package.swift
4+// Zyquo MLX
5+//
6+// Author: Simon-Pierre Boucher
7+// Mail: contact@spboucher.ai
8+//
9+
10+import PackageDescription
11+
12+let package = Package(
13+ name: "ZyquoMLX",
14+ platforms: [
15+ .macOS(.v14)
16+ ],
17+ dependencies: [
18+ // Versions pinned per docs/MLX-RESEARCH.md §8 (verified 2026-07-30).
19+ // Released tags only — mlx-swift main requires an experimental toolchain.
20+ .package(url: "https://github.com/ml-explore/mlx-swift", .upToNextMinor(from: "0.31.6")),
21+ .package(url: "https://github.com/ml-explore/mlx-swift-lm", .upToNextMajor(from: "3.31.4")),
22+ .package(url: "https://github.com/huggingface/swift-huggingface", from: "0.9.0"),
23+ .package(url: "https://github.com/huggingface/swift-transformers", from: "1.3.0"),
24+ ],
25+ targets: [
26+ .executableTarget(
27+ name: "ZyquoMLX",
28+ dependencies: [
29+ .product(name: "MLX", package: "mlx-swift"),
30+ .product(name: "MLXNN", package: "mlx-swift"),
31+ .product(name: "MLXOptimizers", package: "mlx-swift"),
32+ .product(name: "MLXRandom", package: "mlx-swift"),
33+ .product(name: "MLXLMCommon", package: "mlx-swift-lm"),
34+ .product(name: "MLXLLM", package: "mlx-swift-lm"),
35+ .product(name: "MLXVLM", package: "mlx-swift-lm"),
36+ .product(name: "MLXEmbedders", package: "mlx-swift-lm"),
37+ .product(name: "MLXHuggingFace", package: "mlx-swift-lm"),
38+ .product(name: "HuggingFace", package: "swift-huggingface"),
39+ .product(name: "Tokenizers", package: "swift-transformers"),
40+ ],
41+ path: "Sources/ZyquoMLX"
42+ )
43+ ]
44+)
added README.md +55 −0
@@ -0,0 +1,55 @@
1+<!--
2+ README.md
3+ Zyquo MLX
4+
5+ Author: Simon-Pierre Boucher
6+ Mail: contact@spboucher.ai
7+-->
8+
9+# Zyquo MLX
10+
11+**Zyquo MLX** is the foundry of the Zyquo family: a native macOS workbench for
12+the full on-device MLX lifecycle on Apple Silicon — inference of every
13+supported model type, LoRA/QLoRA and full fine-tuning, quantization, format
14+conversion, dataset preparation, training runs with live metrics, evaluation,
15+and export. Swift + SwiftUI, built without the Xcode IDE.
16+
17+## Requirements
18+
19+- Apple Silicon Mac (arm64 only — MLX requires it), macOS 14+
20+- Full Xcode installed **as a toolchain only** (the IDE is never opened) with
21+ the Metal toolchain component — see `docs/BUILD.md` §2:
22+ ```bash
23+ sudo xcode-select -s /Applications/Xcode.app
24+ sudo xcodebuild -license accept
25+ xcodebuild -downloadComponent metalToolchain
26+ ```
27+- `uv` (Python-side pipelines are provisioned at first run into
28+ `~/Library/Application Support/ZyquoMLX/py/`)
29+- For the icon pipeline: `brew install librsvg`
30+
31+## Build
32+
33+```bash
34+make app # release build + assemble "Zyquo MLX.app" (ad-hoc signed)
35+make dev # build + launch
36+make release # Developer ID signed + notarized (Phase 8)
37+```
38+
39+Everything is driven by the `Makefile` — command-line `swift build` /
40+`xcodebuild` only; no `.xcodeproj` exists or ever will.
41+
42+## Documentation
43+
44+- `docs/PLAN.md` — phase-by-phase execution plan and checkpoints
45+- `docs/MLX-RESEARCH.md` — MLX framework ground truth (verified 2026-07-30)
46+- `docs/TRAINING-RESEARCH.md` — fine-tuning on MLX, concretely
47+- `docs/MODELS.md` — Hub API + live-verified curated catalog
48+- `docs/BUILD.md` — the no-Xcode-IDE build recipe (incl. Metal toolchain)
49+
50+## Data locations
51+
52+- Models: `~/Library/Application Support/ZyquoMLX/Models/`
53+- Datasets: `~/Library/Application Support/ZyquoMLX/Datasets/`
54+- Training runs: `~/Library/Application Support/ZyquoMLX/Runs/`
55+- Python env: `~/Library/Application Support/ZyquoMLX/py/`
added Sources/ZyquoMLX/App/HardwareGate.swift +45 −0
@@ -0,0 +1,45 @@
1+//
2+// HardwareGate.swift
3+// Zyquo MLX
4+//
5+// Author: Simon-Pierre Boucher
6+// Mail: contact@spboucher.ai
7+//
8+
9+import Foundation
10+import SwiftUI
11+
12+/// MLX requires Apple Silicon. The binary itself is arm64-only, so on an
13+/// Intel Mac it will not load at all — this runtime check is defense in depth
14+/// (e.g. exotic translation environments) and drives the polite
15+/// unsupported-hardware screen required by the project charter.
16+enum HardwareGate {
17+
18+ /// True when running natively on Apple Silicon.
19+ static let isAppleSilicon: Bool = {
20+ var value: Int32 = 0
21+ var size = MemoryLayout<Int32>.size
22+ // hw.optional.arm64 is 1 on Apple Silicon, absent/0 elsewhere.
23+ let result = sysctlbyname("hw.optional.arm64", &value, &size, nil, 0)
24+ return result == 0 && value == 1
25+ }()
26+}
27+
28+/// Polite, clear unsupported-hardware screen (charter requirement).
29+struct UnsupportedHardwareView: View {
30+ var body: some View {
31+ VStack(spacing: 16) {
32+ Image(systemName: "cpu")
33+ .font(.system(size: 48, weight: .light))
34+ .foregroundStyle(.secondary)
35+ Text("Apple Silicon Required")
36+ .font(.title2.weight(.semibold))
37+ Text("Zyquo MLX is built on MLX, Apple's machine-learning framework, which runs exclusively on Apple Silicon (M-series) Macs. This Mac does not support it.")
38+ .multilineTextAlignment(.center)
39+ .foregroundStyle(.secondary)
40+ .frame(maxWidth: 420)
41+ }
42+ .padding(48)
43+ .frame(minWidth: 560, minHeight: 360)
44+ }
45+}
added Sources/ZyquoMLX/App/ZyquoMLXApp.swift +51 −0
@@ -0,0 +1,51 @@
1+//
2+// ZyquoMLXApp.swift
3+// Zyquo MLX
4+//
5+// Author: Simon-Pierre Boucher
6+// Mail: contact@spboucher.ai
7+//
8+
9+import SwiftUI
10+
11+/// Zyquo MLX — the local MLX foundry for the Mac.
12+///
13+/// Entry point. Gates on Apple Silicon (MLX requires it), activates the app
14+/// properly when launched from a terminal, and hosts the main workbench window.
15+@main
16+struct ZyquoMLXApp: App {
17+
18+ init() {
19+ // Launching a bare executable from the terminal does not activate it;
20+ // make sure the window comes to the front like a real Mac app.
21+ DispatchQueue.main.async {
22+ NSApplication.shared.setActivationPolicy(.regular)
23+ NSApplication.shared.activate(ignoringOtherApps: true)
24+ }
25+ }
26+
27+ var body: some Scene {
28+ WindowGroup {
29+ if HardwareGate.isAppleSilicon {
30+ PlaceholderRootView()
31+ .frame(minWidth: 1080, minHeight: 700)
32+ } else {
33+ UnsupportedHardwareView()
34+ }
35+ }
36+ .defaultSize(width: 1360, height: 880)
37+ }
38+}
39+
40+/// Temporary Phase 1 root; replaced by the workbench in Phase 2/4.
41+private struct PlaceholderRootView: View {
42+ var body: some View {
43+ VStack(spacing: 8) {
44+ Text("Zyquo MLX")
45+ .font(.largeTitle.weight(.semibold))
46+ Text("Foundry under construction — Phase 1")
47+ .foregroundStyle(.secondary)
48+ }
49+ .frame(maxWidth: .infinity, maxHeight: .infinity)
50+ }
51+}
added Support/Info.plist +45 −0
@@ -0,0 +1,45 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!--
3+ Info.plist
4+ Zyquo MLX
5+
6+ Author: Simon-Pierre Boucher
7+ Mail: contact@spboucher.ai
8+-->
9+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
10+<plist version="1.0">
11+<dict>
12+ <key>CFBundleDevelopmentRegion</key>
13+ <string>en</string>
14+ <key>CFBundleDisplayName</key>
15+ <string>Zyquo MLX</string>
16+ <key>CFBundleName</key>
17+ <string>Zyquo MLX</string>
18+ <key>CFBundleExecutable</key>
19+ <string>ZyquoMLX</string>
20+ <key>CFBundleIdentifier</key>
21+ <string>com.zyquo.mlx</string>
22+ <key>CFBundlePackageType</key>
23+ <string>APPL</string>
24+ <key>CFBundleShortVersionString</key>
25+ <string>0.1.0</string>
26+ <key>CFBundleVersion</key>
27+ <string>1</string>
28+ <key>CFBundleIconFile</key>
29+ <string>AppIcon</string>
30+ <key>LSMinimumSystemVersion</key>
31+ <string>14.0</string>
32+ <key>LSApplicationCategoryType</key>
33+ <string>public.app-category.developer-tools</string>
34+ <key>LSArchitecturePriority</key>
35+ <array>
36+ <string>arm64</string>
37+ </array>
38+ <key>NSHighResolutionCapable</key>
39+ <true/>
40+ <key>NSHumanReadableCopyright</key>
41+ <string>© 2026 Simon-Pierre Boucher</string>
42+ <key>NSPrincipalClass</key>
43+ <string>NSApplication</string>
44+</dict>
45+</plist>
modified docs/PLAN.md +10 −1
@@ -65,7 +65,16 @@ Metal kernel compilation → strategy: full Xcode as toolchain, CLI-only builds,
65 65
66 --- 66 ---
67 67
68−## Phase 1 — Project Setup (not started) 68+## Phase 1 — Project Setup (in progress)
69+
70+- [ ] Xcode toolchain provisioned (CLI-only; Metal toolchain component) — download in progress
71+- [ ] `Package.swift` — target `ZyquoMLX`, deps per MLX-RESEARCH.md §8
72+- [ ] `Makefile` — build / app / dev / icon / clean (+ release stub for Phase 8)
73+- [ ] `Info.plist` — Zyquo MLX, com.zyquo.mlx, macOS 14+, arm64, developer-tools
74+- [ ] `@main` SwiftUI entry point + Apple-Silicon gate + terminal activation
75+- [ ] Python bootstrap plan wired (first-run venv per BUILD.md §3.4 — code lands Phase 3)
76+- [ ] `README.md` (build instructions)
77+- [ ] Phase checkpoint: `swift build`/`xcodebuild` green, app launches, zero warnings
69 ## Phase 2 — Architecture + Inference POC (not started) 78 ## Phase 2 — Architecture + Inference POC (not started)
70 ## Phase 3 — Training, Quantization & Conversion (not started) 79 ## Phase 3 — Training, Quantization & Conversion (not started)
71 ## Phase 4 — Design System & UI (not started) 80 ## Phase 4 — Design System & UI (not started)
72 81
Menu

Theme