Construct RTVI VSS CV Service
Scaffolds a deployable custom perception microservice that:
- runs a DeepStream pipeline with YOLO26 primary inference + tracker,
- converts detection metadata to the VSS protobuf schema and publishes it
to the
mdx-raw Kafka topic, and
- drops into the existing VSS compose stack via the
bp_developer_search_2d and bp_developer_alerts_2d_cv profile flags so
the downstream Search Workflow, Alert Verification, and Behavior
Analytics services consume it without further changes.
The scaffolded output is a runnable repo, not a design document.
Scope boundaries
This skill name describes the service type (a VSS-bound RTVI CV
microservice), not a model family. What is generic vs YOLO26-specific:
| Layer |
Scope |
| VSS integration |
Generic — compose profiles, host networking, mdx-raw, protobuf-2 payload, tests, smoketest |
| Scaffold script output |
YOLO26 reference — pgie-yolo26-config.txt, YOLO26_* mount paths, NvDsInferParseYolo26 |
| Other ONNX detectors |
Adapt the scaffold manually, or use rtvi-cv-customize-model to swap the model inside the stock vss-rt-cv perception container |
| Segmentation frame masks |
Documented in integration-contract.md; not auto-generated by the scaffold — extend msgconv/wrapper after scaffolding |
Do not treat the scaffold as a model-agnostic generator. Agents should either
run the YOLO26 scaffold as-is or consciously edit pgie/compose paths for
another detector while keeping the VSS contract fixed.
When to use
Use this skill when the user wants to:
- replace VSS's default perception service (RT-DETR / GDINO / YOLOv11) with
a custom YOLO26-based detector,
- add new object classes or domain-specific tracking logic while keeping
the VSS Search / Alerts / Behavior Analytics workflows intact,
- ship a perception microservice on a customer's hardware that integrates
with a VSS deployment they manage.
Do not use this skill to:
- deploy or operate VSS itself (use VSS deployment runbooks),
- swap the detector in the default
vss-rt-cv container without a new
microservice (use rtvi-cv-customize-model).
This skill assumes a target VSS deployment already exists or will be brought
up separately.
Instructions
- Read references/integration-contract.md first and keep
mdx-raw, msg-conv-payload-type=2, broker reachability, and the protobuf-2 contract fixed unless the user explicitly wants to break VSS compatibility.
- Treat all VSS deployment paths as relative to a separate checkout of the public VSS Blueprint repository, not the DeepStream repository. Clone or reuse a VSS checkout that is v3.2.1 or compatible, then deploy that release (see VSS Quickstart).
- If the user does not have the YOLO26 ONNX, labels file, or custom parser
.so, say so plainly: scaffolding and unit tests can proceed with placeholders, but the live DeepStream app cannot run yet. Point them at Ultralytics/Hugging Face for pretrained weights and ONNX export (see references/yolo26-deepstream.md).
- When assets are missing, stop the "live validation" path at scaffold generation plus host-only unit tests. Do not imply that
docker compose up, deepstream-app, or kafka_smoketest.py can succeed without the customer-supplied ONNX, labels matching num-detected-classes, and a parser exposing NvDsInferParseYolo26.
- Start the generated service only after the VSS Kafka topic initializer has completed. Keep it as a separate Compose application using host networking. Set
KAFKA_BOOTSTRAP to Kafka's host-reachable advertised listener (default: localhost:9092). Compose cannot resolve depends_on across separate invocations.
Examples
- "Create a custom RTVI CV microservice that runs YOLO26 in DeepStream and publishes object metadata so VSS Search and Alerts can consume it."
- "Validate the generated RTVI VSS service scaffold locally, then explain how to verify the live integration on a GPU host with a deployed VSS stack."
- "I do not have a trained YOLO26 ONNX, labels file, or parser
.so yet. Can the live VSS integration still run?"
VSS source location
This skill ships the scaffold generator, but not the VSS deployment. Clone the
public VSS Blueprint repository separately or reuse an existing checkout, then
set VSS_ROOT to that checkout explicitly. Do not search for or clone VSS
relative to the generated service directory:
# Customer-specific path to an existing VSS v3.2.1-compatible checkout.
export VSS_ROOT=/absolute/path/to/video-search-and-summarization
VSS_DEPLOY_DIR="${VSS_ROOT}/deploy/docker"
test -f "${VSS_DEPLOY_DIR}/compose.yml" || {
echo "Missing VSS compose file: ${VSS_DEPLOY_DIR}/compose.yml" >&2
exit 1
}
echo "Using VSS deployment: ${VSS_DEPLOY_DIR}"
Relevant customer-accessible VSS locations include:
The custom service generated by this skill remains in <target-dir> and runs as a separate, host-networked Compose application alongside VSS. Set KAFKA_BOOTSTRAP to Kafka's host-reachable advertised listener (default: localhost:9092). Do not look for generated YOLO26 files inside either the DeepStream or stock VSS checkout.
Required reads
Read these before generating code so the implementation matches the
documented VSS data path rather than a generic Kafka producer:
- references/integration-contract.md — the exact mdx-raw protobuf contract. For segmentation/frame-mask services, read its segmentation frame-mask payload section before implementing msgconv, wrapper, Kafka, or protobuf changes.
- references/yolo26-deepstream.md — DeepStream nvinfer config for YOLO26.
- references/vss-profile-integration.md — how the service plugs into Search / Alerts / Behavior Analytics.
- VSS Object Detection and Tracking —
https://docs.nvidia.com/vss/latest/object-detection-tracking.html
- VSS Behavior Analytics —
https://docs.nvidia.com/vss/latest/behavior-analytics.html
- VSS Search Workflow —
https://docs.nvidia.com/vss/latest/agent-workflow-search.html
- DeepStream
Gst-nvmsgconv — https://docs.nvidia.com/metropolis/deepstream/9.1/text/DS_plugin_gst-nvmsgconv.html
- DeepStream
Gst-nvmsgbroker — https://docs.nvidia.com/metropolis/deepstream/9.1/text/DS_plugin_gst-nvmsgbroker.html
Inputs to confirm
Ask the user for these. Use placeholders if not provided — do not block.
service-name (slug; becomes container name and python package)
yolo26-onnx-path (host path to the YOLO26 ONNX export — not .pt)
yolo26-labels-path (host path to a one-class-per-line labels file)
yolo26-parser-lib (host path to the YOLO26 custom-parser .so, or the
parser function name if compiled into the customer image)
num-classes (integer; must match the labels file)
target-vss-profiles — any subset of:
bp_developer_search_2d (Search Profile)
bp_developer_alerts_2d_cv (Alerts Profile + Behavior Analytics consumer)
kafka-bootstrap (Kafka's host-reachable advertised listener; default localhost:9092)
kafka-topic (default mdx-raw — VSS consumers expect this name)
input-rtsp-uri or input video file path
Workflow
Read references/integration-contract.md. The fixed parts of the
contract (topic name, payload type, schema library) are not negotiable
if the goal is to plug into an existing VSS deployment.
For segmentation/frame-mask services, follow the segmentation payload
contract in that reference before changing msgconv or wrapper code.
Scaffold the YOLO26 reference service (do not generalize pgie paths unless
the user explicitly needs another detector):
python3 scripts/scaffold_rtvi_vss_service.py \
--service-name <service-name> \
--output-dir <target-dir> \
--num-classes <N> \
--vss-profiles bp_developer_search_2d bp_developer_alerts_2d_cv
Drop the customer's YOLO26 ONNX, labels file, and custom-parser library
into the paths the generated service_config.json references.
If those artifacts do not exist yet, stop after scaffolding and host-only
unit tests; the live DeepStream service cannot start correctly without
them.
Build the image:
docker build -t <service-name>:dev <target-dir>
From the separate VSS checkout, bring up the matching Search or Alerts
profile using the VSS Quickstart and deploy/docker/scripts/dev-profile.sh.
Confirm that VSS and its one-shot Kafka topic initializer are ready, then
start the generated service as a separate Compose application:
For Search or Alerts, find the matching one-shot initializer without
assuming a Compose project or container name:
docker ps -a \
--filter label=com.docker.compose.service=kafka-topic-init-container \
--format 'table {{.Names}}\t{{.Status}}'
Identify the selected deployment's initializer and confirm it is
Exited (0), then start the generated service with the matching gate:
cd <target-dir>
docker compose -f compose/service.compose.yml \
--profile bp_developer_search_2d up -d
# Or for Alerts:
docker compose -f compose/service.compose.yml \
--profile bp_developer_alerts_2d_cv up -d
Do not add a cross-file depends_on entry. The generated service uses
network_mode: host. Set KAFKA_BOOTSTRAP to Kafka's host-reachable
advertised listener (default: localhost:9092). The readiness check
enforces startup order.
Verify the metadata flow:
cd <target-dir>
python3 tools/kafka_smoketest.py --describe-only
python3 tools/kafka_smoketest.py --timeout 120
The smoke test auto-detects Kafka only when exactly one matching container
is running. If multiple deployments are active, pass the selected running
name with --kafka-container. Its --bootstrap-server is resolved inside
that Kafka container and normally remains localhost:9092, even when the
detector's host-facing KAFKA_BOOTSTRAP uses a different port.
A successful consume confirms at least one non-empty message arrived on
mdx-raw within the timeout. It does not decode the protobuf payload or
validate sensorId, objects, or bbox fields.
Confirm downstream pickup:
- Search Profile: query the Video Analytics API for ingested events,
run an embed query and an attribute query against the search workflow.
- Alerts Profile: watch
mdx-incidents for behavior-analytics
output; the alert-bridge service should generate VLM-verified
incidents.
- Behavior Analytics: the selected VSS Search or Alerts deployment starts its own behavior consumer. This is part of the VSS stack, not another profile for the generated service. It consumes
mdx-raw and emits behavior windows to mdx-incidents.
Service shape (generated)
The scaffolder emits this layout:
<service-name>/
├── Dockerfile DeepStream 9.1 + custom parser hook
├── README.md customer-facing build/run/plug-in guide
├── service_config.json declarative config (topic, profile flags, paths)
├── compose/
│ └── service.compose.yml service def with profiles for VSS plug-in
├── pipeline/
│ ├── ds-app-config.txt deepstream-test5 derived; msgconv→msgbroker→mdx-raw
│ ├── ds-start.sh container entrypoint
│ └── configs/
│ ├── pgie-yolo26-config.txt nvinfer config skeleton for YOLO26
│ ├── tracker-nvdcf.yml NvDCF tracker config
│ ├── cfg_kafka.txt librdkafka producer overrides
│ ├── msgconv_config.txt mega2d sensor context
│ └── labels.txt class labels placeholder
├── app/
│ ├── __init__.py
│ ├── contracts.py NvDsEventMsgMeta-aligned event envelope
│ ├── pipeline_plan.py declarative stage list (used by tests)
│ └── service.py adapter helpers for extension/derived events
├── tools/
│ └── kafka_smoketest.py consumes one mdx-raw message and asserts it is non-empty
└── tests/
├── test_pipeline_config.py asserts the Kafka adapter contract and msgconv→msgbroker→mdx-raw wiring
├── test_service.py exercises the python adapter without GPU
└── test_compose.py asserts profile gates, host networking, and liveness healthcheck
Non-negotiable contract elements
The customer can change almost everything except these — they're what
the VSS stack consumes:
- Kafka topic
mdx-raw, using the host-reachable advertised listener selected by KAFKA_BOOTSTRAP (default: localhost:9092).
msg-conv-payload-type=2 (NVDS_PAYLOAD_DEEPSTREAM_PROTOBUF) with msg-conv-msg2p-new-api=1 so the generated deepstream-app serializes frame/object metadata directly: protobuf serialized by
msg-conv-msg2p-lib (libnvds_msgconv_mega2d.so, or libnvds_msgconv.so
on DGX-SPARK/THOR); libnvds_kafka_proto.so is the msg-broker-proto-lib
Kafka transport adapter only.
- A protobuf
Frame payload with sensorId, timestamp, and objects[]
carrying id, bbox, type, confidence. This is what
vss-search-analytics-*, vss-behavior-analytics-*, and
vss-video-analytics-api-* deserialize.
network_mode: host.
- An explicit deployment precondition that the VSS
kafka-topic-init-container
completed successfully before this separate Compose application starts.
If any of these change, the customer is no longer plugging into VSS — they
are running an isolated CV service.
Validation
Run unit tests on any host (no GPU required):
cd <target-dir>
python3 -m unittest discover -v -s tests -p 'test_*.py'
Run end-to-end on a host with GPU + a deployed VSS stack:
cd <target-dir>
python3 tools/kafka_smoketest.py --describe-only
python3 tools/kafka_smoketest.py --timeout 120
A successful smoke test confirms non-empty bytes arrived on mdx-raw within the timeout. It does not decode the protobuf payload or prove the message came from this service specifically. To verify downstream pickup, check the Search / Alerts / Behavior Analytics services via their own APIs.
Do not present local unit-test success as proof that live VSS integration is
ready. Without the customer ONNX, labels file, and parser library, the live
DeepStream path remains blocked even if scaffolding and unit tests succeed.
Implementation guardrails
- Do not invent topic names.
mdx-raw is the single perception ingress.
Per-service prefixes break the existing VSS consumers.
- Do not switch to
msg-conv-payload-type=0 or =1. VSS deserializers
expect type 2.
- Do not bridge through a custom Python Kafka producer. The DeepStream
nvmsgconv → nvmsgbroker boundary is what produces correctly-framed
protobuf with timestamps in nanoseconds. A Python producer drift will
silently degrade Behavior Analytics.
- Keep
track_id stable across frames. Behavior Analytics derives dwell
and direction from track continuity; a per-frame regenerated id makes
every frame look like a new object.
- Do not embed credentials, NGC tokens, or absolute customer paths in the
scaffolded files. The generated tree must be portable.
1---2name: rtvi-cv-scaffold-vss-service3description: Scaffold a standalone RTVI CV microservice that plugs into VSS Search and Alerts profiles via Kafka mdx-raw. The shipped scaffold script is a YOLO26 reference implementation (ONNX, labels, custom parser required). Use when building a new perception microservice repo, validating the VSS integration contract, extending that scaffold for segmentation frame-mask payloads, or scaffolding with placeholders before customer YOLO26 assets exist. For swapping the detector in the stock vss-rt-cv container, use rtvi-cv-customize-model instead. Live DeepStream integration cannot run until the customer-supplied ONNX, labels file, and parser library exist.4license: NVIDIA Proprietary5---67# Construct RTVI VSS CV Service89Scaffolds a deployable custom perception microservice that:10111. runs a DeepStream pipeline with **YOLO26** primary inference + tracker,122. converts detection metadata to the VSS protobuf schema and publishes it13 to the **`mdx-raw`** Kafka topic, and143. drops into the existing VSS compose stack via the15 `bp_developer_search_2d` and `bp_developer_alerts_2d_cv` profile flags so16 the downstream Search Workflow, Alert Verification, and Behavior17 Analytics services consume it without further changes.1819The scaffolded output is a runnable repo, not a design document.2021## Scope boundaries2223This skill name describes the **service type** (a VSS-bound RTVI CV24microservice), not a model family. What is generic vs YOLO26-specific:2526| Layer | Scope |27|-------|-------|28| VSS integration | Generic — compose profiles, host networking, `mdx-raw`, protobuf-2 payload, tests, smoketest |29| Scaffold script output | **YOLO26 reference** — `pgie-yolo26-config.txt`, `YOLO26_*` mount paths, `NvDsInferParseYolo26` |30| Other ONNX detectors | Adapt the scaffold manually, or use `rtvi-cv-customize-model` to swap the model inside the stock `vss-rt-cv` perception container |31| Segmentation frame masks | Documented in `integration-contract.md`; not auto-generated by the scaffold — extend msgconv/wrapper after scaffolding |3233Do not treat the scaffold as a model-agnostic generator. Agents should either34run the YOLO26 scaffold as-is or consciously edit pgie/compose paths for35another detector while keeping the VSS contract fixed.3637## When to use3839Use this skill when the user wants to:4041- replace VSS's default perception service (RT-DETR / GDINO / YOLOv11) with42 a custom YOLO26-based detector,43- add new object classes or domain-specific tracking logic while keeping44 the VSS Search / Alerts / Behavior Analytics workflows intact,45- ship a perception microservice on a customer's hardware that integrates46 with a VSS deployment they manage.4748Do **not** use this skill to:4950- deploy or operate VSS itself (use VSS deployment runbooks),51- swap the detector in the default `vss-rt-cv` container without a new52 microservice (use `rtvi-cv-customize-model`).5354This skill assumes a target VSS deployment already exists or will be brought55up separately.5657## Instructions5859- Read [references/integration-contract.md](references/integration-contract.md) first and keep `mdx-raw`, `msg-conv-payload-type=2`, broker reachability, and the protobuf-2 contract fixed unless the user explicitly wants to break VSS compatibility.60- Treat all VSS deployment paths as relative to a separate checkout of the public [VSS Blueprint repository](https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization), not the DeepStream repository. Clone or reuse a VSS checkout that is **v3.2.1 or compatible**, then deploy that release (see [VSS Quickstart](https://docs.nvidia.com/vss/latest/quickstart.html#download-the-deployment-package)).61- If the user does **not** have the YOLO26 ONNX, labels file, or custom parser `.so`, say so plainly: scaffolding and unit tests can proceed with placeholders, but the live DeepStream app cannot run yet. Point them at Ultralytics/Hugging Face for pretrained weights and ONNX export (see [references/yolo26-deepstream.md](references/yolo26-deepstream.md)).62- When assets are missing, stop the "live validation" path at scaffold generation plus host-only unit tests. Do not imply that `docker compose up`, `deepstream-app`, or `kafka_smoketest.py` can succeed without the customer-supplied ONNX, labels matching `num-detected-classes`, and a parser exposing `NvDsInferParseYolo26`.63- Start the generated service only after the VSS Kafka topic initializer has completed. Keep it as a separate Compose application using host networking. Set `KAFKA_BOOTSTRAP` to Kafka's host-reachable advertised listener (default: `localhost:9092`). Compose cannot resolve `depends_on` across separate invocations.6465## Examples6667- "Create a custom RTVI CV microservice that runs YOLO26 in DeepStream and publishes object metadata so VSS Search and Alerts can consume it."68- "Validate the generated RTVI VSS service scaffold locally, then explain how to verify the live integration on a GPU host with a deployed VSS stack."69- "I do not have a trained YOLO26 ONNX, labels file, or parser `.so` yet. Can the live VSS integration still run?"7071## VSS source location7273This skill ships the scaffold generator, but not the VSS deployment. Clone the74public VSS Blueprint repository separately or reuse an existing checkout, then75set `VSS_ROOT` to that checkout explicitly. Do not search for or clone VSS76relative to the generated service directory:7778```bash79# Customer-specific path to an existing VSS v3.2.1-compatible checkout.80export VSS_ROOT=/absolute/path/to/video-search-and-summarization81VSS_DEPLOY_DIR="${VSS_ROOT}/deploy/docker"82test -f "${VSS_DEPLOY_DIR}/compose.yml" || {83 echo "Missing VSS compose file: ${VSS_DEPLOY_DIR}/compose.yml" >&284 exit 185}86echo "Using VSS deployment: ${VSS_DEPLOY_DIR}"87```8889Relevant customer-accessible VSS locations include:9091- [`deploy/docker/scripts/dev-profile.sh`](https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization/blob/v3.2.1/deploy/docker/scripts/dev-profile.sh) — brings up Search or Alerts using the documented Quickstart flow92- [`deploy/docker/developer-profiles/dev-profile-search/`](https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization/tree/v3.2.1/deploy/docker/developer-profiles/dev-profile-search)93- [`deploy/docker/developer-profiles/dev-profile-alerts/`](https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization/tree/v3.2.1/deploy/docker/developer-profiles/dev-profile-alerts)94- [`deploy/docker/services/rtvi/rtvi-cv/`](https://github.com/NVIDIA-AI-Blueprints/video-search-and-summarization/tree/v3.2.1/deploy/docker/services/rtvi/rtvi-cv) — stock RTVI-CV service definition9596The custom service generated by this skill remains in `<target-dir>` and runs as a separate, host-networked Compose application alongside VSS. Set `KAFKA_BOOTSTRAP` to Kafka's host-reachable advertised listener (default: `localhost:9092`). Do not look for generated YOLO26 files inside either the DeepStream or stock VSS checkout.9798## Required reads99100Read these before generating code so the implementation matches the101documented VSS data path rather than a generic Kafka producer:1021031. [references/integration-contract.md](references/integration-contract.md) — the exact mdx-raw protobuf contract. For segmentation/frame-mask services, read its segmentation frame-mask payload section before implementing msgconv, wrapper, Kafka, or protobuf changes.1042. [references/yolo26-deepstream.md](references/yolo26-deepstream.md) — DeepStream nvinfer config for YOLO26.1053. [references/vss-profile-integration.md](references/vss-profile-integration.md) — how the service plugs into Search / Alerts / Behavior Analytics.1064. VSS Object Detection and Tracking — `https://docs.nvidia.com/vss/latest/object-detection-tracking.html`1075. VSS Behavior Analytics — `https://docs.nvidia.com/vss/latest/behavior-analytics.html`1086. VSS Search Workflow — `https://docs.nvidia.com/vss/latest/agent-workflow-search.html`1097. DeepStream `Gst-nvmsgconv` — `https://docs.nvidia.com/metropolis/deepstream/9.1/text/DS_plugin_gst-nvmsgconv.html`1108. DeepStream `Gst-nvmsgbroker` — `https://docs.nvidia.com/metropolis/deepstream/9.1/text/DS_plugin_gst-nvmsgbroker.html`111112## Inputs to confirm113114Ask the user for these. Use placeholders if not provided — do not block.115116- `service-name` (slug; becomes container name and python package)117- `yolo26-onnx-path` (host path to the YOLO26 ONNX export — not `.pt`)118- `yolo26-labels-path` (host path to a one-class-per-line labels file)119- `yolo26-parser-lib` (host path to the YOLO26 custom-parser `.so`, or the120 parser function name if compiled into the customer image)121- `num-classes` (integer; must match the labels file)122- `target-vss-profiles` — any subset of:123 - `bp_developer_search_2d` (Search Profile)124 - `bp_developer_alerts_2d_cv` (Alerts Profile + Behavior Analytics consumer)125- `kafka-bootstrap` (Kafka's host-reachable advertised listener; default `localhost:9092`)126- `kafka-topic` (default `mdx-raw` — VSS consumers expect this name)127- `input-rtsp-uri` or input video file path128129## Workflow1301311. Read [references/integration-contract.md](references/integration-contract.md). The fixed parts of the132 contract (topic name, payload type, schema library) are not negotiable133 if the goal is to plug into an existing VSS deployment.134 For segmentation/frame-mask services, follow the segmentation payload135 contract in that reference before changing msgconv or wrapper code.1362. Scaffold the **YOLO26 reference** service (do not generalize pgie paths unless137 the user explicitly needs another detector):138139 ```bash140 python3 scripts/scaffold_rtvi_vss_service.py \141 --service-name <service-name> \142 --output-dir <target-dir> \143 --num-classes <N> \144 --vss-profiles bp_developer_search_2d bp_developer_alerts_2d_cv145 ```1461473. Drop the customer's YOLO26 ONNX, labels file, and custom-parser library148 into the paths the generated `service_config.json` references.149 If those artifacts do not exist yet, stop after scaffolding and host-only150 unit tests; the live DeepStream service cannot start correctly without151 them.1524. Build the image:153154 ```bash155 docker build -t <service-name>:dev <target-dir>156 ```1571585. From the separate VSS checkout, bring up the matching Search or Alerts159 profile using the VSS Quickstart and `deploy/docker/scripts/dev-profile.sh`.160 Confirm that VSS and its one-shot Kafka topic initializer are ready, then161 start the generated service as a separate Compose application:162163 For Search or Alerts, find the matching one-shot initializer without164 assuming a Compose project or container name:165166 ```bash167 docker ps -a \168 --filter label=com.docker.compose.service=kafka-topic-init-container \169 --format 'table {{.Names}}\t{{.Status}}'170 ```171172 Identify the selected deployment's initializer and confirm it is173 `Exited (0)`, then start the generated service with the matching gate:174175 ```bash176 cd <target-dir>177 docker compose -f compose/service.compose.yml \178 --profile bp_developer_search_2d up -d179180 # Or for Alerts:181 docker compose -f compose/service.compose.yml \182 --profile bp_developer_alerts_2d_cv up -d183 ```184185 Do not add a cross-file `depends_on` entry. The generated service uses186 `network_mode: host`. Set `KAFKA_BOOTSTRAP` to Kafka's host-reachable187 advertised listener (default: `localhost:9092`). The readiness check188 enforces startup order.1891906. Verify the metadata flow:191192 ```bash193 cd <target-dir>194 python3 tools/kafka_smoketest.py --describe-only195 python3 tools/kafka_smoketest.py --timeout 120196 ```197198 The smoke test auto-detects Kafka only when exactly one matching container199 is running. If multiple deployments are active, pass the selected running200 name with `--kafka-container`. Its `--bootstrap-server` is resolved inside201 that Kafka container and normally remains `localhost:9092`, even when the202 detector's host-facing `KAFKA_BOOTSTRAP` uses a different port.203204 A successful consume confirms at least one non-empty message arrived on205 `mdx-raw` within the timeout. It does not decode the protobuf payload or206 validate sensorId, objects, or bbox fields.2072087. Confirm downstream pickup:209 - **Search Profile**: query the Video Analytics API for ingested events,210 run an embed query and an attribute query against the search workflow.211 - **Alerts Profile**: watch `mdx-incidents` for behavior-analytics212 output; the `alert-bridge` service should generate VLM-verified213 incidents.214 - **Behavior Analytics**: the selected VSS Search or Alerts deployment starts its own behavior consumer. This is part of the VSS stack, not another profile for the generated service. It consumes `mdx-raw` and emits behavior windows to `mdx-incidents`.215216## Service shape (generated)217218The scaffolder emits this layout:219220```221<service-name>/222├── Dockerfile DeepStream 9.1 + custom parser hook223├── README.md customer-facing build/run/plug-in guide224├── service_config.json declarative config (topic, profile flags, paths)225├── compose/226│ └── service.compose.yml service def with profiles for VSS plug-in227├── pipeline/228│ ├── ds-app-config.txt deepstream-test5 derived; msgconv→msgbroker→mdx-raw229│ ├── ds-start.sh container entrypoint230│ └── configs/231│ ├── pgie-yolo26-config.txt nvinfer config skeleton for YOLO26232│ ├── tracker-nvdcf.yml NvDCF tracker config233│ ├── cfg_kafka.txt librdkafka producer overrides234│ ├── msgconv_config.txt mega2d sensor context235│ └── labels.txt class labels placeholder236├── app/237│ ├── __init__.py238│ ├── contracts.py NvDsEventMsgMeta-aligned event envelope239│ ├── pipeline_plan.py declarative stage list (used by tests)240│ └── service.py adapter helpers for extension/derived events241├── tools/242│ └── kafka_smoketest.py consumes one mdx-raw message and asserts it is non-empty243└── tests/244 ├── test_pipeline_config.py asserts the Kafka adapter contract and msgconv→msgbroker→mdx-raw wiring245 ├── test_service.py exercises the python adapter without GPU246 └── test_compose.py asserts profile gates, host networking, and liveness healthcheck247```248249## Non-negotiable contract elements250251The customer can change almost everything *except* these — they're what252the VSS stack consumes:253254- Kafka topic `mdx-raw`, using the host-reachable advertised listener selected by `KAFKA_BOOTSTRAP` (default: `localhost:9092`).255- `msg-conv-payload-type=2` (`NVDS_PAYLOAD_DEEPSTREAM_PROTOBUF`) with `msg-conv-msg2p-new-api=1` so the generated `deepstream-app` serializes frame/object metadata directly: protobuf serialized by256 `msg-conv-msg2p-lib` (`libnvds_msgconv_mega2d.so`, or `libnvds_msgconv.so`257 on DGX-SPARK/THOR); `libnvds_kafka_proto.so` is the `msg-broker-proto-lib`258 Kafka transport adapter only.259- A protobuf `Frame` payload with `sensorId`, `timestamp`, and `objects[]`260 carrying `id`, `bbox`, `type`, `confidence`. This is what261 `vss-search-analytics-*`, `vss-behavior-analytics-*`, and262 `vss-video-analytics-api-*` deserialize.263- `network_mode: host`.264- An explicit deployment precondition that the VSS `kafka-topic-init-container`265 completed successfully before this separate Compose application starts.266267If any of these change, the customer is no longer plugging into VSS — they268are running an isolated CV service.269270## Validation271272Run unit tests on any host (no GPU required):273274```bash275cd <target-dir>276python3 -m unittest discover -v -s tests -p 'test_*.py'277```278279Run end-to-end on a host with GPU + a deployed VSS stack:280281```bash282cd <target-dir>283python3 tools/kafka_smoketest.py --describe-only284python3 tools/kafka_smoketest.py --timeout 120285```286287A successful smoke test confirms non-empty bytes arrived on `mdx-raw` within the timeout. It does not decode the protobuf payload or prove the message came from this service specifically. To verify downstream pickup, check the Search / Alerts / Behavior Analytics services via their own APIs.288289Do not present local unit-test success as proof that live VSS integration is290ready. Without the customer ONNX, labels file, and parser library, the live291DeepStream path remains blocked even if scaffolding and unit tests succeed.292293## Implementation guardrails294295- Do not invent topic names. `mdx-raw` is the single perception ingress.296 Per-service prefixes break the existing VSS consumers.297- Do not switch to `msg-conv-payload-type=0` or `=1`. VSS deserializers298 expect type 2.299- Do not bridge through a custom Python Kafka producer. The DeepStream300 `nvmsgconv → nvmsgbroker` boundary is what produces correctly-framed301 protobuf with timestamps in nanoseconds. A Python producer drift will302 silently degrade Behavior Analytics.303- Keep `track_id` stable across frames. Behavior Analytics derives dwell304 and direction from track continuity; a per-frame regenerated id makes305 every frame look like a new object.306- Do not embed credentials, NGC tokens, or absolute customer paths in the307 scaffolded files. The generated tree must be portable.