Skip to main content

Provision with Avocado OS

Avocado OS is a Yocto-based embedded product framework that bridges rapid developer workflows and production-grade reliability. It delivers immutable, composable runtimes with deterministic, cryptographically verifiable images, fault-tolerant updates, and simplified secure boot. Using system extensions (sysext) and configuration extensions (confext), applications and configuration are layered cleanly and reproducibly—without the fragility of traditional runtime package management.

In this guide, you will use the Avocado CLI to initialize a project and orchestrate the creation of your own demo Avocado OS image targeting QEMU. We’ll install the SDK and extensions, build the image, provision a runtime, and boot the system in a virtual machine on a Linux host to experience the end-to-end workflow.

Get the Avocado CLI

To get started with device provisioning, we will first need the Avocado CLI. Grab the latest release for your development architecture from the Github releases page.

info

This guide is intended to be run on a Mac (macOS 10.12+) or Linux (Ubuntu 22.04+, Fedora 39+) development machine. Running these commands on Windows is not currently supported.

Command

avocado

Output

Avocado CLI - A command line interface for Avocado

Usage: avocado [OPTIONS] <COMMAND>

Commands:
sdk SDK related commands
ext Extension related commands
init Initialize a new avocado project
runtime Runtime management commands
hitl Hardware-in-the-loop testing commands
clean Clean the avocado project by removing docker volumes and state files
install Install all components (SDK, extensions, and runtime dependencies)
upgrade Upgrade the CLI to the latest (or specified) version
build Build all components (SDK compile, extensions, and runtime images)
provision Provision a runtime (shortcut for 'runtime provision')
deploy Deploy a runtime to a device (shortcut for 'runtime deploy')

Options:
--target <TARGET> Global target architecture
-h, --help Print help
-V, --version Print version

Initialize your project

Initialize a new Avocado project by generating an avocado.toml with sensible defaults (target qemux86-64, a dev runtime, and baseline SDK/extension dependencies).

By default, the target is set to qemux86-64, as it allows you go exercise all Avocado CLI workflows without a physical device. You can specify a specific hardware target via the --target flag.

Command

avocado init qemu && cd qemu

Output

✓ Created config at /home/user/targets/qemu/avocado.toml.

The generated config defines the dev runtime and dependencies, the SDK container image, and the avocado-dev extension (declared as both sysext and confext) used throughout this guide.

avocado.toml
default_target = "qemux86-64"
supported_targets = ["qemux86-64"]

[runtime.dev]
target = "qemux86-64"

[runtime.dev.dependencies]
avocado-img-bootfiles = "*"
avocado-img-rootfs = "*"
avocado-img-initramfs = "*"
avocado-dev = { ext = "avocado-dev" }

[sdk]
image = "avocadolinux/sdk:apollo-edge"

[sdk.dependencies]
nativesdk-qemu-system-x86-64 = "*"

[ext.avocado-dev]
types = ["sysext", "confext"]

[ext.avocado-dev.dependencies]
avocado-hitl = "*"

[ext.avocado-dev.sdk.dependencies]
nativesdk-avocado-hitl = "*"
info

Run all subsequent commands in this guide from the root of your Avocado project on your host machine — the directory that contains your Avocado config. Code blocks labeled "On Device (VM)" are executed inside the running QEMU VM.

Install dependencies

The avocado install command pulls the SDK container and installs dependencies for the SDK, all declared extensions, and your runtime(s). Use -r to scope to a single runtime and its extensions. Otherwise, by default it builds all runtimes. Prompts may appear during package installation unless you pass --force (-f).

Command

On Host
avocado install --force

Output

[INFO] Using target: qemux86-64 (from config file (default_target))
[INFO] Starting comprehensive install process...
[INFO] Step 1/3: Installing SDK dependencies
[INFO] Using target: qemux86-64 (from config file (default_target))
[INFO] Installing SDK dependencies.
[INFO] Initializing Avocado SDK.
Avocado SDK 1.9 kB/s | 1.9 kB 00:00
Dependencies resolved.
==============================================================================================================================
Package Architecture Version Repository Size
==============================================================================================================================
Installing:
avocado-sdk-qemux86-64 all_avocadosdk 1.0-r0 avocado-sdk 7.9 k

... snip ...

Installed:
avocado-img-bootfiles-1.0-r0.avocado_qemux86_64 avocado-img-initramfs-1.0-r0.avocado_qemux86_64
avocado-img-rootfs-1.0-r0.avocado_qemux86_64

Complete!
[SUCCESS] Successfully installed packages for runtime 'dev'
[SUCCESS] Successfully installed dependencies for 1 runtime(s)
[SUCCESS] All components installed successfully!

Set up user credentials

We must define a password for our root user account.

Passwords can be generated via the openssl passwd -6 command to generate a SHA512 password.

Command

openssl passwd -6 "my-secret-password"

Output

$6$Q98YeorOiEwd2wEo$LEtlJIsT1yJVdBkEGyP9rbeambXPLXN4Ci59G40HEq1/mjy99UkBWAkNQpGHoGdeCi0XGlv.w0ZjbBqzjJ/vp1

With our password hash, we can insert a new config directive configuring our account password.

avocado.toml
default_target = "qemux86-64"
supported_targets = ["qemux86-64"]

