small gleam coding and persistent agent daemon with a detachable cli and a canvas ui forked from okami.mom/albedo
albedo robot-docs release.md
4.3 kB · 76 lines
Markdown
at main

release #

Version tags (v*) build albedo for Linux x86_64 as one AppImage and as deb, rpm and Arch packages, smoke-test each on a clean distro, and upload them with SHA256SUMS to https://albedo-artifacts.fsn1.your-objectstorage.com/releases/<tag>/ (.tangled/workflows/release.yml). A manual run builds and tests the current commit and uploads nothing.

what is built #

release/build.sh [version] runs release/inside.sh in an Ubuntu 22.04 container (podman or docker) and writes build/release/<version>/. The version is semver without the v; the default is git describe. Downloads and the compiled OTP are cached in ~/.cache/albedo-release (ALBEDO_RELEASE_CACHE).

Everything is bundled except glibc (2.35 or newer: Ubuntu 22.04, Debian 12, current Fedora and Arch; not RHEL 9 or Debian 11). One tree serves every format:

bin/albedo           the CLI (static, CGO_ENABLED=0)
bin/rg               ripgrep (musl, static)
bin/albedo-daemon    release/albedo-daemon: bundled tools first on PATH, then the shipment
lib/albedo/          the sealed daemon shipment (gleam export erlang-shipment)
erlang/              OTP 29, built from source: only the apps the daemon calls,
                     no wx, termcap or other GUI apps, OpenSSL linked into crypto,
                     libstdc++/libgcc linked into the emulator
python/              python-build-standalone 3.11, without tests, Tk, IDLE, crypt
web/                 the web client (ALBEDO_WEB_DIST)

inside.sh refuses to package a tree in which any ELF needs a host library other than glibc (or one the tree ships); NixOS hosts have none of the usual ones, so a missing library shows there first. The shipment is sealed (albedo_daemon:seal_build/1, see runtime.md) after Python is compiled, since sealing hashes the finished tree.

  • packages install the tree to /usr/lib/albedo and release/packages/albedo to /usr/bin/albedo, which sets ALBEDO_DAEMON and ALBEDO_WEB_DIST. bin/albedo-daemon beside lib/albedo/albedo is the layout the CLI finds a build seal in, so packaged installs use standbys. nfpm builds all three from release/packages/nfpm.yaml; the maintainer field defaults to nekomimi.pet <meowskulls@nekomimi.pet>; PACKAGE_MAINTAINER overrides it.
  • AppImage is the tree plus release/appimage/AppRun, assembled by hand (mksquashfs, then the pinned type2 runtime prepended), never by running appimagetool: a host that registers AppImages with binfmt_misc (NixOS) routes every AppImage, inside containers too, to its own launcher. AppRun runs the CLI with ALBEDO_DAEMON=$APPIMAGE and ALBEDO_APPIMAGE_DAEMON=1, so the CLI starts the daemon by running the image again: the daemon holds its own mount and keeps its files after the CLI exits. ALBEDO_BUILD names the version, because the image path stays the same across upgrades; replace an image by rename, never in place, since a running daemon reads the old file. The AppImage has no seal path the CLI finds, so it boots cold. Its runtime cannot start under an open-file limit below about 1024.

testing #

release/smoke.sh <artifact> <image> installs the artifact on a clean container the way a user would, then checks that the CLI runs, that albedo daemon starts a daemon that outlives it and answers albedo sessions, and that albedo daemon --stop ends it. The e2e suite runs against an AppImage daemon through a wrapper given as ALBEDO_TEST_DAEMON (ALBEDO_APPIMAGE_DAEMON=1 exec <image> "$@"); tests that require the compiled test snapshot's layout fail there by design.

storage #

The bucket lives in a Hetzner project; keys of a project reach every bucket in it. The CI key lives in a separate project with no buckets, so it has no access until the bucket policy grants it: s3:PutObject under releases/ only. The same policy makes releases/ publicly readable and listable (s3:ListBucket with an s3:prefix condition, which Hetzner enforces): ?list-type=2&prefix=releases/&delimiter=/ names one prefix per release. The key reaches CI as the spindle secrets S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY; release/upload.sh signs with curl --aws-sigv4 (awscli misreads Hetzner's error bodies) and passes the key on stdin.