# Mojo and MAX source release: the whole stack is readable, and two licences cover it

> Satyajit Ghana — Head of Engineering @ Inkers Technology
> canonical: https://ai.thesatyajit.com/articles/mojo-max-open
> date: 2026-10-24
> tags: compilers, kernels, licensing, gpu, hardware

On 23 October Chris Lattner [posted](https://x.com/clattner_llvm/status/2113639627445965251)
that "Mojo and MAX are now fully open - for development, extension, and commercial use",
including "the full Mojo programming language, but also the MAX graph compiler, MLRT runtime
internals, and hardware abstraction logic." The launch post from the day before,
[modular.com/blog/max-license](https://www.modular.com/blog/max-license), uses a different
word in its own title: "MAX is now **source available** and open to everyone."

Both are accurate about something. The source is there: I cloned
[github.com/modular/modular](https://github.com/modular/modular) at `da0db31`
(2026-10-23) and the graph compiler, the runtime and the hardware plugins are all in it, with
their design docs and 68,568 commits of history going back to January 2022. What "fully open"
skips is that the repo now carries two licences, and the one on the newly opened parts is not
an open-source licence. This piece measures which code is under which, reads the new licence
clause by clause, explains what the stack actually does from Mojo source to a GPU, and ends
with a Mojo program I compiled and ran.

<RepoCard repo="modular/modular" />

## Two licences, sorted by file

The top-level `LICENSE` is now seven lines. Mojo "and its contributions" are under Apache
License v2.0 with LLVM Exceptions; "portions of the MAX source code and its binary
distribution" are under the MAX License; "the remainder of the source" is Apache again.
Which portion is which is settled per file: the launch post says "each source file includes
a header identifying the license that applies to it."

So I counted that way. For every tracked `.mojo`, `.py`, `.cpp`, `.h`, `.c`, `.td`, `.mlir`,
`.rs` and `.cu` file I read the first 2.5 KB and classified it by the licence its header
names. All counts below are **measured** from the clone.

| Licence in the file header | Files | Lines |
|---|---:|---:|
| Apache-2.0 with LLVM Exceptions | 9,346 | 2,966,860 |
| MAX License | 974 | 266,760 |
| No header (almost all MLIR lit tests) | 1,231 | 121,295 |
| **Total** | **11,551** | **3,354,915** |

That is about 8% of the code under the MAX License (**reasoned**). By language the repo is 1,493,818 lines of Mojo, 1,117,978 of Python, 553,707 of C++,
121,833 of MLIR, 52,335 of TableGen and 11,758 of Rust (**measured**). There are no
prebuilt compiler or runtime binaries in the tree: no `.so`, `.a` or `.mojopkg` files at all.
The binary files that are there are documentation images, PDFs and videos, small test
checkpoints and goldens, and three `vec_add` `.cubin` files of 3 to 6 KB that a GPU test loads
(**measured**).
`MODULE.bazel` says the rest plainly: "the prebuilt path is gone ... the whole tree builds from source."

The MAX-License code is concentrated in exactly the pieces Lattner named:

- **Graph compiler** (`GraphCompiler/`): 146,198 lines under the MAX License, plus 67,569
  lines of header-less MLIR tests.
- **MLRT runtime** (`MLRT/`): 67,117 lines.
- **Driver, Mojo side** (`max/driver/`): 16,548 lines.
- **Hardware plugins** (`Target/`): 13,739 lines, for CPU, CUDA, HIP and Metal.
- **The HAL C API** (`SDK/include/HAL/`): 1,911 lines, the header set a vendor plugin implements.
- **Python bindings to the engine** (`max/python/max/_core/max_license/`): 15,479 lines.

Everything else a developer touches is Apache: the Mojo compiler (330,903 lines across
`Mojo/lib`, `Mojo/include` and `Mojo/tools`), the Mojo standard library (196,851), the MAX
kernel library (1,078,917 lines, almost all Mojo), the Mojo GPU-programming library
(59,338), the Python framework and server (512,284) and AsyncRT (14,838).

One wrinkle, **measured**: the repo has 32 directories literally named `max_license/`, and 115
of the source files inside them carry an Apache header, all in the Mojo tree
(`Mojo/lib/KGENToLLVM/Target/max_license/AMDGPU/AMDGPULowering.cpp` is one). By the launch
post's own rule the header wins, so those are Apache. The directory names look like a build
partition that predates the licence split, not a statement about terms.

<LicenceMap />

## What the MAX License allows, clause by clause

The full text is at [modular.com/legal/max-license](https://www.modular.com/legal/max-license),
Last Modified 21 October 2026, and is `Licenses/MAX_LICENSE` in the repo. These are
**reported** terms, quoted from it; the reading is mine and is not legal advice.

- **Use, modify, ship binaries (1.1).** A "perpetual, worldwide, non-exclusive, no-charge,
  royalty-free license" to reproduce and prepare Derivative Works, and to distribute them
  "in object code form" under terms of your choosing, as long as the MAX portions stay under
  the MAX License and you include a copy of it.
- **Bundle it in an app (1.2).** Same, if the application has "material additional
  functionality beyond the included portions of MAX."
- **Publish modified source: only to contribute (1.3).** "You may publish modified Modular
  source code in a fork ... of Modular's official repository to contribute to a Modular
  project." That is the only permission to publish modified MAX source. The FAQ says it
  directly: "Publishing modified MAX License source code elsewhere is not permitted."
- **No AI reimplementation (1.4).** You may not use MAX "as training data, fine-tuning data,
  or input to any AI system in order to produce software that reimplements or substitutes for
  MAX." The same clause adds: "This does not restrict using AI tools to read, analyze,
  improve, or explain MAX." Lattner's "Get your agents going!" fits inside that line.
- **Apache parts stay Apache (1.5).** Separately licensed components are governed by their
  own terms, and "nothing in these Terms revokes, narrows, conditions or otherwise modifies"
  them.
- **Hosted services carry a mark (3.3).** A legal entity that "commercially deploy[s] MAX as
  a hosted or managed AI training or inference service" must use the "Modular Accelerated"
  mark and obtain "Modular's written approval prior to any use."
- **Telemetry (2.1)** is on by default. The FAQ gives the opt-outs:
  `MODULAR_TELEMETRY_ENABLED=0` and `MAX_SERVE_DISABLE_TELEMETRY=1`.

By the Open Source Definition, any licence that forbids distributing modified source outside
one vendor's fork is not open source. The MAX License does not pretend otherwise; the launch
post calls it "source available."

### What actually changed, and when

The history is in the repo, which is the best thing about publishing it. **Measured** from git:

- **Until 17 August 2026**, `Licenses/LICENSE` was the *Modular Community License*. It
  licensed binaries "on a discrete physical per-device basis". Production commercial use had
  "no capacity restrictions" on x86 or ARM CPUs and NVIDIA hardware, but other accelerators
  were capped at "no more than eight (8) other discrete physical accelerator devices." It
  also forbade reverse engineering, and any use for "Competitive Activity."
- **On 18 August** (commit `97f5831`) that was replaced by the *Modular MAX Community
  License*. The device cap, the reverse-engineering ban and the competitive-use clause went.
  Most of today's terms arrived here, including the AI-reimplementation clause. This is the
  same month the Mojo compiler went into the repo; the commit `ee4cebf` renaming `KGEN` to
  `Mojo` is dated 31 August.
- **On 22 October** (commits `bb32ac6`, `c776cf6`, `e9a8916`) the August text became the
  *MAX License*. The diff is small: the mark was renamed from "Powered by Modular" to "Modular
  Accelerated", a mandatory attribution notice was dropped, and section 1.3, the contribution
  fork, was added.

So the hardware cap people remember went two months ago. What is new this week is source
for the MAX internals, and section 1.3, which lets you fork it to send a pull request.

### The alliance

[modular.com/alliance](https://www.modular.com/alliance) describes a program, not a
foundation, and it has not launched. The FAQ says Modular is "registering interest now, ahead
of a formal launch in early 2027." The page's pitch is "LLVM, but for AI", with "a conformance
testing ecosystem". The launch post lists what partners get: "a voice in governance and
conformance standards, input into the roadmap, priority for upstream contributions, early
access to model checkpoints, ownership of dedicated hardware backends, and more permissive
licensing." The FAQ is specific about who needs it: organisations that want to keep
"support for proprietary hardware without upstreaming those changes."

That is the commercial shape (**reasoned**). The public licence forbids a vendor from
publishing a modified MAX for its own chip, and the alliance is where a vendor gets that
right. Modular is now "A Qualcomm Company" (the licence names the licensor as "Modular Inc, a
Qualcomm Company"), and the thread says "Modular and Qualcomm are releasing this to help
catalyze an open + unified future." Whether a program run by one chipmaker reads as neutral to its rivals is
a governance question nobody can answer until the alliance's rules exist.

## The stack, from source to silicon

With the internals readable, the design docs answer what each named part does. What follows is
**reported** from `GraphCompiler/docs/GraphCompiler.md`, `MLRT/docs/README.md`,
`Target/README.md` and `Mojo/docs/compiler/MojoCompilerWalkthrough.md`.

<Figure
  src="https://media.thesatyajit.com/ai/articles/mojo-max-open/fig1.png?v=9927f5f0536db999"
  alt="A layered block diagram. At the top, framework op graphs from TensorFlow, PyTorch and XGBoost feed framework dialects. The Graph Compiler box holds a graph importer, the RMO and MO representations, optimization passes, the MOGG representation and fusion and kernel selection. Below it a Kernel Compiler box holds KGEN generated kernels and hand-written kernels. Then a Kernel Graph layer with the MGP representation, a graph exporter called MLIR2MEF, and MEF. Then a Runtime layer with GraphRT, AsyncRT and the Driver. At the bottom, CPU, GPU and ASIC hardware."
  caption="The graph compiler's own architecture diagram, still the first figure in its design doc. It predates the current pipeline: today fusion happens in a MAP dialect between MO and MOGG, which this drawing does not show (High-Level_Modular_Stack_Diagram.png, GraphCompiler/docs in modular/modular)."
/>

**Mojo to LLVM.** The Mojo compiler is "built entirely on top of MLIR", and it has no
traditional AST. The parser emits MLIR operations straight into a source-level dialect called
`lit`. Lifetime and borrow checking run on that, and `LowerLIT` turns it into `kgen`, which the
walkthrough calls the "canonical Mojo IR". Alongside sits `pop`, for SIMD and memory
operations. Both are still *parametric* at this point: a function generic over a SIMD width
is one generator, not many copies. Then the **elaborator** instantiates every generator with
concrete parameters and runs compile-time code through an interpreter. That step is how
`comptime W = simd_width_of[DType.float32]()` in my program below became the number 16 on
this machine. After elaboration, `LowerKGENToLLVM` and `LowerPOPToLLVM` hand off to LLVM, with
upstream `nvvm` and `rocdl` dialects for NVIDIA and AMD GPU intrinsics. The compiler code for
this is Apache: the parser alone is 70,358 lines, the KGEN dialect 19,847 and the KGEN-to-LLVM
lowering 12,900 (**measured**).

<Figure
  src="https://media.thesatyajit.com/ai/articles/mojo-max-open/fig2.png?v=40028a2022421ca2"
  alt="A flow diagram. main.mojo goes through a parser to an AST, then through MLIR-Gen to frontend dialects. These feed a parametric region holding lit, zap, kgen and pop, and a non-parametric region holding index and scf. Arrows labelled LIT Lowering and KGEN Elaborator move code from the parametric to the non-parametric region, and LLVM CodeGen moves it to a target-dependent llvm box."
  caption="The Mojo compiler's dialect diagram, drawn in September 2022 (the file's own metadata). The parametric and non-parametric split, the LIT lowering and the elaborator still match the current walkthrough; the separate AST box does not, since today's parser emits lit directly (dialects.svg, Mojo/docs/compiler/img in modular/modular)."
/>

**The graph compiler.** MAX takes a whole model graph, not a single function. It enters as
**RMO**, a deliberately loose dialect that accepts unknown shapes, and is lowered into **MO**,
which is strictly typed and is where device-independent passes run: shape inference,
constant folding, simplification. Device and layout assignment comes next. Then MO is lowered
to **MAP**, one loop-nest kernel per op, and MAP is "the stage where advanced fusion runs". It
fuses elementwise chains and prologue and epilogue work around structured kernels like
matmul. Fusion is decided by kernel structure, not op name: a Mojo kernel is fusable if it uses
the right Mojo types and implements the fusion interfaces. The fused kernels lower to **MOGG**
for code generation, and the kernels themselves are the Apache Mojo library in `max/kernels`.
This is Lattner's "automatic kernel fusion and generation", and the MAP dialect is 7,471
lines of it.

**MLRT.** The runtime has three libraries: Core (tensors, buffers, a wrapper for Mojo values
in C++), GraphRT ("a low-level execution layer for precompiled dataflow graphs"), and Driver,
"a low-level cross-vendor runtime" for device discovery, memory and kernel launch. It sits on
AsyncRT, which provides the thread pool and is Apache. The Driver is 24,799 lines (**measured**).

**Hardware abstraction.** The Driver talks to hardware only through a C API in
`SDK/include/HAL/`. I count 63 distinct `M_driver_*` functions in those headers (**measured**).
Each vendor plugin in `Target/` implements that API and nothing more. The README says plugins
"must only translate the functionality required by each `M_driver_` HAL API function to
sequences of function calls to HW-vendor driver APIs," and that reference counting, caching
and other "pan-HW intelligence" live above the HAL. The plugins are deliberately small
(**measured**): CUDA 3,000 lines, HIP 2,567, Metal 2,495, CPU 1,566.

The same README says what is missing on purpose: "Plugins for confidential partnerships MUST
NOT be placed here, or anywhere else in the mono-repo!" Lattner's thread lists portability
across "NVIDIA, AMD, Apple, Qualcomm, TPUs and Trainium", then adds "Support for the first 3
are already public and more is coming." That matches the tree: no Qualcomm, TPU or Trainium
plugin appears in it (**measured**, by file name and directory).

One more consequence (**reasoned**). The HAL headers a vendor builds against are themselves
MAX-License files. A chipmaker can implement them and ship its plugin as a binary under any
licence, since that is software that "runs on or interoperates with MAX". What it cannot do
is publish a modified HAL, or a modified MLRT tuned for its part, outside a contribution fork.
That is the fragmentation the licence is written to stop, and the gap the alliance is meant
to fill.

## Running it: a matmul in Mojo, against NumPy

This was the one part of the brief where I ran code. Everything here is **measured** on a
shared 4-core cloud VM (Intel Xeon @ 2.10GHz with AVX-512), CPU only. Every process ran under
`nice -n 19`, and the load average sat near 9.8 because other jobs were using the machine.
Numbers will be noisier and lower than on an idle box.

Install was the documented pip path: `pip install mojo` into a venv pulled `mojo` 1.2.0,
`mojo-compiler` 1.2.0 and its libraries. The venv came to 755 MB, almost all of it the
compiler, LLDB and its libraries. The `mojo` wheel is the language and the standard library
only. `parallelize` now lives in MAX's `max/mojo/max/algorithm`, not in `std`, so my kernels
are single-threaded. I did not install the `max` package; disk on the shared machine was
too tight.

The program has three kernels for the same 512x512 float32 product: the textbook triple
loop, the i-k-j loop with the standard library's `vectorize`, and a register-blocked kernel
that keeps a 4x32 tile of C in eight SIMD registers for the whole k loop.

```mojo
# matmul.mojo: C = A @ B, float32, row-major, single thread.
from std.algorithm.functional import vectorize
from std.sys import simd_width_of
from std.time import perf_counter_ns

comptime N = 512
comptime W = simd_width_of[DType.float32]()


def naive(a: List[Float32], b: List[Float32], mut c: List[Float32]):
    for i in range(N):
        for j in range(N):
            var acc: Float32 = 0
            for k in range(N):
                acc += a[i * N + k] * b[k * N + j]
            c[i * N + j] = acc


def simd_ikj(a: List[Float32], b: List[Float32], mut c: List[Float32]):
    var pa = a.unsafe_ptr()
    var pb = b.unsafe_ptr()
    var pc = c.unsafe_ptr()
    for i in range(N):
        for k in range(N):
            var aik = pa.unsafe_load(i * N + k)
            var crow = i * N
            var brow = k * N

            def row[width: Int](j: Int) {mut}:
                var cv = pc.unsafe_load[width=width](crow + j)
                var bv = pb.unsafe_load[width=width](brow + j)
                pc.unsafe_store[width=width](crow + j, cv + aik * bv)

            vectorize[W](N, row)


def blocked(a: List[Float32], b: List[Float32], mut c: List[Float32]):
    # 4 rows x 2 vectors of C held in registers across the whole k loop.
    var pa = a.unsafe_ptr()
    var pb = b.unsafe_ptr()
    var pc = c.unsafe_ptr()
    for i in range(0, N, 4):
        for j in range(0, N, 2 * W):
            var c00 = SIMD[DType.float32, W](0)
            var c01 = SIMD[DType.float32, W](0)
            var c10 = SIMD[DType.float32, W](0)
            var c11 = SIMD[DType.float32, W](0)
            var c20 = SIMD[DType.float32, W](0)
            var c21 = SIMD[DType.float32, W](0)
            var c30 = SIMD[DType.float32, W](0)
            var c31 = SIMD[DType.float32, W](0)
            for k in range(N):
                var b0 = pb.unsafe_load[width=W](k * N + j)
                var b1 = pb.unsafe_load[width=W](k * N + j + W)
                var a0 = SIMD[DType.float32, W](pa.unsafe_load(i * N + k))
                var a1 = SIMD[DType.float32, W](pa.unsafe_load((i + 1) * N + k))
                var a2 = SIMD[DType.float32, W](pa.unsafe_load((i + 2) * N + k))
                var a3 = SIMD[DType.float32, W](pa.unsafe_load((i + 3) * N + k))
                c00 = a0.fma(b0, c00)
                c01 = a0.fma(b1, c01)
                c10 = a1.fma(b0, c10)
                c11 = a1.fma(b1, c11)
                c20 = a2.fma(b0, c20)
                c21 = a2.fma(b1, c21)
                c30 = a3.fma(b0, c30)
                c31 = a3.fma(b1, c31)
            pc.unsafe_store[width=W](i * N + j, c00)
            pc.unsafe_store[width=W](i * N + j + W, c01)
            pc.unsafe_store[width=W]((i + 1) * N + j, c10)
            pc.unsafe_store[width=W]((i + 1) * N + j + W, c11)
            pc.unsafe_store[width=W]((i + 2) * N + j, c20)
            pc.unsafe_store[width=W]((i + 2) * N + j + W, c21)
            pc.unsafe_store[width=W]((i + 3) * N + j, c30)
            pc.unsafe_store[width=W]((i + 3) * N + j + W, c31)
```

`main()` (omitted here for length) fills A and B with `((i * 7) % 13) * 0.1` and
`((i * 3) % 11) * 0.1`, times each kernel with `perf_counter_ns` (the best of five calls for
the two fast ones), and checks every element of the fast results against the naive one.

My first build failed. The closure captured the loop indices `i` and `k` by `mut`, and the
compiler refused:

```text
matmul.mojo:28:47: error: Cannot capture i by mut because it could be immutable
                var cv = pc.load[width=width](i * N + j)
                                              ^
```

Copying them into `var crow` and `var brow` fixed it. The next build warned that
`load`/`store` on a pointer are deprecated in favour of `unsafe_load`/`unsafe_store`, which is
what the listing uses. The final build is silent:

```bash
$ export MODULAR_TELEMETRY_ENABLED=0
$ mojo --version
Mojo 1.2.0 (2016d0cd)
$ nice -n 19 mojo build matmul.mojo -o matmul    # 6.05 s wall
$ ls -la matmul
-rwxr-xr-x 1 root root 56584 Oct 24 03:35 matmul
```

A 57 KB native executable. `mojo build --emit asm` shows that the blocked kernel's inner loop
is eight `vfmadd231ps` instructions on `zmm` registers, 512-bit AVX-512, which is what
`simd_width_of` picked when it returned 16 lanes of float32.

The Python side is the same product in NumPy (`A @ B`, float32, best of five) and as a pure
Python triple loop. The pure Python loop runs at n = 128, because n = 512 would take minutes.
I ran three rounds, interleaved, with `OPENBLAS_NUM_THREADS` at 1 and 2. Verbatim output:

```text
== round 1  load average: 9.84, 6.93, 3.51
$ ./matmul
N = 512  simd width (float32) = 16
naive  ms: 304.382368  GFLOP/s: 0.8819021212161672
simd   ms: 6.564135  GFLOP/s: 40.89426192483854
block  ms: 2.156174  GFLOP/s: 124.49619372091492
max |naive - simd|, |naive - block| = 0.0  checksum c[0], c[last] = 151.90997 155.06004
$ OPENBLAS_NUM_THREADS=1 python matmul_py.py
numpy  ms: 1.943  GFLOP/s: 138.18  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 563.1  GFLOP/s: 0.0074
$ OPENBLAS_NUM_THREADS=2 python matmul_py.py
numpy  ms: 1.069  GFLOP/s: 251.03  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 554.0  GFLOP/s: 0.0076
== round 2  load average: 9.84, 6.93, 3.51
$ ./matmul
N = 512  simd width (float32) = 16
naive  ms: 263.699274  GFLOP/s: 1.0179605424321343
simd   ms: 6.355364  GFLOP/s: 42.2376210080178
block  ms: 2.054937  GFLOP/s: 130.62953073500552
max |naive - simd|, |naive - block| = 0.0  checksum c[0], c[last] = 151.90997 155.06004
$ OPENBLAS_NUM_THREADS=1 python matmul_py.py
numpy  ms: 2.008  GFLOP/s: 133.66  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 475.1  GFLOP/s: 0.0088
$ OPENBLAS_NUM_THREADS=2 python matmul_py.py
numpy  ms: 1.368  GFLOP/s: 196.28  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 598.5  GFLOP/s: 0.0070
== round 3  load average: 9.84, 6.93, 3.51
$ ./matmul
N = 512  simd width (float32) = 16
naive  ms: 402.364981  GFLOP/s: 0.6671441817149589
simd   ms: 8.057109  GFLOP/s: 33.3165973055596
block  ms: 3.270955  GFLOP/s: 82.06638611659287
max |naive - simd|, |naive - block| = 0.0  checksum c[0], c[last] = 151.90997 155.06004
$ OPENBLAS_NUM_THREADS=1 python matmul_py.py
numpy  ms: 1.878  GFLOP/s: 142.90  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 423.1  GFLOP/s: 0.0099
$ OPENBLAS_NUM_THREADS=2 python matmul_py.py
numpy  ms: 19.672  GFLOP/s: 13.65  c[0], c[last] = 151.91003 155.06006
python ms (n=128): 803.2  GFLOP/s: 0.0052
```

<MatmulRuns />

What the runs say, with the medians across rounds:

- **Same loop, compiled:** the naive Mojo triple loop ran at 0.88 GFLOP/s. Pure Python ran
  the same loop at about 0.0075. That is roughly 117x (**reasoned**, from the two rates), and
  it is the gap between an interpreter and LLVM, not anything specific to Mojo.
- **Loop order and SIMD:** switching to i-k-j and `vectorize` took it to 40.9 GFLOP/s.
- **Register blocking:** holding the C tile in registers took it to 124.5 GFLOP/s at
  2.156 ms, about 141x the naive loop (**reasoned**: 304.38 / 2.156).
- **Against OpenBLAS:** single-thread NumPy ran at 138.2 GFLOP/s, 1.943 ms. My 40-line kernel
  is about 11% slower (**reasoned**: 2.156 / 1.943) and has no packing, no cache tiling and no
  edge handling; it works because 512 divides evenly by its tile. Two-thread NumPy ran at a
  median of 196.3, with one run at 13.65 when the second core was taken by someone else.
- **Same answer:** the three Mojo kernels agree exactly (`max |naive - simd|, |naive -
  block| = 0.0`). NumPy differs in the fifth significant figure (151.90997 vs 151.91003)
  because OpenBLAS sums in a different order.

This is the language half of the release, Apache before this week. It shows how close a
plain `SIMD` type gets to a tuned BLAS in code you can read in a minute. Packing, tiling,
threads and every other shape are what `max/kernels` is for.

### What I did not run

I did not build the compiler from source. The README's path is
`./bazelw run //Mojo:mojo`, and `MODULE.bazel` builds LLVM from a pinned commit with Modular's
own patches applied. That means compiling LLVM, MLIR, the Mojo compiler and its dependencies
with Bazel: many gigabytes of build output and, on four shared cores, far more than the twenty
minutes and 2 GB of disk I had. I also did not install the `max` wheel or run the graph
compiler, so nothing here measures MAX's fusion or its GPU path.

## What to make of it

The release is real. The graph compiler's design docs, its passes, the HAL and the vendor
plugins are readable, with the history that explains them. If a kernel misbehaves, you can
now read the lowering instead of guessing.

It is not open source in the sense that LLVM is, and the post that called it "fully open"
claimed more than the licence grants. Mojo is. The MAX kernels are. The parts that make MAX
run across vendors are source you may read, change, ship as binaries and contribute back,
but may not fork in public. Modular says that is to prevent fragmentation, and the FAQ points
anyone who needs more, such as a chipmaker with a private backend, at an alliance that opens
in 2027.

For the related ground on this site: [Modular's LLM Inference Handbook](/articles/modular-llm-inference-handbook)
is the same company's teaching material, checked formula by formula.
[CUDA Rust](/articles/cuda-rust) is another MLIR-shaped route from a language to GPU code.
[TorchTPU](/articles/torchtpu) shows the other way to get portability, with the framework
compiling down through someone else's compiler. [DeepGEMM](/articles/deepgemm) is what a
production matmul kernel looks like once it grows past forty lines.
