jobsiroh

package module
v0.24.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: AGPL-3.0 Imports: 1 Imported by: 0

README

jobs-iroh

A small, self-contained build system: one server, N runners, and a client, connected only by iroh QUIC. Builds are hermetic (rootless Linux namespace sandbox, no network inside), identified by content (canonical-CBOR definitions and a content-addressed amber store), and described by Starlark recipes. The server embeds NATS JetStream for scheduling — there is no other infrastructure: no HTTP, no database, no container runtime.

Full design: docs/architecture/architecture.md.

Binaries & ALPNs

Three core binaries: jobs-server, jobs-runner, jobs-client — plus an optional jobs-registry (an OCI registry serving build outputs as pullable images). One server endpoint, five ALPNs:

ALPN Who What
jobs-build/1.0 client submit builds, watch, logs, cancel
jobs-runner-nats/3.0 runner NATS tunnel to the embedded scheduler
jobs-runner-amber/1.0 runner store sync (objects + refs)
jobs-admin/1.0 client (TUI) observe builds, stats, fleet, refs, cancel/delete, diagnose
jobs-amber-admin/1.0 client / registry push source trees up, pull outputs home

A build file

A build is a BUILD.jobs Starlark file next to your source. Minimal shape:

def build():
    toolchain = imp(fetcher = "tarball+https",
                    params = {"url": "https://go.dev/dl/go1.24.linux-amd64.tar.gz"})
    return struct(
        inputs       = {"toolchain": toolchain},
        env          = {"GOFLAGS": "-mod=mod"},
        script       = "go build -o $out/app .",
        runtime_deps = [],
    )

Imports (fetches) are the only steps with network access; the script runs in a sandbox with its inputs mounted read-only, the source at $SRC, and the output tree collected from $out. Language plugins (Go, npm, PyPI, cargo, RubyGems, …) expand lockfiles into per-dependency cached imports.

Quickstart: local build

No server needed — builds run hermetically against an embedded store under --data-dir (default ~/.local/share/jobs-iroh):

cd myapp                                            # or any subdirectory of it
jobs-client build                                   # build → prints F + output key
jobs-client run -- arg1                             # build, then exec JOBS.entrypoint
jobs-client develop                                 # interactive shell in the build sandbox
jobs-client image -o app.tar --tag myapp:dev
docker load -i app.tar

