Push Tracker
ria-toolkit-oss/docs/ria_app_hub_handoff.md

5.2 KiB

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:

ria-app configure --registry registry.riahub.ai --namespace qoherent
ria-app pull <app>[:tag]
ria-app run  <app>[:tag] [--config config.yaml]
ria-app list
ria-app logs <app> [-f]
ria-app stop <app>

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 <app-name> Used by ria-app list to filter images
ria.version <git sha or semver> 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/*.ymlsample-build-tools full_generator.pyDockerfile emission), add LABEL instructions to the generated Dockerfile. The values should be computed from the app JSON the user submitted, not hard-coded:

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}}' <ref>).

3. Push with both :<sha> 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.

Add GET /apps to the hub API returning something like:

[
  {
    "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 <path> 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=<name>, ria.version=<sha>.
  • A Composer-built image for an nvidia-x86 app has ria.profile=nvidia-x86.
  • docker image inspect --format '{{json .Config.Labels}}' <ref> shows all five labels.
  • :latest tag is pushed for main-branch builds.
  • Running ria-app run <app> 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.