Embedded Linux — without tears
A set of experiments in what the next-generation embedded Linux build system could look like: native builds, modern languages first-class, AI that understands the system, one tool from laptop to production. Pre-1.0 and rough around the edges — we're sharing the work as it takes shape.
What we're aiming for.
[yoe] next-gen is a vendor-neutral project, built in the open to help small teams do big things. Small teams and startups don't have an enterprise's problems at smaller scale — they have different problems, and we build for those. Three north stars guide the experiment — everything else is in service of these.
Drastically improve developer productivity
Shrink the loop between an idea and a running image. Fewer rebuilds, fewer context switches, fewer tools to learn — so engineers spend their time on the product, not on the build.
Easily integrate complex workloads
Modern edge devices ship Go services, Rust agents, Python ML, container workloads, and kernel drivers side by side. Pulling these together should be straightforward, not a custom integration project each time.
Scale to build anything
From tiny Zephyr images to complex AI workloads. From one application to a complete distributed system — one tool, one mental model, with caching that keeps up as projects grow.
The existing systems have served us well …
With all due respect for the past and those who built Yocto, Buildroot, and other build systems — these are remarkable tools. They have enabled us to build and ship real products, and they solve a real problem. However, these tools were designed for an era of slow ARM hardware, scarce CI, and frozen SDKs. They still work, but they're increasingly bumping up against the demands of today's edge products.
Cross-compilation friction
Sysroot management, host contamination, mismatched pkg-config — time better spent shipping
features.
SDK drift
OS team builds an SDK. App team uses it. Six months later, version mismatches between teams turn into a long debugging session.
Stack traces from generated shell
A failure ten layers deep in machine-generated bash, and the actual fix lives elsewhere in the recipe tree.
Modern languages deserve first-class support
Go, Rust, and Python wheels are where most edge application work happens today — they belong at the center of the build, not bolted on.
Full rebuild for a small change
Tweak a kernel config or bump a single package, and the build wants to start over from scratch. Most edits should be incremental — minutes, not hours.
Updates feel like a risk event
Modern edge devices stay connected and need security patches across their lifetime. Bumping a package or following upstream should be routine, not a dedicated engineering effort.
One tool. Every layer. Built natively.
We're prototyping [yoe] as a single unified tool that builds every layer — kernel, root filesystem, and applications — natively on the target architecture, with no cross-compilation toolchain and no SDK handoff. One engine, three ways to drive it: a traditional CLI, an interactive TUI, and an AI assistant. Pieces work today; pieces are still on the bench.
No cross-compilation
Build ARM and RISC-V on a Mac, on real hardware, or in cloud CI. QEMU user-mode emulation transparently runs foreign-arch containers — same tool, native pipeline, no extra toolchain setup.
Cargo, Go modules, pip — as-is
Modern languages already solved dependency resolution, caching, and reproducibility. [yoe] uses what they ship instead of reinventing it. Even pre-built PyPI wheels just work.
AI as a first-class interface
Starlark units, queryable dependency graphs, structured logs. An assistant can create units from a URL, diagnose a failed build, audit CVEs, and trace why a package is in your image.
Same tool, system to app
System engineers and application developers run the same tool against the same config. New hire clones the
repo, types yoe, ships.
Cached at the unit level
Every unit produces a content-addressed package — apk or deb. Most developers never rebuild — they pull. Local, team, and global cache layers, no global lock.
Per-unit container, bwrap-isolated
Each unit runs in its own Docker container with a bubblewrap sandbox. Toolchain pinning per-unit/task; no host pollution; no leaks between build units.
Alpine, Debian, or Ubuntu — per image
Pick the base the workload needs, image by image. Alpine keeps things small and musl-clean; Debian and Ubuntu bring glibc, systemd, and a far larger catalog. One project builds all three side by side.
Give it a try.
All you need is one self-contained tool, Docker, and Git. No global state, no hidden caches, no SDK to install. The first build assembles a Docker toolchain container, fetches default unit modules, and produces a bootable QEMU image. Expect rough edges — this is an experiment, and we'd love to hear what breaks.
For ARM64, register QEMU user-mode once with
yoe container binfmt, then add
--machine qemu-arm64. The build runs inside a real ARM64
container, transparently emulated by your host kernel.
# Download the binary (Linux x86_64)
curl -L https://github.com/yoebuild/yoe/releases/latest/download/yoe-Linux-x86_64 -o yoe
chmod +x yoe && mv yoe ~/bin/
# Create a project, build, run
yoe init yoe-test
cd yoe-test
yoe build base-image
yoe run base-image
The pieces finally lined up.
A decade ago, this combination wasn't realistic. Three things have changed.
ARM & RISC-V build at full speed
Modern dev boards and cloud instances (AWS Graviton, Hetzner CAX) run native arm64 builds at full clock. QEMU user-mode covers the rest. Native builds are now practical for nearly every target, opening the door to a simpler design.
Languages bring their own tools
Cargo, Go modules, pip, npm, Zig — they already handle resolution, caching, lockfiles, and reproducibility. A modern build system should compose with these, not reimplement them.
An assistant can carry the load
The hardest part of embedded Linux isn't writing recipes — it's knowing which knobs to turn and why. Structured Starlark and a queryable graph let an AI do the legwork, so developers can stay focused on the product instead of holding the whole build system in their head.
Build the future of embedded Linux
We're testing whether ARM, RISC-V, and x86 can share one tool — without a cross-compile dance, an SDK handoff, or a rebuild on every config change. Pre-1.0, plenty unfinished. Try it on a board you care about and tell us what you find.
If any of this resonates, come think it through with us.
Questions, ideas, or things that broke?
We'd like to hear from you — about a board you're targeting, a unit that won't build, or an idea worth trying.