The daemonless supply-chain packager for prebuilt dynamic Linux binaries.
Point Scratchsmith at a dynamically linked glibc ELF binary and get a minimal FROM scratch
OCI image. You need no Dockerfile and no static-linking prerequisite. It resolves the binary's
shared libraries the way ld.so does (RPATH/RUNPATH/$ORIGIN, the interpreter, versioned
soname symlinks). It stages the glibc pieces nothing else remembers (NSS modules, a working
nsswitch.conf, minimal passwd/group). Then it assembles a non-root image with
reproducible layers.
If you can rebuild your service as a static binary (CGO_ENABLED=0, musl), do that. You
need no packer. Scratchsmith is built for the binaries that static linking cannot help:
- Closed-source or vendor binaries you cannot recompile.
- glibc binaries that rely on NSS,
dlopen, or locale behavior. Static glibc breaks these quietly, often only in production. - Anything where "just rebuild it static" is not on the table.
That is the wedge, and it is not a fence. Scratchsmith already packs a static binary too, because the resolver detects it and stages the single file. When you want an SBOM, a hardening report, a non-root image, and no Dockerfile, it is equally handy. You hand-write no multi-stage build. It is purpose-built for the hard case and useful for the easy one.
| Capability | State |
|---|---|
Pack a dynamic glibc ELF → runnable FROM scratch image |
✅ (loaded via docker/podman/nerdctl) |
ld.so-faithful dependency resolution (RPATH/RUNPATH/$ORIGIN, interpreter, sonames) |
✅ |
glibc NSS support staged, so name-service lookups like getent hosts work. Trim the modules with --nss |
✅ |
| Non-root by default (UID 65532), reproducible layers | ✅ |
SBOM generation: --sbom (CycloneDX or SPDX, via syft) |
✅ |
Vulnerability scan: --scan (grype), gate with --scan-fail-on <severity> |
✅ |
ELF hardening lint: lint (PIE/RELRO/NX/canary/FORTIFY), gate with --fail-on |
✅ |
Library policy gate: pack --deny/--require <soname> (a forbidden or missing library fails the pack) |
✅ |
dlopen gap detection + --include escape hatch |
✅ |
Dependency graph: graph (the resolved dependency tree, ASCII or --format json) |
✅ |
Symbol strip (--strip), UPX compression (--upx), size report, smoke-run (--smoke) |
✅ |
Image size budget: --max-size <SIZE> (if the staged image exceeds the budget, the build fails) |
✅ |
Runtime extras: CA certs (--ca-certs), timezone (--tz), init/tini (--init) |
✅ |
Add host files: --add-file SRC[:DST] (copy any host file into the image) |
✅ |
Locale data: --locale NAME (stage one compiled glibc locale, never the host archive) |
✅ |
Symlink modes: --symlinks (keep a named symlink as a link, or flatten it) |
✅ |
Image metadata: labels (--label), HEALTHCHECK (--healthcheck) |
✅ |
Configuration file (scratchsmith.toml) + named profiles (--profile), JSON output (--format json) |
✅ |
Pluggable runtime: --runtime (docker / podman / nerdctl) for the default load sink |
✅ |
Shell completions: --completions <bash|zsh|fish> |
✅ |
Signed releases: amd64 + arm64 binaries, cosign-signed checksums.txt + SLSA provenance, signed multi-arch GHCR image |
✅ |
:toolbox image: a runnable image (Wolfi + the full toolchain) that runs pack inside a container |
✅ |
| Dynamic musl/Alpine binaries | ❌ rejected loudly (glibc comes first, and a musl backend is a future goal) |
Daemonless OCI archive: --oci-archive <file> (no daemon, and skopeo/buildah/registry-ready) |
✅ |
Daemonless registry push: --push <ref> (no daemon, and it uses your docker credentials) |
✅ |
Signing the image pack produces: --push --sign (cosign keyless, by digest) |
✅ |
Multi-arch image index: index (combine per-arch pushes into one tag, daemonless) |
✅ |
Image diff: diff <a> <b> (files added, removed and changed, plus the size delta, and --exit-code gates CI) |
✅ |
Unpack an OCI image: unpack <archive> <dir> (extract the layers to audit an image you did not build) |
✅ |
For a release's signatures and provenance, see Verifying releases.
To run pack inside a container, see the :toolbox section of Usage.
Scratchsmith is Linux only (amd64/arm64). It stages a Linux glibc rootfs, so it does not run on macOS or native Windows. Use a Linux container or WSL2 there.
# One-line install. Downloads the signed binary and verifies its cosign-signed checksums.
curl -fsSL https://raw.githubusercontent.com/schubydoo/scratchsmith/main/install.sh | bash
# ...or a package manager:
brew install schubydoo/scratchsmith/scratchsmith
cargo install scratchsmithRelease binaries, the signed container image, source builds, uninstall, and shell completions
are in Installation. Then run scratchsmith doctor to see which
optional external tools (syft, strip, tini, and the rest) are present.
Pack a dynamic binary into a scratch image and run it:
scratchsmith pack ./app
docker run --rm scratchsmith/app:packed --version # image is named scratchsmith/<name>:packedTo skip the daemon entirely, stage a rootfs, write an OCI archive, or push straight to a registry:
scratchsmith pack --no-build --output ./rootfs ./app # a plain rootfs, no daemon
scratchsmith pack --oci-archive ./app.oci.tar ./app # an OCI archive (skopeo/buildah-ready)
scratchsmith pack --push ghcr.io/you/app:latest ./app # straight to a registryFor more recipes, including the SBOM, scan and size gates, image metadata, and signing, read Usage. To pack in CI, read GitHub Action.
Put the defaults for pack in a scratchsmith.toml and load it with --config. A command-line
flag overrides the file, and [profile.<name>] blocks layer environment-specific overrides on
top. The full key reference and the layering rules are in
Configuration.
Every release is keyless-signed with cosign, carries a SLSA build-provenance attestation, and
ships a CycloneDX SBOM of its own dependency graph. The exact gh attestation and
cosign verify commands are in Verifying releases.
📖 Full docs: https://schubydoo.github.io/scratchsmith/ (searchable, versioned). The sources also render on GitHub:
- Installation: every install method, uninstall, and shell completions.
- Usage: pack recipes, daemonless output, and image metadata.
- GitHub Action: pack in a CI workflow with the composite action.
- Configuration: the
scratchsmith.tomlreference and profiles. - Verifying releases: cosign signatures, SLSA provenance, and the SBOM.
- Comparison & limitations: how Scratchsmith compares, and what it does not do.
- Architecture: how resolve → stage → assemble works, and the 1.0 stability contract.
- Contributing · Compatibility · Security · Code of Conduct
Read CONTRIBUTING.md for the dev setup, the invariants, and the PR flow, and read the Code of Conduct. Report security issues through SECURITY.md.
MIT.