Metadata-Version: 2.4
Name: holoscan-cli
Version: 5.0.0
Summary: Command line interface for HoloHub-style Holoscan source-project workflows.
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: AI,holoscan,medical,streaming,HPC,nvidia,docker,container
Author: NVIDIA
Maintainer: NVIDIA
Requires-Python: >=3.11,<3.15
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: GPU :: NVIDIA CUDA :: 12
Classifier: Environment :: GPU :: NVIDIA CUDA :: 13
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Healthcare Industry
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Provides-Extra: create
Requires-Dist: cookiecutter (>=2.7.1) ; extra == "create"
Requires-Dist: jsonschema (>=4.18,<5.0) ; extra == "create"
Requires-Dist: referencing (>=0.30) ; extra == "create"
Project-URL: Documentation, https://docs.nvidia.com/holoscan/sdk-user-guide/index.html
Project-URL: Homepage, https://github.com/nvidia-holoscan/holoscan-cli
Project-URL: Repository, https://github.com/nvidia-holoscan/holoscan-cli
Description-Content-Type: text/markdown

[![Code Check](https://github.com/nvidia-holoscan/holoscan-cli/actions/workflows/main.yaml/badge.svg)](https://github.com/nvidia-holoscan/holoscan-cli/actions/workflows/main.yaml)
[![Coverage Status](https://coveralls.io/repos/github/nvidia-holoscan/holoscan-cli/badge.svg)](https://coveralls.io/github/nvidia-holoscan/holoscan-cli)

# Holoscan CLI

Command-line tool for creating, discovering, building, running, testing, and packaging Holoscan Modules and applications. Published as the [`holoscan-cli`](https://pypi.org/project/holoscan-cli/) PyPI package and installs the `holoscan` console script.

## Overview

The CLI presents a single command surface for the source-project development lifecycle:

- **Project lifecycle:** `build`, `run`, `test`, `install`, `package`
- **Container:** `build-container`, `run-container`
- **Discovery / diagnostics:** `list`, `modes`, `status`, `env-info`, `env-check`, `autocompletion_list`, `version`
- **Workspace:** `lint`, `setup`, `clear-cache`, `create`

Run `holoscan <command> --help` for per-command flags.

Per-repo wrappers install this package and delegate to `holoscan`, layering on their own configuration via `HOLOSCAN_CLI_*` environment variables:

| Repo | Wrapper | Adds |
| --- | --- | --- |
| [HoloHub](https://github.com/nvidia-holoscan/holohub) | `./holohub` | source-project metadata search paths, container/workspace names |
| [I4H Workflows](https://github.com/isaac-for-healthcare/i4h-workflows) | `./i4h` | RTI DDS license auto-download + mount, TTY serial device passthrough |

Common env vars:

- `HOLOSCAN_CLI_ROOT` — repo root
- `HOLOSCAN_CLI_SEARCH_PATH` — directories or exact `metadata.json` files to discover
- `HOLOSCAN_CLI_PATH_PREFIX` — placeholder prefix in metadata templates
- `HOLOSCAN_CLI_REPO_PREFIX` — container image name prefix
- `HOLOSCAN_CLI_CONTAINER_PREFIX` — standalone Module image name prefix
- `HOLOSCAN_CLI_CREATE_TEMPLATE` — default template for `holoscan create`

`holoscan env-info` lists every env var the CLI reads in the current shell.

## Project trust model

Holoscan source projects are executable code, not passive data. In particular,
`metadata.json` can define a `run.command` (directly or through a mode), and
`holoscan run` executes that project-defined command. Build files, Dockerfiles,
setup scripts, and test configuration can execute project code as well. Review
the source and metadata before building or running a repository you do not
trust.

For a plain `run.command` string, the CLI expands Holoscan placeholders, parses
the result into an argument vector, and launches it without an implicit shell.
A project can still request a shell explicitly (for example, `bash -c ...`) or
name any other executable. Local execution runs with the invoking user's
permissions; elevation happens only when the user explicitly passes
`--as-root`.

Use `holoscan run <project> --dryrun --local --verbose` to inspect the resolved
local build and run commands without executing them. A dry run helps with
review, but it is not a sandbox and does not make untrusted project code safe.

## JSON output

`list`, `modes`, `status`, `env-info`, `env-check`, and `version` accept `--json`
and print a single machine-readable document instead of prose.

Every payload starts with a `schema_version` field, currently `1`. Within a
version the payloads change additively: new keys may appear, existing keys are
not removed or renamed. Consumers should ignore keys they do not recognize; a
removal or rename bumps `schema_version`.

`env-info --json` reports host state, so the values vary by machine — the
`docker`, `cuda_gpu`, and `git` sections are `null` when unavailable.

## CPU limits

For local Docker daemons, `run` and `run-container` forward the caller's cgroup
CPU set and CPU-time quota separately. They do not restrict containers to the
launcher's thread affinity or shrink the permitted CPU set to match the quota.
Applications can pin threads to isolated cores when the cgroup permits those cores.
Unrestricted hosts receive no automatic CPU options.

Image builds and compile containers (`build`, `install`, `package`, `test`) keep
the affinity/quota-based smaller CPU set for tools that size parallel work from
affinity, such as `nproc`. Builds inside `run` and `run-container` use runtime limits.
The CLI's default CMake job count uses `os.cpu_count()`, which ignores affinity.
Use `--parallel` or `CMAKE_BUILD_PARALLEL_LEVEL` to set that job count explicitly.

To choose runtime cores explicitly, use `--docker-opts='--cpuset-cpus=0,11-13'`,
not `taskset`. Supplying `--cpuset-cpus`, `--cpus`, `--cpu-quota`, or `--cpu-period`
in the configured Docker run options disables all automatic run CPU limits.

## Source layout

```text
src/holoscan_cli/
  cli.py              top-level argparse + dispatch (HoloscanCLI)
  configuration.py    effective-configuration reporting
  commands/           one file per subcommand + a central registry
  container/          HoloscanContainer + docker arg helpers + parser builders
  cmake/              packaged CMake support copied into standalone Modules
  utils/              io.py, text.py, sdk.py, docker.py, host_setup.py,
                      env_info.py, holohub.py
  setup_scripts/      bundled bash scripts backing `setup --scripts` and
                      `build-container --extra-scripts`
  metadata/           project metadata JSON schemas
  templates/module/   standalone Module cookiecutter
  testing/            CTest helpers shipped in the wheel
```

## Prerequisites

A platform supported by the [NVIDIA Holoscan SDK](https://docs.nvidia.com/holoscan/sdk-user-guide/sdk_installation.html#prerequisites): an x64 PC with Ubuntu and an NVIDIA GPU, or a supported NVIDIA ARM development kit.

## Installation

Python 3.12 or 3.13 is recommended for this walkthrough. Check the selected
release's Python requirement before using another interpreter.

With [uv](https://docs.astral.sh/uv/), try the CLI without a persistent install:

```bash
uvx holoscan-cli --help
```

The package also provides the canonical `holoscan` command. For a persistent
pip environment:

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install holoscan-cli
holoscan --help
```

### Create and work on a standalone module

Creating a module requires the `create` extra. CLI 5.0 pre-releases are on
NVIDIA's package index (`uv` 0.4.23 or later):

```bash
uvx --index https://pypi.nvidia.com --from 'holoscan-cli[create]>=5.0.0rc1' holoscan create my-sensor --interactive false --context holoscan_version=5.0.0 --dryrun
uvx --index https://pypi.nvidia.com --from 'holoscan-cli[create]>=5.0.0rc1' holoscan create my-sensor --interactive false --context holoscan_version=5.0.0
cd holoscan-my-sensor
uv run holoscan list --json
uv run holoscan build my_sensor_pipeline --dryrun --verbose
```

The packaged template creates C++ modules for Holoscan SDK 5.0.0 or later.
Replace `5.0.0` with the module's intended minimum SDK version. CLI and SDK
versions are independent. Review the preview before running the build without
`--dryrun`; builds require the module's documented SDK/container prerequisites.
The generated project records the creating CLI version, and `uv run` prepares
its development environment without installing the module itself.

For the pip alternative, install the same creation extra in the activated
`.venv`, then run `holoscan create` with the same arguments:

```bash
python -m pip install --extra-index-url https://pypi.nvidia.com 'holoscan-cli[create]>=5.0.0rc1'
```

In an existing generated module, use its `requirements-cli.txt` to provision
a pip environment. Follow its `README.md` and `DEVELOPER.md` for implementation,
tests, packaging, and consumer verification. No HoloHub checkout or copied
wrapper is needed.

See the [CLI reference](https://github.com/nvidia-holoscan/holoscan-cli/blob/main/CLI_REFERENCE.md) for project selection, command
semantics, previews, diagnostics, and cleanup. For contributing to the CLI
itself, see [CONTRIBUTING.md](https://github.com/nvidia-holoscan/holoscan-cli/blob/main/CONTRIBUTING.md).

### Project configuration

Standalone Modules can persist a small set of settings that cannot be inferred
from `metadata.json` or the host:

```toml
[tool.holoscan]
cuda = 13
ctest-script = "ci/container.ctest"
forward-env = ["IS_CI_BUILD"]
docker-build-args = ["--build-arg", "PROJECT_FEATURE=ON"]
docker-run-args = ["--network=host"]

[tool.holoscan.base-images]
x86_64 = "registry.example.com/holoscan/sdk-build-x86_64:5.0.0-cuda13"
aarch64 = "registry.example.com/holoscan/sdk-build-aarch64:5.0.0-cuda13"
```

`cuda` and `ctest-script` provide Module-wide toolchain defaults,
`forward-env` contains names only, the Docker argument arrays provide static
defaults, and `base-images` contains exact images for the supported target
architectures. Use command options for one-off choices. See
[Configuring Holoscan CLI](https://github.com/nvidia-holoscan/holoscan-cli/blob/main/CONFIGURATION.md)
for the complete user-facing behavior.

## Versioning

`holoscan-cli` release versions are aligned with Holoscan SDK GA release
versions. For example, the CLI released with Holoscan SDK 4.4.0 is published as
`holoscan-cli==4.4.0`; the CLI released with Holoscan SDK 4.5.0 is published as
`holoscan-cli==4.5.0`.

CLI-only fixes between SDK releases use the patch component for the current SDK
release line, for example `holoscan-cli==4.4.1` before the next SDK-aligned
`4.5.0` release.

Version alignment does not imply that the CLI selects, installs, or requires a
matching Holoscan SDK runtime or container base image. For container builds, the
base image can be set with the CLI when your component's Dockerfile is configured
with `FROM ${BASE_IMAGE}`, using any of the methods below:

1. Pass the image to the `--base-img` flag:

   ```bash
   holoscan build-container my_app --base-img nvcr.io/nvidia/clara-holoscan/holoscan:v4.4.0-cuda13
   ```

2. Set `HOLOSCAN_CLI_BASE_IMAGE` to an exact tagged or digested image. It is
   used without adding another tag:

   ```bash
   export HOLOSCAN_CLI_BASE_IMAGE=nvcr.io/nvidia/clara-holoscan/holoscan:v4.4.0-cuda13
   holoscan build-container my_app
   ```

3. Set `HOLOSCAN_CLI_BASE_IMAGE` to an image repository (no tag) and
   `HOLOSCAN_CLI_BASE_SDK_VERSION` to a Holoscan semantic version. The base image
   then resolves to
   `$HOLOSCAN_CLI_BASE_IMAGE:v$HOLOSCAN_CLI_BASE_SDK_VERSION-$CUDA_TAG`, with the
   CUDA tag chosen dynamically from your host environment:

   ```bash
   export HOLOSCAN_CLI_BASE_IMAGE=nvcr.io/nvidia/clara-holoscan/holoscan
   export HOLOSCAN_CLI_BASE_SDK_VERSION=4.4.0
   # Resolves to nvcr.io/nvidia/clara-holoscan/holoscan:v4.4.0-cuda13 on hosts with NVIDIA drivers >= 580
   holoscan build-container my_app
   ```

   SDK 5.x supports CUDA 13 only. For those versions the tag is always
   `cuda13`, and the `CUDA_MAJOR` build argument defaults to `13` instead of
   following the host driver. Requesting another CUDA version for SDK 5.x is
   an error.

If none of these is configured, the CLI asks for a base image instead of
inferring one from its own package version.

Advanced wrappers can set `HOLOSCAN_CLI_BASE_IMAGE_FORMAT` with
`{base_image}`, `{sdk_version}`, and `{cuda_tag}`, or
`HOLOSCAN_CLI_DEFAULT_IMAGE_FORMAT` with `{container_prefix}`,
`{sdk_version}`, and `{cuda_tag}`. An explicit base-image format controls
composition; without one, tagged images and digests are exact while an
untagged environment repository uses the SDK/CUDA-derived tag.

## Build from source

Python 3.11–3.14 and [Poetry 2.0+](https://python-poetry.org/docs/#installation) required.

```bash
# Create + activate a virtual environment
poetry env use python3.12
eval $(poetry env activate)

# Install dependencies + dev tooling
poetry install --with test
pre-commit install

# Run the test suite
poetry run pytest

# Build sdist + wheel
poetry build
```

### Testing against an in-tree source-project fixture

The repo ships a minimal HoloHub-style fixture at
`tests/fixtures/holohub_smoke/` (one application with a `metadata.json` that
validates against the application schema). Point the CLI at it without
needing a HoloHub / I4H checkout:

```bash
HOLOSCAN_CLI_ROOT=tests/fixtures/holohub_smoke holoscan list
HOLOSCAN_CLI_ROOT=tests/fixtures/holohub_smoke holoscan modes smoke_app
```

The same fixture is what `.github/scripts/smoke_test.sh` exercises against
the installed wheel on every CI run, so a passing fixture run locally is a
strong proxy for the `smoke-test` job passing on push.

### Testing against the downstream wrappers

Each consuming repo (HoloHub / I4H Workflows) carries a
`test_holoscan_cli_consolidation.py` that exercises the unified `holoscan`
CLI against its project tree. Point the wrapper at a local checkout via
`HOLOSCAN_CLI_SOURCE`:

```bash
cd /path/to/holohub
HOLOSCAN_CLI_SOURCE=/path/to/holoscan-cli \
  python -m pytest -q -o addopts='' utilities/cli/tests/test_holoscan_cli_consolidation.py
```

The wrapper prepends `<HOLOSCAN_CLI_SOURCE>/src` to `PYTHONPATH`, so an
in-progress branch can be exercised end-to-end without publishing a wheel
first.

## Contributing

See
[CONTRIBUTING.md](https://github.com/nvidia-holoscan/holoscan-cli/blob/main/CONTRIBUTING.md)
for details.
[`.github/CI.md`](https://github.com/nvidia-holoscan/holoscan-cli/blob/main/.github/CI.md)
covers the CI/release pipelines that back the workflow badges at the top of
this page.

## Deprecations

### HAP/MAP application packaging

Application packaging (HAP/MAP) is no longer part of this CLI: `holoscan nics`
and the `monai-deploy` console script are intentionally not provided. The current
`holoscan package` command is for building Holoscan Module distribution artifacts;
it is not the legacy HAP/MAP application packager. Before holoscan v4.3.0,
`holoscan run` was the HAP/MAP packaged-image runner; since v4.3.0 the same name
now drives the HoloHub-style source-project runner, so it no longer launches
packaged images. Developers that still rely on HAP/MAP packaging should pin both
`holoscan-cli<=4.2.0`, the last CLI release that shipped that interface, and
`holoscan<=4.2.0`, because the legacy package command depends on the artifacts
JSON manifest and was only tested with those SDK versions. Otherwise, migrate to
the Holoscan SDK packaging workflows directly. See
[issue #164](https://github.com/nvidia-holoscan/holoscan-cli/issues/164) for the
deprecation timeline.

