The example dataflow pulled opencv-video-capture and pyarrow-sender from dora-hub, needed a webcam, and left `bbox` unwired because every bbox source is a detector. examples/source.py emits an animated frame, the box around the square in it, and a caption, so the dataflow exercises all three inputs with nothing outside this checkout. SOURCE_FRAMES bounds the run, which lets CI run the dataflow headless rather than only validate it. Drops the dora-zed and dora-yolo wirings from the README and trims AGENTS.md to what the code and README do not already say. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018WLVZCFFcCH1EpTXGfS9aD
4.6 KiB
AGENTS.md
This file provides guidance to AI coding assistants when working with code in this repository.
What this is
A dora-rs Python node that displays a video stream with overlays: it keeps a current frame, bbox set and text string, and every image event redraws all three into an OpenCV window. It is a display sink — it produces no outputs. README.md documents the inputs, the encodings and the environment variables; this file covers only what the code and the README do not say.
Everything the example dataflow needs is in this checkout. Do not reintroduce a dependency on another repository — the example must keep running with no camera, no detector and no network.
It is Python on purpose. The node was first written in Rust against the opencv crate; that crate generates its bindings from the OpenCV headers installed on the build machine, so it needs libopencv-dev and libclang-dev on every machine and every architecture and does not cross-compile. Every dependency here ships prebuilt wheels for linux-x86_64, linux-aarch64 and macos-arm64, so uv sync is the whole install. Do not reintroduce a dependency that has to be compiled from source.
Commands
uv sync --group dev # deps plus pytest and ruff
uv run pytest && uv run ruff check . # no camera/dataflow/display needed
dora run dataflow.yml --uv # the example, in a window
CI=true SOURCE_FRAMES=30 dora run dataflow.yml --uv # the same, headless
dora build --uv / dora run --uv rewrites each manifest's build: pip install . to uv pip install . and gives the node its own managed venv under .dora/python-envs/<node-id>/, so what it imports at runtime is what was installed at build time.
Architecture
dora_plot/main.py— Argument parsing and the dora event loop, nothing else. The env var wins over the CLI flag forPLOT_WIDTH/PLOT_HEIGHT, matching the upstream node.Node(args.name)rather thanNode()so the node also runs standalone as a dynamic node.dora_plot/decode.py—to_bgr(): every supported encoding to a writable BGR array. Two behaviours are deliberate, not bugs:bgr8copies (the payload may be a read-only view on shared memory, and the frame is annotated in place), andyuv420converts withCOLOR_YUV420p2RGBrather than...2BGR— the upstream node converts to RGB and then displays it as BGR, and that channel swap is part of the behaviour callers already see.dora_plot/plot.py—Plot(the overlay state and the window) andBboxes.headless(fromCI=true) skips only the window: every input is still decoded, which is what makes the node safe in a pipeline test.dora_plot/bbox.py— Parses thebboxstruct into xyxy corners.xywhis centre-based (x, y are the box centre)._flat()unwraps the single-element list thatpa.array([{...}])produces around each field, and reads a field stored flat as-is.examples/source.py— The synthetic source node: an animated frame, the box around the square in it, and a caption. It exists so the example dataflow exercises all three inputs without a camera or a detector, and so CI can run the dataflow rather than only validate it.SOURCE_FRAMESbounds the run, which is what lets CI wait for a clean exit instead of killing it on a timeout.dora-node.yml— Node manifest (apiVersion: 1).dora validateinjects these types into any dataflow that reaches the node bypath:; agit:-sourced node does not pick it up, which is why the example builds from the checkout.imageandtextcarry type URNs naming the element type because each payload is a raw buffer described by its metadata, not an Arrow struct.bboxis deliberately untyped: senders disagree on whether its numeric fields are 32- or 64-bit, and the node reads either.dataflow.yml— The example and the CI gate, withstrict_types: true.sourcecarriesoutput_types:because it has no manifest of its own;bboxis annotated on neither side, matching the manifest..gitea/workflows/validate.yml— CI: validates and runs the dataflow headless, and runs the unit tests. Needs no camera and no display.
A caveat on typed optional inputs
dora validate --strict injects a contract type for every typed manifest input and then warns input_types key "..." not found in inputs list for any the dataflow does not wire. So a typed optional input forces the example dataflow to wire it. If a typed input is added to the manifest, either wire it in dataflow.yml or leave it untyped.
Rules
- Do not mention AI tools in commit messages or documentation.