Run Python scripts anywhere. No Python required.
taipan is a single ~31 MB executable with CPython 3.14 inside. It runs Python files — including PEP 723 scripts with inline dependencies — on machines with nothing installed, and compiles scripts into standalone executables.
Highlights
- No Python required — the interpreter ships inside the binary.
- Inline dependencies — PEP 723 blocks are installed with uv and cached; one install per dependency set, ever.
- ~10 ms warm starts — about 3× faster than
uv run. - Standalone executables —
taipan buildbundles a script, or a whole package and its console script, into one file that runs offline. - Supports Linux, macOS, and Windows.
Installation
# On macOS and Linux. curl -LsSf https://raw.githubusercontent.com/FarhanAliRaza/taipan/main/install.sh | sh
# On Windows. irm https://raw.githubusercontent.com/FarhanAliRaza/taipan/main/install.ps1 | iex
Or download a binary for your platform from the
releases page (rename it
to taipan, and on Linux/macOS chmod +x it).
Usage
Run a script (taipan run script.py is the explicit equivalent):
taipan script.py [args...]
sys.argv, __file__, exit codes, tracebacks, threads, and every
multiprocessing start method behave as they would under a regular CPython.
Declare dependencies inline with PEP 723:
# /// script # dependencies = ["httpx"] # /// import httpx print(httpx.get("https://example.com").status_code)
taipan example.py # installs httpx on the first run; cached after thatEvery later run — of this script or any script with the same dependency
set — reuses the cached environment with no network and no uv invocation.
Installs are delegated to uv, found via $TAIPAN_UV, then PATH; if
neither exists, taipan downloads a static copy into its cache once (this
needs curl and tar). Scripts without dependencies never touch uv.
uv uses the embedded interpreter, so it never downloads a Python of its own.
This includes dependencies that publish no wheel: they are compiled from
source against the same CPython 3.14 that runs your code, and need a C
compiler (cc, or MSVC on Windows).
The exception is on Windows, where a package that embeds Python needs
python314.lib, an import library taipan does not ship. For those builds uv
falls back to its own interpreter and downloads one if it finds none. taipan
tells you when this happens.
Standalone executables
Bundle a script, the interpreter, and its dependencies into one file:
taipan build app.py -o app ./app
The result runs on the same platform with no Python, uv, or network access.
The output name defaults to the script name without .py (.exe added on
Windows). Dependencies are resolved at build time, so the first build of a
dependency set needs network; rebuilds are byte-identical.
Add sibling modules with --include-local and data files with --include:
taipan build app.py --include-local --include templates/ --include settings.json
--include-local bundles the .py files beside the entry script, keeping
their relative layout so import helper and from pkg import x work; it
skips .git, virtualenvs, __pycache__, and similar noise. It bundles what
exists — it does not compute an import graph. --include paths (repeatable,
file or directory) keep their basename next to the script; read them with
Path(__file__).with_name("settings.json"). Duplicate paths warn at build
time, and the last copy wins.
Building a package
taipan build also accepts a project directory or any requirement uv
understands. taipan installs the package with its dependencies, and the
executable runs one of its console scripts:
taipan build ./omniload -e omniload -o omniload # from a local project taipan build 'omniload==0.7.0' -e omniload # from a package registry
Use -e to name the console script, the same name pip install would put on
your PATH. Omit it if the package declares exactly one; if it declares
several, taipan lists them and asks. Only console_scripts entry points are
considered, not gui_scripts.
If no console script does what you want, -e also accepts an import target:
taipan build ./omniload -e omniload.main:main
The output name defaults to the console script's name.
A local project is reinstalled on every build, since its contents may have changed; uv's cache keeps this cheap. A pinned requirement reuses taipan's cached environment, so pin the version if you want rebuilds to fetch nothing.
How it works
The binary embeds a stripped CPython 3.14 and a bytecode-compiled standard
library, extracted to a local cache on first use. Dependencies are installed
by uv into content-addressed environments and precompiled once. Script
bytecode is cached and startup modules are frozen into the runtime, so a warm
start does almost no work. Threads and every multiprocessing start method
are supported.
taipan build appends the entry script and its installed environment to a
copy of the launcher, sealed with a digest that serves as both integrity
check and cache key. For a package build, taipan generates the entry script.
On the target, the first launch verifies and extracts the payload; later
launches read only the 64-byte footer. A truncated or modified executable
fails with a clear error.
The cache lives at ~/.cache/taipan (%LOCALAPPDATA%\taipan on Windows) and
is disposable — deleting it costs one re-extraction on the next run. Set
TAIPAN_CACHE to move it, or TAIPAN_UV to use a specific uv executable.
Comparison with uv run
uv run covers similar ground: it runs PEP 723 scripts and can download an
interpreter on first use — and taipan itself uses uv for installs. If you
have uv and network access, it is a good way to run scripts. taipan differs
where that assumption breaks:
- The interpreter is inside the binary, so a single file copy works on air-gapped and locked-down machines.
- Warm starts skip environment revalidation: roughly 10 ms versus 30 ms per run.
taipan buildproduces one executable that needs nothing on the target. uv has no equivalent.
taipan is not a project manager. For lockfiles, multiple Python versions, and day-to-day work inside a project, use uv.
Limitations
- Linux builds require glibc; musl (Alpine) is not supported yet.
- Dependency sets are not locked — the first resolution wins and is cached.
Pin versions in the PEP 723 block (
"httpx==0.28.1") for reproducibility. - A dependency with no wheel is compiled against the build machine's system libraries, so the executable only runs on systems at least as new as the one that built it. Wheels from PyPI target manylinux and carry no such restriction.
- Standard-library tracebacks show file and line but not source text, and
code that expects stdlib modules to exist as ordinary files may fail.
tkinter,idlelib,venv, andensurepipare not included. sys.executablepoints at the taipan launcher; it supports running scripts and CPython's multiprocessing worker protocol, not the full CPython CLI (no-m, no REPL).- PEP 723
requires-pythonis parsed but not enforced. - TLS uses the operating system's certificate store. If stdlib
sslcannot find certificates, setSSL_CERT_FILE; packages like httpx and requests bundle their own via certifi and are unaffected.
Building from source
Builds are native — the bundled CPython must match the host platform (Linux x86_64/arm64, macOS, Windows x86_64):
./tools/fetch_toolchain.sh ./vendor/zig/zig build
The executable lands in zig-out/bin/taipan. The toolchain script downloads
pinned, checksum-verified copies of Zig and CPython into vendor/.