5 releases

Uses new Rust 2024

0.1.6 Mar 29, 2026
0.1.5 Mar 29, 2026
0.1.4 Mar 21, 2026
0.1.3 Mar 20, 2026
0.1.0 Mar 16, 2026

#1013 in Unix APIs


Used in 3 crates

MIT license

115KB
3K SLoC

nao

nao is a task runner for local development and CI. It runs tasks in parallel, respects dependencies between tasks, and keeps concurrent output separated so logs stay readable.

This project is a work in progress.

Why use nao?

  • Use the same task graph locally and in CI
  • Run independent work in parallel
  • Keep task output easy to inspect
  • Get useful failure reporting and timing information
  • Stay independent of a specific CI provider

What can a task be?

A task can be a shell command, a Bash script, a container invocation, or another executable step. Container tasks currently execute as generated docker run commands, so Docker must be installed when you use them. Compose-backed tasks execute as generated docker compose commands and are intended for services that rely on Compose-managed configuration such as volumes.

See docs/OVERVIEW.md for the higher-level project overview. See docs/RELEASE.md for the release process.

How can I build a portable Linux binary?

Release artifacts are built as statically linked x86_64-unknown-linux-musl binaries so they run on a wider range of Linux distributions.

Install the Rust target:

rustup target add x86_64-unknown-linux-musl

On Debian or Ubuntu, install the musl linker:

sudo apt-get update
sudo apt-get install --yes musl-tools

Then build:

cargo build --release --target x86_64-unknown-linux-musl -p nao --locked

The binary will be at target/x86_64-unknown-linux-musl/release/nao.

How can I use the TUI?

nao includes a full-screen terminal UI behind the --tui flag. Run it from a repository root that contains .nao/nao.kdl with:

cargo run -p nao -- --tui

Or point it at a different recipe file:

cargo run -p nao -- --tui --config path/to/nao.kdl

The first version provides:

  • a task launcher for choosing one or more goal tasks
  • a run detail screen for live and completed runs
  • a run history screen backed by .nao/runs
  • task log, event stream, and summary browsing without leaving the TUI

Key bindings:

  • 1, 2, 3 switch between launcher, run detail, and history
  • Tab and Shift-Tab cycle pane focus
  • j and k move the current selection or scroll the focused pane
  • Space toggles launcher task selection
  • Enter starts a run from the launcher or opens a run from history
  • t, o, e, and s focus tasks, output, events, and summary in run detail
  • L toggles log auto-follow for active runs
  • ? opens help and q exits

How can I use the devcontainer?

This repository includes a checked-in devcontainer under .devcontainer/devcontainer.json. Open the repository in a devcontainer-compatible editor or CLI workflow to get a container with:

  • pinned Rust via the devcontainer build definition
  • Cargo, rustfmt, and clippy
  • build-time Codex CLI installation

The container runs bash .devcontainer/post-create.sh after creation to print tool versions and prefetch Cargo dependencies. Codex is installed in the image, but authenticated usage may still require logging in with your own credentials once the container starts.

Use scripts/dev.sh to start the devcontainer from the command line and enter a Bash shell:

./scripts/dev.sh

The wrapper automatically rebuilds the devcontainer when .devcontainer/devcontainer.json, .devcontainer/Dockerfile, or .devcontainer/post-create.sh changes.

Force a rebuild anyway when you want to blow away the existing container:

./scripts/dev.sh --rebuild

Pass a command to run it inside the container instead of opening an interactive shell:

./scripts/dev.sh cargo build --workspace

The wrapper keeps Cargo, Rustup, and Cargo target caches in .devcontainer/state on the host, so builds stay warm across container rebuilds without baking cache state into the image.

How can I use Flox for a reproducible Rust sandbox?

This repository includes a checked-in Flox environment under .flox/env/manifest.toml. It pins the Rust toolchain and common development commands used by this project:

  • rustc
  • cargo
  • rustfmt
  • clippy
  • cargo-nextest
  • native build helpers such as gcc and pkg-config

Activate it with:

flox activate
./dev-shell.sh

The environment keeps Cargo state inside .flox/cache, which helps isolate builds from host machine state and keeps local sandboxing predictable.

Common workflows:

./dev-shell.sh ./scripts/check-code.sh
./dev-shell.sh cargo build --workspace
./dev-shell.sh cargo nextest run --workspace --all-targets --all-features
flox activate -- ./scripts/check-code.sh
flox activate -- cargo build --workspace
flox activate -- cargo nextest run --workspace --all-targets --all-features

How can I use the Docker runner?

This repository includes a Compose-based Rust runner under .docker/docker-compose.yaml and a wrapper script at scripts/docker.sh.

Use it to run the Rust container with --build --rm every time:

./scripts/docker.sh scripts/check-code.sh
./scripts/docker.sh cargo build --workspace

Without a command, it opens an interactive Bash shell in the container.

This helper is for the repository development container. It is separate from recipe container tasks, which run as one-shot docker run commands declared in .nao/nao.kdl.

Use Flox when you want a reproducible local toolchain without opening the devcontainer. Use the devcontainer when you want a fully containerized editor or CLI environment. Use ./dev-shell.sh when you want the shortest path into the checked-in Flox environment.

How can I run Codex with less host filesystem access?

Use scripts/run-codex-sandbox.sh on Linux to start Codex inside a bubblewrap sandbox. The wrapper mounts the repository read-write, mounts the Codex state directory under ~/.codex, mounts the Cargo and Rustup homes so Cargo-installed tools such as cargo-nextest remain available, mounts the pnpm-installed Codex package read-only, and hides the rest of /home.

Run:

./scripts/run-codex-sandbox.sh

Pass normal Codex arguments after the script name. If you need to expose additional host paths, set NAO_CODEX_EXTRA_RO_BIND or NAO_CODEX_EXTRA_RW_BIND to colon-separated absolute paths before launching the wrapper.

Dependencies

~20–37MB
~448K SLoC