[runtime.dev]
target = "qemux86-64"

[runtime.dev.dependencies]
avocado-img-bootfiles = "*"
avocado-img-rootfs = "*"
avocado-img-initramfs = "*"
avocado-dev = { ext = "avocado-dev" }

[sdk]
image = "avocadolinux/sdk:apollo-edge"

[sdk.dependencies]
nativesdk-qemu-system-x86-64 = "*"

[ext.avocado-dev]
types = ["sysext", "confext"]

[ext.avocado-dev.users.root]
password = "$6$Q98YeorOiEwd2wEo$LEtlJIsT1yJVdBkEGyP9rbeambXPLXN4Ci59G40HEq1/mjy99UkBWAkNQpGHoGdeCi0XGlv.w0ZjbBqzjJ/vp1"

[ext.avocado-dev.dependencies]
avocado-hitl = "*"

[ext.avocado-dev.sdk.dependencies]
nativesdk-avocado-hitl = "*"

Additional user accounts can be added by inserting more users entries:

avocado.toml
default_target = "qemux86-64"
supported_targets = ["qemux86-64"]

[runtime.dev]
target = "qemux86-64"

[runtime.dev.dependencies]
avocado-img-bootfiles = "*"
avocado-img-rootfs = "*"
avocado-img-initramfs = "*"
avocado-dev = { ext = "avocado-dev" }

[sdk]
image = "avocadolinux/sdk:apollo-edge"

[sdk.dependencies]
nativesdk-qemu-system-x86-64 = "*"

[ext.avocado-dev]
types = ["sysext", "confext"]

[ext.avocado-dev.users.root]
password = "$6$Q98YeorOiEwd2wEo$LEtlJIsT1yJVdBkEGyP9rbeambXPLXN4Ci59G40HEq1/mjy99UkBWAkNQpGHoGdeCi0XGlv.w0ZjbBqzjJ/vp1"

[ext.avocado-dev.users.linus]
password = "$6$lpwMHiXhb/3aZJxL$iwmuDI5SwZutHRVpUy2/JdPdHxZ8qf4.9r74O43rGTE6891A.VtJ1TGeGDuqAf/ug098KU1izlmxPbWfG9pGf."

[ext.avocado-dev.dependencies]
avocado-hitl = "*"

[ext.avocado-dev.sdk.dependencies]
nativesdk-avocado-hitl = "*"
tip

To set no password, set this value to an empty string.

[ext.avocado-dev.users.root]
password = ""

Any time user or password values are changed, you will need to re-run build and provision commands (avocado build + avocado provision -r dev).

Build all components

The avocado build command compiles any required SDK code for extensions, builds extension images, and produces the runtime image(s) as defined in your avocado config. By default, all runtimes are built, (use -r to build a specific runtime).

Command

On Host
avocado build

Output

[INFO] Using target: qemux86-64 (from config file (default_target))
[INFO] Starting comprehensive build process...
[INFO] Step 1/4: Analyzing dependencies and compiling SDK code
[INFO] No SDK compilation needed.
[INFO] Step 2/4: Building extensions
[INFO] Building sysext extension 'avocado-dev'.

... snip ...

[SUCCESS] Created.
[SUCCESS] Successfully ran SDK lifecycle hook 'avocado-build' for target 'qemux86-64'.
[SUCCESS] Successfully built runtime 'dev'
[SUCCESS] All components built successfully!

Provision a runtime

The avocado provision command prepares the specified runtime by transforming the output of the build, and depending on the target, either: writing final artifacts to disk, or even provisioning a physical device via USB, network, etc.

Command

On Host
avocado provision -r dev

Output

[INFO] Provisioning runtime 'dev'

... snip ...

[SUCCESS] Provision script 'stone-provision-img.sh' completed successfully.
[SUCCESS] Provision completed.
[SUCCESS] Successfully ran SDK lifecycle hook 'avocado-provision' for target 'qemux86-64'.
[SUCCESS] Successfully provisioned runtime 'dev'

In this guide, we are targeting QEMU, so our provisioning process will write the necessary artifacts to disk to run.

Run virtual target

Run the built image under QEMU using the SDK container. sdk run -iE launches an interactive session with the Avocado SDK environment sourced and invokes the VM launcher for the dev runtime.

Command

On Host
avocado sdk run -iE vm dev

Output

Runtime: dev

... snip ...

Avocado OS 0.1.0 avocado-qemux86-64 ttyS0

avocado-qemux86-64 login:

You may log in using the root account and the appropriate password as configured in your Avocado config. If you configured an empty password, just press Enter when prompted for one.

Verify extensions

Once logged into the running virtual machine, you have a fully-running Avocado operating system.

A validation command you may run is avocadoctl ext status to list the status of all extensions.

Command

On Device (VM)
avocadoctl ext status

Output

Extension Status
================

System Extensions (/opt, /usr):
--------------------------------
/opt -> avocado-dev (since Tue 2025-08-12 22:53:26 UTC)
/usr -> avocado-dev (since Tue 2025-08-12 22:53:26 UTC)

Configuration Extensions (/etc):
---------------------------------
/etc -> avocado-dev (since Tue 2025-08-12 22:53:33 UTC)