# kaze CLI Reference
`kaze` is a Zephyr build companion that orchestrates **configure / build / flash / run** for both **single-image** apps and **sysbuild multi-image** projects, with declarative configuration via `kaze.toml`.
This project is heavily inspired by [zync](https://gitlab.com/byarocks/zync) and should follow it for implementation details such as resulting system commands called.
## Synopsis
```bash
kaze [OPTIONS] <COMMAND> [COMMAND_OPTIONS] [-- <EXTRA_ARGS>...]
```
## Global options
| `-h, --help` | Show help |
| `-V, --version` | Show version |
| `-v..., --verbose` | Verbosity (repeatable) |
| `-c, --clean` | Pre-clean the active build dir before running the command |
| `-a, --all` | Run command for all configured profiles (overrides `--profile` and defaults) |
| `-p, --profile <profile>` | Select a configured profile |
| `-b, --board <board>` | Override resolved board |
| `-r, --runner <runner>` | Override resolved runner |
| `--project <path>` | Explicit project root (otherwise auto-detect by traversal) |
### Notes
- `--all` applies only when profiles exist; otherwise it behaves like normal single build.
- `--clean` pre-cleans **only the active build directory** (profile-specific when profiles are enabled).
## Commands
| `init` | `i` | Initialize project config (`kaze.toml`) |
| `boards` | `bo` | List available Zephyr boards |
| `runners` | `rn` | List available Zephyr runners |
| `profiles` | `p` | List configured profiles |
| `clean` | `c` | Clean build output (root or active profile build dir) |
| `conf` | `cf` | Configure via CMake |
| `build` | `b` | Build via Ninja (auto-configures if needed) |
| `flash` | `f` | Flash using configured/selected runner |
| `run` | `r` | Run simulation (native_sim/qemu), or run target-specific runner behavior |
### Shared command options
All commands support:
- `--board/-b` and `--runner/-r` overrides (precedence over config)
Commands that accept extra args via `--`:
- `conf`, `build`, `flash`, `run`
Example:
```bash
kaze build -- -j 0
kaze conf -- -DOVERLAY_CONFIG=overlay.conf
kaze flash -- --hex-file path/to/other.hex
kaze run -- -flash=../../seed/flash.bin
```
## Sysbuild image selection (flash/run)
`flash` and `run` support sysbuild image selection:
| `--list, -l` | List available sysbuild images |
| `--image, -i <name-or-index>` | Select image to flash/run |
Rules:
- If no image selected, default is **first non-bootloader** image (e.g. prefer `app` over `mcuboot`).
- Indexing is 1-based in CLI output.
- Using `--list` or `--image` on a non-sysbuild project returns an error.
Example:
```bash
kaze flash --list
kaze flash --image app
kaze flash --image 1
```
## `run` behavior and `--norebuild`
`kaze run`:
- By default, performs a build first, then runs the simulator binary directly if found.
- If simulator binary is not found, falls back to `ninja run` behavior (extra args after `--` are not appended in that fallback mode).
Options:
- `-n, --norebuild` — skip the pre-run rebuild and run immediately.
---
# `kaze.toml` Configuration Spec
`kaze.toml` is a declarative config located at the **project root**.
## File discovery
`kaze` locates the project by:
1) if `--project <path>` is given, use it
2) else traverse upward from `cwd` until `kaze.toml` is found
3) if run from a build directory, traverse upward to find the owning project root
## Configuration layers and precedence
Resolved configuration is produced by merging layers in this order:
1) **Defaults**
2) **User config (optional)**: `~/.config/kaze/config.toml`
3) **Project config**: `<project>/kaze.toml`
4) **Environment variables**: `KAZE_*`
5) **CLI flags** (`--profile`, `--board`, `--runner`, etc.)
Within the project config:
- global values apply first
- active profile values override global values
- CLI overrides override both
## Top-level schema overview
Recommended top-level tables:
- `[project]` — defaults and profile selection
- `[zephyr]` — workspace and base paths
- `[build]` — build directory rules
- `[project.args]` — extra args per phase (global)
- `[profile.<name>]` — per-profile board/runner + per-profile args
## Logging
Kaze emits user-facing logs prefixed with `kaze:`. Log lines are green when
color output is supported by the terminal.
Error output (including runner output surfaced on failure) is red when color
output is supported by the terminal.
Commands emit completion logs on success (for example, after build/run/flash or
after listing available items).
Environment variables:
- `KAZE_TESTING=1` suppresses logs (useful for tests).
- `KAZE_LOGS=1` re-enables logs during tests.
Verbosity levels:
- `-v` (1): quiet — no kaze logs, no command output
- default / `-vv` (2): normal — kaze logs only; command output only on error
- `-vvv`+ (3+): verbose — kaze logs + command output always
Spinner:
- At verbosity `-vv`, commands show a `SimpleDots` spinner after the log message while the command runs.
- The spinner is suppressed for `-v` (quiet) and `-vvv`+ (verbose).
## `[project]`
| `board` | string | *(none)* | Default Zephyr board |
| `runner` | string | *(none)* | Default Zephyr runner |
| `default_profile` | string | *(none)* | Default profile name |
| `name` | string | *(optional)* | Display name for the project (optional) |
### Profile selection rules
When profiles are defined:
1) if `--all` set → all profiles selected
2) else if `--profile` set → that profile selected
3) else if `default_profile` set → selected
4) else → first profile in config file order (or lexicographic if order isn’t preserved)
When profiles are not defined:
- profile selection is ignored and build is profile-less.
## `[profile.<name>]`
Each profile is a partial override of the global project config.
| `board` | string | Profile board |
| `runner` | string | Profile runner |
| `args` | table | Per-phase args for the profile |
Example:
```toml
[profile.sim]
board = "native_sim"
[profile.prod]
board = "nucleo_f767zi"
runner = "openocd"
```
## `[zephyr]`
| `workspace` | string | auto-detect | Zephyr workspace root |
| `base` | string | `${zephyr_ws}/zephyr` | Zephyr base directory |
Auto-detection order (when not set):
1) `ZEPHYR_BASE` environment variable
2) find `.west/` by traversing upward; if found, treat its parent as workspace
3) (optional) fallback helpers can be added later
## `[build]`
| `root` | string | `"build"` | Root build output directory |
| `layout` | string enum | `"auto"` | Build layout mode: `auto`, `profiles`, `single` |
| `link_compile_commands` | bool | `true` | When profiles enabled, create root `build/compile_commands.json` symlink |
### Build output layout
- Profile-less mode: `./<build.root>/`
- Profiles mode: `./<build.root>/<profile>/`
If profiles mode and `link_compile_commands=true`:
- `./<build.root>/compile_commands.json` is a symlink to the selected default/first profile’s `compile_commands.json`
Linking is skipped when profiles are not configured or when `link_compile_commands=false`.
## `[project.args]` and per-profile args
Args are configurable for phases:
- `conf` (CMake configure)
- `build` (Ninja)
- `flash` (west flash / runner invocation)
- `run` (simulator binary or fallback command)
Value forms:
- string → treated as a single argument string (split behavior is implementation-defined; recommended to use arrays)
- array of strings → preferred, exact args list
Example:
```toml
[project.args]
conf = ["-DHG_TEST=ON"]
build = ["-j", "0"]
flash = ["--hex-file", "path/to/other.hex"]
run = ["-flash_mount=../../seed/sd"]
[profile.sim.args]
run = ["-flash=../../seed/flash.bin", "-wait_uart"]
```
### Arg merge order
For a given phase:
1) global `[project.args.<phase>]`
2) profile `[profile.<name>.args.<phase>]`
3) CLI passthrough args after `--`
Note: Top-level `[args]` is no longer supported. Move global args under `[project.args]`.
---
# Interpolation Spec (`${key}`)
`kaze` supports `${key}` placeholders in string config values (most commonly in args and paths).
## When interpolation runs
Interpolation runs after:
1) config layers are merged
2) active profile is resolved
3) CLI overrides are applied
So `${board}` reflects the **final** resolved board, etc.
## Supported keys
Resolved from the active configuration + runtime context:
- `board` — resolved board
- `runner` — resolved runner
- `profile` — selected profile name (empty if profile-less)
- `build_dir` — active build directory (profile-specific when profiles enabled)
- `project_dir` — project root directory
- `zephyr_ws` — Zephyr workspace
- `zephyr_base` — Zephyr base (usually `${zephyr_ws}/zephyr`)
- `cwd` — current working directory
- `is_build` — `"true"`/`"false"` (whether invoked from build dir context)
- `sysbuild` — `"true"`/`"false"` (whether project detected as sysbuild)
## Rules / limitations
- Missing keys are left unchanged (`${missing}` stays as-is).
- Interpolation applies only to strings (numbers/bools stringify if referenced).
- Cycles are not expanded further (self-references remain `${key}`).
- Interpolation is single-pass (no recursive expansion).
---
# Minimal examples
## 1) Simple project (profile-less)
```toml
[project]
board = "nucleo_f767zi"
runner = "openocd"
```
## 2) Project with profiles
```toml
[project]
runner = "openocd"
default_profile = "sim"
[profile.sim]
board = "native_sim"
[profile.prod]
board = "nucleo_f767zi"
```
## 3) Args + interpolation
```toml
[zephyr]
workspace = "/opt/zephyr"
base = "${zephyr_ws}/zephyr"
[project.args]
conf = ["-DBOARD=${board}", "-DZEPHYR_BASE=${zephyr_base}"]
build = ["--build-dir", "${build_dir}"]
run = ["-flash_mount=../../seed/sd"]
```