# pon: a Rust JIT and AoT compiler for Python 3.14 with no interpreter

> pon lowers Python 3.14 through the ruff parser into one shared IR, then compiles it with Cranelift either in-process or into a standalone binary. Byte-exact differential testing against CPython is the acceptance gate, and that gate is the interesting part.

**can1357/pon** — Python 3.14, compiled to metal — JIT & AoT native compiler and runtime in Rust. Cranelift backend, ruff parser, Green Tea GC, byte-exact differential testing against CPython.

- Repository: https://github.com/can1357/pon
- Stars: 569 · Forks: 22
- Language: Rust
- License: not declared
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/can1357-pon

## What pon replaces, and for whom

CPython executes Python by compiling source to bytecode and walking that bytecode in an interpreter loop. pon removes both halves of that arrangement. The README states plainly that there is no interpreter and no bytecode: every module is parsed with the ruff parser, lowered to one shared intermediate representation, and compiled to machine code through Cranelift. The audience is narrow and specific. This is a project for compiler engineers, runtime engineers, and people who want to read a working Python tiering JIT in Rust, not for teams looking for a faster way to run a Django service this quarter. The README frames the ambition as "the bun/v8 of Python", which tells you the intended shape: a runtime that passes the CPython test suite, runs a multi-tier JIT, ships single-binary executables, and bundles a package manager and tooling. The same README then separates that ambition from present reality, pointing readers at a Status section for "what is true today versus where it is going". That distinction is the honest part of the document, and it should govern how you read everything else.

## One IR, two backends, and a NULL-sentinel ABI

The architecture is the reason to look at this repository. Source goes through the ruff parser, pinned to git tag 0.14.0 with PythonVersion::PY314, and lands in pon-ir. From there a single lowering path feeds every tier. In `pon run`, pon-codegen emits Cranelift CLIF that cranelift-jit compiles in-process. In `pon build`, the same CLIF goes through cranelift-object into an object file that is linked into a native executable. Baseline JIT, optimizing JIT and AoT all call the same `pon_*` helper functions in pon-runtime, so the runtime ABI does not fork per tier. Two decisions stand out. First, the object model is described as CPython's heap object layout minus the refcount header, with errors crossing the ABI as NULL sentinels rather than unwinding. That is a deliberate simplification: no refcount means no refcount traffic, but it also means every error path has to be checked at the boundary. Second, integers are arbitrary-precision through num-bigint behind PyLong, with a tagged small-int fast path described as landing in the typed tier. The tiering itself is conventional in outline: tier-0 compiles everything boxed with no type feedback and serves as the correctness baseline, forced by PON_TIER0_ONLY=1. Runtime helpers populate FeedbackCell type profiles from the first execution, hot functions recompile on a background thread, and running loops enter optimized code through on-stack replacement. The GC is where the two tiers genuinely diverge. Tier-0 scans the stack conservatively with a register-flush trampoline at safepoints; the typed tier upgrades to precise Cranelift user stack maps. That is a real engineering split, and it means the collector's behaviour is not identical across tiers.

## Building pon from source and running your first module

There are no published releases in the README, so installation means building the workspace. The pinned toolchain is nightly-2026-04-29 in rust-toolchain.toml, with rust-version = "1.94.0" and edition 2024, and Cargo.lock is committed. The README's quickstart writes a small file and runs it through the JIT, then through the AoT path. The first command produces hello.py, which defines a function, prints a string, and prints the result of add(2, 3).

```bash
printf 'def add(a, b):\n    return a + b\n\nprint("hello, world")\nprint(add(2, 3))\n' > hello.py
cargo run -p pon -- run hello.py
```

The README states that both paths print the same bytes CPython would. For this file you should see the greeting line followed by 5. The AoT command compiles the same IR through cranelift-object and links a native executable, which you then run directly.

```bash
cargo run -p pon -- build hello.py -o hello
./hello
```

The CLI surface documented in the README is small: `pon run <file> [args]`, `pon build <file> -o <out> [--allow-dynamic] [--opt] [--target <triple>]`, `pon repl`, `pon -c 'print(40 + 2)'`, and `pon - < script.py` for reading from standard input. Note that `run` takes trailing arguments for the script, which is the shape you want for anything that reads sys.argv. The build flags are worth reading twice: `--allow-dynamic` and `--target` both imply constraints the README does not spell out, and the AoT parity floor is lower than the JIT floor, which tells you the AoT path covers less ground.

## The differential harness is the actual product claim

Most compiler projects assert correctness in prose. pon asserts it with a ratchet. A corpus module passes only if pon produces byte-identical output to CPython v3.14.0 under TZ=UTC and PYTHONHASHSEED=0, and passing sets are committed into floor files that CI enforces, failing on any regression below the floor. The committed numbers in the README are 244 modules for the JIT suite and 206 for the AoT subset, with the full CPython Lib/test suite listed as "being brought up". Two details make this more credible than a badge. Corpus files are immutable once landed: new coverage arrives as a new module, verified byte-identical against python3.14 before it enters the manifest. And divergences that are CPython's own problem are recorded in pon-conformance/divergence-ledger.toml rather than smoothed over. The gate script is the only thing the README treats as a gate claim, which is a pointed instruction to ignore any other source of numbers:

```bash
bash scripts/gate.sh fast    # build + workspace tests + conformance floor + AoT floor + ft-stress
bash scripts/gate.sh full    # + cpython-full, bench, tier0-only diff, fuzz, package-manager E2E
```

You can also run a single suite directly. The fuzz suite is required to stay at zero divergences, and the ft-stress suite exercises no-GIL threading in the default runtime. If you are evaluating this project, run the fast gate before reading any further documentation. The floor files are the claim; the gate is the evidence.

## Where pon is the wrong tool

The README is unusually direct about the gaps, and they matter more than the architecture diagram. The CPython test suite is not passing yet; cpython-full is listed as being brought up, with its own floor file. The package manager, described as uv-style with pubgrub resolution over pyproject.toml and the PyPI simple index, is explicitly "not yet integrated into the runtime gates". That sentence should stop anyone planning to use `pon install` as a drop-in for pip or uv in a pipeline that has correctness requirements. The AoT story carries a second constraint: the AoT parity floor is 206 modules against the JIT's 244, so compiling to a standalone binary covers less of the corpus than running in-process. That is expected for a younger backend, but it means "pon build" is not simply "pon run, frozen". There is also a toolchain cost that will filter out most teams. The workspace pins nightly-2026-04-29 and six Cranelift crates in exact lockstep at =0.133.1, with ruff consumed as a git tag dependency rather than a crates.io release. The README says these pins are settled workspace-wide and enforced by Cargo.lock and rust-toolchain.toml, and instructs readers not to drift them casually. A nightly pin plus git-tag dependencies means builds depend on upstream availability and on a specific nightly being installable. Finally, there is no homepage and no retrieved release, so there is no packaged artifact to evaluate; you build from source or you do not evaluate it at all.

## How pon differs from CPython and from Nuitka

The closest comparison in kind is Nuitka, which also compiles Python ahead of time into a native executable. The difference in approach is what happens before code generation. Nuitka works from CPython's own parsing and semantics and emits C that is then compiled by a C toolchain, keeping CPython's runtime model, including reference counting, largely intact. pon replaces the front end with the ruff parser, owns its own IR, and emits machine code directly through Cranelift without a C intermediate. That removes the C compiler from the build path and gives the project control over tiering, which is what makes an in-process optimizing JIT possible at all. The cost is that pon has to reimplement the runtime semantics that Nuitka inherits for free, and the conformance floors are the visible measure of how much of that work remains. Against CPython itself the difference is categorical rather than incremental: CPython's interpreter loop is the execution engine, while pon has no interpreter and no bytecode at all. That is why the differential harness compares output bytes rather than performance, and why the project's own framing puts passing the CPython test suite ahead of beating CPython on speed.

## Maintenance, pins and licensing

The last push to the default branch was on 2026-07-07, and the repository is not archived. That is a recent push, but the README's own description of the project as under heavy active development is the more useful signal for planning: the interfaces you would build against are the ones the README says are still moving. The upgrade cost is concentrated in the pins. Cranelift is held at =0.133.1 across six crates in lockstep, so any Cranelift bump is a coordinated change. The toolchain is pinned to nightly-2026-04-29, and the MSRV is rust-version = "1.94.0" with edition 2024. ruff is a git dependency on tag 0.14.0 rather than a published crate, so a fetch requires network access to that repository. On licensing, no licence identifier is given, and the repository's top-level listing contains no LICENSE file. That is a gap you must resolve yourself before depending on the code in any form, because the terms under which you may use, modify or redistribute it are not stated anywhere in what is available. This is a factual observation about missing information, not a legal conclusion; if the terms matter to you, get them from the maintainer.

## Conclusion

pon is worth adopting if you want to read or contribute to a Python compiler rather than ship Python today, and if you are comfortable building a nightly Rust workspace. Do not adopt it as a production runtime: the README states the package manager is not yet integrated into the runtime gates and that the CPython test suite is still being brought up. Verify two things before anything else: the committed floors in conformance-floor.json and aot-parity-floor.json, and whether the licence file exists, since the repository listing shows no LICENSE entry.

## FAQ

### How do I install pon?

There is no retrieved release, so installation means building the workspace from source with cargo. The pinned toolchain is nightly-2026-04-29 in rust-toolchain.toml, with rust-version = "1.94.0" and edition 2024, and Cargo.lock is committed.

### Does pon use an interpreter or bytecode?

No. The README states there is no interpreter and no bytecode: every module is parsed with the ruff parser, lowered to one shared IR, and compiled to machine code through Cranelift, either just-in-time with `pon run` or ahead-of-time with `pon build`.

### What is the difference between `pon run` and `pon build`?

`pon run` compiles in-process through cranelift-jit, while `pon build` sends the same IR through cranelift-object into an object file linked into a standalone native executable. The AoT path covers less of the corpus: the committed floors are 244 modules for the JIT suite and 206 for the AoT subset.

## Sources

- [can1357/pon on GitHub](https://github.com/can1357/pon)
- [Issues](https://github.com/can1357/pon/issues)
- [README](https://github.com/can1357/pon/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/can1357-pon
