inspect-robots-yam 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. inspect_robots_yam-0.3.0/.github/workflows/ci.yml +91 -0
  2. inspect_robots_yam-0.3.0/.github/workflows/release.yml +23 -0
  3. inspect_robots_yam-0.3.0/.gitignore +28 -0
  4. inspect_robots_yam-0.3.0/.pre-commit-config.yaml +52 -0
  5. inspect_robots_yam-0.3.0/CITATION.cff +9 -0
  6. inspect_robots_yam-0.3.0/CLAUDE.md +64 -0
  7. inspect_robots_yam-0.3.0/LICENSE +21 -0
  8. inspect_robots_yam-0.3.0/PKG-INFO +221 -0
  9. inspect_robots_yam-0.3.0/README.md +186 -0
  10. inspect_robots_yam-0.3.0/plans/0001-yam-molmoact2-design.md +328 -0
  11. inspect_robots_yam-0.3.0/pyproject.toml +110 -0
  12. inspect_robots_yam-0.3.0/src/inspect_robots_yam/CLAUDE.md +32 -0
  13. inspect_robots_yam-0.3.0/src/inspect_robots_yam/__init__.py +37 -0
  14. inspect_robots_yam-0.3.0/src/inspect_robots_yam/config.py +158 -0
  15. inspect_robots_yam-0.3.0/src/inspect_robots_yam/embodiment.py +246 -0
  16. inspect_robots_yam-0.3.0/src/inspect_robots_yam/operator.py +66 -0
  17. inspect_robots_yam-0.3.0/src/inspect_robots_yam/packing.py +74 -0
  18. inspect_robots_yam-0.3.0/src/inspect_robots_yam/policy.py +120 -0
  19. inspect_robots_yam-0.3.0/src/inspect_robots_yam/preflight.py +94 -0
  20. inspect_robots_yam-0.3.0/src/inspect_robots_yam/py.typed +0 -0
  21. inspect_robots_yam-0.3.0/tests/test_api_snapshot.py +42 -0
  22. inspect_robots_yam-0.3.0/tests/test_compat.py +99 -0
  23. inspect_robots_yam-0.3.0/tests/test_config.py +109 -0
  24. inspect_robots_yam-0.3.0/tests/test_embodiment.py +322 -0
  25. inspect_robots_yam-0.3.0/tests/test_eval_end_to_end.py +60 -0
  26. inspect_robots_yam-0.3.0/tests/test_operator.py +54 -0
  27. inspect_robots_yam-0.3.0/tests/test_packing.py +83 -0
  28. inspect_robots_yam-0.3.0/tests/test_policy.py +151 -0
  29. inspect_robots_yam-0.3.0/tests/test_preflight.py +115 -0
