Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
mirtal
Mirtal is a native Rust execution gateway for Apple MLX and Metal. It provides explicit devices and streams, lazy tensor graphs, MLX graph compilation, safetensor loading, and compile-time checked custom Metal kernels without exposing C++ ownership to its consumers.
Mirtal is intentionally model-agnostic. It does not parse model configuration,
render prompts, own K/V policy, schedule inference requests, or implement an
HTTP server. Those responsibilities belong to libraries such as libmir.
Status
Mirtal is pre-1.0 and currently targets Apple Silicon on macOS. Its safe Rust surface is already used for complete local LLM execution, but API changes may still occur while native interop is reduced and execution contracts stabilize.
The runtime path contains no Python, PyTorch, NumPy, or Transformers dependency.
mirtal-sys is the private CXX/C++20 bridge to MLX; applications depend only on
mirtal and never receive native smart pointers through the safe API.
Requirements
- Apple Silicon and macOS;
- full Xcode selected through
xcode-select, including Clang with C++20 and the macOS SDK; - the Xcode Metal toolchain component;
- native MLX installed through Homebrew or selected with
MLX_PREFIX; - rustup and the pinned
nightly-2026-07-13toolchain with Clippy and rustfmt.
Prepare and verify the Apple toolchain before building:
Mirtal requires include/mlx/mlx.h, lib/libmlx.dylib, and
lib/mlx.metallib. It searches /opt/homebrew/opt/mlx and
/usr/local/opt/mlx; set MLX_PREFIX for another installation. Its procedural
macros invoke the Metal compiler during cargo build, so standalone Xcode
command-line tools without the downloaded component are insufficient.
Python, PyTorch, NumPy, Transformers, mlx_lm, model checkpoints, and Trunk are
not required to compile or use mirtal.
Dependency
[]
= "0.1"
Consumers should not depend directly on mirtal-sys or mirtal-macros.
Basic Graph
Every operation is associated with an explicit stream. Graph construction is
lazy; eval, read, read_scalar_u32, async_eval, and synchronize are the
observable execution boundaries.
use ;
Array::clone shares the native MLX array handle and tensor storage. It does
not copy the tensor. Host data enters through Array::from_slice or
Array::from_shape; host data leaves through an explicit stream read.
Compiled Rust Graphs
Stream::compile traces a typed Rust closure through MLX. The compiled
attribute generates a named factory while keeping graph composition as ordinary
Rust code:
use ;
#
Compiled<INPUTS, OUTPUTS> records the creating stream and rejects calls made
with another stream. Compilation does not imply a host read or synchronization.
Checked Metal Kernels
metal_kernel! declares input/output arity and dtype constraints in Rust. Its
source can be inline or loaded from a manifest-relative .metal file. During
the Rust build, the macro invokes xcrun metal -fsyntax-only, turning invalid
MSL into a compile error at the macro invocation.
metal_kernel!
Create OutputSpec and Dispatch explicitly, then call
MetalKernel::dispatch. When output shapes, templates, and launch geometry stay
constant, MetalKernel::prepare creates a PreparedMetalKernel that reuses
native launch storage while accepting new arrays.
Complete MSL translation units use metal_library!. MetalLibrary::export
returns a named MetalFunction; functions that mutate or reuse existing output
allocations use AliasingDispatch or typed PreparedAliasing. Aliases,
constants, stride bindings, grid size, and threadgroup size remain explicit in
safe Rust.
Execution Contract
Deviceselects CPU or GPU and creates aStream.Streamis the execution and synchronization context and is deliberately notSync; each independent execution session should own its stream state.Graph<'stream>borrows a stream, preventing accidental implicit-device operations.- MLX operations remain lazy until an explicit evaluation boundary.
Arrayis immutable and cheap to clone; aliases share storage.- Kernel dispatch returns lazy device arrays and does not read them into Rust.
interopis a transitional unsafe/native escape hatch, not an application API for normal execution.
Keeping decode loops on the accelerator requires retaining arrays, compiled graphs, prepared launches, and one stable stream rather than reading values or rebuilding static launch descriptions per token.
Public API
Runtime and storage
| API | Purpose |
|---|---|
Device, DeviceKind |
Select an MLX CPU/GPU device and create a stream. |
Stream |
Build graphs, evaluate, synchronize, and explicitly read host values. |
Array |
Shared RAII tensor handle, metadata, async evaluation, and graph export. |
Shape, shape! |
Validated dimensions and checked element counts. |
DType, Element |
Device dtypes and supported host transfer types (f32, u32). |
TensorFile |
Load, inspect, evaluate, and retrieve arrays from safetensors. |
memory |
Allocator statistics, cache clearing, and recommended wired limit. |
version |
Report the linked MLX version. |
Error, Result |
Typed thiserror boundary for validation and native failures. |
Graph operations
Graph exposes these lazy operation groups:
| Group | Methods |
|---|---|
| Arithmetic | add, subtract, multiply, divide, power, floor_divide, scalar add/multiply/power, negative, exp, reciprocal, minimum, maximum. |
| Activations and norm | sigmoid, sigmoid_multiply, silu, tanh, rms_norm, rms_norm_unit. |
| Shape and dtype | astype, reshape, transpose, expand_dims, squeeze_axis. |
| Creation | arange, full, concatenate, stack, repeat, conv1d. |
| Reduction | softmax, logsumexp, cumulative_sum, reduce_max, reduce_sum, argmax_axis. |
| Selection | slice, slice_update, take, take_along_axis, argpartition, argsort, depends. |
| Logic | less, greater_equal, logical_and. |
| Quantized | quantize, dequantize, quantized_matmul, gather_qmm. |
| Transformer primitives | rope, rope_with_frequencies, scaled_dot_product_attention. |
Model-specific tensor layouts, attention policy, expert routing, K/V paging, and sampling are composed by the consumer from these operations.
Compilation and Metal
| API | Purpose |
|---|---|
CompileOptions, Compiled, compiled |
Typed MLX compilation of Rust graph functions. |
metal_kernel!, MetalKernel, KernelDescriptor |
Compile-time checked fixed-arity custom kernels. |
Dispatch, OutputSpec |
Grid, threadgroup, templates, initialization, output shape, and dtype. |
TemplateArg, TemplateValue, TemplateParameter, TemplateKind |
Typed Metal specialization arguments and declarations. |
DTypeConstraint |
Exact, floating-point, or template-bound tensor dtype validation. |
PreparedMetalKernel |
Reusable native launch plan for ordinary kernels. |
metal_library!, MetalLibrary, MetalLibraryDescriptor |
Checked complete MSL libraries and retained MLX library cache. |
MetalFunction, AliasingDispatch, StrideBinding |
Named functions with explicit persistent-output aliasing. |
PreparedAliasing |
Reusable typed aliasing pipeline, metadata, and input storage. |
MetalSource |
Dynamic low-level source escape hatch without macro-time validation. |
Typed options
Quantization, Quantized, QuantizedArrays, and GatherQmmOptions describe
affine quantized execution without loosely ordered scalar arguments.
RopeOptions, FrequencyRopeOptions, AttentionMask, and
ScaledDotProductAttention make transformer primitive configuration explicit.
Native interop
The public interop module exposes native handles only for staged migration of
existing native integrations. Handle lifetimes remain tied to their Rust
owners; adoption is unsafe and single-use. New consumers should request a safe,
generic mirtal operation instead of building execution around native addresses.
Examples
cargo run --example basicbuilds and reads a lazy graph.cargo run --example compiledcompiles and reuses Rust graph code.cargo run --example metal_kernellaunches an included, checked MSL kernel.
Documentation
These targets build rustdoc for mirtal, mirtal-macros, and mirtal-sys
with warnings denied. This README is embedded as the public crate landing page;
rustdoc provides signatures and implementors for every exported item.
Validation
Releases
The Forgejo workflow in .forgejo/workflows/publish.yml is currently disabled
with a job-level if: false guard, so it does not allocate a runner. Once the
guard is removed, it validates every push to main and publishes mirtal-sys,
mirtal-macros, and mirtal, in that order, when the version under
[workspace.package] is not present on crates.io. Pushes that retain an already
published version are validated and then skipped.
Publishing requires a self-hosted Apple Silicon Forgejo runner labeled
macos-arm64 with Xcode, the Metal toolchain, Homebrew MLX, and rustup. The
Codeberg repository must provide a CARGO_REGISTRY_TOKEN Actions secret.