Start with the quickstart if you want a running add/2. How Mojo and the BEAM own values is ownership.md. The stage verdicts are in stages/report.md. The API is API.md. Packaging limits are runtime.md. The compatibility table is compatibility.md.
This file is also the Stage 0 path: a Mojo shared library that the BEAM loads as the NIF Elixir.Mojoler.POC.add/2. Chapters 00–09 below are that record. Units 1–20 are the library curriculum. Where a Stage 0 sentence is now too narrow, the chapter says so at the top and points at the later measurement.
Read GLOSSARY.md when a word is doing more work than it looks like. The command logs live in evidence-ledger.md. The verdict is 09-feasibility-report.md. How we know the binary is Mojo is direct_mojo_proof.md.
Each numbered chapter has the same ten sections: objectives, why it matters, a mental model, theory, a hands-on exercise, a walkthrough, the ABI or compiler detail, failure modes, a Rustler/Zigler note, and a checkpoint. Exercises describe the shape of the output. The ledger is where the actual text from this machine is quoted.
Chapters
- 00 — Environment and sources. What was installed, and why
enif_get_int64is a macro here. - 01 — Research questions. The bar for calling the experiment a NIF.
- 02 — Mojo language and compiler.
def,abi("C"), and the LLVM add. - 03 — FFI and the C ABI. Thin function pointers versus a pointer to a stack slot.
- 04 — BEAM NIF internals. Schedulers, terms, badarg, and why a trap kills the VM.
- 05 — OTP ABI map. The measured 32-byte and 96-byte structs.
- 06 — Mojo meets that ABI. The eight experiments and the
callocdecision. - 07 — Memory and lifetime. What is borrowed, what is leaked, what was not attempted.
- 08 — Schedulers and runtime. Dirty flags,
initialize_runtime, and the overhead samples. - 09 — Feasibility. PASS for
add/2on this Mac and on Linux x86-64. One Apple GPU call also returned 42.
Units
Each unit has objectives, a model, a lab command, a failure, and a checkpoint answer.
- From Stage 0 to a library
- Mojo language essentials
- Mojo compiler pipeline
- ABI and layout
- Dynamic linking
- BEAM internals for NIF authors
- OTP ABI automation
- Safe conversion design
- Memory across runtimes
- Resources and finalizers
- Binary ownership
- Scheduling
- Mojo runtime and threads
- Mix integration
- DSL and code generation
- Debugging native failures
- Performance engineering
- GPU internals and ownership
- CI and compatibility
- Design comparison and capstone
Suggested order of commands
scripts/doctor.sh
scripts/run-abi-experiments.sh
scripts/test-isolated.sh
scripts/inspect-abi.sh
If doctor fails, stop. The later commands assume .venv/bin/mojo and OTP 28.3.1.
What you should be able to say at the end
The BEAM wants a nif_init that returns a 96-byte ErlNifEntry for NIF 2.17, and a callback it will call as a C function. Mojo 1.1.0 emits that callback as a thin function and that entry as a RegisterPassable struct whose offsets matched clang. They meet because dlopen binds enif_get_long to beam.smp and the VM calls the function pointer stored in the entry. The result succeeds on this Mac and, for the CPU add/2, on the Linux Actions runner: add(20, 22) is 42. A separate Apple GPU NIF also returned 42 once (E17). It is not evidence about NVIDIA, concurrent GPU calls, or binaries.