Skip to content

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
$ uv run app.py

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:

$ sudo dnf install alsa-lib fontconfig libxcb libxkbcommon \
    libxkbcommon-x11

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-devel
    

    Other distributions carry the same libraries under their own names. python3-devel is only for apps with @py escapes, whose build embeds CPython. - The crates the build compiles against live in the repository, and the first gate or build fetches the checkout matching your version into ~/.cache/yokan/ (about 11 MB). There is nothing to clone by hand. Run yokan inside a checkout and it uses that one; PIXIE_REPO points 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.