@@ -0,0 +1,91 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ # Least privilege: every job only reads the repo contents.
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ci-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ # Lint + strict typing, once. mypy targets the 3.10 floor via pyproject; running
19
+ # it on 3.11 avoids NumPy's 3.12-only stub syntax.
20
+ quality:
21
+ name: lint · type
22
+ runs-on: ubuntu-latest
23
+ timeout-minutes: 10
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v5
28
+ with:
29
+ enable-cache: true
30
+ cache-dependency-glob: "**/pyproject.toml"
31
+ - name: Create venv
32
+ run: uv venv --python 3.11
33
+ - name: Install (dev extras; inspect_robots + kitchenbench from git tags)
34
+ run: uv pip install -e ".[dev]"
35
+ - name: Ruff (lint)
36
+ run: uv run ruff check .
37
+ - name: Ruff (format check)
38
+ run: uv run ruff format --check .
39
+ - name: Mypy (strict)
40
+ run: uv run mypy
41
+
42
+ # Blocking test gate across the supported OS x Python matrix (100% coverage).
43
+ test:
44
+ name: test (${{ matrix.os }}, py${{ matrix.python-version }})
45
+ runs-on: ${{ matrix.os }}
46
+ timeout-minutes: 15
47
+ strategy:
48
+ fail-fast: false
49
+ matrix:
50
+ os: [ubuntu-latest, macos-latest]
51
+ python-version: ["3.11", "3.12"]
52
+ steps:
53
+ - uses: actions/checkout@v4
54
+ - name: Install uv
55
+ uses: astral-sh/setup-uv@v5
56
+ with:
57
+ enable-cache: true
58
+ cache-dependency-glob: "**/pyproject.toml"
59
+ - name: Create venv (py${{ matrix.python-version }})
60
+ run: uv venv --python ${{ matrix.python-version }}
61
+ - name: Install (dev extras)
62
+ run: uv pip install -e ".[dev]"
63
+ - name: Pytest (100% coverage)
64
+ run: uv run pytest --cov --cov-report=term-missing
65
+
66
+ # Dependency hygiene: the package must import with ONLY its runtime deps
67
+ # (inspect_robots + numpy) — no requests, json_numpy, or i2rt (those are lazy extras).
68
+ import-hygiene:
69
+ name: import without client/hardware extras
70
+ runs-on: ubuntu-latest
71
+ timeout-minutes: 10
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+ - name: Install uv
75
+ uses: astral-sh/setup-uv@v5
76
+ with:
77
+ enable-cache: true
78
+ cache-dependency-glob: "**/pyproject.toml"
79
+ - name: Create venv
80
+ run: uv venv --python 3.12
81
+ - name: Install runtime only (no extras)
82
+ run: uv pip install -e .
83
+ - name: Assert optional deps absent, then import
84
+ run: |
85
+ uv run python - <<'PY'
86
+ import importlib.util
87
+ for mod in ("requests", "json_numpy", "i2rt"):
88
+ assert importlib.util.find_spec(mod) is None, f"{mod} unexpectedly installed"
89
+ import inspect_robots_yam
90
+ print("inspect_robots_yam", inspect_robots_yam.__version__, "imported with runtime deps only")
91
+ PY
@@ -0,0 +1,23 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI via trusted publishing (OIDC) — no API tokens.
4
+ # Authenticates against the PyPI trusted-publisher entry for this repo
5
+ # (workflow: release.yml, environment: pypi).
6
+ on:
7
+ release:
8
+ types: [published]
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ permissions:
15
+ id-token: write # OIDC token for PyPI trusted publishing
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+ - name: Build sdist + wheel
21
+ run: uv build
22
+ - name: Publish to PyPI
23
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,28 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # Virtualenvs
10
+ .venv/
11
+ venv/
12
+
13
+ # Test / coverage
14
+ .pytest_cache/
15
+ .coverage
16
+ coverage.xml
17
+ htmlcov/
18
+ .mypy_cache/
19
+ .ruff_cache/
20
+
21
+ # Secrets / env
22
+ .env
23
+ .env.*
24
+
25
+ # OS / editor
26
+ .DS_Store
27
+ .idea/
28
+ .vscode/
@@ -0,0 +1,52 @@
1
+ # Pre-commit hooks for inspect-robots-yam. Install once per clone:
2
+ #
3
+ # uv run pre-commit install # sets up both pre-commit and pre-push hooks
4
+ #
5
+ # On commit: file hygiene + ruff (lint & format) + mypy (strict).
6
+ # On push: pytest with the 100% coverage gate.
7
+ #
8
+ # Local hooks run through `uv run` so they use this project's dev environment
9
+ # (matching CI) regardless of whether a virtualenv is activated. Requires uv.
10
+ default_install_hook_types: [pre-commit, pre-push]
11
+
12
+ repos:
13
+ - repo: https://github.com/pre-commit/pre-commit-hooks
14
+ rev: v5.0.0
15
+ hooks:
16
+ - id: trailing-whitespace
17
+ - id: end-of-file-fixer
18
+ - id: check-yaml
19
+ - id: check-toml
20
+ - id: check-merge-conflict
21
+ - id: check-added-large-files
22
+
23
+ - repo: local
24
+ hooks:
25
+ - id: ruff-check
26
+ name: ruff (lint, autofix)
27
+ entry: uv run ruff check --fix
28
+ language: system
29
+ types_or: [python, pyi]
30
+ require_serial: true
31
+
32
+ - id: ruff-format
33
+ name: ruff (format)
34
+ entry: uv run ruff format
35
+ language: system
36
+ types_or: [python, pyi]
37
+ require_serial: true
38
+
39
+ - id: mypy
40
+ name: mypy (strict)
41
+ entry: uv run mypy
42
+ language: system
43
+ types: [python]
44
+ pass_filenames: false
45
+
46
+ - id: pytest-coverage
47
+ name: pytest (100% coverage gate)
48
+ entry: uv run pytest --cov --cov-report=term-missing
49
+ language: system
50
+ always_run: true
51
+ pass_filenames: false
52
+ stages: [pre-push]
@@ -0,0 +1,9 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ title: "Inspect Robots YAM: Adapters for I2RT YAM bimanual arms"
4
+ authors:
5
+ - name: "Robocurve"
6
+ type: software
7
+ license: MIT
8
+ repository-code: "https://github.com/robocurve/inspect-robots-yam"
9
+ version: "0.3.0"
@@ -0,0 +1,64 @@
1
+ # inspect-robots-yam — agent guide
2
+
3
+ Inspect Robots adapters that let evals (e.g. [KitchenBench](https://github.com/robocurve/kitchenbench))
4
+ run on real **I2RT YAM bimanual arms** driven by **MolmoAct2**. This is a
5
+ **plugin package** in the Inspect Robots ecosystem — the framework lives in
6
+ [inspect-robots](https://github.com/robocurve/inspect-robots); benchmarks are separate repos
7
+ indexed by [WorldEvals](https://github.com/robocurve/worldevals).
8
+
9
+ ## The one big idea
10
+
11
+ Inspect Robots evals swap two inputs: a `Policy` (VLA brain) and an `Embodiment` (robot
12
+ body + world). We ship both for one real stack:
13
+
14
+ - **`molmoact2` policy** — a thin HTTP client for MolmoAct2's first-party
15
+ bimanual-YAM `/act` server. The model runs in its own process (GPU + weights);
16
+ we never import torch here.
17
+ - **`yam_arms` embodiment** — the i2rt joint-position driver.
18
+
19
+ Both declare the **same 14-D `joint_pos` contract** (2 arms × [6 joints +
20
+ gripper], cameras `top/left/right`, packed `joint_pos` state). That makes
21
+ `inspect_robots.compat.check_compatibility` pass with zero errors **and** zero warnings
22
+ — the property `tests/test_compat.py` locks down.
23
+
24
+ ## Layout
25
+
26
+ - `src/inspect_robots_yam/` — the package (see `src/inspect_robots_yam/CLAUDE.md`).
27
+ - `tests/` — pytest; everything (driver, cameras, `/act`, clock, operator stdin)
28
+ is injected, so the suite needs **no hardware, no server, no stdin**.
29
+ - `plans/0001-yam-molmoact2-design.md` — the design + plan (approved after two
30
+ adversarial subagent critique rounds). Read it before changing the contract.
31
+
32
+ ## Working here
33
+
34
+ - Dev loop: `uv venv && uv pip install -e ".[dev]"`, `uv run pre-commit install`,
35
+ then `uv run pytest --cov`.
36
+ - **Local install gotcha:** `uv pip install -e ".[dev]"` resolves inspect-robots +
37
+ kitchenbench from git tags. To work against sibling checkouts instead:
38
+ `uv pip install -e ../inspect-robots && uv pip install --no-deps -e ../kitchenbench`
39
+ (the `--no-deps` avoids an inspect-robots URL conflict with kitchenbench's own
40
+ `tool.uv.sources`).
41
+ - Gates (all blocking in CI): `ruff check .`, `ruff format --check .`,
42
+ `mypy` (strict), `pytest --cov` at **100%**.
43
+ - **mypy + numpy:** numpy 2.5's stubs use 3.12-only syntax that mypy (py3.10
44
+ target) rejects; the dev extra pins `numpy<2.5` and CI runs mypy on 3.11.
45
+ - **No torch.** The model lives in the MolmoAct2 server. Hardware/client deps
46
+ (`requests`, `json_numpy`, `i2rt`) are optional extras, lazily imported behind
47
+ `# pragma: no cover` seams; the `import-hygiene` CI job enforces that
48
+ `import inspect_robots_yam` works with only inspect_robots + numpy.
49
+
50
+ ## Safety invariants (do not weaken)
51
+
52
+ - `YAMEmbodiment.step()` **always clamps** to `YamConfig.joint_low/high` before
53
+ commanding, independent of any `Approver`. This is the last line of defense.
54
+ - The declared `control_mode` is `joint_pos` (absolute). Delta checkpoints are
55
+ converted to absolute *inside* `step()` (`joints_are_delta=True`) so the
56
+ declared semantics stay honest. There is no `joint_delta` control mode in
57
+ Inspect Robots, so compat cannot verify abs-vs-delta — that's a hardware check.
58
+ - Success reaches the scorer **only** via `StepResult.termination_reason="success"`
59
+ (stock `rollout` never sets `operator_judgement`).
60
+
61
+ ## Out of scope
62
+
63
+ Launching/serving MolmoAct2 (that's the `allenai/molmoact2` repo), single-arm or
64
+ non-YAM I2RT robots, and model fine-tuning.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 RoboCurve
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: inspect-robots-yam
3
+ Version: 0.3.0
4
+ Summary: Inspect Robots adapters for I2RT YAM bimanual arms driven by MolmoAct2.
5
+ Project-URL: Homepage, https://github.com/robocurve/inspect-robots-yam
6
+ Project-URL: Framework, https://github.com/robocurve/inspect-robots
7
+ Project-URL: Collection, https://github.com/robocurve/worldevals
8
+ Author: RoboCurve
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: bimanual,inspect-robots,molmoact,robotics,vla,yam
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: inspect-robots>=0.3
20
+ Requires-Dist: numpy>=1.24
21
+ Provides-Extra: client
22
+ Requires-Dist: json-numpy>=2.1; extra == 'client'
23
+ Requires-Dist: requests>=2.31; extra == 'client'
24
+ Provides-Extra: dev
25
+ Requires-Dist: kitchenbench; extra == 'dev'
26
+ Requires-Dist: mypy>=1.11; extra == 'dev'
27
+ Requires-Dist: numpy<2.5; extra == 'dev'
28
+ Requires-Dist: pre-commit>=3.5; extra == 'dev'
29
+ Requires-Dist: pytest-cov>=5.0; extra == 'dev'
30
+ Requires-Dist: pytest>=8.0; extra == 'dev'
31
+ Requires-Dist: ruff>=0.6; extra == 'dev'
32
+ Provides-Extra: yam
33
+ Requires-Dist: i2rt; extra == 'yam'
34
+ Description-Content-Type: text/markdown
35
+
36
+ <div align="center">
37
+
38
+ # 🦾 inspect-robots-yam
39
+
40
+ **Run [Inspect Robots](https://github.com/robocurve/inspect-robots) evals on real
41
+ [I2RT YAM](https://i2rt.com/products/yam-6-dof-arm) bimanual arms driven by
42
+ [MolmoAct2](https://github.com/allenai/molmoact2).**
43
+
44
+ [![CI](https://github.com/robocurve/inspect-robots-yam/actions/workflows/ci.yml/badge.svg)](https://github.com/robocurve/inspect-robots-yam/actions/workflows/ci.yml)
45
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
46
+ [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/robocurve/inspect-robots-yam/actions/workflows/ci.yml)
47
+ [![Built on Inspect Robots](https://img.shields.io/badge/built%20on-Inspect%20Robots-indigo)](https://github.com/robocurve/inspect-robots)
48
+
49
+ </div>
50
+
51
+ Inspect Robots has **two** swappable inputs: a `Policy` (the VLA brain) and an
52
+ `Embodiment` (the robot body + world). This package provides both for the
53
+ YAM + MolmoAct2 stack, so any embodiment-agnostic Inspect Robots task — e.g. all of
54
+ [KitchenBench](https://github.com/robocurve/kitchenbench) — runs on real arms:
55
+
56
+ - **`molmoact2` policy** — a thin client for MolmoAct2's first-party bimanual-YAM
57
+ `/act` server (the model owns the GPU + weights in its own process).
58
+ - **`yam_arms` embodiment** — the I2RT joint-position driver, with a hard safety
59
+ clamp, operator-in-the-loop success, and self-paced control.
60
+
61
+ Both declare the **same 14-D joint-position contract** (2 arms × [6 joints +
62
+ gripper], cameras `top/left/right`, packed `joint_pos` state), so Inspect Robots's
63
+ compatibility check passes with **zero errors and zero warnings** — verifiable
64
+ before any motion.
65
+
66
+ ```bash
67
+ inspect-robots run --task kitchenbench/pour_pasta --policy molmoact2 --embodiment yam_arms
68
+ ```
69
+
70
+ > **Note:** the CLI forwards scalar `key=value` knobs only — it cannot inject a
71
+ > `camera_reader`, which hardware runs require. Launch from Python (see *Run on
72
+ > hardware*) or register your own entry-point factory that bundles the cameras;
73
+ > otherwise `yam_arms` fails fast with a `ConfigError` at `reset()`, before any
74
+ > driver connect or motion.
75
+
76
+ ## Install (on the robot/GPU machine)
77
+
78
+ ```bash
79
+ # Inspect Robots isn't on PyPI yet; uv resolves it (and the optional i2rt driver) from git.
80
+ uv pip install "inspect-robots-yam[client,yam] @ git+https://github.com/robocurve/inspect-robots-yam"
81
+ ```
82
+
83
+ - `client` → `requests` + `json-numpy` (the `/act` transport).
84
+ - `yam` → the I2RT `i2rt` driver (GitHub-only).
85
+
86
+ Then download the model weights (needs a Hugging Face token) and start the server,
87
+ from the [MolmoAct2 repo](https://github.com/allenai/molmoact2):
88
+
89
+ ```bash
90
+ huggingface-cli download allenai/MolmoAct2-BimanualYAM
91
+ python examples/yam/host_server_yam.py # serves /act on :8202
92
+ ```
93
+
94
+ ## Preflight — *prove compatibility before any motion*
95
+
96
+ ```bash
97
+ inspect-robots-yam-preflight # dims/semantics/cameras/state
98
+ inspect-robots-yam-preflight --task kitchenbench/pour_pasta # + scene realizability
99
+ inspect-robots-yam-preflight --dry-run # affirm no motion
100
+ ```
101
+
102
+ A green preflight means action dim (14), control mode (`joint_pos`), cameras, and
103
+ state keys all line up. **It does not prove the joint values are interpreted the
104
+ same way** — see *Safety* below.
105
+
106
+ ## Run on hardware
107
+
108
+ You must provide a `camera_reader` (there is no universal camera API) returning
109
+ `{"top_cam", "left_cam", "right_cam": HxWx3 uint8}`. From Python:
110
+
111
+ ```python
112
+ from inspect_robots import eval
113
+ from inspect_robots.approver import ClampApprover
114
+ from inspect_robots_yam import MolmoAct2Policy, YAMEmbodiment, YamConfig
115
+
116
+ emb = YAMEmbodiment(YamConfig(left_channel="can0", right_channel="can1"),
117
+ camera_reader=my_camera_reader)
118
+ pol = MolmoAct2Policy(server_url="http://127.0.0.1:8202")
119
+
120
+ (log,) = eval("kitchenbench/pour_pasta", pol, emb,
121
+ approver=ClampApprover(emb.info.action_space)) # defense in depth
122
+ print(log.status, log.results.metrics)
123
+ ```
124
+
125
+ At each episode end the embodiment asks the operator (y/N); a `yes` records
126
+ `termination_reason="success"`, which KitchenBench's `task_success` scorer reads.
127
+ The operator prompts need an interactive terminal — a dead stdin raises
128
+ `EmbodimentFault` (the framework's always-halt path). For runs with no operator,
129
+ set `YamConfig(unattended=True)` (CLI: `-E unattended=true`): all operator
130
+ prompts are skipped and every episode runs to `max_steps`, scoring as a failure.
131
+
132
+ ## Safety
133
+
134
+ - **Hard clamp backstop.** Every command is clipped to `YamConfig.joint_low/high`
135
+ *inside* `step()`, independent of any Inspect Robots `Approver` — unclamped model
136
+ outputs can never reach the motors. **Set the arm slots to your real YAM joint
137
+ limits** (the defaults are conservative placeholders: joints ±π, gripper 0–1) —
138
+ but note the limits are in *policy units* per the table below: gripper slots 6
139
+ and 13 stay normalized 0–1, only slots 0–5 and 7–12 are radians.
140
+ - **Use `ClampApprover`** on hardware for a second layer.
141
+ - **Zero-gravity handoff jump.** The arms connect in zero-gravity mode by default
142
+ (`YamConfig(zero_gravity_mode=True)`, passed through to the i2rt driver), so the
143
+ first stiff PD command — homing or the first action — can jump from wherever the
144
+ arm was idling. Nothing bounds the per-step joint delta yet (tracked as a known
145
+ issue); stand clear at `reset()` and prefer a `home_pose` near the resting pose.
146
+ - **Absolute vs. delta joints — verify first.** MolmoAct2's YAM `actions` are
147
+ treated as **absolute** joint targets by default. If your checkpoint emits
148
+ deltas, set `YamConfig(joints_are_delta=True)` (the embodiment converts to
149
+ absolute internally so the declared `joint_pos` stays honest). Inspect Robots's
150
+ compat check *cannot* tell these apart — confirm with `--dry-run` and a single
151
+ slow jog before running a task.
152
+ - **Gripper polarity/trim.** The i2rt driver already exposes the YAM gripper as
153
+ normalized 0–1 in both directions, so the defaults (`gripper_open=0.0`,
154
+ `gripper_closed=1.0`) are an identity map and correct for standard grippers.
155
+ `YamConfig(gripper_open=..., gripper_closed=...)` is a polarity/trim remap over
156
+ that already-normalized range — its main use is a gripper wired with inverted
157
+ polarity (`gripper_open=1.0, gripper_closed=0.0`). The remap is a bijection:
158
+ commands are de-normalized on the way out and observations are re-normalized on
159
+ the way back, so the model always sees 0–1. **Warning:** values outside [0, 1]
160
+ are forwarded on a path i2rt does *not* clip — avoid them unless you have
161
+ verified your firmware's behavior.
162
+
163
+ ## Configuration
164
+
165
+ ### Units — every 14-D vector uses the same layout
166
+
167
+ `joint_low`/`joint_high`, `home_pose`, actions, and the observed `joint_pos`
168
+ state all use *policy units*:
169
+
170
+ | Slots | Meaning | Unit |
171
+ |-------|---------|------|
172
+ | 0–5, 7–12 | left / right arm revolute joints | radians |
173
+ | 6, 13 | left / right gripper | normalized 0–1 (0 = open, 1 = closed) |
174
+
175
+ Hardware gripper units (via `gripper_open`/`gripper_closed`) exist only at the
176
+ driver boundary; nothing you configure here is in hardware gripper units.
177
+
178
+ `YamConfig`: `left_channel`, `right_channel`, `gripper_type` (i2rt `GripperType`
179
+ enum *name*, e.g. `LINEAR_4310`; grippers only — `NO_GRIPPER`/`YAM_TEACHING_HANDLE`
180
+ would break the 14-D packing and are rejected), `control_hz`, `cam_height/width`,
181
+ `joint_low/high`, `home_pose`, `gripper_open/closed`, `joints_are_delta`,
182
+ `zero_gravity_mode` (default `True`; see *Safety*), `unattended` (default `False`;
183
+ skip operator prompts).
184
+ `MolmoActConfig`: `server_url`, `endpoint`, `num_steps`, `timeout_s`,
185
+ `camera_order`, `state_key`, `cam_height/width`.
186
+
187
+ Scalar knobs are settable from the CLI:
188
+ `inspect-robots run -P server_url=http://gpu:8202 -E left_channel=can0 ...`.
189
+
190
+ ## Development
191
+
192
+ ```bash
193
+ uv venv && uv pip install -e ".[dev]" # inspect_robots + kitchenbench from git tags
194
+ uv run pre-commit install
195
+ uv run pytest --cov # 100% coverage required
196
+ uv run ruff check . && uv run mypy
197
+ ```
198
+
199
+ The whole suite runs with **no hardware, no server, and no stdin** — the i2rt
200
+ driver, cameras, the `/act` transport, the clock, and operator I/O are all
201
+ injected. The default hardware seams are excluded from coverage (`# pragma: no
202
+ cover`).
203
+
204
+ ## Citation
205
+
206
+ If you use Inspect Robots YAM in your research, please cite it:
207
+
208
+ ```bibtex
209
+ @software{inspect-robots-yam,
210
+ author = {Robocurve},
211
+ title = {Inspect Robots YAM: Adapters for I2RT YAM bimanual arms},
212
+ year = {2026},
213
+ url = {https://github.com/robocurve/inspect-robots-yam},
214
+ version = {0.3.0},
215
+ license = {MIT}
216
+ }
217
+ ```
218
+
219
+ ## License
220
+
221
+ [MIT](LICENSE)