# Mojo 1.0 Metal integration spike (#84) ## Decision **STOP** the product integration at the license/runtime gate. DS4Server can pin and invoke the Mojo 1.0 compiler through `uv`, but Mojo 1.0's open standard library does not provide the host-side `DeviceContext` needed to load and run a Metal kernel. That API is delivered by MAX and links to separately shipped AsyncRT and KGEN runtime libraries whose redistribution status is not explicit. This is a mandatory stop under issue #84, not a performance conclusion. The existing Objective-C Metal backend remains the production path. DS4Server now targets Apple silicon and macOS 15 or newer, matching Mojo 1.0's supported host floor. No MAX wheel, runtime library, virtual environment, or Modular source checkout is bundled. Run the committed proof from the repository root: ```sh tools/mojo-spike/check.sh ``` The command syncs the locked `uv` environment, checks the exact compiler build, emits a C-ABI object and dynamic library, records their closure under `target/mojo-spike`, and verifies that the compiler-only environment cannot import the GPU host API. Once the lock has been synced, the same proof runs without network access as `UV_OFFLINE=1 tools/mojo-spike/check.sh`. ## Pinned environment | Component | Pin / observation | | --- | --- | | Mojo compiler | `mojo-compiler==1.0.0` | | Compiler identity | `Mojo 1.0.0 (ed45d567)` | | Dependency manager | `uv.lock` revision 3; hashes recorded for every wheel | | Mojo source tag | `mojo/v1.0.0`, commit `b4497b7ce9ba96331c72c637ad41b44bab374f33` | | MAX probe | `max==26.5.0`, isolated outside the project environment | | Host | Apple M5 Max, arm64, macOS 26.6.2 (25G83) | | Xcode / Metal | Xcode 26.6 (17F113), Metal toolchain 17F109 | Only `mojo-compiler` is a project build dependency. The broader `mojo` package and MAX are intentionally absent because they add tools and runtimes that the committed proof does not need or may not redistribute. ## Build and ABI findings `@export` produces a callable C symbol and `mojo build --emit object` produces a Mach-O object that can be linked by the platform linker. This is the viable ABI boundary if the GPU runtime gate is resolved: opaque handles, fixed-width C scalars, caller-owned buffers, integer status codes, and an explicit last-error function. Rust unwinding and Mojo exceptions must never cross it. `mojo build --emit shared-lib` is not self-contained. Even the trivial `ds4_mojo_probe` export has this non-system dependency: ```text @rpath/libKGENCompilerRTShared.dylib ``` The object form avoids that dependency for the trivial CPU export, but it does not provide a way to construct a Metal device context or launch a GPU kernel. Importing `DeviceContext` from the open `std.gpu.host` package fails because it is not exported there. Importing the working API from `max.gpu.host` fails in the compiler-only environment because MAX is not installed. Compiling the Apache-licensed `max.gpu.host` Mojo sources directly did not make the program self-contained. The link still required these external symbols: ```text _AsyncRT_DeviceContext_create _AsyncRT_DeviceContext_deviceName _AsyncRT_DeviceContext_release _AsyncRT_DeviceContext_strfree ``` An isolated `max==26.5.0` probe could enumerate the Apple M5 Max, proving that the API is technically viable when the proprietary runtime is present. Its executable closure included: ```text @rpath/libKGENCompilerRTShared.dylib @rpath/libAsyncRTMojoBindings.dylib /usr/lib/libSystem.B.dylib ``` That probe is deliberately not part of the repository dependency graph. ## License and redistribution inventory | Component | Source / package evidence | Product decision | | --- | --- | --- | | Mojo language, compiler sources, and standard library | Apache-2.0 with LLVM exceptions in the `modular/modular` repository | Approved for build use, subject to normal notices | | `mojo-compiler` and `mojo-compiler-mojo-libs` wheels | Pinned by hash; wheel metadata identifies the MAX Platform Software License | Build-only; do not redistribute the wheels | | MAX Mojo source modules | Repository source is Apache-2.0 with LLVM exceptions, while Modular separately states MAX usage and distribution remain under the Community License | Source license alone does not approve the runtime closure | | `max`, `max-core`, and `max-mojo-libs` wheels | Wheel metadata: `LicenseRef-MAX-Platform-Software-License` | Not a product dependency; do not bundle | | `libAsyncRTMojoBindings.dylib` and related AsyncRT libraries | Supplied only by the MAX wheel in this probe; no component-specific redistribution grant found | Blocked | | `libKGENCompilerRTShared.dylib` | Required by compiler-emitted shared libraries and the MAX GPU executable; no component-specific redistribution grant found | Blocked | | Apple Metal frameworks and system libraries | Supplied by macOS | Approved system dependency | | Existing DS4Server Objective-C Metal backend | Existing project code and Apple system frameworks | Remains the production implementation | The governing sources are the [Mojo repository license](https://github.com/modular/modular/blob/mojo/v1.0.0/LICENSE), the [Modular repository notice separating MAX licensing](https://github.com/modular/modular#license), and the [MAX and Mojo Community License](https://www.modular.com/legal/max-mojo-license). The Community License permits redistribution only for components Modular expressly identifies as redistributable and subject to its conditions. No authoritative component list was found that names the two required dylibs. Silence is not permission, so packaging is blocked. ## Platform and packaging result Mojo 1.0 officially requires Apple silicon, macOS 15 or newer, Xcode or Command Line Tools 16 or newer, and the Metal toolchain. DS4Server now declares that same architecture and OS floor in its build environment, package metadata, and README. The native backend remains necessary because the license/runtime gate, not the platform floor, blocks the Mojo backend. The required package proof cannot pass today: - a clean machine would need non-system MAX runtime dylibs; - their exact redistributable status and required notices are unresolved; - an ad-hoc signed `.app` cannot be accepted while those dylibs are absent or copied without permission; - CUDA viability cannot be inferred from this Metal probe and remains a separate Linux/NVIDIA build, runtime, and license audit. ## Performance result No parity number is reported. The approved compiler-only environment cannot launch a Metal operation, so there is no license-safe Mojo candidate to compare with native Metal. Timing a MAX-backed or CPU-only substitute would answer a different question and create a misleading baseline. The parity harness and raw GPU/wall-clock measurements begin only after an approved host/runtime path can build, link, and package. ## Conditions to resume All of the following are required before issue #85 or later implementation may replace native code: 1. Modular publishes an authoritative redistribution grant naming every required runtime library, or Mojo exposes a host-side Metal launch path whose complete closure is under an approved open-source/system license. 2. The locked environment still builds through `uv` and works offline after dependency installation. 3. `otool -L` and `nm -u` show only system libraries and explicitly approved, packaged runtime components. 4. A clean-machine ad-hoc signed app launch proves install-name, rpath, code-sign, and notice handling. 5. The parity harness records identical workloads, correctness, GPU execution time, wall time, and repeated samples against the native Metal oracle. Until then, later milestone issues are design and inventory work only; they may not introduce MAX as a Cargo, `uv`, build-script, or application dependency.