Runtime pack and licenses
Runtime pack and licenses
A bundle compile (--embed-python=bundle, or the default auto mode when the compiler’s interpreter has no usable shared libpython, as inside the release binary) links and runs a pinned CPython runtime pack instead of the host interpreter.
The pack is fetched once, sha256-verified, cached, and carries its licenses with it.
This page is the licensing and provenance contract that the pack and every output built from it follow.
What the pack contains
The pack for each supported platform (macOS arm64 and Linux x86_64 in the first slice) is a tarball produced from the pinned python-build-standalone release recorded in packaging/runtime.lock.toml:
libpython3.14shared library and the version headers,- the standard library as a safe-trimmed zip (modules a program can import; test, idle, tkinter and similar trees are not bundled),
- the
licenses/directory from the matchingfullarchive: the CPython license text plus the license of every third-party component compiled into libpython (for example expat, libffi, mpdecimal, OpenSSL, SQLite, zlib, zstd; the authoritative list is the inventory in the pack, not this page).
The lock file pins the release tag, the asset name, the sha256 and the CPython micro version. A pack that does not match the lock is refused before anything is linked.
Fetching and caching
pyscriptc embed fetch # this machine
pyscriptc embed fetch --platform linux-x86_64
The compressed pack is tens of megabytes (roughly 27 MB on macOS arm64, 35 MB on Linux x86_64). It is fetched on demand, not at install time: a bundle compile without a cached pack says so and names the fetch command before downloading. The unpacked pack is cached under ~/.cache/pyscriptc/runtime/<pack-id>/.
Offline and air-gapped machines point PYSC_RUNTIME_DIR at an already-unpacked pack directory; the compiler then never touches the network.
Licenses in the output
The CPython license (PSF License Agreement) is permissive and allows redistribution in binary form provided the license text and copyright notice travel with the binary. A bundle compile therefore writes OUT/share/licenses/ with:
LICENSE.cpython.txt, the license text of the bundled runtime itself, copied from the pack (lib/pythonX.Y/LICENSE.txtof the pinned asset),- one
LICENSE.<component>.txtper third-party component compiled into libpython (expat, libffi, mpdecimal, OpenSSL, SQLite, zlib, zstd, ncurses and the rest of the inventory inpackaging/third-party.toml); the texts are vendored in the compiler’s package data (pyscriptc/pbs_licenses/) and copied into the output, NOTICE, the third-party notice rollup of the bundled runtime, generated byscripts/gen_third_party_notices.pyfrompackaging/third-party.tomland the runtime lock, and- one directory per bundled third-party distribution (issue #660), holding the
licenses/tree of its*.dist-infometadata.
The third-party texts are vendored because the pinned python-build-standalone asset the pack is cut from (install_only_stripped) ships no licenses/ directory; the full archive of the same release does, and scripts/sync_pbs_licenses.py vendors its texts with their sha256 pinned in packaging/pbs_licenses.toml. A runtime bump refreshes the vendored texts, the inventory and NOTICE together (see the operational doc).
The compiler itself is Apache-2.0; the preflight checker (pyrefly, MIT) ships inside the install. Neither license changes when a program is compiled with a bundled runtime, but the runtime’s own licenses must be present in every redistributed output directory, which the bundle step does automatically.
Asking before shipping
The third-party inventory of the first pack build is confirmed with the project owner before the first public release that ships a pack (the inventory check, not legal advice).
The self-compiled pyscriptc
pyscriptc can compile itself into a binary that needs no Python, uv or pip on the host. The build is one command from a checkout:
pyscriptc compile src/pyscriptc --program --skip-check --island --emit bin \
--embed-python bundle --embed-headers --bundle-exclude mypy -o dist/selfbin
The output is a relocatable directory, dist/selfbin/, laid out as:
bin/selfbin, the compiler itself (about 3 MB; every module ofsrc/pyscriptcis compiled into it, and the program’s non-Python files live inbin/pyscriptc-data/: the C runtime sourcesps_*.c, the vendored typeshed, the pyright stubs and the runtime lock),lib/, the pinned runtime:libpython3.14.so, the stdlib zip andlib/python3.14/(dynload modules plus the bundled pure-Python dependencies),include/, the CPython headers, staged by--embed-headers, so the binary can compile island programs (which includePython.h) at run time,share/licenses/, the license texts of the bundled runtime.
This is a two-file layout in spirit: the directory is the artifact, and it runs from any path. It is not a single file because the interpreter is a shared library and the stdlib is a zip; both must sit on disk next to the binary for the dynamic loader and the import system.
What the binary needs at run time, and what it does not:
- No Python, uv or pip. The interpreter and the stdlib travel in
lib/.env -i PATH=/nonexistent dist/selfbin/bin/selfbinprints its usage, and compiling a program that does not touch the island needs nothing else. - A C toolchain on PATH (clang or zig) for
--emit binandrun, exactly like the installed compiler. A compile with no toolchain fails with PS0001, which names the install options. - pyrefly for
checkand the preflight of a compile without--skip-check. The binary resolves it like the installed compiler: thePYREFLY_BINoverride, then apyreflyon PATH. When none is found the compile says so instead of half-running. - No network and no pack cache for
--embed-python bundlecompiles: the binary links user programs against the runtime it carries.
--bundle-exclude mypy declares the optional mypy bridge an extern dependency: the import stays in the compiled compiler, and the host answers it exactly like CPython answers a dead import. Without the exclusion the bundle refuses the compile, because mypy ships a compiled extension and a bundle carries pure Python only (PS4302).