Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/precommit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Precommit

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
precommit:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6

- uses: prefix-dev/setup-pixi@v0.9.3

Check failure on line 18 in .github/workflows/precommit.yml

View workflow job for this annotation

GitHub Actions / Run Zizmor

unpinned-uses

precommit.yml:18: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
pixi-version: latest
cache: true

# ── Stubs cache ────────────────────────────────────────────────
- name: Restore typings cache
uses: actions/cache@v5
id: typings-cache
with:
path: typings
key: typings-${{ hashFiles('pyproject.toml') }}

- name: Generate stubs if cache miss
if: steps.typings-cache.outputs.cache-hit != 'true'
run: pixi run pybind11-stubgen mujoco -o typings/

# ── Pre-commit (ruff lint, ruff format, trailing whitespace, etc.)
- name: Run pre-commit
run: pixi run pre-commit run --all-files

# ── Type checking ──────────────────────────────────────────────
- name: Run Pyright
run: pixi run pyright sumo/
48 changes: 48 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Test

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v6

- uses: prefix-dev/setup-pixi@v0.9.3

Check failure on line 19 in .github/workflows/test.yml

View workflow job for this annotation

GitHub Actions / Run Zizmor

unpinned-uses

test.yml:19: unpinned action reference: action is not pinned to a hash (required by blanket policy)
with:
pixi-version: latest
cache: true

# ── Build C++ extensions ──────────────────────────────────────
- name: Restore build cache
id: ext-cache
uses: actions/cache@v5
with:
path: |
g1_extensions/build
key: build-${{ hashFiles('pixi.lock', 'g1_extensions/**/*.cpp', 'g1_extensions/**/*.h', 'g1_extensions/**/CMakeLists.txt') }}

- name: Build extensions
run: pixi run build

# ── Download mesh assets ──────────────────────────────────────
- name: Download meshes from release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: pixi run python -c "from judo.utils.assets import download_and_extract_meshes; from judo import MODEL_PATH; download_and_extract_meshes(str(MODEL_PATH))"

# ── Pre-warm robot_descriptions cache ─────────────────────────
- name: Cache mujoco_menagerie meshes
run: pixi run python -c "from robot_descriptions import spot_mj_description"

# ── Tests ─────────────────────────────────────────────────────
- name: Run tests
run: pixi run pytest -rsx
220 changes: 220 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# macOS
.DS_Store

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
#uv.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
#poetry.toml

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
#pdm.lock
#pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
#pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/

# Ruff stuff:
.ruff_cache/

# PyPI configuration file
.pypirc

# Cursor
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
# refer to https://docs.cursor.com/context/ignore-files
.cursorignore
.cursorindexingignore

# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/

# judo source checkout for building mujoco_extensions
.judo-src/

out/
outputs/

# typings
# see: https://github.com/google-deepmind/mujoco/issues/1292
typings/
17 changes: 17 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.11.8
hooks:
- id: ruff
types_or: [ python, pyi, jupyter ]
args: [ --fix, --config=pyproject.toml ]
- id: ruff-format
types_or: [ python, pyi, jupyter ]
args: [ --config=pyproject.toml ]
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Repository Guidelines

## Project Structure & Module Organization
`sumo/` is the active package. Put task code in `sumo/tasks/g1/` or `sumo/tasks/spot/`, controller wrappers in `sumo/controller/`, CLI and MPC entrypoints in `sumo/cli.py` and `sumo/run_mpc/`, and MuJoCo XML/mesh assets under `sumo/models/`. `g1_extensions/` contains the optional pybind11 extension for G1 backends. `tests/` holds the pytest suite. Treat `judo-private/` as an old fork used only as migration reference; match new code to the public `judo-rai` repo instead. Use `.judo-src/` as the local reference checkout when porting behavior.

## Build, Test, and Development Commands
Use `pixi` by default:

```bash
pixi install
pixi run build
pixi run build-judo-ext
pixi run pytest tests/ -v
pixi run sumo --init-task g1_box --num-episodes 1
```

`pixi run build` compiles `g1_extensions`; `pixi run build-judo-ext` builds Judo's `mujoco_extensions` backend for Spot tasks. `pixi install -e dev` remains equivalent to `pixi install` for this repo, but `pixi run` without `-e` already targets the default full app environment. Use `pip install -e .` only as a lightweight fallback when you do not need the managed `pixi` environment.

## Coding Style & Naming Conventions
Write Python with 4-space indentation, explicit imports, and type-aware dataclass configs. Follow existing naming: `snake_case` for modules/functions, `PascalCase` for classes, and `*Config` for task/config dataclasses such as `G1BoxConfig`. New task modules should follow patterns like `g1_box.py` or `spot_table_drag.py`. Prefer `ruff check .` before submitting changes. When porting code, preserve `judo-rai` APIs and conventions first, even if `judo-private/` differs.

## Testing Guidelines
Add tests in `tests/` and name files `test_*.py`. Cover imports, task registration, and task-specific behavior such as `reset()`, `reward()`, and control shape. Mark extension-only tests with `@pytest.mark.g1_extensions`; `tests/conftest.py` skips them when `g1_extensions` is unavailable. When adding a task, update registration in `sumo/tasks/__init__.py` and add at least one smoke test.

## Commit & Pull Request Guidelines
The repo history is minimal, so use short imperative commit subjects. Scoped messages are preferred, for example `feat(tasks): port spot_table_drag`. PRs should summarize the port or feature, note what was aligned to public `judo-rai`, list commands run, and include screenshots or logs for simulator-facing changes. Avoid mixing migration cleanup with unrelated refactors.
Loading
Loading