Nishikaze - The West Wind
A CLI companion that orchestrates the whole lifecycle of Zephyr-based projects using a declarative config.
Index
Why?
Because Zephyr's west sucks, that's why. Even though at first glance this meta
tool looks exactly like west, you have the option to configure your project
declaratively. I admit, when building a simple Zephyr app, you can just use pure
CMake + ninja/make and configure everything in CMake. However, when building a
multi-image app using sysbuild (e.g. updatehub OTA + mcuboot + app image) then
you're stuck with passing a mile of args into west as you cannot configure it
declaratively and cannot externally modify mcuboot's CMake config.
Features
- Manage the whole lifecycle of a Zephyr app - config, build, flash, sim runs
- Supports both simple Zephyr apps and multi-image apps with sysbuild
- Automatic Zephyr workspace detection
- Declarative config through
kaze.toml@ project root - Automatic project dir navigation (can be run from both project root or build dir)
- Automatically detects
sysbuildprojects and adjusts the build accordingly - Supports multiple build profiles (can build multiple binaries for a specific app, useful for simulations or multiple board targets)
Installation
Install using cargo:
Usage
)
)
)
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
Kaze config
π Note: Under construction. This doc section contains some features that are not yet implemented.
kaze.toml is a declarative config located at the project root.
File discovery
kaze locates the project by:
- if
--project <path>is given, use it - else traverse upward from
cwduntilkaze.tomlis found - 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:
- Project config:
<project>/kaze.toml - 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
Logging
Kaze emits user-facing logs prefixed with kaze: and uses colored logs if colour output is supported by the terminal.
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
Environment variables:
KAZE_TESTING=1suppresses logs (useful for tests).KAZE_LOGS=1re-enables logs during tests.
[project]
| Key | Type | Default | Summary |
|---|---|---|---|
board |
string | (none) | Default Zephyr board |
runner |
string | (none) | Default Zephyr runner |
args |
table | Per-phase args for the profile | |
default_profile |
string | (none) | Default profile name |
name |
string | (optional) | Display name for the project (optional) |
[profile.<name>]
Each profile is a partial override of the global project config.
| Key | Type | Summary |
|---|---|---|
board |
string | Profile board |
runner |
string | Profile runner |
args |
table | Per-phase args for the profile |
Example:
[]
= "native_sim"
[]
= "nucleo_f767zi"
= "openocd"
Profile selection rules
When profiles are defined:
- if
--allset β all profiles selected - else if
--profileset β that profile selected - else if
default_profileset β selected - else β first profile defined in config file
When profiles are not defined:
- profile selection is ignored and build is profile-less.
[zephyr]
| Key | Type | Default | Summary |
|---|---|---|---|
workspace |
string | auto-detect | Zephyr workspace root |
base |
string | ${zephyr_ws}/zephyr |
Zephyr base directory |
Auto-detection order (when not set):
ZEPHYR_BASEenvironment variable- find
.west/by traversing upward; if found, treat its parent as workspace - (optional) fallback helpers can be added later
[build]
| Key | Type | Default | Summary |
|---|---|---|---|
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 layout (
singleorautowith no profiles configured):./<build.root>/ - Profiles layout (
profilesorautowith profiles configured):./<build.root>/<profile>/
If building with profiles layout and link_compile_commands=true:
./<build.root>/compile_commands.jsonis a symlink to the selected default/first profileβscompile_commands.jsonLinking is skipped when building insinglelayout or whenlink_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:
[]
= ["-DHG_TEST=ON"]
= ["-j", "0"]
= ["--hex-file", "path/to/other.hex"]
= ["-flash_mount=seed/sd"]
[]
= ["-flash=seed/flash.bin", "-wait_uart"]
Arg merge order
For a given phase:
- global
[project.args.<phase>] - profile
[profile.<name>.args.<phase>] - CLI passthrough args after
--
Minimal examples
1) Simple project (profile-less)
[]
= "nucleo_f767zi"
= "openocd"
2) Project with profiles
[]
= "sim"
[]
= "native_sim"
= "native"
[]
= "nucleo_f767zi"
= "openocd"
Similar projects
License
This project is licensed under either of:
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed under the Apache-2.0 and MIT license, without any additional terms or conditions.
Development
Only requires just to bootstrap all tools and configuration.
To run:
To test:
Before committing work:
To see all available commands: