The alp CLI
alp is the Alp SDK's single command-line front door. One verb set scaffolds a project, builds it (multi-core aware), runs it on the simulator or in Renode, checks its footprint against the SoM memory budget, flashes it, bundles it for OTA, cleans it, inspects the generated configuration, validates board.yaml, compiles AI models, sanity-checks the host environment, opens a serial console, and scaffolds the metadata for porting a new SoM.
It is the headless companion to the VS Code extension: both front doors sit on the same shared core as the west alp-* extension commands, so a validate in CI matches what the editor sees, and a CLI-driven build behaves identically to a west one.
Install
The bootstrap scripts install alp automatically as an editable install into the workspace venv — scripts/bootstrap.sh on Linux / macOS / WSL2, scripts/bootstrap.ps1 on native Windows (see Installation). Because the install is editable, a git pull in the alp-sdk checkout updates the CLI in place.
Without an install it also runs straight from a checkout:
# From the alp-sdk repo root (or with <sdk>/scripts on PYTHONPATH):
PYTHONPATH=scripts python3 -m alp_cli --help
Every verb is a thin wrapper — the actual logic lives in the same scripts and packages the west alp-* commands drive (scripts/alp_orchestrate/, scripts/alp_project.py, scripts/validate_board_yaml.py, scripts/flash_backends/). The CLI adds discoverability and sane defaults; it never forks the behaviour.
alp vs west alp-* — which do I use?
Both front doors drive the same underlying pipeline; pick by ergonomics, not capability:
| You are… | Use |
|---|---|
| In an app directory, want the shortest command | alp build / alp run / alp flash — they find board.yaml by walking up from the cwd |
| Scripting CI or a west-centric workflow | west alp-build <app> / west alp-flash <app> — explicit app path, no cwd magic |
| Outside any west workspace (validate, emit, doctor, model, monitor) | alp … — these verbs don't need a workspace |
| Building Zephyr for one named board target directly | either alp build --board <target> or plain west build -b <target> |
Rules of thumb:
alp build==west alp-build,alp flash==west alp-flash, andalp size/alp clean/alp image/alp renode== theirwest alp-*twins — same implementation, same flags; thealpform finds the app by walking up from the cwd, the west form takes the app path explicitly.alp emitis a superset ofwest alp-emit: every artefact either front door can generate is reachable fromalp emit(one catalog, below).west alp-emitexposes the orchestrator's ADR-0014 subset for west-centric scripting. The same emitter runs underneath either way — the two can never produce different output for the same mode.
Verb reference
alp init — scaffold a new project
alp init my-app --som E1M-AEN701 --preset e1m-evk --peripherals uart,gpio
alp init my-app # interactive: pick SoM / preset / peripherals
Copies the hello-world template, rewrites board.yaml for the chosen SoM SKU + board preset, and seeds the optional starter peripherals: list. Omit any flag to be prompted.
| Option | Meaning |
|---|---|
NAME (argument) | New project directory (must not exist) |
--som | SoM SKU, e.g. E1M-AEN701 |
--preset | Board preset from metadata/boards/, e.g. e1m-evk |
--peripherals | Comma-separated starter peripherals (uart,gpio,i2c,spi,pwm) |
alp new-som — scaffold metadata for a new SoM port
alp new-som --sku E1M-NX9555 --soc-ref nxp:imx9:imx95 --family nxp-imx9
alp new-som # interactive: prompts for every field
The vendor-N+1 porting kit. Generates the two metadata skeletons a new SoM port needs — metadata/e1m_modules/<SKU>.yaml (the SoM preset) and, when the target SoC has no spec yet, metadata/socs/<vendor>/<family>/<part>.json — with every schema-required hardware-fact field present as an explicit TBD placeholder. Values are never invented; the JSON carries its TODOs in the schema-sanctioned _pending_reason + notes fields. Both skeletons are schema-valid on arrival, and the command finishes by printing a numbered porting checklist (fill the TBDs, extend the schema sku pattern for a brand-new family, register the silicon ref, validate, regenerate, run the conformance suite).
The scaffold is committable as-is: every input is validated before anything is written (a rejected invocation never leaves half-written files). Use --dry-run to see the planned files — and run the full validation — without writing anything. In a pipe or CI, missing required flags fail fast with an explicit list instead of dropping into the prompts. The full walkthrough lives in the SDK's docs/porting-new-som.md.
| Option | Meaning |
|---|---|
--sku | New SoM SKU, e.g. E1M-NX9555 |
--soc-ref | Silicon triple-colon ref, e.g. nxp:imx9:imx95 |
--family | Human-readable family slug, e.g. nxp-imx9 |
--vendor | Vendor display name for the SoC JSON (default: soc-ref vendor segment) |
--display-name | Preset display name (default derived from the SKU) |
--inference-backend | ethos_u / drpai / deepx_dxm1 / tbd (default tbd) |
--ethos-u-variant | u55 / u65 / u85; required with --inference-backend ethos_u |
--cores | Comma-separated canonical core ids (default: a tbd_core0 placeholder) |
--default-board | Stock carrier board (default E1M-EVK) |
--default-hw-rev | Default hardware revision (default r1) |
--output-root | Root to generate metadata/ under (default: the SDK checkout) |
--dry-run | Validate and print the planned files; write nothing |
--force | Overwrite an existing preset for this SKU |
alp build — build the project (multi-core aware)
alp build # nearest board.yaml upward from the cwd
alp build path/to/app # explicit app directory
alp build --core m33_sm # iterate on one slice only
alp build --board native_sim # single-image fallback: plain `west build`
Default path: validate board.yaml, then fan out every non-off core via the orchestrator — exactly what west alp-build does. Outputs land under <app>/build/: per-slice build directories plus system-manifest.yaml, the single source of truth that alp flash, alp image, and OTA consume.
--board <zephyr-board> skips the orchestrator and performs a plain single-image west build -b <board> into build/<board>/ — the right tool for a one-core Zephyr app when you want to name the board target directly.
| Option | Meaning |
|---|---|
APP_PATH (argument, optional) | App directory (default: walk up from cwd) |
--core | Limit the fan-out to one core ID |
--no-parallel | Force sequential slice dispatch |
--no-validate | Skip the board.yaml pre-flight validation |
--build-root | Override the build root (default: <app>/build) |
--board | Single-image fallback: west build -b <board> |
alp run — build + run on the simulator
alp run # build for native_sim and execute it
alp run --board <target> # real-hardware build instead
alp run --board <target> --flash # …then west flash
Builds through the same single-image path as alp build --board, then executes the produced zephyr.exe (native_sim). For heterogeneous multi-core projects use alp build + alp flash instead — native_sim is a single-image target.
alp flash — program the built project
alp build && alp flash # the whole system, one-liner
alp flash --core m33_sm # one slice only
alp flash --helper gd32_bridge # one helper MCU only
alp flash --dry-run # print commands, touch nothing
Walks build/system-manifest.yaml (produced by alp build / west alp-build) and programs every slice + helper MCU via the registered flash backends, in boot_order:. Identical to west alp-flash.
| Option | Meaning |
|---|---|
APP_PATH (argument, optional) | App directory (default: walk up from cwd) |
--core | Flash only the slice with this core ID |
--helper | Flash only the helper MCU with this name |
--dry-run | Print the flash commands but don't run them |
--build-root | Override the build root |
--skip-missing-tools | Warn + skip slices whose flash tool is missing |
alp size — footprint vs the SoM memory budget
alp build && alp size # does each image fit the silicon?
alp size --fail-over-budget # CI gate: non-zero exit when over
alp size --json # machine-readable (VS Code extension)
Walks build/system-manifest.yaml, measures every Zephyr slice's zephyr.elf, and compares FLASH and RAM usage against the budget resolved from the SoM's SoC metadata — before you flash. Slices that aren't built report not built, Yocto/baremetal slices n/a, and an unresolvable budget unknown (never a guessed number). Identical to west alp-size.
alp image — assemble a flashable bundle
alp build && alp image # produces build/image-bundle/
Reads build/system-manifest.yaml and assembles a single flashable bundle under build/image-bundle/: per-slice tar.gz archives, helper-MCU firmware, and a bundle-manifest.json with per-artefact SHA-256s. Identical to west alp-image.
alp clean — remove build outputs
alp clean # remove <app>/build + orchestrator cache
alp clean --dry-run # list what would go, delete nothing
Removes the per-project build directory and the orchestrator's .alp-build-state.json. Identical to west alp-clean.
alp renode — boot the build in Renode (no hardware)
alp build && alp renode # headless smoke boot
alp renode --expect "[hello] done" # exit 0 when seen, 1 if not
alp renode --log out.log --timeout 60
Boots the built system manifest's Zephyr slice in the Renode emulator, headless, with a wall-clock timeout — a no-hardware smoke test. The SoM family maps to a platform descriptor under metadata/renode/. Requires the renode binary on PATH; exits non-zero with install guidance when absent, never a silent pass. Identical to west alp-renode.
| Option | Meaning |
|---|---|
--log | Tee the console output to this file (default build/renode.log) |
--timeout | Wall-clock cap in seconds (default 120) |
--expect | Stop early (exit 0) when this substring appears; exit 1 if it never does |
alp emit — print one generated artefact (no build)
alp emit zephyr-conf # the per-core Zephyr fragment
alp emit system-manifest # the full-system manifest
alp emit carrier-netlist --output nets.json # Studio carrier handoff
alp emit hw-info-h --output hw_info.h # write instead of stdout
Read-only: shows exactly what a consuming tool (CMake, Yocto, the IDE, Alp Studio) would see. This is the one catalog of every generated artefact — alp emit reaches everything scripts/alp_project.py --emit and west alp-emit can produce, delegating each mode to the single implementation that owns it:
| Mode | Artefact | Emitted by |
|---|---|---|
zephyr-conf | Per-core Zephyr alp.conf Kconfig fragment | alp_project.py |
cmake-args | Per-core -D CMake argument list | alp_project.py |
yocto-conf | Per-core local.conf fragment | alp_project.py |
dts-overlay | Board DTS overlay (bus aliases + pin array) | alp_project.py |
hw-info-h | Build-time hw_info.h macro header | alp_project.py |
west-libraries | west.yml fragment for libraries: deps | alp_project.py |
system-manifest | Full-system manifest (slices, boot order) | orchestrator |
dts-reservations | DTS reserved-memory overlay (cross-core carve-outs) | orchestrator |
ipc-contract-h | Cross-core IPC contract header | orchestrator |
os-topology | Per-core natural-vs-effective OS facts | orchestrator |
composed-route-table | JSON route-table dump (demonstrator) | alp_project.py |
carrier-netlist | Studio-facing carrier nets + BOM JSON handoff | alp_project.py |
dts-partitions | DTS fixed-partitions overlay (storage: entries) | orchestrator |
storage-mounts-c | Static C storage mount table | orchestrator |
tfm-sysbuild-conf | TF-M sysbuild child-image overlay (security.psa:) | orchestrator |
build-plan | Per-slice build plan, JSON (IDE / CI consumers) | orchestrator |
| Option | Meaning |
|---|---|
--input | Path to board.yaml (default: nearest one upward) |
--output | Write to this path instead of stdout |
--core | Scope per-core modes to one core ID |
--build-root | Build root used for build-plan slice paths |
See carrier-netlist in the board.yaml reference for what the Studio handoff contains — and, just as importantly, what it deliberately excludes.
alp validate — check a board.yaml
alp validate # ./board.yaml
alp validate path/to/board.yaml
Runs the rich diagnostic validator (JSON-Schema pass, SoM/preset cross-references, peripheral-vs-SoC capability check) and renders every finding as a Rust-style diagnostic block with an ALP-Bxxx code — decode any code with alp explain ALP-B001. Exit 0 when clean, 1 on errors. The schema pass is the same shared implementation scripts/validate_board_yaml.py (the west alp-build pre-flight) and the orchestrator's loader use, so all front doors report identical violations.
alp model — compile + package AI models
alp model build # compile board.yaml `models:` entries
alp model build --board path/to/board.yaml --out build/models
Compiles every models: entry declared in board.yaml into a .alpmodel package via the SoM-appropriate backend (Vela for Ethos-U, DRP-AI for RZ/V2N, …). See Inference for the end-to-end flow.
alp doctor — host environment preflight
alp doctor # human-readable PASS/WARN/FAIL report
alp doctor --json # machine-readable
alp doctor --strict # WARNs also fail the exit code
Strictly hardware-free: checks Python / west / CMake / Ninja / dtc / gperf / imgtool / host compiler / J-Link presence, the Zephyr pin (read live from west.yml), the workspace venv, ZEPHYR_BASE, the Zephyr SDK, plus Windows-specific traps (git core.autocrlf, long-path support). Exit 0 = ready to build; every FAIL/WARN comes with a remediation hint. Run it first whenever a build machine misbehaves.
alp monitor — serial console
alp monitor --port COM7 # Windows
alp monitor --port /dev/ttyUSB0 # Linux
alp monitor # lists available ports if none given
Opens pyserial's miniterm (Ctrl+] to quit). Baud defaults to 115200 (--baud to override). When no port is given, or the requested one doesn't exist, it lists every serial port on the host and exits non-zero instead of hanging on a wrong device.
alp explain / alp faultdecode — diagnostics
alp explain ALP-B001 # cause + fix + doc link for a validator code
alp faultdecode fault.txt # decode an ARMv8-M (M33/M55) fault dump
alp explain prints the cause, fix, and doc link for any ALP-Bxxx validator diagnostic. alp faultdecode decodes a Cortex-M fault-register dump into a human-readable cause chain.
Environment
| Variable | Effect |
|---|---|
ALP_SDK_ROOT | Explicit path to the alp-sdk checkout; otherwise the CLI locates the repo it was installed (editable) from |
ZEPHYR_BASE | The Zephyr tree used by single-image builds + checked by alp doctor |
The delegating verbs (build, flash, emit, size, image, clean, renode) export ALP_SDK_ROOT, append the SDK to EXTRA_ZEPHYR_MODULES, and put <sdk>/scripts on PYTHONPATH for their sub-processes — the same wiring the west alp-* wrappers use.
See also
- Installation — bootstrap the workspace + the CLI
- VS Code extension — the same shared core behind a GUI
board.yamlreference — the schemaalp validateenforces- Heterogeneous Builds — the orchestrated multi-core pipeline
alp buildfronts - Architecture — where the orchestrator fits into the build