Installation
Develop: uv is everything you need
A Yokan app is an ordinary Python file. Declare the dependency in the PEP 723 header and uv does the rest:
# /// script
# requires-python = ">=3.14"
# dependencies = ["yokan"]
# ///
from yokan import State, button, column, run, text
That covers the whole develop experience — the GPU window, the state-preserving live reload, headless script runs. No Rust involved.
On Linux the window uses the machine's own graphics, font and keyboard libraries rather than carrying copies, so what you see while developing is what the app you ship draws. A desktop already has them; a bare container needs them installed:
Debian and Ubuntu call the same five libasound2t64,
libfontconfig1, libxcb1, libxkbcommon0 and
libxkbcommon-x11-0. Opening a window also wants the Vulkan loader
and a driver, which the Ship section below names.
In a project instead of a script: uv add yokan. For the yokan
command: uv tool install yokan. Plain pip works too.
From the first file to a release
$ uv tool install yokan # the yokan command
$ yokan init app.py # the first file, its tests, a workflow
$ uv run app.py # develop: window, live reload
$ yokan check app.py # is it inside the dialect?
$ yokan gate app.py --script "click:+1" # both runs, compared
$ yokan build app.py --release --onefile # ship one file
The first four need nothing but uv. The last two compile, so they need Rust — and they fetch the crates they compile against by themselves.
yokan translate app.py prints the .pix the release build
compiles, at any point along the way.
Platforms
Today: macOS on Apple silicon and Linux, Python 3.14+.
Ship: a Rust toolchain
- Install Rust via rustup; the compiler version is pinned by the repository and fetched automatically on the first build.
- On macOS you also need Xcode's Metal toolchain (the GPU engine builds shaders).
-
On Linux the engine draws through Vulkan and opens its window on Wayland or X11, so the build needs a C compiler and the libraries it links against. On Fedora:
$ sudo dnf install gcc alsa-lib-devel fontconfig-devel \ freetype-devel libxkbcommon-devel libxkbcommon-x11-devel \ libxcb-devel vulkan-loader mesa-vulkan-drivers python3-develOther distributions carry the same libraries under their own names.
python3-develis only for apps with@pyescapes, whose build embeds CPython. - The crates the build compiles against live in the repository, and the firstgateorbuildfetches the checkout matching your version into~/.cache/yokan/(about 11 MB). There is nothing to clone by hand. Runyokaninside a checkout and it uses that one;PIXIE_REPOpoints it anywhere else. - That first build compiles the engine and takes a few minutes; later builds are incremental.
Upgrading, and the cache
Upgrading is uv tool upgrade yokan (or pip install -U yokan).
The next native build fetches the checkout for the new version and
removes the one it replaces. The build tree sits beside the
checkouts rather than inside one, so an upgrade compiles what
changed instead of the engine all over again.
$ yokan version
yokan 0.2.1
checkout ~/.cache/yokan/repo-0.2.1 (v0.2.1, fetched)
builds ~/.cache/yokan/target (3.4G)
$ yokan clean # throw the cache away
Everything under ~/.cache/yokan/ is one fetch and one build away,
which is what makes clean the way out of a state you don't trust.
Writing Yokan with an agent
skills/yokan/SKILL.md
is a guide for an agent: the whole dialect in one file, with every
refusal and what to write instead. Put it where your agent looks for
skills — for Claude Code that is ~/.claude/skills/:
$ curl --create-dirs -o ~/.claude/skills/yokan/SKILL.md \
https://raw.githubusercontent.com/i2y/yokan/main/skills/yokan/SKILL.md
An agent that has read it gets the subset right the first time, instead of learning it from refusals at build time.
The loop it works in — three commands, and what each hands back — is on Building with an agent.
What a build produces
If the app uses no @py escapes, the executable contains no
CPython at all — zero links to Python, 14.7 MB (11.3 MB
stripped), millisecond startup.
Apps that do use @py ship CPython embedded:
$ yokan build app.py --release --bundle # app folder + runtime
$ yokan build app.py --release --onefile # one distributable file
--onefile is about 17 MB stdlib-only, about 21 MB with
numpy; the first launch unpacks to a cache and later launches start
in about 40 ms. Add --app (alone or with --bundle) for a macOS
.app bundle in dist/ — Dock identity, double-click launch, an
icon from <stem>.png if present. Either way, the receiving
machine needs no Python and no pip.
On Linux the shapes are Linux's: --app writes an AppDir and
--appimage packs it into one .AppImage, carrying the libraries a
host is not expected to have. --bundle and --onefile carry CPython
in Apple's layout, so they name themselves and stop there.
Measured (macOS/arm64, release): 4.7 ms start, ~1 ms live reload.