go-pkgx is the pkgx world rebuilt in pure CGO_ENABLED=0 Go:
a runtime (pkgx) that runs packages on the fly, an installer
(pkgm) that mirrors the reference CLI, and the bottle backend they both
share. The reference tools shell out to pkgx + deno + curl + openssl + xz — ~515 MB
of runtime closure. These replace all of it with single ~9 MB static binaries that need no libc at
all — so they run on a literally-empty FROM scratch image and materialise real packages
there.
Install
One line β downloads the static binary for your os/arch from the latest
release, verifies it against the release SHA256SUMS, and puts
it on your PATH. Installs pkgm by default; pass a
tool name to install pkgx or mirror instead.
Linux / macOS
curl -fsSL https://go-pkgx.github.io/install.sh | sh # pkgm (default)
curl -fsSL https://go-pkgx.github.io/install.sh | sh -s -- pkgx # or pkgx / mirror
Windows (PowerShell)
irm https://go-pkgx.github.io/install.ps1 | iex # pkgm
$env:PKGX_TOOL='pkgx'; irm https://go-pkgx.github.io/install.ps1 | iex # or pkgx / mirror
Re-running is the updater β it skips the download when
the target version is already installed. Pin a version with
PKGM_VERSION=v0.1.0 (or PKGX_VERSION /
MIRROR_VERSION), force a reinstall with PKGM_FORCE=1.
Go users: go install github.com/go-pkgx/pkgm@latest. Then
pkgm install lz4.org β installs verify against the signed
registry by default.
# a FROM scratch image whose ONLY file is the pkgx binary
FROM scratch
COPY pkgx /bin/pkgx
ENV PKGX_DIR=/pkgx
ENTRYPOINT ["/bin/pkgx"]
$ docker run --rm pkgx-scratch gnu.org/wget --version
GNU Wget 1.25.0 built on linux-gnu.
$ docker run --rm pkgx-scratch +sqlite.org -- sqlite3 --version # bring pkgs into env
3.53.4 2026-07-24 β¦
The runtime. Run any package on the fly β pkgx node@22 --version β or bring several into an environment β pkgx +git +gnu.org/bash -- ./build.sh. It materialises each package’s full dependency closure on demand and execs through the pkgx glibc loader, so it works on a literally-empty FROM scratch image. A single CGO_ENABLED=0 binary.
The installer. Resolves a package’s runtime closure from the pkgx pantry, downloads the bottles, and installs them β mirroring the reference pkgm CLI (install/uninstall/shim/list/outdated/update/pin) as a drop-in replacement, plus a run that completes the closure from ELF DT_NEEDED and runs it on FROM scratch.
The shared backend both tools import β one source of truth for the pkgx bottle protocol: resolution, download, soname-exact FROM scratch closure completion, and loader-aware exec. net/http with an embedded CA bundle replaces curl+openssl; compress/gzip + a pure-Go xz decoder replace info-zip+xz.
Sync a local mirror of pkgx bottles from the official dist into the same servable tree layout β per os/arch, incremental, with --closure to pull a package’s full runtime closure (plus the implicit FROM scratch system libs). Serve it statically and point pkgm/pkgx at it with PKGX_DIST=<mirror-url>.
Documentation (MkDocs Material): usage, the full-pantry FROM-scratch conformance sweep (1818 projects), and the maintained soname β project fix list. A pantry-wide audit found 1818 of 1896 projects publish a linux bottle, and after the soname-exact fix 73 of 81 previously-failing projects run on scratch.
A signed, attested package registry
The org also runs its own bottle registry β
ghcr.io/go-pkgx/packages. A pure-Go factory builds
pkgx pantry recipes with
bk (a CGO-free re-implementation of
brewkit) for every platform β linux (x86-64 & aarch64),
darwin (x86-64 & aarch64) and windows (x86-64) β publishing through
two channels: the signed ghcr.io/go-pkgx/packages
OCI registry and a GitHub Pages pkgx-dist mirror at
go-pkgx.github.io/packages.
Auth uses the workflow's native GITHUB_TOKEN
β no long-lived PAT β and every (project, version, platform) already
in ghcr is skipped, so the catalog grows progressively.
Each bottle carries, as OCI referrers, a CycloneDX SBOM, an
in-toto SLSA provenance statement, and a
cosign-style + minisign signature that verifies against a pinned
public key. On install, PKGX_VERIFY=1 is fail-closed:
an unsigned or badly-signed bottle is refused. Builds are isolated in a pinned
debian container today (Phase A), with an experimental FROM-scratch
pkgx-glibc toolchain proven feasible (Phase B).
# install from the signed OCI registry, verifying against the pinned key
$ PKGX_DIST=oci://ghcr.io/go-pkgx/packages PKGX_VERIFY=1 pkgm install lz4.org
# β¦or from the all-platform GitHub Pages mirror
$ PKGX_DIST=https://go-pkgx.github.io/packages pkgm install lz4.org
# β¦or pull a bottle with any OCI client
$ docker pull ghcr.io/go-pkgx/packages/lz4.org:1.10.0
factory Β·
registry docs Β·
supply chain
One backend, no duplication: both tools import go-pkgx/bottle β the single
source of truth for the pkgx bottle protocol. net/http (with an embedded CA bundle) replaces
curl+openssl, compress/gzip + a pure-Go xz decoder replace info-zip+xz, and there is no
script runtime at all. pkgm's command surface and prefix logic mirror the reference pkgm, so it is a
drop-in replacement; pkgx's <pkg> and +pkg forms mirror
the reference runtime.
Pure Go with cgo disabled — no C toolchain, no runtime fetch, no vendored
assets — binaries that cross-compile to six 64-bit targets (linux & darwin,
amd64/arm64, plus riscv64 & ppc64le). On FROM scratch the bottle backend reads each
bottle's ELF DT_NEEDED to auto-complete the implicit libc/gcc closure the pantry graph
omits, pulling the provider version that ships the exact soname an ABI needs. Everything is
BSD-3-Clause.