# `ria-app` Hub-Side Handoff **Repo:** `ria-hub` **Goal:** Make containerized apps built by Application Composer self-describing so the new `ria-app` CLI in `ria-toolkit-oss` can auto-configure GPU/USB/network flags at `docker run` time. No user copy-paste of flags. --- ## Context — what exists today In `ria-toolkit-oss` (branch `screens-connection`) there is now a `ria-app` CLI: ```bash ria-app configure --registry registry.riahub.ai --namespace qoherent ria-app pull [:tag] ria-app run [:tag] [--config config.yaml] ria-app list ria-app logs [-f] ria-app stop ``` `ria-app run` inspects OCI image labels and auto-adds runtime flags: | Label | Value (example) | Effect | |---|---|---| | `ria.profile` | `native-x86`, `nvidia-x86`, `holoscan` | `nvidia`/`holoscan`/`cuda` → adds `--gpus all` | | `ria.hardware` | comma list: `pluto,usrp,rtlsdr,hackrf,bladerf,thinkrf` | USB-attached SDRs → `--device /dev/bus/usb`; networked SDRs → `--net host` | | `ria.app` | `` | Used by `ria-app list` to filter images | | `ria.version` | `` | Informational | If the labels are missing, `ria-app run` still works but can't auto-configure — the user has to pass `--docker-args ...` themselves. So the value here is entirely in getting CI to stamp the labels. --- ## What to change in `ria-hub` ### 1. Stamp OCI labels on every built image In the Application Composer build flow (follow the path from `application_composer.go:172` `ComposerBuildTrigger` → generated `.riahub/workflows/*.yml` → `sample-build-tools` `full_generator.py` → `Dockerfile` emission), add `LABEL` instructions to the generated Dockerfile. The values should be computed from the app JSON the user submitted, not hard-coded: ```dockerfile LABEL ria.app="${APP_NAME}" LABEL ria.profile="${PROFILE}" # native-x86 | nvidia-x86 | holoscan | ... LABEL ria.hardware="${HARDWARE_CSV}" # e.g. "pluto,usrp" (empty string if none) LABEL ria.version="${GIT_SHA}" LABEL ria.operators="${OPERATORS_CSV}" # optional, nice for debugging ``` `HARDWARE_CSV` derivation: walk the operator graph in the submitted app JSON and collect the set of hardware backends that any operator requires. The mapping from operator → hardware tag should live next to the existing `operator_generator.py` apt-dep resolution (that code already knows, per operator, whether it needs `libuhd-dev`, `libad9361-dev`, `libhackrf-dev`, `librtlsdr-dev`, etc.). Reuse that table — just emit the short tag (`usrp`, `pluto`, `hackrf`, `rtlsdr`) alongside the apt package name. Allowed hardware tags (must match what `ria-app` recognizes): - `pluto`, `rtlsdr`, `hackrf`, `bladerf` → USB - `usrp`, `thinkrf` → network - (extend here when new SDR backends are added) If an operator needs both (e.g. Pluto over USB *and* its iio network endpoint), list it once — `ria-app` already applies both USB and host-net when `pluto` appears. ### 2. Prefer `LABEL` over `ARG`-only The CI job likely already passes things like `APP_NAME` and `GIT_SHA` as build args. Those args disappear after build unless promoted to `LABEL`. Make sure each of the five labels above ends up in the final image layer (verify with `docker image inspect --format '{{json .Config.Labels}}' `). ### 3. Push with both `:` and `:latest` tags `ria-app` defaults to `:latest` when the user omits a tag. If CI only pushes immutable SHA tags today, also push `:latest` on main-branch builds so `ria-app run my-classifier` Just Works. ### 4. (Optional but recommended) App index endpoint Add `GET /apps` to the hub API returning something like: ```json [ { "name": "my-classifier", "image": "registry.riahub.ai/qoherent/my-classifier:latest", "profile": "nvidia-x86", "hardware": ["pluto"], "updated_at": "2026-04-14T10:00:00Z" } ] ``` This lets `ria-app list --remote` show available apps without the user knowing image names. Not required for MVP — skip if it adds scope. ### 5. (Optional) Ship a default `config.yaml` inside the image at a known path `ria-app run --config ` mounts the user's config to `/config/config.yaml` and sets `RIA_CONFIG=/config/config.yaml`. The runtime already falls back to an embedded config per your handoff notes, so this just needs to keep working — no change unless you want to standardize the embedded path. --- ## Acceptance checklist - [ ] A Composer-built image for a native-x86 app with a Pluto operator has labels: `ria.profile=native-x86`, `ria.hardware=pluto`, `ria.app=`, `ria.version=`. - [ ] A Composer-built image for an nvidia-x86 app has `ria.profile=nvidia-x86`. - [ ] `docker image inspect --format '{{json .Config.Labels}}' ` shows all five labels. - [ ] `:latest` tag is pushed for main-branch builds. - [ ] Running `ria-app run ` on a user's machine starts the container with the right `--gpus` / `--device` / `--net` flags without the user passing anything beyond the app name. --- ## Out of scope - Anything on the `ria-toolkit-oss` side — the CLI is already implemented on branch `screens-connection`. - Changes to the generated C++ code, CMakeLists, or runtime config lookup. - Artifact downloads — we're distributing via the container registry only.