Contributing

July 3, 2026 · View on GitHub

Setup

python -m venv .venv && . .venv/bin/activate
pip install -e .[dev]        # core + pytest
pip install -e .[api]        # + hosted-API lane (openai/google-genai/anthropic/dotenv)
pip install -e .[heavy]      # + local open-weight inference (torch/transformers/decord)

Copy .env.example.env and fill in only the keys for the providers you use. Never commit .env (it's gitignored). The repo ships .env.example only.

Tests

pytest -q                                              # offline unit tests
DATASET_ROOT=/path/to/robot-bench pytest -q            # also runs the real-GT schema test

Tests are offline by default (no network, no GPU). Live-API / live-GPU checks are run manually (see HANDOFF.md), never in the unit suite. When you add a stage behavior, add a test that pins it; when you change a model-facing message or parser, add a golden/differential test (that's how the eval/annotate migrations were proven not to drift).

Layout

src/egosafetybench/
  common/    schema · taxonomy · ids · io · paths        (depends on nothing)
  models/    spec · registry · transports · families · cost/budget/limits/retry · preflight
  scenegen/  Stage 1 — scenario authoring
  render/    Stage 2 — text-to-video + manifest emitter
  annotate/  Stage 3 — two-axis GT labeling
  eval/      Stage 4 — VLM-guard scoring
  cli/       one CLI per stage (esb-* entry points)
tests/       common · models · annotate · render · cli · scenegen
configs/     pipeline.yaml + models/<name>.yaml (one ModelSpec each)
docs/        DESIGN.md · MODELS.md

DAG: common ← models ← {scenegen, render, annotate, eval} ← cli. A stage may import common and models; it must not import another stage.

See docs/DESIGN.md for the data flow + contracts and docs/MODELS.md for the model abstraction.

Conventions

  • No secrets, no absolute paths, no org/personal identifiers in committed code or configs — everything goes through env vars / config with neutral defaults. (Run a quick grep before committing; the tree is currently clean.)
  • One ModelSpec YAML per model; one transport per provider; one CLI per stage.
  • Generation params live in spec.gen (one source of truth). Paths resolve from env/config via common/paths.py (DATASET_ROOT / OUTPUT_DIR / HF_HOME).
  • Heavy/optional deps (torch, anthropic, google-genai, requests, huggingface_hub, sentence-transformers) are lazy-imported inside the functions that use them, so the core package imports without the extras.