Omitting --source builds where you stand: the nearest ancestor of the current directory holding a BUILD.jobs, searched no higher than the repository root. The whole repository becomes the ingest context — that is what makes sibling references (../lib, //lib/common) resolvable — and the build root is the directory the recipe was found in. Each command prints what it resolved:

context: /home/you/myrepo  (dir services/api, recipe BUILD.jobs)

Pass --source <dir> to name the tree explicitly; --source-root moves the ceiling, --no-repo-root pins it to the source itself.

Quickstart: server, runner, remote build

# 1. Server (prints its endpoint ID on startup):
jobs-server --data-dir /var/lib/jobs-iroh

# 2. Runner(s), anywhere that can reach the server over iroh:
jobs-runner --server <endpoint-id> [--addr host:port] [--size c1-m2]

# 3. Client: push source, build remotely, pull the output home
#    (--source omitted → resolved from the cwd, exactly as for local builds):
cd myapp && jobs-client remote-build --server <endpoint-id>
jobs-client watch  --server <endpoint-id> --request-id <id>   # re-attach
jobs-client status --server <endpoint-id>                     # one-shot tables
jobs-client tui    --server <endpoint-id>                     # interactive admin

remote-build streams the running steps' build output alongside the progress block by default (--no-logs opts out). When something fails, jobs-client diagnose --server <id> --request <id> prints the durable failure trail — every failed attempt with its captured output, surviving retries and server restarts (--json for the machine-friendly shape).

Local and remote builds share the same canonical definitions, so the same source yields the same build identity K/F everywhere — remote outputs pulled home join the local cache and vice versa.

Registry: docker pull a build

jobs-registry serves build outputs straight to docker/containerd/k8s — no export/load/push hop:

jobs-registry --server <endpoint-id> [--addr host:port] --listen :5000
docker pull my-registry-host:5000/jobs:<build-K>

Images live in a single jobs repository whose tags are build keys K (the value remote-build prints); /v2/jobs/tags/list enumerates every submitted build (a local build's bare F key also pulls, but is not listed). Images have two layers — the runtime closure under /jobs/store/<key> plus the platform shell (script entrypoints need their #!/bin/sh shebang; --no-shell opts out), and the build artifact at the root — assembled on the fly from the registry's own store, which syncs from the jobs-server on demand. Layers are uncompressed (…image.layer.v1.tar) and generated straight from that store on every request rather than stored as blobs, so serving costs CPU per pull instead of disk, and --cache-ttl (default 24h) now expires only the small manifest/config blobs. Size the volume for the store, which holds every synced build and is never reclaimed. The registry is pull-only and speaks plain HTTP: terminate TLS at an ingress or mark it insecure in the container runtime. A sample k8s Deployment lives in deploy/jobs-registry/.

Dev setup

Go toolchain comes from the Nix devShell:

direnv allow          # sets up the flake shell + GOPRIVATE
# or without direnv:
nix develop -c go test ./...

GOPRIVATE=github.com/jobs-build/* is required for module fetches (exported by .envrc).

Tests

nix develop -c go build ./... && nix develop -c go vet ./...
nix develop -c go test ./...

# macOS is a dev-fallback target (no hermetic sandbox); build tags mean a
# Linux-only `go build` never type-checks the !linux files, so cross-check:
nix develop -c env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go vet ./...

License

AGPL-3.0-or-later.

Documentation

Overview

Package jobsiroh holds repo-root embeds. go:embed can only reference files in the embedding package's own directory, so the checked-in fetchers.toml is embedded here and consumed via bootstrap.LoadEmbedded.

Index

Constants

This section is empty.

Variables

View Source
var FetchersTOML []byte

FetchersTOML is the checked-in fetcher manifest (fetchers.toml), embedded so every binary carries the fetcher pins it was built with and a standalone binary can provision fetchers from any working directory.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
Package amber is the jobs-iroh content-addressed store seam over github.com/jobs-build/amber-store-core: an embedded, in-process store — no daemon, no HTTP, no signing.
Package amber is the jobs-iroh content-addressed store seam over github.com/jobs-build/amber-store-core: an embedded, in-process store — no daemon, no HTTP, no signing.
Package amberclient is the importable client half of the amber sync protocol — the dial/push/pull/refs orchestration that upstream lives only in amber-store-iroh's cmd/amber mains, lifted into a library so jobs-iroh components can sync stores over any of the server's amber ALPNs (jobs-runner-amber/1.0, jobs-amber-admin/1.0).
Package amberclient is the importable client half of the amber sync protocol — the dial/push/pull/refs orchestration that upstream lives only in amber-store-iroh's cmd/amber mains, lifted into a library so jobs-iroh components can sync stores over any of the server's amber ALPNs (jobs-runner-amber/1.0, jobs-amber-admin/1.0).
Package amberiroh moves amber store content between peers over iroh QUIC.
Package amberiroh moves amber store content between peers over iroh QUIC.
Package api is the frame protocol of the jobs-build/1.0 and jobs-admin/1.0 ALPNs: 4-byte big-endian length + CBOR frame {t, b}.
Package api is the frame protocol of the jobs-build/1.0 and jobs-admin/1.0 ALPNs: 4-byte big-endian length + CBOR frame {t, b}.
Package bootstrap owns the JOBS bootstrap floor: the embedded seed artifacts ({tarball+https, shell, hostmusl, github}) that the jobs binary self-seeds into amber on startup, and the fetcher manifest — since the recipe-declared-fetchers design (2026-07-10) an inventory of those seed leaves ONLY.
Package bootstrap owns the JOBS bootstrap floor: the embedded seed artifacts ({tarball+https, shell, hostmusl, github}) that the jobs binary self-seeds into amber on startup, and the fetcher manifest — since the recipe-declared-fetchers design (2026-07-10) an inventory of those seed leaves ONLY.
Package builddef defines the JOBS build job definition and the unifying Input type, with their canonical CBOR encoding.
Package builddef defines the JOBS build job definition and the unifying Input type, with their canonical CBOR encoding.
Package clientcli wires the jobs-client command surface: hermetic LOCAL builds (`build`), build-then-execute (`run`), the interactive build-sandbox shell (`develop`, flock held for the whole session), and OCI image export (`image`, by --source or by build key) over the embedded amber-store-core store under --data-dir, plus the remote surface against a jobs-server — `remote-build` (push source, submit, watch, pull outputs home), `watch`, and the thin `admin` frame calls (stats/fleet/requests/refs).
Package clientcli wires the jobs-client command surface: hermetic LOCAL builds (`build`), build-then-execute (`run`), the interactive build-sandbox shell (`develop`, flock held for the whole session), and OCI image export (`image`, by --source or by build key) over the embedded amber-store-core store under --data-dir, plus the remote surface against a jobs-server — `remote-build` (push source, submit, watch, pull outputs home), `watch`, and the thin `admin` frame calls (stats/fleet/requests/refs).
cmd
jobs-client command
Command jobs-client is the jobs-iroh end-user CLI: hermetic local builds (build) and build-then-execute (run) against the embedded store under --data-dir/JOBS_DATA_DIR.
Command jobs-client is the jobs-iroh end-user CLI: hermetic local builds (build) and build-then-execute (run) against the embedded store under --data-dir/JOBS_DATA_DIR.
jobs-registry command
Command jobs-registry is a read-only OCI registry that serves jobs build outputs as pullable container images named jobs:<build-K>.
Command jobs-registry is a read-only OCI registry that serves jobs build outputs as pullable container images named jobs:<build-K>.
jobs-runner command
Command jobs-runner is the jobs-iroh worker: it dials the server's iroh endpoint twice (NATS tunnel + amber sync), pulls work-queue jobs for every size class that fits its capacity, runs the ported stage drivers in the namespace sandbox against a private cache store, and reports results.
Command jobs-runner is the jobs-iroh worker: it dials the server's iroh endpoint twice (NATS tunnel + amber sync), pulls work-queue jobs for every size class that fits its capacity, runs the ported stage drivers in the namespace sandbox against a private cache store, and reports results.
jobs-server command
Command jobs-server is the single shared authority of a jobs-iroh deployment: one iroh endpoint serving the client build API, the runner NATS tunnel, CAS sync, and the admin API over an embedded amber store and an embedded NATS server.
Command jobs-server is the single shared authority of a jobs-iroh deployment: one iroh endpoint serving the client build API, the runner NATS tunnel, CAS sync, and the admin API over an embedded amber store and an embedded NATS server.
Package cover computes the covered source closure and the KP identity of a widened-context build (sibling-sources design §5, §6).
Package cover computes the covered source closure and the KP identity of a widened-context build (sibling-sources design §5, §6).
Package events defines the jobs-iroh build-event schema (ported from jobs' build-events design): every fetch/build state change (server) and every execution step incl.
Package events defines the jobs-iroh build-event schema (ported from jobs' build-events design): every fetch/build state change (server) and every execution step incl.
fetchers
alpineapk command
Command fetch is the JOBS Alpine-apk fetcher: it downloads one Alpine Linux package (.apk) from the Alpine CDN, verifies its sha256, and extracts the package's file tree into JOBS_OUTPUT_DIR.
Command fetch is the JOBS Alpine-apk fetcher: it downloads one Alpine Linux package (.apk) from the Alpine CDN, verifies its sha256, and extracts the package's file tree into JOBS_OUTPUT_DIR.
cargocrate command
Command fetch is the JOBS crates.io fetcher: it downloads one crate's .crate archive from static.crates.io, verifies its sha256 against the Cargo.lock checksum, unpacks it into JOBS_OUTPUT_DIR, and writes a .cargo-checksum.json so cargo's directory-source replacement accepts it.
Command fetch is the JOBS crates.io fetcher: it downloads one crate's .crate archive from static.crates.io, verifies its sha256 against the Cargo.lock checksum, unpacks it into JOBS_OUTPUT_DIR, and writes a .cargo-checksum.json so cargo's directory-source replacement accepts it.
github command
Command fetch is the JOBS GitHub fetcher: it imports a GitHub repository tree at a given ref (tag, branch, or SHA) into amber.
Command fetch is the JOBS GitHub fetcher: it imports a GitHub repository tree at a given ref (tag, branch, or SHA) into amber.
npm command
Command fetch is the JOBS npm fetcher: it downloads one package tarball from its resolved registry URL (as recorded in yarn.lock / package-lock.json), verifies the Subresource-Integrity digest (sha512-… or sha1-…), and writes the raw .tgz into JOBS_OUTPUT_DIR.
Command fetch is the JOBS npm fetcher: it downloads one package tarball from its resolved registry URL (as recorded in yarn.lock / package-lock.json), verifies the Subresource-Integrity digest (sha512-… or sha1-…), and writes the raw .tgz into JOBS_OUTPUT_DIR.
pypi command
Command fetch is the JOBS PyPI fetcher: it downloads one wheel or sdist from its uv.lock URL, verifies its sha256, and either writes the raw .whl into JOBS_OUTPUT_DIR (a one-entry wheelhouse the recipe merges via --find-links) or extracts a .tar.gz sdist with the top-level directory stripped so the package root lands directly at JOBS_OUTPUT_DIR.
Command fetch is the JOBS PyPI fetcher: it downloads one wheel or sdist from its uv.lock URL, verifies its sha256, and either writes the raw .whl into JOBS_OUTPUT_DIR (a one-entry wheelhouse the recipe merges via --find-links) or extracts a .tar.gz sdist with the top-level directory stripped so the package root lands directly at JOBS_OUTPUT_DIR.
rubygems command
Command fetch is the JOBS RubyGems fetcher: it downloads one .gem from rubygems.org, verifies its sha256 (the value RubyGems publishes — identical to the Gemfile.lock CHECKSUMS entry, so the content address has no trust gap), and writes the raw .gem into JOBS_OUTPUT_DIR.
Command fetch is the JOBS RubyGems fetcher: it downloads one .gem from rubygems.org, verifies its sha256 (the value RubyGems publishes — identical to the Gemfile.lock CHECKSUMS entry, so the content address has no trust gap), and writes the raw .gem into JOBS_OUTPUT_DIR.
tarballhttps command
Command fetch is the JOBS tarball+https fetcher: it downloads a .tar.gz from a URL, verifies its sha256, and extracts it into JOBS_OUTPUT_DIR with an optional leading-component strip.
Command fetch is the JOBS tarball+https fetcher: it downloads a .tar.gz from a URL, verifies its sha256, and extracts it into JOBS_OUTPUT_DIR with an optional leading-component strip.
tarballxz command
Command fetch is the JOBS tarball+xz fetcher: it downloads a .tar.xz from a URL, verifies its sha256, and extracts it into JOBS_OUTPUT_DIR with an optional leading-component strip.
Command fetch is the JOBS tarball+xz fetcher: it downloads a .tar.xz from a URL, verifies its sha256, and extracts it into JOBS_OUTPUT_DIR with an optional leading-component strip.
tarextract
Package tarextract untars a (already-decompressed) tar stream into a directory with an optional leading-component strip, preserving file modes and — critically — symlink targets EXACTLY.
Package tarextract untars a (already-decompressed) tar stream into a directory with an optional leading-component strip, preserving file modes and — critically — symlink targets EXACTLY.
Package hostaddr picks which of the machine's own addresses are worth telling a peer about.
Package hostaddr picks which of the machine's own addresses are worth telling a peer about.
Package importdef defines the JOBS import job definition and its canonical encoding.
Package importdef defines the JOBS import job definition and its canonical encoding.
Package natsiroh tunnels the NATS client protocol over iroh QUIC streams.
Package natsiroh tunnels the NATS client protocol over iroh QUIC streams.
plugins
goplugin command
Command goplugin is a JOBS build plugin (build.md §6) for Go programs.
Command goplugin is a JOBS build plugin (build.md §6) for Go programs.
Package registryd implements jobs-registry: a read-only OCI Distribution registry that serves jobs build outputs as pullable container images.
Package registryd implements jobs-registry: a read-only OCI Distribution registry that serves jobs build outputs as pullable container images.
Package resources defines the CPU/RAM scheduling value type used by the engine (admission control), the runner (advertised capacity), and the wire protocol (resolved per-node requirement).
Package resources defines the CPU/RAM scheduling value type used by the engine (admission control), the runner (advertised capacity), and the wire protocol (resolved per-node requirement).
Package runner holds the JOBS stage drivers and their execution machinery: it resolves and runs fetchers for imports, assembles and runs the hermetic build sandbox, ingests outputs into amber, and publishes result refs through the RefWriter seam.
Package runner holds the JOBS stage drivers and their execution machinery: it resolves and runs fetchers for imports, assembles and runs the hermetic build sandbox, ingests outputs into amber, and publishes result refs through the RefWriter seam.
Package runnerd is the jobs-runner daemon loop (design 2026-07-23 §3): it owns a private amber store as materialization cache, reaches the server over two iroh ALPNs (the NATS tunnel for scheduling, the amber sync for objects), announces itself on runners.hello, and serves every work-queue class that fits inside its size with an admission-gated pull loop.
Package runnerd is the jobs-runner daemon loop (design 2026-07-23 §3): it owns a private amber store as materialization cache, reaches the server over two iroh ALPNs (the NATS tunnel for scheduling, the amber sync for objects), announces itself on runners.hello, and serves every work-queue class that fits inside its size with an admission-gated pull loop.
Package sched is the single-process jobs-iroh scheduler: an in-memory dependency graph over the server's amber store, driven by the embedded NATS layout of docs/design/2026-07-23-sched-and-wire.md.
Package sched is the single-process jobs-iroh scheduler: an in-memory dependency graph over the server's amber store, driven by the embedded NATS layout of docs/design/2026-07-23-sched-and-wire.md.
Package serve wires the jobs-server process: one iroh endpoint whose ALPNs multiplex every service — the client build API, the runner NATS tunnel, the runner and admin CAS sync, and the admin API — over a single embedded amber store and a single embedded NATS server.
Package serve wires the jobs-server process: one iroh endpoint whose ALPNs multiplex every service — the client build API, the runner NATS tunnel, the runner and admin CAS sync, and the admin API — over a single embedded amber store and a single embedded NATS server.
Package tailbuf provides a bounded tail buffer that retains only the last max bytes written to it.
Package tailbuf provides a bounded tail buffer that retains only the last max bytes written to it.
Package tui is the jobs-client admin TUI over the jobs-admin/1.0 ALPN: live build requests (with per-build snapshot watch, node logs, cancel and delete), the runner fleet, server stats, and a prefix-filterable ref browser.
Package tui is the jobs-client admin TUI over the jobs-admin/1.0 ALPN: live build requests (with per-build snapshot watch, node logs, cancel and delete), the runner fleet, server stats, and a prefix-filterable ref browser.
Package version carries the single release version of the jobs-iroh binaries.
Package version carries the single release version of the jobs-iroh binaries.
Package wire is the shared vocabulary of the jobs-iroh scheduler: the NATS stream/subject/KV layout, the size-class ladder, the job and result payload schemas, and the node-name grammar.
Package wire is the shared vocabulary of the jobs-iroh scheduler: the NATS stream/subject/KV layout, the size-class ladder, the job and result payload schemas, and the node-name grammar.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL