← all posts

I'm restarting a Python compiler. Here's why most of my last attempt was wasted.

Let me be honest with you.

My last project, pycc, had 255 architecture decision records, a 100% diff-coverage gate, a performance gate with five-run medians, a governance audit workflow, a search-visibility ledger… and a compiler that was still pre-alpha.

I built a bureaucracy and called it engineering. 🧱

Today I’m starting over. Same mission, zero ceremony.

The mission 🎯

Take the Python you already write - with type hints - and:

  • ⚡ run it at Rust-like speed
  • 🛑 catch type errors at compile time, not at 3 a.m. in production
  • 🤝 keep it importable from normal Python, so numpy and torch just work

No new language. No dialect. Your code, just faster and stricter.

What I’m doing differently 🔥

1. Interop is day one, not “v0.7”. Real Python lives next to numpy, torch and friends. A binary without CPython sounds cool and is useless for that. The main output is now a CPython extension module: typed code runs native, the boundary speaks PyObject*.

2. Two modes, no excuses. strict - every type known, Any is an error, values become raw i64, f64, structs. non-strict - code I can’t prove compiles to C-API calls, like Cython. Still compiled. Still correct. You choose per module.

3. The process is a README, not a religion. An 8-line AGENTS.md. One CI job. This blog. That’s it.

4. Ownership is an optimization, not a personality. Python references are shared. I won’t pretend they aren’t. I’ll skip refcounts where I can prove it’s safe - after profiling, not before.

The inspiration 💡

ts-rust ported the TypeScript compiler with agents by doing one thing well: compare against the real thing, on real inputs, all the time. My oracle is CPython 3.13. If my output differs from CPython’s, I’m wrong. Simple.

Day 1 results 📊

I didn’t throw away the good parts. I took the compiler itself from pycc - parser, type checker, IR, LLVM backend, runtime - and left every ADR and gate behind.

  • ✅ Builds on LLVM 22
  • ✅ 8,846 tests passing out of the box (the 8 failures: 6 permission tests that can’t fail when you run as root, 2 that read docs I deliberately didn’t bring)
  • ✅ fib(32): ~3x faster than CPython, process start included
  • ✅ And this, at compile time:
error[T0021]: argument 1 of `fib` expects `int`, got `str`

No runtime. No surprise. Just a compiler telling you the truth.

What’s next 👀

Non-strict mode, then numpy arrays as first-class types - that’s where the 50-100x lives. I’ll post the benchmarks, including the ones that make me look bad.

Follow along. This is going to be fun. 🚀