go-pkgx

The pkgx world in pure Go β€” run and install packages on FROM scratch, with one static binary each and a shared backend.

pure Go Β· CGO=0 one static binary each zero runtime deps runs FROM scratch shared backend BSD-3-Clause
pkgx pkgm docs org
pkg.go.dev Go License

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 …

pkgx ready

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.

pkgm ready

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.

bottle ready

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.

mirror ready

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

docs ready

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

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.