Language-agnostic components ============================ A node does not have to be Python. Videoflow defines a **language-agnostic wire and runtime contract** so a component can be written in any language, shipped as its own container image, and dropped into a Python-authored graph by reference. This is the foundation for a component **marketplace**. The Python process only ever *builds and compiles* the graph. A remote component's ``next`` / ``process`` / ``consume`` run out-of-process in the vendor image, driven by that image's own SDK speaking the protocol; the Python worker never imports the component. The ``component()`` factory --------------------------- You wire a remote component in with the ``component()`` factory instead of importing a class:: from videoflow.core import Flow, component from videoflow.core.constants import BATCH def build_flow(): reader = component('oci://ghcr.io/acme/camera-reader:1.0.0', params={'address': 'rtsp://...'}, name='reader') tracker = component('oci://ghcr.io/acme/sort-tracker:1.2.0', params={'max_age': 30})(reader) # a Rust/C++/... node sink = component('./my-consumer')(tracker) # a local descriptor dir return Flow([sink], flow_type=BATCH) A remote node behaves like a normal producer / processor / consumer for wiring, validation, scaling (``nb_tasks``, ``partition_by``) and manifest generation; the compiler records a ``component_ref`` and descriptor instead of a Python class. Component descriptors --------------------- A component is described by a ``component.yaml`` (validated against ``spec/descriptor/component-schema.json``) declaring its params, inputs/outputs, device support, protocol version, and the container image(s) to run. A descriptor with a ``spec.runtime.pythonClass`` names a Python node the worker imports directly; without one it is a **native** component that runs its own image entrypoint. Validate any descriptor before shipping it:: videoflow component validate ./sort-tracker/component.yaml Publishing and consuming (OCI) ------------------------------ Descriptors are distributed as **OCI artifacts** (media type ``application/vnd.videoflow.component.v1+yaml``) alongside the images they reference, so a consumer can inspect a component's contract without pulling multi-gigabyte ML images. An ``oci://`` reference in ``component()`` is pulled and cached under ``~/.videoflow/components/`` automatically:: videoflow component push ./sort-tracker oci://ghcr.io/acme/sort-tracker:1.2.0 videoflow component inspect oci://ghcr.io/acme/sort-tracker:1.2.0 # params/io, no images videoflow component pull oci://ghcr.io/acme/sort-tracker:1.2.0 --verify # cosign See ``spec/DISTRIBUTION.md`` for the reference grammar and publishing model. The wire protocol and spec -------------------------- Every flow runs over one language-neutral **protobuf envelope (wire v4)** with well-known payload types (``Tensor``, ``Frame``, ``Detections``, ``Tracks``, ``BlobRef``, ``Value``). A ``Value`` may nest a ``Tensor``, so a mixed container such as a ``(frame_index, frame)`` tuple is carried without any Python-specific codec. A payload type with no built-in encoding registers one with ``register_payload_encoder``; arbitrary Python objects are never put on the wire (see ``spec/rfcs/0001``). The normative contract lives in the ``spec/`` directory: ``spec/PROTOCOL.md`` (protocol v1 — every requirement an SDK must implement, with stable IDs), the protobuf IDL under ``spec/proto/videoflow/v1/``, and golden test vectors in ``spec/vectors/`` replayed against every SDK to enforce lockstep. A vendor can hand-write a conforming component against the spec today; the Python worker is the executable reference implementation.