Tutorial
Create a New Project
Use an Airfield project when you want one workspace to own multiple packages, shared dependency manifests, and runnable plans.
1. Create the project
airfield project init ./my_robot --ros-distro jazzy
cd my_robot
This creates:
my_robot/
airfield.yaml
packages/
dependencies/
x86_64/
arm64/
plans/
example.yaml
.dockerignore
.gitignore
airfield.yaml marks the directory as an Airfield project:
kind: project
name: my_robot
version: 0.1.0
ros_distro: jazzy
The ros_distro value becomes the default for packages created inside the
project unless a package overrides it. Supported distributions are noetic,
humble, jazzy, kilted, and rolling. The generated .gitignore keeps
machine-local files (.air, .airfield/, build/, log/, install/) out
of the repository.
Two optional project-level fields are worth knowing about early:
base_imagepins one container base image for every package in the project (a package’s ownbase_imagestill wins). This is how a whole project targets a specific board image from a single line.subprojectsrecords the source repositories that make up the project, soairfield subpackages checkoutcan restore them on a fresh clone. Thesubpackages trackcommand fills it in for you.
2. Check the project
airfield status
The status output should show Project status, the project root, the selected
ROS distribution, dependency target folders, and available plans.
3. Add dependency manifests
Project-scoped dependency manifests live under:
dependencies/x86_64/*.yaml # x86_64-only recipes
dependencies/arm64/*.yaml # arm64-only recipes
dependencies/xplatform/*.yaml # recipes that work on both
project init scaffolds the two architecture folders; create xplatform/
yourself when you first need it.
When a package build resolves a dependency name, Airfield searches in order:
the project’s dependencies/<target-device>/, the project’s
dependencies/xplatform/, then the same two folders in the shared Airfield
packages repository. The first manifest found wins, so local project manifests
always override shared ones.
Example:
name: tqdm
version: 1.0.0
system: []
user:
- python3 -m pip install --break-system-packages tqdm
Note the --break-system-packages flag: recent ROS base images run on Ubuntu
24.04, where the system Python is marked externally managed (PEP 668) and a
plain pip install refuses to run. Inside a dedicated container image the
flag is safe, and pip manifests need it to work on jazzy and newer.
4. Add packages
Create a package inside the project:
airfield package init nav_stack
The package is created at:
packages/nav_stack/
airfield.yaml
src/
README.md
.dockerignore
.gitignore
See Create a Package for the package metadata fields and how to wrap existing ROS code.
5. Launch the example plan
project init scaffolds plans/example.yaml:
name: example
windows:
- name: hello
layout: main-vertical
panes:
- echo "Hello from plan 'example'. Replace these panes with launch commands."
# Run a command inside a package's container:
# - package: my_package
# cmd: ros2 launch my_package bringup.launch.py
Launch it as a tmux session:
airfield project up example
Plans are how a whole robot stack comes up with one command. See Create a Plan for the full format.