Skip to main content

jaxplorer

A compiler explorer TUI for JAX. Put a jitted function on the left, watch its jaxpr, StableHLO and optimized HLO on the right, and see all three change as you type.

┌─ source ──────────────────┬─ Jaxpr │ StableHLO │ Optimized HLO │ Analysis │ Errors ─┐
│ def f(x, w):              │ { lambda ; a:f32[8,16] b:f32[16,4]. let                 │
│     return jnp.tanh(x @ w)│     c:f32[8,4] = dot_general[...] a b                   │
│                           │     d:f32[8,4] = tanh c                                 │
└───────────────────────────┴────────────────────────────────────────────────────────┘
 cpu · jax 0.11.0 · 134 ms · ok

Installation

uv sync                             # in a checkout
uv tool install "jaxplorer[jax]"    # standalone, with its own jax
uv tool install jaxplorer           # standalone, borrowing a project's jax (see below)

Needs Python 3.12+ and textual >= 6.0. jax >= 0.9 is an extra, since the jax worth inspecting is usually a project's own. Any CPU-only jax install is enough; a GPU or TPU backend is only needed to compile for one.

Usage

uv run jaxplorer                      # scratch buffer
uv run jaxplorer examples/mlp.py      # open a snippet and edit it in place
uv run jaxplorer examples/mlp.py --watch   # keep editing in your own editor; jaxplorer reloads on save
key
ctrl+r recompile now
ctrl+s save the buffer
ctrl+z, ctrl+y undo, redo in the editor (cmd+z / cmd+y also work)
ctrl+f or / find in the active pane; n / N cycle the hits
f2 switch backend (skips ones that already failed here)
f3 show or hide the HLO debug tables
f6 collect per-pass HLO and LLVM IR, then recompile
alt+1alt+7 jump to a pane
down from the tab bar into the IR, then arrows scroll it
y copy the active pane to the clipboard
escape from the IR back to the tab bar
ctrl+q quit

Click any HLO instruction to select the source line that produced it.

Other options: --python PATH (compile under another environment's jax, see below), --platform cpu|gpu|tpu, --x64, --timeout SECONDS, --stages jaxpr,stablehlo,... (stopping before optimized_hlo skips XLA, which is much faster on a large model), and --passes to collect per-pass HLO and LLVM IR from the start.

Against your own project's jax

jaxplorer compiles in a subprocess, and that subprocess can be your project's interpreter:

cd my-project
uv run jaxplorer model.py                     # lookup via uv (VIRTUAL_ENV)
jaxplorer model.py --python .venv/bin/python   # or name the interpreter outright.

The interpreter is chosen in this order: --python, then $VIRTUAL_ENV, then the one running jaxplorer. uv run and a plain activate both export VIRTUAL_ENV, so inside a project the flag is rarely needed.

Anatomy of a snippet

A snippet is an ordinary Python module that defines a callable f and a tuple args of example inputs. Nothing needs to import jaxplorer.

import jax
import jax.numpy as jnp


def f(x, w):
    return jnp.tanh(x @ w).sum()


args = (
    jax.ShapeDtypeStruct((8, 16), jnp.float32),
    jax.ShapeDtypeStruct((16, 4), jnp.float32),
)

args may hold concrete arrays or jax.ShapeDtypeStruct specs. jaxplorer only traces and compiles f, never runs it, so shape specs are enough. Optionally define kwargs, static_argnums, static_argnames or donate_argnums; they are passed to jax.jit. See examples/ for an MLP, a lax.scan loop, and causal attention with a static argument.

How it works

Each pane is one step of JAX's public lowering chain:

pane source
Jaxpr jax.jit(f).trace(*args).jaxpr
StableHLO .lower().as_text()
Optimized HLO .compile().as_text(), after XLA's optimization passes
Analysis .cost_analysis() and .memory_analysis()
Passes a snapshot between every XLA pass, diffed to show which pass changed what
LLVM IR what the CPU backend handed to LLVM

Stages are reported independently, so a lowering failure still leaves you a valid jaxpr to read, and a buffer that does not even parse keeps the last IR that did compile on screen.

Compilation happens in a subprocess (python -m jaxplorer.worker) that stays warm between edits: JAX takes seconds to boot, XLA can abort the process outright, and the platform and x64 flags can only be set before JAX is imported.

For the rest of the pipeline (per-pass HLO dumps, LLVM IR, object code, and comparing two XLA builds against each other) see docs/xla-introspection.md.

jaxplorer executes the buffer. It is your own code in your own environment, but a snippet is run at module level on every recompile, so treat it the way you would treat python snippet.py.

Development

Contributions welcome. Here's the general testing and formatting workflow of the repo:

uv run --group test pytest
uvx prek run --all-files
uv run --group typing ty check

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jaxplorer-0.1.0.tar.gz (71.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jaxplorer-0.1.0-py3-none-any.whl (39.8 kB view details)

Uploaded Python 3

File details

Details for the file jaxplorer-0.1.0.tar.gz.

File metadata

  • Download URL: jaxplorer-0.1.0.tar.gz
  • Upload date:
  • Size: 71.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for jaxplorer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7e752e297da80f55d108fb109f333b9314cb01c833b565d5b14074e0cc22d6ec
MD5 69023a2343b1a21ce8a323530b7e26ab
BLAKE2b-256 33a0ed26876d33c02a0a48679dc94c44be128162cc9569f260933de0a09cf5c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for jaxplorer-0.1.0.tar.gz:

Publisher: release.yml on nicholasjng/jaxplorer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jaxplorer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: jaxplorer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for jaxplorer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 995306e3f9adce302384888c160fadee10c2c4833cc7994eb6eff132b7679119
MD5 24d5a88d44bdbcab20e06fb2577ea824
BLAKE2b-256 d1e0087139886895e8134f76bfdf838eb582a4552eee8dd5f2f2a4b56b67b17b

See more details on using hashes here.

Provenance

The following attestation bundles were made for jaxplorer-0.1.0-py3-none-any.whl:

Publisher: release.yml on nicholasjng/jaxplorer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page