Standard Library

Want ships a standard library of Spore packages. Planning files can import these packages. An import names a package (a directory of .sp files) or a single file. Standard-library packages are namespaced: the want standard library is want: and the spore standard library is core:. An import with no colon resolves in the same source as the importing file — a module-relative path in your module, or a sibling package within a standard library:

ns    = (#import "core:ns")
build = (#import "want:build")
linux = (#import "want:linux")
paths = (#import "want:build/paths")

Callers are responsible for spawning and awaiting Jobs through their job port; the standard library functions take that port (build.JobCtx) as their first argument, by convention. A tool package may set up a package-specific context instead and take it first: the zig and go commands take a zig.Ctx or go.Ctx (built with new from the job port, limits, platform, and version).

build

The core of the build library (stdlib/build).

Types

  • FS: a wantfs tree. This is the value a do proc returns and the type almost everything operates on.
  • Ctx: the build context handed to a do proc:
    Ctx = (#Struct { .jobs = JobCtx .input = FS .secrets = (#List (#Port Unit Unit)) })
    
    secrets is empty unless the build publishes; see SinkCtx below.
  • SinkCtx: the context handed to a unit file's .sink proc by want build --publish: (#Struct { .jobs = JobCtx .input = FS .internet = (#Port Unit Unit) .secrets = (#List (#Port Unit Unit)) }). input is the target's do result; secrets is the file's granted secret ports, in the order the WANT's .secrets names them (supplied with --secret NAME:PATH or --secrets NAME:PATH). Sinks run only for targets the build query names directly, and a publish build fails if a directly queried target (or its running sink) is granted a name that was not supplied.
  • JobCtx: the jobs port used to spawn and await child Jobs.
  • Task, JobID, JobState, JobResult: the job system's wire types.
  • Limits: the resource ceiling a spawn requests for its child ((#Struct { .memory = B64 .cpu = B64 .max_duration = B64 })). memory is bytes, cpu is microseconds per second, and max_duration is seconds (0 means no ceiling); a child running longer than max_duration is cancelled.

Jobs

  • spawn jc limits op input -> JobID: start a child job for a Task under limits.
  • limits jc -> Limits: the current job's spawn-time ceiling. Passing it to spawn propagates the ceiling down the tree unchanged.
  • await jc id -> AnyValue: wait for a child; a failed child faults the parent.
  • inspect jc id -> JobState: check a child without blocking.
  • awaitAny jc ids -> JobID: wait for any of several children.

Filesystem

  • pick jc root path -> FS: re-root the tree at path; picking a file yields a flat single-file FS.
  • pickRoot jc root path -> FS: the same operation, named for re-rooting a directory.
  • fileAt jc root path -> FS: pick a single file (a synonym for pick).
  • place jc ents -> FS: mount named single-file FSes at their names:
    (build.place jc [
        (build.ent "bin/hello" exe)
    ])
    
  • ls jc root path -> (#List String): the immediate children of a directory.
  • filterPaths jc root set -> FS: keep only the entries of root whose path the PathSet set contains; entry paths are unchanged, so the filtered tree is not re-rooted.
  • emptyDir jc -> FS: a tree with no entries.

Downloads

  • downloadFile jc task -> FS: fetch a file from one of task.urls, verified against task.hash; a non-none task.compression decompresses the verified payload into the returned file.
  • downloadTree jc task -> FS: fetch an archive (tar, zip, or deb) and expand it into a tree. task.compression names the archive payload's compression (gzip, xz, zstd, or none); decompression is explicit, never sniffed.

OCI

  • downloadOciImage jc task -> FS: pull an OCI/Docker image into an OCI layout.
  • pushOciImage jc task -> PushedOCIImage: push an OCI layout to a registry repository and attach the task's tags. The push is idempotent: blobs, manifests, and tags the registry already holds are skipped. The registry credentials come from task.secrets, a --secrets map whose exports include .OCI_USERNAME and .OCI_PASSWORD.
  • OCIImageTask (url, repo, algo, hash), PushOCIImageTask (url, repo, tags, image, secrets), and PushedOCIImage (digest, tags): the OCI wire types.

Importing build also gives you its download, job, and oci modules' exported functions, since a package is compiled from every immediate child .sp file.

build/paths

The PathSet constructors used in .input and .output:

  • Set: the PathSet tagged union itself ((#TaggedUnion {.unit = String .prefix = String .suffix = String})), the parameter type of build.filterPaths.
  • unit p -> Set: the single path p.
  • prefix p -> Set: every path beginning with p.
  • suffix s -> Set: every path ending in s.

linux

The Linux container executor (stdlib/linux).

  • run jc cspec -> CSpawnResult: run a container described by cspec, and return its exit code plus the tree captured from its output mount.
  • CSpec: the container description: init, args, env, wd, mounts, network, stdin, stderr, stdout.
  • initMemfd fs: run an executable from a flat single-file FS (copied into an anonymous memfd).
  • initPath p: run the executable already at path p inside the container.
  • Mount sources: snapshot fs (read-only), output, emptyDir, tmpfs n, drive n, overlay rlayer wlayer (lower may be a snapshot/drive; upper must be a writable drive/tmpfs), devNull, procfs, sysfs, cgroup2fs, devpts.
  • mount dst src -> Mount: pin a source at a container path.
  • net name backend, loopback, private, internet cap: network interfaces.
  • stdio: stdinNull, stdin ctx, stdout ctx, stderr ctx, outputLog, outputClosed, stdinClosed.
  • fileAtPath jc root path -> FS: pull a file out of a container tree.

linux/dist/alpine

A pinned Alpine minirootfs: a small musl userland with the busybox shell.

  • rootfs jc -> FS: expand the pinned minirootfs tarball into a tree.
  • fileAt jc path -> FS: pull a single file out of it.
  • version, arch: the pinned release.

linux/dist/debian

A pinned rblaine95/debian base image (a GHCR mirror of Docker Hub's official image). Like Alpine, but a full glibc userland.

  • image jc -> FS: pull the pinned image as an OCI layout.
  • rootfs jc -> FS: unpack the image's root filesystem.
  • fileAt jc path -> FS: pull a single file out of it.

linux/dist/arch

Arch Linux packaging on top of a pinned official Arch container image (with the bash, pacman, and bsdtar makepkg itself uses). package takes already-built artifacts as a build.FS tree and produces the .pkg.tar.zst pacman installs; nothing is compiled.

  • rootfs jc -> FS: the pinned image's root filesystem.
  • fileAt jc path -> FS: pull a single file out of it.
  • version: the pinned image build.
  • Spec: the required metadata (.name, .version, .arch, .desc, .builddate, .files). version is the full pkgver including the pkgrel (and optional epoch), and builddate is a decimal Unix timestamp that fixes every file's mtime, so equal inputs produce equal packages.
  • Meta: the full metadata record; meta spec -> Meta fills the optional fields with defaults.
  • withUrl, withPackager, withLicense, withDepends, withOptdepends, withProvides, withConflicts, withReplaces, withGroups, withBackup, withInstall: rebind one optional field.
  • filename meta -> String: the output file's name, name-version-arch.pkg.tar.zst.
  • pkginfo meta -> String: the rendered .PKGINFO.
  • package jc meta -> FS: assemble the package and return the tree captured from the output mount (one file, filename meta); use build.fileAt for the package as a flat single-file tree. The target faults if the packager fails.
  • checkExit code -> Unit: fault unless a container exited zero.

The payload is a tree rooted at /, built with build.place or picked from a build output:

files = (build.place jc [
    (build.ent "usr/bin/hello" exe),
])
m = (arch.meta {.name = "hello" .version = "1.0-1" .arch = "x86_64"
                .desc = "..." .builddate = "1700000000" .files = files})
m = (arch.withLicense m ["MIT"])
pkg = (arch.package jc m)

docker

  • pull jc task -> FS: pull an OCI image.
  • umoci jc -> FS: the pinned umoci binary.
  • rootfs jc img -> FS: unpack a pulled image's root filesystem.

git

A pinned static git build (darkvertex/static-git), used to give a container a git binary with no package manager or network.

  • tool jc -> FS: the expanded static git tree (git at its root). Mount it on PATH (e.g. at /git) and set GIT_TEMPLATE_DIR to an existing directory.

github

Upload release assets to an existing GitHub release (stdlib/github). Credentials come from a --secrets map whose only required export is .GITHUB_TOKEN, a token with write access to the repository's releases (contents: write). The preferred setup is a spore file:

.GITHUB_TOKEN = "..."
want build --publish --secrets github:~/.config/want/github.sp
  • Ctx: the GitHub context ((#Struct {.jobs = JobCtx .secrets = (#Port Unit Unit)})); build it once with new.
  • new jc secrets -> Ctx: bind the job port and the secrets port granted by the WANT's .secrets.
  • UploadOpts: (#Struct {.owner = String .repo = String .tag = String}), naming the existing release to attach assets to.
  • Asset: one uploaded asset (.id, .name, .size, .content_type, .browser_download_url).
  • ReleaseUpload: the op's result: the release and the assets it now carries.
  • uploadRelease ctx opts assets -> ReleaseUpload: upload every top-level file in assets as an asset of the named release; an existing asset with the same name is replaced.

go

The pinned Go toolchain (stdlib/go).

  • Ctx: the go environment ((#Struct {.jc = JobCtx .limits = Limits .platform = Platform .version = Version .modcache = FS .env = (#List String)})). Every command takes it as its first argument.
  • new jc limits platform version -> Ctx: set up the environment once, then hand it to every command. platform/version select the toolchain distribution to fetch; jc and limits are the job resources commands run under. The module cache starts empty.
  • withModcache ctx modcache -> Ctx: rebind the module cache to the tree returned by pkg.
  • withEnv ctx env -> Ctx: rebind the command-wide environment. Entries are prepended to the fixed environment and the first entry for a variable wins, so they override it (for example GOFLAGS, GOPROXY, CGO_ENABLED).
  • withTarget ctx platform -> Ctx: prepend GOOS/GOARCH for platform, cross-compiling pure-Go builds with the host toolchain.
  • LATEST, v1_27_1: the pinned Version values; linux_amd64 is the pinned Platform; GOOS_*/GOARCH_* name every target.
  • dist ctx -> FS: download the pinned distribution and re-root it as a container root.
  • pkg ctx src hash -> FS: run go mod download for the module tree src (under the context's environment) in a network-enabled container and return the resulting module cache, audited against hash.
  • cmd ctx cwd args -> CSpawnResult: run the pinned go tool over the module tree cwd (mounted at /src) in a container with no network. args is the full argv, e.g. ["go", "build", "-o", "/out/app", "./cmd/foo"].
  • build ctx modfs entrypoint -> FS: compile the main package at entrypoint into a static executable.
  • test ctx modfs -> CSpawnResult: run go test ./...; its stdout and stderr are captured as /stdout and /stderr in the output tree.
  • testBinaries ctx modfs -> CSpawnResult: compile every package's test binaries into the output tree without running them.
  • checkExit code -> Unit: fault the build unless code is zero.

go/dist

The Go release pins and the mirror URLs used to fetch them (stdlib/go/dist.sp, part of the go package): Version, LATEST, v1_27_1, Platform, linux_amd64, tarballName, topDir, dist, and mkurls.

python

The pinned Python toolchains: CPython (the interpreter, from python-build-standalone) and uv (the package manager), each fetched from its own release artifacts (stdlib/python).

  • Ctx: the python environment ((#Struct {.jc = JobCtx .limits = Limits .platform = Platform .uv = UvVersion .python = PythonVersion .venv = FS .env = (#List String)})). Every command takes it as its first argument.
  • new jc limits platform uv python -> Ctx: set up the environment once, then hand it to every command. platform selects both distributions; uv and python pin the versions to fetch (see below). jc and limits are the job resources commands run under. The project environment starts empty.
  • withVenv ctx venv -> Ctx: rebind the project environment to the tree returned by pkg; commands mount it at /venv and prefer its bin/ on PATH.
  • withEnv ctx env -> Ctx: rebind the command-wide environment. Entries are prepended to the fixed environment and the first entry for a variable wins, so they override it (for example UV_NO_DEV).
  • UV_LATEST, PYTHON_LATEST, PYTHON_3_13: the pinned UvVersion and PythonVersion values; x86_64_linux is the pinned Platform.
  • uvDist ctx -> FS: the pinned uv distribution (uv and uvx), to mount at /uv.
  • pythonDist ctx -> FS: the pinned CPython distribution, to mount at /python.
  • pkg ctx src hash -> FS: run uv sync --frozen for the project tree src (which must contain pyproject.toml and uv.lock) in a network-enabled container with the pinned toolchains, and return the resulting venv, audited against hash. Mount the result on the context with withVenv before running commands.
  • cmd ctx cwd argv -> CSpawnResult: run any command over the tree cwd in the hermetic command container; argv is resolved on PATH through the venv, the pinned interpreter, and uv, and each element is passed verbatim.
  • python ctx cwd args, uv ctx cwd args, sh ctx cwd script: cmd with the pinned interpreter, uv, or the Debian shell (for pipelines and redirects) as the program.
  • checkExit code -> Unit: fault the build unless code is zero.

python/dist

The uv and CPython release pins and the asset URLs used to fetch them (stdlib/python/dist.sp, part of the python package): UvVersion, PythonVersion, UV_LATEST, PYTHON_LATEST, PYTHON_3_13, Platform, x86_64_linux, uvUrl, pythonUrl, uvDist, and pythonDist.

zig

The pinned Zig toolchain.

  • Ctx: the zig environment ((#Struct {.jc = JobCtx .limits = Limits .platform = Platform .version = Version .pkgfs = FS .env = (#List String)})). Commands take it as their first argument.
  • new jc limits platform version -> Ctx: set up the environment once, then hand it to every command. platform/version select the toolchain; jc and limits are the job resources commands run under. The package directory starts empty.
  • withPkgfs ctx pkgfs -> Ctx: rebind the package directory to the tree returned by pkg; commands mount it at /src/zig-pkg.
  • withEnv ctx env -> Ctx: rebind the command-wide environment. Entries are prepended to the fixed environment and the first entry for a variable wins, so they override it.
  • LATEST, STABLE, v0_16_0: the pinned Version values; x86_64_linux is the pinned Platform.
  • dist ctx -> FS: download the pinned distribution and re-root it as a container root.
  • pkg ctx src hash -> FS: fetch the build.zig.zon dependencies of src through zig build --fetch, audited against hash (the zig-pkg fingerprint).
  • cmd ctx cwd args -> CSpawnResult: run the pinned zig tool over the source tree cwd (mounted at /src); args is the full argv, e.g. ["/zig/zig", "build", "test"].
  • buildArgs ctx src args -> CSpawnResult: cmd plus the fixed --build-file, --prefix, and --cache-dir flags, for arbitrary zig build steps; returns the exit code plus the captured output tree.
  • build ctx src target -> FS: run the binaries step for the Zig target triple target and return its output tree.
  • checkExit code -> Unit: fault the build unless code is zero.
  • run ctx args -> AnyValue: run the compiler with stdio wired to the host.
  • watch ctx stdin stdout stderr -> B8: run zig build --watch on the build context's working directory, with stdio wired to the given ports; returns the container's exit code.

zig/dist

The Zig release pins and the mirror URLs used to fetch them (stdlib/zig/dist.sp, part of the zig package): Version, LATEST, STABLE, v0_16_0, Platform, x86_64_linux, tarballName, topDir, dist, and mkurls.

mdbook

Renders a markdown book to static HTML, using the pinned static-musl mdbook release inside an Alpine container. The environment (Alpine rootfs and mdbook) is mounted from constant snapshots, so only the book source changes between builds.

  • tool jc -> FS: the pinned mdbook distribution, re-rooted.
  • build jc src book_toml summary -> FS: render the markdown in src, with book_toml as its book.toml and summary as src/SUMMARY.md, and return the generated site. The build faults if mdbook fails or produces no index.html.

sys

Types for the surrounding system context used by entrypoints (not by build planning files): Ctx, ctxPort, and the NetBackend choices.

ns

Helpers for building namespaces (NS, get, mkEntry), used when a Spore entrypoint is handed its context as a namespace.

bits

Bit-width aliases (B8…B256) and the bitwise primitives: AND, OR, and XOR on Bit, plus b32AND and b32OR on B32.

strings

Byte-level string helpers mirroring a subset of Go's strings (a String is a List of bytes):

  • len s -> B32.
  • hasPrefix s p -> Bit, hasSuffix s p -> Bit, contains s p -> Bit.
  • index s p -> (Maybe B32): the first index of p in s, or Nothing.
  • count s p -> B32: non-overlapping instances of p; an empty p counts len(s) + 1 insertion points.
  • split s sep -> (#List String): an empty sep splits into single bytes.
  • join parts sep -> String, repeat s count -> String.
  • trimPrefix s p -> String, trimSuffix s p -> String, trimSpace s -> String (ASCII whitespace).