Installation

One binary, several ways in. The script is the default; the rest is for people who want to see what it does, or who cannot run it.

The installer

$ curl -fsSL https://kapsl.sh/install | sh

The script is POSIX sh, and it does five things in order:

  1. Detects the platform from uname -s / uname -m and maps it to a target triple (the table below).
  2. Resolves the version from https://kapsl.sh/releases/latest — a plain-text file holding just the version string, deliberately not a JSON API: the script has no jq, and grepping JSON is the kind of parsing that breaks silently on a formatting change.
  3. Downloads kapsl-<version>-<target>.tar.gz and its .sha256 from https://kapsl.sh/releases/<version>/, with curl or wget.
  4. Verifies the checksumsha256sum -c, or shasum -a 256 on macOS — and stops on a mismatch: the download "may be corrupted or tampered with".
  5. Installs to ~/.local/bin (creating it if needed, then chmod +x on the binary) and prints a PATH hint — the exact export line — when the directory is not on your PATH.

Requires curl or wget, tar, and sha256sum/shasum. Environment overrides: KAPSL_VERSION to pin an exact version (do this in CI so a pipeline is reproducible), KAPSL_INSTALL_DIR to install elsewhere, KAPSL_BASE_URL to point at a mirror.

Manual install

The targets the script knows:

PlatformTarget
Linux, x86-64x86_64-unknown-linux-musl
Linux, arm64aarch64-unknown-linux-musl
macOS, Intelx86_64-apple-darwin
macOS, Apple Siliconaarch64-apple-darwin

The same five steps, spelled out — the URL layout is the script's:

$ version=$(curl -fsSL https://kapsl.sh/releases/latest)
$ target=aarch64-apple-darwin
$ curl -fsSLO "https://kapsl.sh/releases/${version}/kapsl-${version}-${target}.tar.gz"
$ curl -fsSLO "https://kapsl.sh/releases/${version}/kapsl-${version}-${target}.tar.gz.sha256"
$ shasum -a 256 -c "kapsl-${version}-${target}.tar.gz.sha256"
$ mkdir -p ~/.local/bin
$ tar -xzf "kapsl-${version}-${target}.tar.gz" -C ~/.local/bin

Use sha256sum -c instead of shasum on Linux. The script installs the archive's kapsl binary straight into the directory.

Build from source

$ cargo build --release
$ cp target/release/kapsl ~/.local/bin/

A Rust toolchain is the only prerequisite.

Choosing the runtime

kapsl prefers Podman and falls back to Docker when podman is not installed. The full precedence, highest first:

  1. --runtime <name> — one invocation.
  2. KAPSL_RUNTIME — inherited by every kapsl process this shell spawns; the only mechanism that also reaches tools which call kapsl from inside a container.
  3. [global] runtime in ~/.config/kapsl/kapsl.toml.
  4. Whatever engine is installed — podman preferred, docker when podman is absent.
$ kapsl --runtime podman [email protected] --version
Python 3.12.14

$ KAPSL_RUNTIME=podman kapsl [email protected] --version
Python 3.12.14

Uninstall

List what is installed, reclaim the disk, then remove the binary, the shims, and the data:

$ kapsl --list
Installed shims (1):
  jq

$ kapsl --clean all --dry-run
  ■ INFO       10 items · 15 MB to remove
                  12 MB  cache/scanner    ~/.cache/kapsl/scanner/attestations
                 2.9 MB  cache/scanner    ~/.cache/kapsl/scanner/scan-cache.json
                  61 KB  cache/index      ~/.cache/kapsl/index/catalog.json

               kapsl-env-* images, package caches and the vulnerability database (not enumerated under --dry-run)
  ■ INFO       --dry-run: nothing removed

--clean takes a target — scratch, images, cache, all, decisions (comma-separated; the default is scratch,images, the two that cost nothing to recreate). It always prints the plan first; cache and all ask before acting, and --yes pre-answers. decisions is never part of all, on purpose: it is the human-decisions store — accepted CVE sets, trusted projects — small, precious, and yours.

Then:

$ rm ~/.local/bin/kapsl ~/.local/bin/jq    # the binary, and each shim from --list
$ rm -rf ~/.local/share/kapsl ~/.cache/kapsl

~/.cache/kapsl is everything regenerable — environment images, the scanner's vulnerability database, the catalogue cache; ~/.local/share/kapsl is your recorded decisions. Removing both returns the machine to the state it was in before the install. If you created ~/.config/kapsl/kapsl.toml, remove it too — there is no default file, and the absence is a working configuration.