Yokan
Write Python. Ship native.
A compiler that takes a statically typed subset of Python to native
code. What you write is a slice of Python, and inside that slice your
code behaves exactly as Python. While you develop, the whole app runs
on real CPython; when you ship, the same source becomes a machine-code
executable. Whether the two behave the same is something you
can check, with yokan gate.
The whole picture
One source, two roads to run it.
Both roads stand on the same Rust foundation — pixie, the
substrate language Yokan compiles through; the .pix in the middle
of the release road is its readable source, so you can open it and
see what your app compiled to (yokan translate app.py prints it).
What it looks like

demo/opsboard
— a three-module dashboard: two stores, a sum-typed health model
matched in the view, charts, a virtualized alert feed, theme flip.
Written entirely in Python; ships as one native binary.
Write it, run it, ship it
The smallest complete app:
# /// script
# requires-python = ">=3.14"
# dependencies = ["yokan"]
# ///
from yokan import State, button, column, run, text
count: State[int] = State(0)
def view():
with column(spacing=12, padding=16):
text(f"count: {count()}", size=34)
button("+1", on_click=lambda: count.set(count() + 1))
if __name__ == "__main__":
run(view, title="counter")
Run it with uv run app.py and this window opens (the renderer is
gpui, the engine behind the Zed editor):

Edit the running app's source and save — the app updates in place, views and handler behavior alike, with the state intact. The GIF below is that moment (editing another small demo); note the tick counter never stops:

Ship it:
No @py escapes in the app? Then the executable contains no
CPython at all — zero links to Python, 14.7 MB (11.3 MB stripped),
millisecond startup. The person receiving it installs nothing.
"But it worked on my machine"
Hand it a sequence of interactions and it replays them against the CPython run and the machine-code build, then byte-compares the resulting screens. Yokan calls it the gate:
Yokan's own modules — files, SQLite, HTTP, the clipboard — are one
implementation that both runs call, so there is nothing for them to
disagree about. Python's own modules (math, re, datetime and
the rest) are answered by CPython while you develop and by a twin
once compiled, and the gate is what holds those two together. What
Yokan cannot do yet is listed, with reasons, in
What does not work yet.
Two ports
Two of the bundled demos are ports of apps written in Python, and they sit at opposite ends of how much Python the shipped app carries.
Pyxel's example games are ported almost line for line: the same pixel canvas, the same thirty frames a second, the same keys read while they are held. The binary carries no Python at all, and a script of keystrokes and frames replays both runs, so the gate compares every frame of the game.
demo/shooter
and demo/jump
— Pyxel's two examples, ported to the canvas.
At the other end is Buzz's screen and its flow: drop a recording,
pick a model and a language, watch it work, read the segments, export
TXT / SRT / VTT. The transcription is Whisper — real Python, running
on an embedded CPython through @py — and --bundle --app makes a
.app that carries its own runtime. The gate compares the transcript
and the SRT it writes, byte for byte.

demo/transcribe
— Buzz's screen and flow, with mlx-whisper inside the escape.
When an agent is writing it
An agent writes a file and reads what comes back, so what comes back decides how the session goes. The first two commands answer in about a second, with no compiler and no window: a refusal that names what to write instead, and the screen as text. The gate is the proof at the end.
Building with an agent walks the whole loop, and
skills/yokan/SKILL.md
is the guide to hand your agent.
What else is in it
-
The rest of Python stays
Mark a function
@pyand it runs on real CPython embedded in the executable. numpy, pandas, your existing code — all of it. -
Rust crates, yours or crates.io's
yokan add app.py deunicode 1— declare a crates.io version or a local path and call it from your Yokan code. The crate side is ordinary Rust; nothing has to be written for Yokan. -
Typed and checked
Bundled stubs make pyright/Pylance check Yokan apps clean —
@storesingletons bind correctly,@model/@valuecarry field constructors,Weak[Node]reads asNode | None.
Where next
-
uv runcovers development; a native build needs a Rust toolchain. macOS on Apple silicon and Linux today. -
One pass over how apps are written — state, views, forms, memory, Rust crates, the gate — closing with what does not work yet. (日本語版)
-
Every bundled demo, screenshotted — from the smallest counter to the OpsBoard dashboard.
-
The compiler, the engine, and the demos.
The name is the Japanese confection — yokan (羊羹), a dense solid block made to be sliced and handed out. Which is what your app becomes.
"Python" is a trademark of the Python Software Foundation.