Files
dora-image-view/AGENTS.md
T
cristhianandClaude Opus 5 e2debe0581 refactor: rename the node from opencv-plot to dora-plot
The repository is dora-plot, but the package, the entrypoint, the manifest
name and the window title were all opencv-plot. Consumers wire the node by
`path:`, so the split name was visible in every dataflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WLVZCFFcCH1EpTXGfS9aD
2026-09-14 16:08:48 -05:00

4.9 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.

Based on opencv-plot from dora-hub, brought up to the dora 1.0 node contract and packaged with uv.

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.

Build

uv sync          # runtime deps
uv sync --group dev   # plus pytest and ruff

dora build --uv / dora run --uv rewrites the 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.

Requirements: dora 1.0+ (verified with dora-cli 1.0.1), Python 3.11+ (dora-rs 1.0.1 requires it), uv, and a display — or CI=true.

Run

dora run dataflow.yml --uv

Test

uv run pytest      # 14 tests, no camera/dataflow/display needed
uv run ruff check .

Architecture

  • dora_plot/main.py — Argument parsing and the dora event loop, nothing else. image decodes and redraws; bbox and text only store state. The env var wins over the CLI flag for PLOT_WIDTH/PLOT_HEIGHT, matching the upstream node. Node(args.name) rather than Node() so the node also runs standalone as a dynamic node.
  • dora_plot/decode.py — to_bgr(): every supported encoding to a writable BGR array. width/height are only consulted for the raw encodings (bgr8, rgb8, yuv420); the rest carry their own dimensions, so a missing dimension is an error only where it actually matters. Two behaviours are deliberate, not bugs: bgr8 copies (the payload may be a read-only view on shared memory, and the frame is annotated in place), and yuv420 converts with COLOR_YUV420p2RGB rather 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) and Bboxes. show() draws, resizes and displays, and returns whether q was pressed. Resizing only happens when both PLOT_WIDTH and PLOT_HEIGHT are set. headless (from CI=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 the bbox struct into xyxy corners. xywh is centre-based (x, y are the box centre). _flat() unwraps the single-element list that pa.array([{...}]) produces around each field, and reads a field stored flat as-is.
  • dora-node.yml — Node manifest (apiVersion: 1). dora validate injects these types into any dataflow that reaches the node by path:; a git:-sourced node does not pick it up, which is why the dataflow builds from the checkout. image and text carry type URNs naming the element type (std/core/v1/UInt8, .../String) because each payload is a raw buffer described by its metadata, not an Arrow struct. bbox is deliberately untyped: senders disagree on whether its numeric fields are 32- or 64-bit, and the node reads either.
  • dataflow.yml — Example dataflow: a webcam and a one-shot caption feeding the viewer, with strict_types: true. Note the output_types: on the two git:-sourced nodes — their own manifests are not injected, so without those annotations strict validation fails on an untyped upstream. bbox is left unwired on purpose; every bbox source is a detector, and wiring one would put a model download in front of a webcam preview.
  • .gitea/workflows/validate.yml — CI gate running dora validate on the dataflow on push and pull request. 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. That is why dataflow.yml wires text from pyarrow-sender — dropping it would fail CI. 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.