xmojo is an interactive Mojo environment built on Modular's ORC execution
engine. One command provides a terminal REPL, native compilation, package
precompilation, and a Jupyter kernel with persistent state and rich display.
xmojo is created by Jeremy Howard from Answer.AI. It is not a Modular project.
xmojo supports Apple Silicon on macOS 12 or newer, and ARM64 or x86-64 Linux systems with glibc 2.35 or newer:
uv pip install xmojoThe wheel is self-contained. It includes the Mojo compiler, runtime, and standard library used by xmojo, so it does not require a Modular checkout, Bazel, or a separate Mojo installation. It also installs a Jupyter kernelspec.
Each xmojo release targets one exact Mojo nightly. Its numeric release component
ends with that nightly's timestamp; a .postN suffix denotes packaging or
documentation updates for the same build.
xmojo # interactive ORC REPL
xmojo -e 'print("hello")' # evaluate one cell
xmojo example.mojo # execute a Mojo file
xmojo build hello.mojo -o hello # build a native executable
xmojo precompile mypackage -o mypackage.mojoc # precompile a package
xmojo kernel -f connection.json # run as a Jupyter kernel
xmojo --versionInstall xmojo in the environment used by Jupyter, start your preferred Jupyter frontend, and select Mojo (xmojo):
uv pip install xmojo jupyterlab
jupyter labThe kernel provides:
- persistent functions, types, and typed top-level variables;
- exact streaming of
stdoutandstderr; - automatic display of a cell's final expression;
- explicit rich display with textual MIME bundles;
- compiler-backed completion, inspection, and input completeness;
- source-mapped compiler diagnostics and Mojo runtime stack traces; and
- continued use of the session after ordinary compilation or runtime errors.
Compilation failures execute nothing and add no names. Mutations completed before a runtime error remain visible, while new variables from the raising cell are not persisted.
display() publishes explicit output. Mojo repr traits provide
compiler-checked HTML, Markdown, SVG, LaTeX, or complete MIME-bundle
representations:
from xmojo import HTMLRepr, display
@fieldwise_init
struct HTML(HTMLRepr):
var source: String
def _repr_html_(self) -> String:
return self.source
display(HTML("<b>explicit display</b>"))
HTML("<b>automatic final-expression result</b>")The other traits are MarkdownRepr, SVGRepr, LaTeXRepr, and
MIMEBundleRepr. A Writable value also receives a text/plain
representation; other values receive a type-name fallback.
- Interrupting a running cell is not yet supported.
- Rich display currently supports textual MIME data, without binary buffers, display metadata, or transient display IDs.
- Persistent variables cannot be redeclared or implicitly captured by functions defined in other cells.
- GPU support is opt-in and currently targets top-level noncapturing kernels.
GPU sessions use the exactly matched official Mojo compiler and MAX runtime. Install the optional dependency from Modular's nightly package index:
uv pip install --prerelease=allow \
--extra-index-url https://whl.modular.com/nightly/simple/ \
'xmojo[modular-gpu]'On Apple Silicon, install Xcode's optional Metal toolchain once:
xcodebuild -downloadComponent MetalToolchainStart a GPU-enabled REPL with:
xmojo --modular-gpuThe launcher detects the local accelerator and supplies the matched compiler, MAX imports, and AsyncRT runtime automatically. Compile and launch an ordinary top-level Mojo function:
from std.gpu import global_idx
from max.gpu.host import DeviceContext
from xmojo.gpu import compile
def increment(output: Pointer[Float32, MutAnyOrigin], size: Int32):
var i = global_idx.x
if i < Int(size):
output[unsafe_offset=i] += 1
with DeviceContext() as context:
var buffer = context.enqueue_create_buffer[DType.float32](256)
var kernel = compile[increment](context)
kernel.enqueue(buffer, Int32(256), grid_dim=1, block_dim=256)
context.synchronize()compile[...] caches device objects under ~/Library/Caches/xmojo/gpu.
Set XMOJO_GPU_CACHE_DIR to choose another directory. Kernels must currently
be top-level, nonparameterized, noncapturing functions with an ordinary name.
Launch argument count and device types are checked while compiling the cell.
The installed Jupyter kernelspec is CPU-only. To add a separate GPU kernel:
gpu_kernel="$(jupyter --data-dir)/kernels/xmojo-gpu"
mkdir -p "$gpu_kernel"
cat > "$gpu_kernel/kernel.json" <<'JSON'
{
"argv": ["xmojo", "--modular-gpu", "kernel", "-f", "{connection_file}"],
"display_name": "Mojo (xmojo, Modular GPU)",
"language": "mojo"
}
JSONSelect Mojo (xmojo, Modular GPU) in Jupyter.
Run xmojo without arguments. A blank line submits each cell:
$ xmojo
Mojo ORC REPL
Expressions are delimited by a blank line. :quit exits.
1> def answer() -> Int:
.. return 42
..
2> print(answer())
..
42Declarations and variables persist between cells:
var total = 40total += 2
totalThe final expression produces Int(42) in Jupyter. Persistent variables keep
their original type and cannot be redeclared. They must own their data or refer
only to static storage; copy borrowed views into an owned value before
persisting them.
xmojo build uses Modular's native Mojo build driver with an ordinary stdlib,
so compiled programs retain normal standalone I/O behavior:
hello.mojo:
def main():
print("Hello from Mojo")xmojo build hello.mojo -o hello
./helloHello from Mojo
Precompile a directory containing __init__.mojo and other Mojo modules:
xmojo precompile mypackage -o mypackage.mojocThe result can be supplied to Mojo through its normal import paths.
See DEV.md for architecture, source builds, dependency revisions, testing, and contributor workflow.
Apache License v2.0 with LLVM Exceptions. See LICENSE.