Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.9.1] - 2026-05-01
yoe deploy <unit>now installs the package’s runtime deps too. Previously it only built and published the named unit, so deploying a package withruntime_depsoutside what the device already had on disk failed with a crypticapk adderror likesqlite (no such package). Deploy now walks the full runtime closure (the same expansionimage()does at image-build time), so every transitive dep ends up in the feed beforeapk addruns.- Deploy refreshes the device’s apk index every time. The on-device
apk updatestep now usesapk --no-cache update, forcing a refetch of every repo’sAPKINDEXinstead of trusting whatever is in/var/cache/apk/. apk-tools 2.x can otherwise hold onto a stale index across a yoe-dev rebuild and silently miss packages you just published. - Added sqlite unit
[0.9.0] - 2026-05-01
- New design doc on libc and init choice.
docs/libc-and-init.mdlays out why yoe is musl + OpenRC + Alpine today, where that stack works (gateways, IoT, networking gear), where it doesn’t (Jetson, vendor BSPs, Adaptive AUTOSAR), and the planned rootfs-base abstraction that would let a single yoe codebase serve both Alpine and Ubuntu/L4T projects. Establishes the invariant that yoe stays apk-native on every target — Debian-derived bases get adeb_pkgconversion class, not dpkg/apt on the device. - Pull packages straight from Alpine. A new
units-alpinemodule wraps prebuilt Alpine.apkfiles as yoe units via thealpine_pkg()class — no source build, no patches, just fetch + verify + repack.muslandsqlite-libsship today; add more by pinning a version and sha256. muslnow comes from Alpine. The hand-rolled musl unit that copied the dynamic linker out of the build container is gone;muslis now an Alpine apk wrapped byalpine_pkg(). Output is byte-identical to the Alpine package other projects already ship..apkURLs work as a source type. Yoe’s source workspace now recognises.apkextensions and bare-copies them so the unit’s install task can extract the multi-stream gzip with GNU tar. Bare-copied sources also keep their URL filename, so install steps can reference the file by name instead of by cache hash.- Override an upstream unit by name. Define a unit with the same name in a
higher-priority module (or in the project itself) and it shadows the upstream
one — no
providesboilerplate needed. The project root beats every module, and later modules beat earlier ones. A notice on stderr tells you which one won. - Deploy from the TUI. Press
Don a non-image unit to deploy it to a running yoe device — host prompt is pre-filled from the last-used target, build + ssh + apk add output stream into the view, and the host is saved back tolocal.staron success. - Deploy actually updates the device’s apk index.
yoe deployandyoe device repo addpreviously wrote to/etc/apk/repositories.d/yoe-dev.list, which apk-tools 2.x ignores. They now append a marker block to/etc/apk/repositoriesso the nextapk updateactually fetches the dev feed andapk add <unit>finds the freshly built package. - TUI starts a feed automatically. When you launch
yoe, it brings up the project’s apk feed (or reuses one already running on the LAN), so devices configured withyoe device repo addcan pull packages without any extra setup. Status is shown in the header. - SSH target shorthand.
yoe deployandyoe device repo {add,remove,list}accept[user@]host[:port]— e.g.yoe device repo add localhost:2222for a QEMU vm oryoe deploy myapp pi@dev-pi.local:2200. The--ssh-portflag is gone. - APK live deployment tooling.
yoe deploy <unit> <host>builds and installs a unit on a running yoe device with full apk dependency resolution. Pair withyoe serveandyoe device repo addto keep a device pointed at your dev feed for ad-hocapk addfrom the device. See docs/feed-server.md.
[0.8.6] - 2026-04-30
- Container runtime build path documented.
docs/containers.md now walks through what it takes to
ship Docker, containerd, and runc on a musl yoe rootfs — why prebuilt “static”
binaries don’t work, the per-component build breakdown, and how cgo units like
runc plug into yoe’s existing Go toolchain and
toolchain-muslcontainer viadepsinstead of needing a new Go+GCC container image. - Rename
debugunits todev. - Expand roadmap. Reorganized as a pointer index into the design docs, with new sections for the app-developer build/deploy loop, hardware access, testing, self-hosting, and distribution variants.
- New testing design doc at docs/testing.md covers the
planned
yoe testdriver, build-time package QA, on-device upstream tests (Yoctoptestanalog), image smoke tests, and CI integration. - Kernel modules now ship in images — the
linux,linux-rpi4, andlinux-rpi5units previously built only the in-tree kernel image, so drivers compiled as loadable modules (Wi-Fi, USB, sound, many filesystems) were silently dropped. Modules are now built and installed to/lib/modules/<kver>/in the rootfs, somodprobefinds them at runtime. - Fix rPI4 builds package arch did not match what apk was expecting.
[0.8.5] - 2026-04-30
- `Yazi, Zellij, and Go units added.
- Clear error when an image’s rootfs won’t fit the partition. Yoe points at
the partition size to bump instead of failing mid-
mkfs.ext4with a cryptic ext2 error. - SSH works out of the box on
dev-image.sshdstarts on boot with per-device host keys;ssh -p 2222 user@localhost(passwordpassword) just works, and passwordless root SSH matches the serial console. - Image rebuilds recover from prior failed builds. A previous failure no longer wedges the next run on “Permission denied” — yoe reports the real error and cleans up automatically.
- New
binaryclass for prebuilt binaries. Units can ship upstream release binaries with SHA256 verification, no rebuild from source. Used bygo,helix, andyazi. apk addworks against the signed repo. Image-time and on-targetapkcommands no longer fail with “BAD signature” or need--allow-untrusted/--keys-dir.apk addandapk upgradework on yoe-built devices.dev-imageshipsapk-toolsand the project’s signing key, so OTA-style updates use stockapkcommands. Seedocs/on-device-apk.md.- Signed apks and APKINDEX. Every artifact is RSA-signed at build time and
verified by stock
apkon the target.yoe key generate/yoe key infomanage the project key; seedocs/signing.md. - Rootfs builds with APK. Much faster.
providesis now a list. Useprovides = ["a", "b"]; the string formprovides = "x"no longer parses.replacesis documented. New “Shadow files” section indocs/naming-and-resolution.mdcovers when to use it and how to read apk’s “trying to overwrite” errors.- “One .apk per unit” principle, documented. Image-to-image variation
belongs at runtime, not in build-flag forks. See
docs/naming-and-resolution.md. - SSH configured to autostart and work with blank passwords for dev builds.
[0.8.4] - 2026-04-29
- Networking picks the better DHCP client when available. The default
S10networkrunsdhcpcdif it’s onPATH(IPv6 SLAAC, DHCPv6, IPv4LL fallback) and falls back to busyboxudhcpcotherwise — so an image that shipsdhcpcdgets the modern client without changing the init script. - File conflicts in image builds now fail loudly. Units can declare
replaces = ["pkg", ...]to opt into shadowing another package’s files (e.g.util-linuxover busybox’s/bin/dmesg); apk honors that at install time and rejects any conflict that wasn’t declared. Image assembly no longer passes--force-overwrite, so a new shadow becomes a real error instead of a buried warning. - Unit edits no longer get masked by stale cache hits. Editing a unit’s
description, license, runtime deps, replaces, conffiles, build environment,
scope, image partitions, image excludes, or install-step files now invalidates
the cache as it should — previously these silently kept the old apk. A new
test in
internal/resolvefails if a future Unit field is added without being incorporated into the cache key. ipworks again ondev-image. iproute2 no longer pulls in libelf at link time, so/sbin/ipruns without “Error relocating /sbin/ip: elf_getdata: symbol not found” on images that don’t ship elfutils.- Boot no longer hangs when DHCP fails. The default network init script
waits briefly for the link to come up before starting udhcpc, runs udhcpc in
the background, and limits its retries — so
dev-imagereaches a login shell even when no DHCP server is reachable, instead of looping on “Network is down”. - Image rootfs is assembled by upstream
apk add. yoe no longer loopstar xzfover each apk; image builds runapk addagainst the project’s local repo, getting real dependency resolution, file-conflict detection, and an installed-package database in/lib/apk/dbfor free. On-target you can nowapk info,apk verify, and (once apk-tools ships as a unit)apk addandapk upgradeagainst the same repo. - Service symlinks ship inside the apk. A unit’s
services = [...]declaration is materialized as real/etc/init.d/SXX<name>symlinks inside the package’s data tar at build time. On-targetapk add <pkg>produces the same rootfs as image-time assembly — yoe never patches the rootfs after install. - Repo layout switched to Alpine-native —
repo/<project>/<arch>/<pkg>-<ver>-r<N>.apkplus a per-archAPKINDEX.tar.gz..apkfilenames no longer carry a scope suffix. Existingrepo/directories are obsolete; the next build repopulates the new layout. - Yoe-built apks install with upstream Alpine apk-tools.
.apkfiles andAPKINDEXproduced by yoe now round-trip through stockapk add --allow-untrusted: no checksum errors, no format warnings, and package metadata (name, version, arch, deps, origin, commit, install size) matches whatapk indexitself would emit. - Nine new units in
dev-image—e2fsprogs(mkfs.ext4 / fsck.ext4 / tune2fs on the target),eudev(full udev for dynamic /dev),iproute2(fullip/tc),dhcpcd(a DHCP client beyond busybox udhcpc),bash,less,file,procps-ng(realps/top/free/vmstat), andhtopare now built and included indev-imageso they’re available out of the box on a booted dev system.gperfis also added as a build-time dependency for eudev. - Updated units roadmap —
util-linux,kmod, andca-certificatesare marked done;dropbearis dropped (the project standardizes onopenssh); remaining work is nownftables(blocked on libmnl/libnftnl/gmp deps) anddbus. - Documented when NOT to use
provides—docs/naming-and-resolution.mdnow spells out thatprovidesis for leaf artifacts only (kernel, base-files, init, bootloader). Using it for build-time libraries or runtime alternatives forks every transitive consumer into a per-machine apk. Runtime alternatives likemdevvseudevshould ship side-by-side and be selected at boot from init scripts. - Image rootfs assembly now warns on path collisions — when two packages
install to the same path (e.g., busybox’s
/sbin/ipsymlink vs iproute2’s full binary), the later package silently overwrote the earlier one with no trace. Image assembly now emits awarning:line per collision naming the surviving package and the shadowed ones, plus a total count. The warnings appear in the image’sbuild.log(and on terminal whenyoe build -vis used). Existing dev-image builds surface 27 expected shadows of busybox applets by full alternatives — no behavior change, just visibility.
[0.8.3] - 2026-04-28
- mDNS via new
mdnsdunit — the dev-image now answers<hostname>.localon the LAN, sossh user@yoe-dev.localworks without knowing the device’s IP. Uses troglobit/mdnsd (a small dbus-free mDNS responder) and ships a default_ssh._tcpservice record so the host A record is advertised and SSH discovery works for Bonjour-aware tools. - NTP at boot via new
ntp-clientunit — boards without a battery- backed RTC (e.g., Raspberry Pi) booted at 1970, which broke TLS with “certificate is not yet valid”.ntp-clientdoes a blocking initial sync at S20 (retried a few times to cover DNS settling right after udhcpc) so subsequent services start with real time, then leaves a busyboxntpddaemon running to discipline drift over uptime. Added todev-imageby default.base-filesalso gets/var/runso daemons that write a pidfile have a place to put it. - Fix
simpleiotfailing to start at boot — the unit installed the binary as/usr/bin/simpleiotbut its init script invoked/usr/bin/siot, so booting the dev image showedsiot: not foundand the service never ran. The binary now installs assiotto match upstream.go_binarygains abinarykwarg for cases where the installed command name should differ from the apk package name. - Per-developer machine override via
local.star— when you switch machines from the TUI’s setup view, yoe now writeslocal.starat the project root with your selection. Subsequentyoecommands use that machine without you re-passing--machineevery time. The file is gitignored so each developer can pin their own target.--machineon the command line still wins. yoe flash listand TUI device picker —yoe flash listenumerates removable USB sticks and SD cards (filtered against the disk hosting the running system). In the TUI, pressingfon an image unit opens a device picker with a live progress bar during the write.yoenever invokessudoitself; if the device isn’t writable, it prompts once for consent and runssudo chown <you> /dev/....- Honest flash progress —
yoe flashnow opens the target device withO_DIRECTso writes bypass the kernel page cache and the progress bar tracks actual device throughput. Previously the bar could hit 100% with hundreds of MB still buffered in RAM, freezing the UI for tens of seconds during the final flush. WithO_DIRECTthe wait is paid out across the write itself, and “Flash complete” appears when the data is really on the card. - Fix
yoe flashrejecting non-system disks —flashpreviously refused to write to/dev/sda,/dev/nvme0n1, and/dev/vdaregardless of the actual layout. It now detects which disk hosts the running system (/,/boot,/boot/efi,/usr) and refuses only that disk, so flashing to a USB or external SATA drive named/dev/sdaworks on machines whose root is on NVMe. - Fix images silently shipping without packages — if an artifact’s apk was
missing from the local repo (e.g., its build was cancelled), the image used to
build anyway with a
warning: package X not found, skippingand produce a kernel-panicking rootfs. Image assembly now hard-fails with a clear message naming the missing package. The build cache now also treats a unit as out-of-date when its apk has gone missing, and rebuilding any unit invalidates its dependents — so reruns auto-recover instead of reusing stale outputs.
[0.8.2] - 2026-04-24
- Fix extlinux install under Docker 29 —
--privilegedcontainers no longer auto-populate/dev/loop*, solosetup --findfailed during image assembly. Pre-create/dev/loop0..31withmknodbefore callinglosetup.
[0.8.1] - 2026-04-24
- Fix rootfs ownership on booted systems — files under
/,/bin,/etc,/usr, etc. are now owned byroot:rooton the booted system instead of showing up as whatever user built the project. - Compare rootfs ownership handling across projects —
docs/comparisons.mdnow has a section explaining how Alpine, Debian, Buildroot, Yocto, and NixOS handle root ownership during image builds, and where[yoe]fits.
[0.8.0] - 2026-04-24
- Class task merge semantics — units passing
tasks=[...]to a class (autotools,cmake,go_binary) no longer fully replace the class’s default task list. Instead, overrides are merged by name: a same-named task replaces in place (preserving position and using the override’sstepsfully), a new-named task is appended, andtask("name", remove=True)drops a base task. This lets units add a new task (e.g.,init-script) without restating the class-generatedbuildtask. The merge is implemented in a newclasses/tasks.starhelper (merge_tasks(base, overrides)) shared by the three classes. Thesimpleiotunit dropped its duplicatedbuildtask as a result; existing units that overridebuildare unaffected (replace-in-place yields the same result as the previous full-replacement semantics). - Fix install_template/install_file path resolution for helper functions —
template paths now resolve relative to the
.starfile containing theinstall_template()/install_file()call, not to the file that ultimately callsunit(). Previously, a helper likebase_files(name = "base-files-dev")inunits/base/base-files.starinvoked fromimages/dev-image.starlooked for templates underimages/base-files-dev/instead ofunits/base/base-files/, breaking thedev-imagebuild. The base directory is now captured at install-step construction time from the Starlark caller frame; existing units that define and use install steps in the same.starfile are unaffected. - File templates — units can declare external template files (
.tmpl) and static files in a directory alongside the.starfile and install them via newinstall_template()andinstall_file()step-value constructors placed directly intask(..., steps=[...])alongside shell strings. Templates render through Gotext/templatewith a unifiedmap[string]anycontext auto-populated withname/version/release/arch/machine/console/projectand any extra kwargs passed tounit(). The context map and the contents of the unit’s files directory are hashed so template edits and extra-kwarg changes invalidate the cache. Install steps run on the host (not inside the sandbox), so$DESTDIR/$SRCDIR/$SYSROOTin install paths expand to host paths rather than the container bind-mount paths.base-files,network-config, andsimpleiotmigrated off inline heredocs. Seedocs/file-templates.md. - CLI flag parsing with flag.NewFlagSet — refactored all subcommands
(
build,run,flash,init,clean,log,refs,graph) from manual switch-based parsing to Go’sflag.NewFlagSet. Adds free--helpfor every subcommand, consistent-flag/--flagsupport, and repeatable flags (e.g.,--port). Net reduction of ~70 lines. - Go module cache — Go units now persist module and build caches across
builds via
cache_dirs = {"/go/cache": "go"}. The executor mountscache/go/from the project directory into the container, andGOMODCACHEandGOCACHEpoint to it. Subsequent builds skip module downloads. - Fix service enablement for S-prefixed init scripts — services declared
with an
S<NN>prefix (likeS10network) no longer get a symlink created on top of the actual script, which was causing a symlink loop and breaking networking at boot. - Unit environment field — units can declare
environment = {"KEY": "VAL"}which the executor merges into the build environment for all tasks. The Go class uses this forGOMODCACHE/GOCACHEso custom tasks (like simpleiot) get the cache env vars automatically. - QEMU port forwarding in machine config —
qemu_config()now accepts aportsfield (e.g.,ports = ["2222:22", "8118:8118"]) for default port forwarding. CLI--portflags extend these. Fixed a bug where multiple ports created duplicate QEMU netdevs. Fixed hostfwd syntax to use QEMU’shost-:guestformat. QEMU machines default to SSH (2222:22), HTTP (8080:80), and SimpleIoT (8118:8118). - Service enablement moved to units — units now declare
services = ["sshd"]to indicate which init scripts they provide. The image assembly auto-enables services by readingservicemetadata from installed APKs and creatingS50<name>symlinks (or custom priority likeS10network). Theservicesparameter onimage()is removed. - Design specs — added
docs/starlark-packaging-images.md(move packaging and image assembly to composable Starlark tasks) anddocs/file-templates.md(external template files using Gotext/template, replacing inline heredocs in units). - Go class uses golang container —
go_binary()now defaults to thegolang:1.24external container image instead oftoolchain-musl. Cross-compilation is handled viaGOARCH/GOOSenvironment variables withCGO_ENABLED=0for static binaries, so the container always runs at host architecture (no QEMU overhead). - Per-unit sandbox and shell selection — units now have
sandbox(bool, default false) andshell(string, default “sh”) fields. The autotools, cmake, and image classes setsandbox=True, shell="bash"for bwrap isolation. External containers (likegolang:1.24) use the defaults — no bwrap, POSIX sh — since they don’t ship bwrap or bash. - simpleiot unit — new
go_binaryunit for SimpleIoT v0.18.5, an IoT application for sensor data, telemetry, and device management. - ca-certificates unit — Mozilla CA bundle for TLS verification. Added to dev-image alongside simpleiot.
- Per-task container resolution — tasks can override the unit-level
container via
task(container = "..."). The executor resolves the container per-task, falling back to the unit default. - TUI: amber
[yoe]title — the top-left title in the TUI now renders[yoe]in amber on black, matching the project logo. - Fix module URLs in
initgenerated project file.
[0.7.1] - 2026-04-06
- Unit
releasefield — units can now specifyrelease = Nfor packaging revisions (apk-rNsuffix). Defaults to 0. Bump when the unit definition changes but the upstream version doesn’t. - Build metadata — each unit’s build directory now contains a
build.jsonwith status, start/finish times, duration, build disk usage, installed size (destdir/apk), and input hash. The TUI detail view shows build time and sizes alongside the unit name. - Persistent build output — executor output (
executor.log) is now written for both CLI and TUI builds, so the TUI detail view shows build output regardless of how the build was triggered.
[0.7.0] - 2026-04-06
- Container units — build containers are now Starlark units
(
toolchain-musl) instead of an embedded Dockerfile. Containers participate in the DAG, caching, and versioning. Classes setcontainerandcontainer_archexplicitly.run(host = True)enables host-side execution for container builds. The embedded Dockerfile andEnsureImage()are removed. Container images are tagged with arch for explicitness (yoe-ng/toolchain-musl:15-x86_64). Cross-arch containers usedocker buildxautomatically. - Container image prefix renamed — Docker image prefix changed from
yoe-ng/toyoe/(e.g.,yoe/toolchain-musl:15-x86_64). Arch is always included in the tag for explicitness. Cross-arch containers usedocker buildxautomatically. - TUI: detail view log search — press
/in the unit detail view to search build output and logs. Matching lines are highlighted in yellow;n/Njump to next/previous match. Firstescclears the search, second returns to the unit list. - TUI: color-coded unit types — unselected units are now subtly colored by
class: blue for regular units, magenta for images, cyan for containers.
Selected unit uses a brighter green for visibility. Search (
/) also matches unit class, so typing “image” or “container” filters to units of that type. - E2E build test scripts — added
yoe_e2e,yoe_e2e_x86_64, andyoe_e2e_arm64shell functions inenvsetup.shthat buildbase-imagefrom the e2e test project for x86_64 and arm64 (cross-build via QEMU user-mode).
[0.6.0] - 2026-04-03
- TUI: ctrl+f/ctrl+b page scrolling — added vim-style page-forward and page-back keybindings in both the unit list and detail views, alongside the existing PgUp/PgDn keys.
- Heavy development notice — GitHub releases and
yoe updatenow remind users to clean their build directory and re-create projects with each new release. - Updated plan/spec indexes — all specs and plans marked with current implementation status; added plans INDEX.
- Remove
repository()builtin — therepository(path = "...")config inPROJECT.staris removed. APK repos are now always atrepo/<project-name>/, derived from the project name. This eliminates a confusing override that defeated per-project repo scoping. - TUI: show all units — removed the filter that only showed units reachable from image definitions. The TUI now lists all units in the project.
- README: “Is Yoe-NG Right for You?” — new section clarifying when to use Yocto vs Yoe-NG. Added container workloads on the target device to the roadmap in Design Priorities.
- Fix
yoe updatedownload URL — binary name now matches goreleaser’s naming convention (yoe-Linux-x86_64) instead of incorrectly including the version (yoe-v0.1.0-Linux-x86_64), which caused 404 errors. - Unit name collision detection — duplicate unit names now error at evaluation time with a clear message showing which module first defined the unit.
- PROVIDES collision detection — two units providing the same virtual name in the same module now error. Units from higher-priority modules (later in the module list) override lower-priority ones with a notice.
--projectflag —yoe --project projects/customer-a.star buildselects an alternate project file. Available on all subcommands.- Per-project APK repo — package repositories are now scoped per project
name (
repo/<project>/) to prevent stale packages across project switches. - README: Principles section — added six core design principles covering leveraging existing infrastructure, aggressive caching, custom containers per unit, no intermediate formats, one tool for all levels, and tracking upstream closely.
- README: Build dependencies and caching — new section explaining the three kinds of build dependencies (host tools via containers, library deps via sysroot/apk, language-native deps via their own package managers), symmetric caching at the unit level, and how native builds unlock existing package ecosystems (e.g., PyPI wheels on ARM).
- README: Cross-compilation is optional — updated from “no cross compilation” to “cross compilation is optional,” acknowledging that Go and some C/C++ packages cross-compile easily while fussy packages can avoid it.
- Raspberry Pi in yoe init — rpi machine added to the project initialization template.
- Fix false “old build layout” warning —
warnOldLayoutwas written for the oldbuild/<arch>/<unit>/directory structure but the current layout isbuild/<unit>.<scope>/, causing every build directory to trigger a spurious warning.
[0.5.1] - 2026-04-02
- Remove version from release binary name to fix stable download URL.
[0.5.0] - 2026-04-02
BASE-IMAGE boots on RPI4
- Tasks replace build steps —
build = [...]replaced bytasks = [...]with named build phases. Each task hasrun(shell string),fn(Starlark function), orsteps(mixed list). Classes (autotools, cmake, go) are now pure Starlark. run()builtin — Starlark functions can execute shell commands directly during builds. Errors show.starfile and line number, not generated shell.run(cmd, check=False)returns exit code/stdout/stderr for conditional logic.run(cmd, privileged=True)runs directly in the container as root for operations like losetup/mount that bwrap can’t do.- Unit scope — units declare
scope = "machine","noarch", or"arch"(default). Machine-scoped units (kernels, images) build per-machine. Build directories are flat:build/<name>.<scope>/. Repo is flat with scope in filenames:repo/<name>-<ver>-r0.<scope>.apk. - Machine-portable images — images no longer hard-code machine-specific
packages or partitions.
MACHINE_CONFIGandPROVIDESinject machine hardware specifics automatically.base-imageworks across QEMU x86, QEMU arm64, and Raspberry Pi without changes. PROVIDESvirtual packages — units and kernels declareprovidesto fulfill virtual names.provides = "linux"onlinux-rpi4means images that list"linux"get the RPi kernel when building forraspberrypi4.- Image assembly in Starlark — disk image creation moved from Go to
classes/image.starusingrun(). Fully readable, customizable, forkable. - Raspberry Pi BSP module (
units-rpi) — machine definitions, kernel fork units, GPU firmware, and boot config for Raspberry Pi 4 and 5. - Runtime dependency resolution — image assembly now resolves transitive
runtime dependencies automatically.
RUNTIME_DEPSpredeclared variable available after unit evaluation. Three-phase loader: machines → units → images. - Layers renamed to modules —
layer()→module(),LAYER.star→MODULE.star,yoe layer→yoe module,layers/→modules/. Aligns terminology with Go modules model used for dependency resolution.
[0.4.0] - 2026-03-31
ARM BUILDS ON X86 NOW WORK
- TUI global notifications — the TUI now shows a yellow banner for background operations like container image rebuilds. Previously these events were only visible in build log files.
- cmake added to build container — cmake is now available as a bootstrap tool in the container (version bump to 14), enabling units that use the cmake build system.
- xz switched to cmake — the xz unit now uses the cmake class instead of autotools with gettext workarounds, simplifying the build definition.
- TUI reloads .star files before each build — editing unit definitions or classes no longer requires restarting the TUI. The project is re-evaluated from Starlark on each build, picking up any changes to build steps, deps, or configuration.
- Fix xz autoreconf failure — xz’s
configure.acusesAM_GNU_GETTEXTmacros which require gettext’s m4 files. The xz unit now provides stub m4 macros and skipsautopoint, allowingautoreconfto succeed without gettext installed in the container. - Cross-architecture builds — build arm64 and riscv64 images on x86_64 hosts
using QEMU user-mode emulation. Target arch is resolved from the machine
definition. Run
yoe container binfmtfor one-time setup, thenyoe build base-image --machine qemu-arm64works transparently. - Arch-aware build directories — build output is now stored under
build/<arch>/<unit>/and APK repos underbuild/repo/<arch>/, supporting multi-arch builds in the same project. Note: existing build caches underbuild/<unit>/will need to be rebuilt (yoe clean --all). yoe container binfmt— new command to register QEMU user-mode emulation for cross-architecture container builds. Shows what it will do and prompts for confirmation.- Multi-arch QEMU —
yoe runnow auto-detects cross-architecture execution and uses software emulation (-cpu max) instead of KVM. Container includesqemu-system-aarch64andqemu-system-riscv64. - TUI setup menu — press
sto open a setup view for selecting the target machine. Shows available machines with their architecture and highlights the current selection. Designed to accommodate future setup options.
[0.3.4] - 2026-03-30
- Build lock files — a PID-based
.lockfile is written during builds so otheryoeinstances can detect in-progress work instead of marking active builds as failed. Builds are skipped if another process is already building the same unit. yoe clean --locks— removes stale lock files left behind by crashed or killed builds.- TUI edit for cached layers — pressing
eon a unit now also searches the layer cache, so editing works for units from layers cloned viayoe layer sync.
[0.3.3] - 2026-03-30
- HTTPS layer URLs —
yoe initnow uses HTTPS URLs for the units-core layer instead of SSH, removing the need for SSH key setup to get started.
[0.3.2] - 2026-03-30
- TUI scrolling — both the unit list and detail log views are now
scrollable. The unit list shows
↑/↓overflow indicators when there are more units than fit on screen. The detail view supportsj/k,PgUp/PgDn,g/Gnavigation through the full build output and log, with auto-follow during active builds. - Auto-sync layers —
yoe buildand other commands that load the project now automatically clone missing layers on first use, matching the lazy container-build pattern. Existing cached layers are not fetched/updated, so there is no added latency on subsequent runs. Explicityoe layer syncis still available to update layers. - TUI confirmation prompts — quitting (
q/ctrl+c) and cancelling a build (x) now prompt for confirmation when builds are active, preventing accidental loss of in-progress builds. Declining a prompt clears the message cleanly. - Fix build cancellation not stopping containers — cancelling a build (via
TUI quit or
ctrl+con the CLI) now explicitly stops the Docker container (docker stop) instead of only killing the CLI client, which left containers running in the background. - Fix stale cache after cancelled builds — the cache marker is now removed before building so a cancelled or failed rebuild no longer appears cached from a previous successful build.
[0.3.1] - 2026-03-30
ALL UNITS ARE NOW BUILDING
- Per-unit sysroots — each unit’s build sysroot is assembled from only its
transitive
deps, not every previously built unit. Fixes busybox symlinks shadowing container tools (e.g., musl-linkedexprbreaking autoconf). - Run from TUI — press
ron an image unit to launch it in QEMU. - Log writer plumbing — container stdout/stderr in image assembly and source fetch/prepare output now route through the build log writer instead of os.Stdout. Fixes TUI alt-screen corruption during background builds.
- Autotools maintainer-mode override —
makeinvocations passACLOCAL=true AUTOCONF=true AUTOMAKE=true AUTOHEADER=true MAKEINFO=trueto prevent re-running versioned autotools (e.g.,aclocal-1.16) that aren’t in the container. Fixes gawk and similar packages. - rcS init script —
base-filesnow includes/etc/init.d/rcSwhich runs all/etc/init.d/S*scripts at boot. - network-config unit — new unit that configures a network interface via an init script.
- Build failure context — when a unit fails, the output now lists all downstream units blocked by the failure. The TUI shows cached units in blue and displays the full build queue (waiting/cached) before work begins.
- dev-image — added
kmodandutil-linuxto the development image. - Image rootfs dep fix — image assembly now follows only
runtime_depswhen resolving packages, not build-timedeps. Fixes build-only packages (e.g., gettext via xz) being installed into the rootfs and overflowing the partition.
[0.3.0] - 2026-03-30
THIS RELEASE DOES NOT WORK - this release is only to capture rename and TUI updates. Wait for a future one to do any work.
BREAKING CHANGE - due to rename, recommend deleting any external projects and starting over.
- Terminology rename — “recipe” is now “unit” and “package” is now
“artifact” throughout the codebase. The Starlark
package()function is nowunit(), the image fieldpackagesis nowartifacts, and therecipes/directory in layers is nowunits/. Therecipes-corelayer is nowunits-core. The Gointernal/packagingpackage is nowinternal/artifact. yoe log— view build logs from the command line. Shows the most recent build log by default, or a specific unit’s log withyoe log <unit>. Use-eto open the log in$EDITOR.yoe diagnose— launch Claude Code with the/diagnoseskill to analyze a build failure. Uses the most recent build log by default, or a specific unit’s log withyoe diagnose <unit>.- TUI rewrite —
yoewith no args launches an interactive unit list with inline build status (cached/waiting/building/failed). Builds run in-process viabuild.BuildUnits()with real-time status events — dependencies show as yellow “waiting”, then flash green as they build. Features: background builds (b/B), edit unit in$EDITOR(e), view build log (l), diagnose with Claude (d), add unit with Claude (a), clean with confirmation (c/C), search/filter (/), and a split detail view showing executor output and build log tail. Theyoe tuisubcommand has been removed. - Build events —
build.Options.OnEventcallback notifies callers (e.g., the TUI) as each unit transitions through cached/building/done/failed states.
[0.2.10] - 2026-03-30
yoe container shell— interactive bash shell inside the build container with bwrap sandbox, sysroot mounts, and the same environment variables recipes see during builds. Useful for debugging build failures and sandbox issues.
[0.2.9] - 2026-03-30
- Bash for build commands — switched build shell from busybox sh to bash.
Avoids autoconf compatibility issues (e.g.,
AS_LINENO_PREPAREinfinite loop) and matches what upstream build scripts expect. Removed per-recipe bash workaround from util-linux. - User account API — new
classes/users.starprovidesuser()andusers_commands()functions for defining user accounts in Starlark.base-filesis now a callablebase_files()function that accepts ausersparameter — image recipes can override it to add users (e.g., dev-image adds auseraccount with passwordpassword).
[0.2.8] - 2026-03-30
- meson build system support — added samurai (ninja-compatible build tool),
meson, and kmod recipes. Container updated to v11 with python3 and
py3-setuptools for meson. Build environment now sets
PYTHONPATHto the sysroot so Python packages installed by recipes are discoverable. - Container versioning note — CLAUDE.md now documents that both
Dockerfile.buildandinternal/container.gomust be bumped together. - gettext recipe — builds GNU gettext from source as a recipe instead of
relying on the container. Provides
autopointneeded by packages like xz that use gettext macros in their autotools build. - Sysroot binaries on PATH —
/build/sysroot/usr/binis now prepended toPATHduring builds, so executables from dependency recipes are discoverable. - Autotools class respects explicit
buildsteps — no longer prepends default autoreconf/configure when a recipe provides its own build commands. - Claude Code plugin — added
.claude/plugin with AI skills for recipe development:diagnose(iterative build failure analysis),new-recipe(generate recipes from URLs/descriptions),update-recipe(version bumps),audit-recipe(review against best practices and other distros). --cleanbuild flag — deletes source and destdir before rebuilding.--forcenow only skips the cache check without cleaning.--force/--cleanscoped to requested recipes — dependency recipes still use the cache, only explicitly named recipes are force-rebuilt.- Fixed
YOE_CACHEhelp text — was~/.cache/yoe-ng, actually defaults tocache/in the project directory.
[0.2.7] - 2026-03-27
- Per-recipe build logs — build output written to
build/<recipe>/build.log. Console is quiet by default; on error the log path is printed. Use--verbose/-vto stream build output to the console. - Fixed QEMU machine templates — removed UEFI firmware (
ovmf/aavmf/opensbi) incompatible with MBR+syslinux boot, fixed root devicevda2→vda1.
[0.2.6] - 2026-03-27
- base-files recipe — provides filesystem skeleton:
/etc/passwd(root with blank password),/etc/inittab(busybox init + getty),/boot/extlinux/(boot config), and essential mount point dirs (/proc,/sys,/dev, etc.). Moved from hardcoded Go to a recipe so users can customize via overlays. - Serial console uses
gettyfor proper login prompt.
[0.2.5] - 2026-03-27
Added
- musl libc recipe — copies the musl dynamic linker from the build container into the image so dynamically linked packages work at runtime.
- Automatic package dep resolution — image assembly now resolves transitive build and runtime deps from recipe metadata. e.g., openssh automatically pulls in openssl and zlib without listing them in the image recipe.
- Recipes without source — recipes with no
sourcefield (e.g., musl) skip source preparation instead of erroring.
Fixed
- Disable ext4 features (
64bit,metadata_csum,extent) incompatible with syslinux 6.03 so bootloader can load kernel from any partition size. - Image package dep resolution walks both
depsandruntime_depsso shared libraries are included. - OpenSSL recipe uses
--libdir=libso libraries install to/usr/libinstead of/usr/lib64— fixes “Error loading shared library libcrypto.so.3”. - Inittab no longer tries to mount
/dev(already mounted by kernel viadevtmpfs.mount=1). - Skip
TestBuildRecipes_WithDepsin CI — GitHub Actions runners don’t support user namespaces inside Docker. - Most stuff in
dev-imagenow works.
[0.2.4] - 2026-03-27
- update BL config
[0.2.3] - 2026-03-27
Changed
- Container as build worker —
yoeCLI always runs on the host. The container is now a stateless build worker invoked only for commands that need container tools (gcc, bwrap, mkfs, etc.). Eliminates container startup overhead for read-only commands (config,desc,refs,graph,clean). - File ownership — build output uses
--user uid:gidso files created by the container are owned by the host user, not root. - QEMU host-first —
yoe runtries hostqemu-system-*first, falls back to the container if not found. --forcescoped to requested recipes —--forceand--cleanonly force-rebuild the explicitly requested recipes; dependencies still use the cache for incremental builds.- Busybox init — images use busybox
/sbin/initwith a minimal/etc/inittabinstead ofinit=/bin/sh. Shell respawns on exit, clean shutdown viapoweroff.
Fixed
- Shell quoting in bwrap sandbox commands — semicolons in env exports no longer split the command at the outer shell level.
- Package installation in image assembly — always extracts
.apkfiles viatarinstead of gating onapkbinary availability. - Rootfs mount points (
/proc,/sys,/dev,/tmp,/run) now included in disk images via.keepplaceholder files. devtmpfs.mount=1added to kernel cmdline so/devis populated before init.
Removed
YOE_IN_CONTAINERenvironment variable — no longer needed.ExecInContainer/InContainer/HasBwrapAPIs — replaced byRunInContainer.- Container re-exec pattern — the yoe binary is no longer bind-mounted into the container.
[0.2.2] - 2026-03-27
Added
- Layer
pathfield — layers can live in a subdirectory of a repo viapath = "layers/recipes-core". Layer name derived from path’s last component. - Project-local cache — source and layer caches default to
cache/in the project directory instead of~/.cache/yoe-ng/ .gitignoreinyoe init— new projects get a.gitignorewith/buildand/cache- Autotools
autoreconf— autotools class auto-runsautoreconf -fiwhen./configureis missing (common with git sources) - SSH URL support for source fetching (
git@host:user/repo.git) - Design: per-recipe tasks and containers — planned support for named
task()build steps with optional per-task Docker container images. Container resolves: task → package → bwrap. Seedocs/superpowers/plans/per-recipe-containers.md.
Changed
- Default layer in
yoe inituses SSH URL (git@github.com:YoeDistro/yoe-ng.git) withpath = "layers/recipes-core" - Container no longer mounts a separate cache volume — cache/ is accessible through the project mount
- Container runs with
--privileged(needed for losetup/mount during disk image creation and /dev/kvm for QEMU)
[0.2.1] - 2026-03-27
Added
- Dev-image with 10+ packages — new
dev-imagebuilds end-to-end with sysroot, including essential libraries (openssl, ncurses, readline, libffi, expat, xz), networking (curl, openssh), and debug tools (strace, vim) - Remote layer fetching —
yoe layer syncclones/fetches layers from Git - Sysroot + image deps in DAG — build sysroot and image dependencies resolved as part of the dependency graph
yoe_sloc— source lines of code counter usingscc
Fixed
- Correct partition size for
losetup, ensure sysroot dir exists - Recipe fixes for end-to-end dev-image builds
Changed
- Moved design docs into
docs/directory - Expanded build-environment and comparisons documentation
[0.2.0] - 2026-03-26
Added
- Bootable QEMU x86_64 image — end-to-end flow from recipes to a partitioned disk image that boots to a Linux kernel with busybox
- Starlark
load()support — class imports and@layer//pathlabel-based references across layers,//resolves to layer root when inside a layer - Recursive recipe discovery —
recipes/**/*.stardirectory traversal recipes-corelayer — autotools/cmake/go/image classes, busybox/zlib/ syslinux/linux recipes, base-image, qemu-x86_64 machine- APKINDEX generation —
APKINDEX.tar.gzfor apk dependency resolution - Bootstrap framework —
yoe bootstrap stage0/stage1/status - Container auto-enter — host
yoebinary bind-mounted into container, Dockerfile embedded in binary, versioned image tags
Fixed
- Build busybox as static binary (no shared lib dependency on rootfs)
- APKINDEX uses SHA1 base64 as required by apk
- Handle git sources in workspace (tag upstream without re-init)
- bwrap sandbox inside Docker with
--security-opt seccomp=unconfined - Mount git root for layer resolution
Changed
- Prefer git sources with shallow clone over tarballs
- Move build commands to
envsetup.sh(yoe_build,yoe_test)
[0.1.0] - 2026-03-26
Initial release of yoe-ng — a next-generation embedded Linux distribution builder.
Added
- CLI foundation —
yoe init,yoe config show,yoe clean,yoe layercommands with stdlib switch/case dispatch (no framework) - Starlark evaluation engine — recipe and configuration evaluation using
go.starlark.net with built-in functions (
project(),machine(),package(),image(),layer_info(), etc.) - Dependency resolution — DAG construction, Kahn’s algorithm topological
sort with cycle detection,
yoe desc,yoe refs,yoe graph - Content-addressed hashing — SHA256 cache keys from recipe + source + patches + dep hashes + architecture
- Source management —
yoe source fetch/list/verify/cleanwith content-addressed cache and patch application - Build execution —
yoe buildwith bubblewrap per-recipe sandboxing, automatic container isolation via Docker/Podman - Package creation — APK package creation,
yoe repocommands, local repository management - Image assembly — rootfs construction, overlay application, disk image generation with syslinux MBR + extlinux
- Device interaction —
yoe flashwith safety checks,yoe runfor QEMU with KVM - Interactive TUI — Bubble Tea interface for browsing recipes and machines
- Developer workflow —
yoe dev extract/diff/statusfor source modification - Custom commands — extensible CLI via
commands/*.star - Patch support — per-recipe patch files applied as git commits