Contributing#
Thanks for helping! This page covers contributions to the engine repo (graph-as-policy): how to set up a dev environment, how the test suite is organized, what CI enforces, and how to build these docs.
Note
Skill and tool bundles are contributed to the sibling open-robot-skills repo instead β one directory, one PR. See Authoring bundles for the bundle format and its contribution checklist, and Testing bundles for the scaffolded tests.
Dev setup#
git clone --recurse-submodules https://github.com/graph-robots/graph-as-policy.git
git clone https://github.com/graph-robots/open-robot-skills.git # side-by-side (uv resolves it by path)
cd graph-as-policy
uv sync # engine + dev tools (pytest/ruff/mypy) β enough for the default suite
# optional, for sim-marked work (needs Linux + EGL):
uv sync --extra libero
The default test suite runs on a bare install β no GPU, no sim stack, no API keys:
uv run pytest tests -q
If you forgot --recurse-submodules, git submodule update --init fixes
uv syncβs βdoes not appear to be a Python projectβ error. More install
detail (extras, pip path, CUDA notes):
Installation.
Test markers#
pyproject.toml sets
addopts = "-m 'not llm and not gpu and not sim and not real'", so the
heavy suites are deselected by default and opt-in. Every test also runs
under a 300-second timeout (timeout = 300, via pytest-timeout).
Marker |
Needs |
Run with |
|---|---|---|
(none) |
nothing (CPU, core deps) |
|
|
|
|
|
model weights + NVIDIA GPU |
|
|
|
|
|
robot hardware |
manual release checklist |
The split follows one design rule: every LLM boundary has a recorded
artifact. The deterministic suite exercises parsing, validation,
execution, tracing, and viz against canned LLM outputs and golden graphs;
llm-marked tests regenerate those artifacts live and check structural
equivalence, not byte-equality.
What CI enforces#
CI (.github/workflows/ci.yml) runs
three jobs on every push to main and every pull request.
Lint#
ruff check gap tests
ruff is pinned to a minor line, >=0.15,<0.16 β ruff adds and retires
rules between minors, and the repo is kept clean against exactly this line.
Keep your local ruff on it too:
uvx ruff@0.15 check gap tests
Bare-install test matrix#
The default suite must collect and pass on a bare install. CI runs
pip install -e . with no extras on Python 3.10, 3.11, and 3.12, then:
python -m pytest tests -q --collect-only # the collect gate
python -m pytest tests -q # the default suite
The collect-only gate is the canary for the most common regression: importing a heavy dependency at module scope. The practical rule β never import mujoco/torch/transformers/gymnasium/pyzed at the top of any module a test file imports. Use the lazy-import pattern: import inside the function or factory, and raise an error with a pip hint when the dependency is missing.
Wheel contents#
CI builds the wheel and asserts its contents with a small script:
gap/viz/frontend/dist/ (including index.html) must ship β pip users get
gap viz without Node β and no frontend/src/ or node_modules files may
leak into the wheel. dist/ is checked into the repo for the same reason.
Warning
If you touch gap/viz/frontend/src/, rebuild dist/ and commit it in
the same PR β otherwise the wheel ships a stale frontend that no test
notices.
Pull request guidelines#
Keep PRs focused β one subsystem per PR.
New runtime behavior needs deterministic tests. Use the public gap.testing fixtures β
FakeContext(aNodeContextstand-in with scripted per-tool responses and a full call log),make_test_observation(geometrically consistent synthetic camera data),assert_graph_validβ not live models or API calls.Respect the stability guarantees. The on-disk trace layout (
dag_trace.json,node_data/<id>/β see Traces) and the skill-authoring import surface (gap.NodeContext,gap.types,gap.errors,gap.skills,gap.testing) are commitments to users. Changes to either need a strong justification and a migration note.Donβt bump submodule pins (
third_party/) as a side effect of an unrelated change.Hardware-touching changes: state what robot you ran on, and read Safety first. Safety-relevant bugs get the
safetylabel and priority review.
Building the docs#
The docs live in docs/ (Sphinx + MyST markdown) with their own
requirements file:
pip install -r docs/requirements-docs.txt # or: uv venv .venv-docs && uv pip install -r docs/requirements-docs.txt
./docs/build.sh # one-shot HTML build into docs/build/html
./docs/build.sh --watch 8000 # live-reload dev server (sphinx-autobuild)
./docs/build.sh --clean # remove build artifacts
The build treats warnings as errors (sphinx-build -W --keep-going) β
a broken cross-reference or unbalanced directive fails the build, so run it
locally before pushing docs changes.
Where next#
Architecture β the design rationale behind the modules you are changing
Roadmap β what is deliberately out of scope right now
Authoring bundles β contributing skills instead of engine code