Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Aves

Aves SDE is an embedded firmware development environment. It bundles a library of packages, a reproducible build system, and a CLI that bootstraps its own toolchain.

There are no installed dependencies on the host system — every build runs inside a hermetic toolchain provided by nix-portable, which the CLI fetches automatically on first use.

What’s it for

The Aves SDE is intended to grow into a complete embedded SDE: a Rust kernel for nRF52-class MCUs, plus the supporting packages — bootloaders, vendor SoftDevices, board definitions, build helpers — needed to develop, flash, and ship firmware.

This documentation covers the build system and CLI as they exist today. Start with installation, then follow the quickstart to build the example bootloader.

Status

Alpha / pre-release.

The build pipeline works end-to-end for one example package — the Adafruit nRF52 UF2 bootloader. Most kernel and infrastructure packages are not yet committed.

What’s stable

  • The CLI build pipeline (fetch sources, sandbox, build, emit artifacts).
  • The TOML manifest format (workspace, project, package, board).
  • Build reproducibility under a pinned nixpkgs revision.

What’s not yet stable

  • The set of board.toml fields the build pipeline actually consumes (most are ahead-of-time declarations for upcoming consumers).
  • Per-dependency build overrides in aves_manifest.toml.
  • The flashing workflow (aves flash).

See the roadmap for what’s planned next.

Installation

Quick install

curl -fsSL https://sh.avesde.com | sh

Linux and macOS are supported.

The install script downloads the latest aves binary, verifies its checksum, and writes it to ~/.local/bin/aves. Make sure ~/.local/bin is on your PATH:

export PATH="$HOME/.local/bin:$PATH"

From source

If you’d rather build from source, clone the repo and use Cargo:

git clone https://git.paximi.com/samuel/aves
cd aves
cargo build --release --manifest-path aves-cli/Cargo.toml
cp target/release/aves-cli ~/.local/bin/aves

First run

On the first build, the CLI will prompt to download nix-portable into ~/.local/share/aves/nix/<version>/. The download is cached and reused across every project on the machine.

Source clones for each package are also kept outside the project tree, under ~/.local/share/aves/src/<pkg>/, so a single clone of an upstream repository can be reused across workspaces.

Quickstart

Three TOML files describe an Aves build:

FileScopePurpose
aves.tomlWorkspacePins nixpkgs, sets policy, picks a runtime.
aves_manifest.tomlProjectPicks the board and the packages to build.
packages/<name>/package.tomlPackageDefines a single buildable component.

Plus board files at boards/<name>.toml.

1. Edit the manifest

aves_manifest.toml:

[nixpkgs]
channel = "nixos-25.05"

[project]
name  = "my-device"
board = "feather_nrf52840_express"

[packages.nrf52-adafruit-uf2-bootloader]
version = "0.10.0"

2. Build

aves build

You’ll see something like:

fetch    nrf52-adafruit-uf2-bootloader@0.10.0
toolchain gcc-arm-embedded, gnumake, python3, adafruit-nrfutil
build    feather_nrf52840_express
✓ build/nrf52-adafruit-uf2-bootloader/feather_nrf52840_express/bootloader.uf2

3. Find the output

Artifacts land at:

build/<package>/<board>/*.{uf2,hex,zip}

The exact extensions depend on the package’s [build] outputs globs — see Packages.

What happened

  1. The CLI read aves.toml to resolve the pinned nixpkgs revision and the nix-portable runtime.
  2. It read aves_manifest.toml to learn the board (feather_nrf52840_express) and the package list (just one bootloader).
  3. For each package, it cloned the source into ~/.local/share/aves/src/<pkg>/, evaluated the [build] inputs as Nix expressions, opened a sandbox, and ran the [build] command inside it with {board} substituted from the manifest.
  4. Files matching [build] outputs globs were copied into build/<package>/<board>/.

Because both the toolchain and the package versions are pinned, the same workspace produces byte-identical artifacts on any machine.

Workspace (aves.toml)

aves.toml is the workspace-wide configuration. Every package built in the workspace sees the same aves.toml; project-specific concerns belong in aves_manifest.toml instead.

Example

[nixpkgs]
channel = "nixos-25.05"
rev     = "<lock-hash>"

[policy]
allow_unfree   = true
allow_insecure = true

[nix-portable]
runtime = "proot"

Sections

[nixpkgs]

Pins the nixpkgs revision used to evaluate every package’s [build] inputs. Pinning is what makes builds reproducible across machines and across time.

KeyTypeRequiredDescription
channelstringyesNixpkgs channel name, e.g. "nixos-25.05".
revstringnoSpecific commit hash. Required for full lock.

[policy]

Workspace-wide gates for permissive build flags. Each gate is checked when a package’s [build] requests the matching flag.

KeyTypeDefaultDescription
allow_unfreeboolfalsePermit packages whose inputs include unfree licenses.
allow_insecureboolfalsePermit packages whose inputs include insecure-marked deps.

[nix-portable]

Configures the nix-portable backend.

KeyTypeDefaultDescription
runtimestring(auto)One of proot, bwrap. Pins the sandbox runtime.

Project manifest (aves_manifest.toml)

The project manifest declares what to build: which board the project targets, which packages to pull in, and which versions to pin.

Example

[nixpkgs]
channel = "nixos-25.05"

[project]
name  = "my-device"
board = "feather_nrf52840_express"

[packages.nrf52-adafruit-uf2-bootloader]
version = "0.10.0"

Sections

[nixpkgs]

Same shape as in aves.toml. Anything set here overrides the workspace pin for this project.

[project]

KeyTypeRequiredDescription
namestringyesHuman-readable project name.
boardstringyesBoard key — see Boards.

The board field is resolved against project-local boards/ first, then the global registry at ~/.local/share/aves/boards/.

[packages.<name>]

One table per package the project depends on. The table key is the package name (matching the name field in the package’s own package.toml).

KeyTypeRequiredDescription
versionstringyesPinned version. Must exactly match a release.

Per-package overrides (variables passed into the build, source revisions, etc.) are on the roadmap.

Packages (package.toml)

A package is a single buildable component — a bootloader, a SoftDevice, a flashing helper, the kernel. Each package lives at packages/<name>/package.toml.

The build recipe is parameterized by the manifest’s board, so one package recipe builds for every compatible target.

Example

[package]
name     = "nrf52-adafruit-uf2-bootloader"
category = "bootloader"
version  = "0.10.0"

[supports]
socs = ["nrf52840"]

[source]
git        = "https://github.com/adafruit/Adafruit_nRF52_Bootloader.git"
rev        = "6180d8a26b8ca4c494158e4c5e9ca183f6801826"
submodules = "recursive"

[build]
inputs       = [
  "gcc-arm-embedded",
  "gnumake",
  "python3.withPackages (ps: [ ps.intelhex ])",
  "adafruit-nrfutil",
]
command      = ["make", "BOARD={board}", "all"]
allow_unfree = true
outputs      = ["_build/build-{board}/*.{uf2,hex,zip}"]

Sections

[package]

KeyTypeRequiredDescription
namestringyesPackage name, must match its directory.
categorystringyesOne of bootloader, kernel, softdevice, tool, library.
versionstringyesSemver string. Treated as opaque by the build.

[supports]

Compatibility declarations. The build will refuse to run if the manifest’s board doesn’t match.

KeyTypeRequiredDescription
socsstring[]noList of compatible SoC keys, e.g. ["nrf52840"].
platformsstring[]noList of compatible platform keys.

[source]

Where to clone the upstream source.

KeyTypeRequiredDescription
gitstringyesUpstream repository URL.
revstringyesPinned commit hash.
submodulesstringnoOne of none, shallow, recursive.

[build]

How to actually build the package.

KeyTypeRequiredDescription
inputsstring[]yesNix expressions evaluated under with pkgs;.
commandstring[]yesargv for the build command. {board} is substituted.
outputsstring[]yesGlobs of files to copy out of the sandbox. {board} is substituted.
allow_unfreeboolnoRequired if any input is unfree. Gated by workspace [policy].

inputs accepts bare attribute names (gcc-arm-embedded) and function calls (python3.withPackages (ps: [ ps.intelhex ])). {board} placeholders in command and outputs are substituted from the project manifest’s board field.

Boards (board.toml)

A board file describes a piece of hardware: SoC, memory map, peripherals, bootloader region, USB family ID, and so on.

Project-local boards live alongside the manifest at boards/<name>.toml. Shared boards can be installed into the global registry at ~/.local/share/aves/boards/. The manifest’s board field is resolved against project-local boards first, then the global registry.

Example

name     = "feather_nrf52840_express"
soc      = "nrf52840"
platform = "nrf5"

[memory.flash]
origin = 0x00000000
length = 0x00100000

# … peripherals, bootloader region, USB family ID, etc.

Top-level fields

KeyTypeRequiredDescription
namestringyesBoard key. Must match the manifest’s [project] board.
socstringyesSoC key, e.g. "nrf52840". Used by [supports] socs.
platformstringyesPlatform family, e.g. "nrf5".

Sections

[memory.<region>]

Memory region declarations. Multiple regions are supported (flash, ram, softdevice, …).

KeyTypeRequiredDescription
originintegeryesRegion base address (hex literal or int).
lengthintegeryesRegion length in bytes.

Status

Most board fields aren’t consumed by the build pipeline yet — they’re ahead-of-time declarations for upcoming consumers (linker script generation, kernel features gated on peripherals, flash tooling). The fields will be tightened up as the consumers land.

CLI

The aves command-line interface drives every workspace operation.

aves build

Build everything declared in aves_manifest.toml for the project’s board.

aves build

Outputs land at build/<package>/<board>/*.{uf2,hex,zip} (the exact extensions depend on each package’s [build] outputs globs).

aves packages list

List packages discovered in the workspace.

aves packages list

Filter by category:

aves packages list --category bootloader

Categories follow the [package] category field — bootloader, kernel, softdevice, tool, library.

Roadmap

Aves is alpha — the build pipeline works, the rest of the SDE is arriving piece by piece.

Near term

  • Kernel. A Rust nRF52840 kernel as a first-class package.
  • Vendor packages. Nordic SoftDevice, nrfutil, flashing helpers, and the supporting glue.
  • aves init. Scaffold a workspace from a template.

Medium term

  • Per-dependency overrides in aves_manifest.toml — override variables passed to a single package’s build without forking the package definition.
  • aves flash — push artifacts onto a connected board over DFU/UF2/JTAG.
  • Linker script generation from board.toml memory regions.

Longer term

  • Additional MCU families beyond nRF52-class. The build system is not nRF-specific; the package and board libraries grow with contributions.
  • Multi-target builds — emit artifacts for several boards from a single aves build invocation.
  • Signed releases and a public registry for third-party packages.

Filing requests in the issue tracker is the best way to influence what lands first.

Contributing

Aves is a small, opinionated project — contributions are welcome, but please open an issue before starting any non-trivial work so we can agree on shape.

Filing issues

The issue tracker lives at https://git.paximi.com/samuel/aves/issues. Bug reports should include:

  • The output of aves --version.
  • The host platform (Linux distribution + kernel version, or macOS version).
  • The relevant aves.toml, aves_manifest.toml, and (if applicable) the failing package.toml.
  • The full error output, with RUST_BACKTRACE=1 set if the CLI panicked.

Submitting a patch

  1. Open an issue describing the change.
  2. Fork and branch from main.
  3. Run cargo fmt and cargo clippy --all-targets -- -D warnings before pushing.
  4. Send a pull request that references the issue.

Adding a package

New packages live under packages/<name>/package.toml. See the package reference for the schema, and the existing nrf52-adafruit-uf2-bootloader package for a working example.

Adding a board

New boards live under boards/<name>.toml. See boards for the schema. Project-local boards should be added to the project itself; shared boards belong in the global registry and are reviewed before merging.