Getting started

Getting started

pyscriptc compiles typed Python to a native binary. This page gets you from nothing to a running binary in a few minutes.

Install

Run the install script for your platform. It checks the prerequisites, installs uv and, with the flag, zig where it can, then installs pyscriptc and runs pyscriptc doctor. It never uses sudo or an admin shell: for anything it will not install itself it prints the exact command to run as your normal user.

macOS / Linux
Windows
curl -LsSf https://raw.githubusercontent.com/sigilco/pyscriptc/master/docs/install.sh | sh
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/sigilco/pyscriptc/master/docs/install.ps1 | iex"

The script is a convenience: it does the two commands below and nothing more. To install by hand, use uv tool install pyscriptc.

From a checkout of the repository, run the script from the file instead of the URL:

sh docs/install.sh           # macOS and Linux
.\docs\install.ps1           # Windows

Pass --yes (or -Yes on Windows) to let the script install uv and zig too.

Prerequisites

You need two things:

  • CPython 3.11 or later, to run the compiler. On an older CPython, uv tool install --python 3.14 pyscriptc fetches a suitable interpreter.
  • The compiled program always targets CPython 3.14 semantics, whatever host runs the compiler. A source the host cannot parse (syntax newer than the host) is a syntax error before the compiler sees it; see Divergences.
  • A C toolchain on PATH, to link compiled programs. zig also enables cross-compilation.

The type checker ships inside the package, so there is nothing extra to install for it.

C toolchain by platform

Platform Install a compiler
macOS xcode-select --install (or brew install zig)
Debian / Ubuntu sudo apt install clang (or sudo apt install zig on newer releases)
Fedora sudo dnf install clang
Arch sudo pacman -S clang
Any Linux or macOS mise use -g zig
Windows winget install zig.zig (or scoop install zig)

You only need one of clang or zig. Run pyscriptc doctor after installing to see what was found.

No system zig? Install it as a wheel

If the host has no zig and no clang, install pyscriptc with the zig extra:

uv tool install "pyscriptc[zig]"

The extra pulls the ziglang wheel, which ships the zig toolchain. The wheel registers only a python-zig console script, so pyscriptc installs a zig PATH shim over python -m ziglang and reports it as zig: ... [PATH shim for pip install ziglang] in doctor. With that in place --driver zig and cross-compilation (--target) work with no other setup.

The same works with pipx install "pyscriptc[zig]" and pip install "pyscriptc[zig]". The extra is the wheel route only: a system zig (brew, winget, mise, the distro package) is found directly and needs no shim.

Install pyscriptc

These pages describe master; the newest released wheel can lag it.
uv tool install pyscriptc installs the newest release; installing from the repository
(uv pip install git+https://github.com/sigilco/pyscriptc) installs master.
pyscriptc doctor prints the installed version, so you can see which one you have.

Install pyscriptc as a tool:

uv tool install pyscriptc

pipx install pyscriptc and pip install pyscriptc do the same thing. Prebuilt binaries for Linux, macOS and an experimental Windows build are on the releases page; the binary still needs clang or zig on PATH to link programs.

Then check the toolchain:

pyscriptc doctor

doctor prints the pyscriptc version, the checker it found, the C compiler or zig it will link with, and the cache locations. If something is missing, fix it with the table above and run doctor again.

For an automated check, pyscriptc doctor --json prints the same facts as JSON. The zig.found and clang.found fields answer whether this machine can compile a binary at all.

First run

Create a small typed script:

# sum_squares.py
def sum_squares(n: int) -> int:
    total: int = 0
    for i in range(1, n + 1):
        total = total + i * i
    return total


if __name__ == "__main__":
    print(sum_squares(10))

Compile and run it:

pyscriptc run sum_squares.py

pyscriptc run compiles once, caches the binary under ~/.cache/pyscriptc/bin, and runs it. A second run of an unchanged file skips the compile. Arguments after -- reach the program as sys.argv.

To compile a function and run it directly:

pyscriptc compile sum_squares.py --run --call sum_squares --args '[10]' -o /tmp/sum_squares

--call names the function to run and prints its return value, --args passes a Python list of arguments, and -o names the output binary. Every subcommand and flag is listed in the CLI reference.

When a compile stops

If a file cannot be compiled, pyscriptc prints a table naming each construct and a code such as PS2003, and exits with a status that says what happened:

Exit Cause
0 Compiled (plus the binary’s own status with --run)
1 An internal compiler error
2 The type checker rejected the file (or a command-line syntax error)
3 The file uses something pyscriptc cannot compile yet
4 A version or target mismatch

Run pyscriptc explain PS2003 to see what a code means and how to change your code. The full list of diagnostic codes is in Diagnostics, and the general reference for unsupported behavior is Divergences from CPython.

If your app is framework-heavy

Reflection-heavy and framework-heavy code (pydantic models, Flask routes, agent frameworks) does not compile to native code.
It does not fail either: once an untyped import sits at a module top level, that module’s functions are pulled onto the embedded CPython island with it, and the program runs there.
What it costs is the island: those parts run at interpreter speed, and every call crossing between a native function and an island one pays a marshalling cost.
The fences that remain in your own code (a missing annotation, an Any annotation, a construct outside the subset) still stop the build, and each names the line to change.

Before building, run pyscriptc assess on the tree and read the plane map it prints: what runs native, what runs on the island and why, and the policy lines that route each unsupported import.
The rules are in What runs native and what runs on the island, the island mechanics and what a crossing costs in Libraries and fallback mode, and how this compares with other tools in Comparison with other tools.