# The mni-ml framework ships twelve native packages and Linux ARM gets only the CPU one

> A TypeScript machine learning library with Rust backends for CPU, CUDA and WebGPU, built to be read as much as used. The packaging is where the interesting detail is: the backend you can install is not the backend the documentation promises, and the documented CPU build command names a macOS library.

**mni-ml/framework** — A machine learning library with a TypeScript API and Rust backend. CUDA and WebGPU compatibility. Built to understand how ML frameworks and models work internally.

- Repository: https://github.com/mni-ml/framework
- Website: http://mni.ml
- Stars: 1,013 · Forks: 130
- Language: Rust
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/mni-ml-framework

## Twelve native packages, and one platform has a single backend

The manifest ships the native side as optional dependencies, one per platform and per backend, and counting them is revealing. There are four for macOS: Apple silicon and Intel, each in a plain and a WebGPU variant. There are four for Windows on x86, again plain, CUDA and WebGPU alongside a base build. There are four for Linux on x86, with the same four-way spread. And there is exactly one for Linux on ARM, the plain one. No CUDA sibling, no WebGPU sibling. So the promise that WebGPU runs on any graphics stack through one abstraction, and that the backend is selected by a compile-time flag rather than at runtime, holds on paper for three platforms and holds on paper only for one architecture. If you are on an ARM Linux machine, the CPU path is what will resolve.

## The default build command names a macOS library

The source build instructions give four commands, and the first one is labelled as the default with no platform mentioned:

```bash
# CPU (default)
npm run build:native

# CUDA (requires CUDA toolkit)
npm run build:native:cuda

# WebGPU
npm run build:native:webgpu

# Build TypeScript
npm run build
```

The script behind the first one is a change into the native source directory, a release build with the CPU feature enabled, and then a copy of one specific library file to one specific name. Both the extension and the platform in that name are macOS and Apple silicon, so the command described as the default is the macOS on ARM build. Nothing about it is wrong, it is just narrower than the label, and someone on Linux will find a copy step for a library their build never produced. This is also the section that says building is only needed if you are contributing or want a custom build, which is fair given that most people are installing a prebuilt package.

## The feature list promises an optimizer the API page does not show

Put the two lists side by side. The features section advertises two optimizers, one of them named as a variant of the other, and says they come with learning rate scheduling. The API reference then constructs exactly two optimizer classes, the base one taking a learning rate, two decay coefficients, an epsilon and a weight decay term, and a plain stochastic gradient one taking a learning rate and nothing else. Neither constructor takes a scheduler, no scheduler type is imported anywhere in the examples, and the variant name does not appear as a class in the reference. That is not proof the capability is missing, since the reference is a summary, but it does mean the headline feature line is ahead of the documented surface, and it is the kind of gap you find only after writing the code that would use it.

## Three backends, three builds, one autograd tape

The architecture is a short chain and it is worth reading precisely, because it rules out the design most people assume. The TypeScript side is three files, one for tensors, one for the neural network pieces and one for optimizers, and it talks to a single native bridge module. Behind that bridge sit three backends: a CPU backend written in plain Rust over a float vector, a CUDA backend built on a Rust CUDA wrapper with kernels in a separate source extension, and a WebGPU backend built on the cross-platform graphics abstraction with shaders in another source extension. All three share the same autograd tape and the same tensor store, which is what makes a graph portable between them. But the backend is chosen by a feature flag at compile time and the flags are mutually exclusive, so this is three separate builds of one library rather than one build that picks a device at startup.

## The quick start imports two names it never uses

The example at the top is short and close to runnable, which makes its small faults easy to see. It imports six names from the package, and two of them, a parameter type and a softmax function, are never used in the visible code even though the softmax function is the natural companion to the loss it computes. The training loop it does show is otherwise complete for one step: build a random batch, make two fully connected layers, forward with a rectified activation, compute a cross entropy loss, call backward on the loss, gather the parameters from both layers, construct the optimizer with a learning rate, and step. The listing then stops partway through a second optimizer call, so the loop is implied rather than written. Nothing here is wrong for a README, but it does mean the parameter and optimizer APIs have to be read from the reference rather than from the example.

## A browser entry point and a set of native binaries, two delivery paths

The manifest describes two ways for the library to arrive. The exports map has a browser condition pointing at a separate web bundle with its own type declarations, and a default condition pointing at the main bundle. Underneath, the published file list includes the compiled output, a glob for native binaries in a source subdirectory, an npm support directory and the readme. So the browser build and the native backends are two different mechanisms serving the same import path, which is the right way to ship something that runs both in a bundler and in Node, and it also means the browser path is the one that cannot use the native backends. The engine floor is a recent Node version, specified as a minimum, and the type is the module system rather than a build of commonjs, so anything still on the older module system will not load it.

## One example, in the other language, plus a directory named toy

The repository carries a single example file and it is written in JavaScript, not TypeScript, and its subject is the exclusive-or problem, which is the traditional hello-world of this library because it is the smallest thing that fails without a hidden layer. There is also a directory at the root whose name suggests a second, smaller set of the same kind of thing, and there is no mention of either in the documentation. The version lives only in the manifest, at a zero point three line, and there are no GitHub releases, so the published version is the only version marker anyone outside the project can see. The homepage is registered as a plain unencrypted address, and the last commit to the repository is dated 2026-04-20, which is a good six months before the version number suggests the code is being changed.

## Conclusion

Use this framework if you want to understand how a machine learning library is put together, since the code is written to be read, and if you are on a CPU, an Apple Silicon Mac or an x86 machine with a supported graphics stack. Three things to check first. On Linux on ARM you get the CPU backend and nothing else, whatever the documentation says about the other two. The build command labelled as the default compiles a macOS library by name, so a build from source on another platform is not the one command shown. And the feature list promises an optimizer variant and a learning rate scheduler that the API reference does not show, so check the exported names before you plan around them.

## FAQ

### How do I install the mni-ml framework?

One npm install of the package. It requires Node 22.18.0 or newer, and the native side arrives as an optional dependency chosen for your platform, so there is no separate install step for the backend.

### Which backends does the mni-ml framework support?

A CPU backend in plain Rust, a CUDA backend with kernels in a separate source file, and a WebGPU backend with shaders in another. The backend is selected by a mutually exclusive compile-time feature flag, so they are separate builds.

### Can I use the mni-ml framework on Linux with an ARM processor?

The CPU backend only. The manifest lists a plain Linux ARM package with no CUDA or WebGPU siblings, while macOS, Linux on x86 and Windows each get the full set of variants.

### Does the mni-ml framework have AdamW and learning rate scheduling?

The feature list advertises an Adam variant with learning rate scheduling, but the API reference documents only the base optimizer and a plain gradient one, and neither constructor takes a scheduler. Check the exported names before relying on it.

### How do I build the mni-ml framework from source?

You need Rust, and the instructions give separate commands for the CPU, CUDA and WebGPU backends plus a TypeScript compile. The command labelled as the default copies a specific macOS library to a specific name, so it is narrower than the label suggests.

### What version of the mni-ml framework is current?

The manifest says 0.3.1 and there are no GitHub releases, so the published version is the only version marker. The last commit to the repository is dated 2026-04-20.

## Sources

- [Issues](https://github.com/mni-ml/framework/issues)
- [License: MIT](https://github.com/mni-ml/framework/blob/main/LICENSE)
- [mni-ml/framework on GitHub](https://github.com/mni-ml/framework)
- [Project website](http://mni.ml)
- [README](https://github.com/mni-ml/framework/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mni-ml-framework
