An exploration in embedded Linux

Embedded Linux — without tears

A next-generation embedded Linux build system optimized for the day-to-day developer experience. Software that used to mean a day of fighting cross-compilation now goes from idea to running on target hardware in minutes. Pre-1.0 — we're sharing the work as it takes shape.

Goals

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. One priority guides everything: the day-to-day developer experience — fast, transparent, efficient, and approachable. The goals below are how that priority shows up, and every other concern is secondary.

01 / Productivity

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.

02 / Integrate

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.

03 / Grow

Start simple, grow from there

The first goal is to do the simplest thing well: a read/write root filesystem with bootloader, kernel, and applications. One tool, one mental model, with caching that keeps up as the project grows. Immutability, containers, and more can follow.

The status quo

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

There is still a lot of software not designed for cross-compilation, resulting in embedded engineers debugging these issues — 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.

What we're exploring

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. Much like the Go language, the aim is not to be the best at any single thing, but good enough at all of them while keeping the developer experience excellent.

01 / Native

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.

02 / Languages

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.

03 / AI

AI as a first-class interface

Starlark units, queryable dependency graphs, structured logs. Integrated debugging of build failures. Also create units from a URL, audit CVEs, and trace why a package is in your image.

04 / No SDK

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.

05 / Cache

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.

06 / Sandboxed

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.

07 / Distros

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.

Try it

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. We'd love to hear what you think.

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.

Full quickstart →

~/yoe-test  ·  bash
# 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 && mkdir -p ~/bin && mv yoe ~/bin/

# Create a project, build, run
yoe init yoe-test
cd yoe-test
yoe build base-image
yoe run base-image

          
Why now

The pieces finally lined up.

A decade ago, this combination wasn't realistic. Three things have changed.

Hardware

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.

Ecosystems

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.

AI

An assistant that shares 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 help with the legwork. Making the system simpler for humans makes it simpler for AI too, so both move faster and developers stay focused on the product.

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.

Sponsors

[yoe] is supported by

Interested in supporting the project? Get in touch →

Questions, ideas, or feedback?

We'd like to hear from you — about a board you're targeting, a unit that won't build, or an idea worth trying.