Linux workflow (AgileRL/AgileRL)
The Linux workflow from AgileRL/AgileRL, explained and optimized by Latchkey.
CI health: B - good
Run this on Latchkey for self-healing, caching, and up to 58% lower cost.
Grade your own workflow free or run it on Latchkey →What it does
This is the Linux workflow from the AgileRL/AgileRL repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
---
name: Linux
on:
push:
branches: [main, nightly]
paths:
- agilerl/**
- tests/**
- .github/workflows/**
- pyproject.toml
pull_request:
paths:
- agilerl/**
- tests/**
- .github/workflows/**
- pyproject.toml
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
tests:
runs-on: gha-runner-scale-set
strategy:
fail-fast: false
max-parallel: 4
matrix:
python-version: ['3.10', '3.11', '3.12', '3.13']
container:
image: pytorch/pytorch:2.11.0-cuda13.0-cudnn9-devel
options: --user root
# Workspace (/__w) is ~1GB with little free space; root (/) has plenty. Put cache and venv on /.
env:
UV_CACHE_DIR: /tmp/uv-cache
UV_PROJECT_ENVIRONMENT: /tmp/agilerl-venv
HF_HOME: /tmp/hf-cache
TORCHINDUCTOR_CACHE_DIR: /tmp/inductor-cache
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v7
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
- name: Cache HuggingFace models
uses: actions/cache@v4
with:
path: /tmp/hf-cache
key: hf-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: hf-${{ matrix.python-version }}-
- name: Cache torch inductor compilations
uses: actions/cache@v4
with:
path: /tmp/inductor-cache
key: inductor-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
restore-keys: inductor-${{ matrix.python-version }}-
- name: Install dependencies
# swig is needed to build box2d-py from source (no pre-built wheels for py3.10+).
run: |
uv sync --locked --all-groups --extra all
echo "$UV_PROJECT_ENVIRONMENT/bin" >> $GITHUB_PATH
- name: Reset coverage data
run: rm -f .coverage .coverage.*
# Single phase: `-n auto --dist loadgroup` from pyproject gives 8
# workers on the gha-runner-scale-set node. `vllm`- and `gpu`-marked
# tests share the 4 `gputest0..gputest3` xdist groups defined in
# `tests/conftest.py`, which caps GPU-touching concurrency at 4
# workers regardless of -n; the remaining ~4 workers fan out across
# CPU-only tests. See the `pytest_collection_modifyitems` docstring
# for the GPU-memory and port-race rationale behind the 4-group cap.
#
# Single invocation = single coverage run; pytest-cov auto-combines
# the per-worker `.coverage.*` shards before writing `coverage.xml`,
# so we don't need a manual `coverage combine` step (which was
# tripping over corrupted shards under the old two-phase setup).
- name: Run tests
run: uv run pytest --exitfirst --cov=agilerl --cov-report=xml --durations=0 --durations-min=1.0
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
--- name: Linux on: push: branches: [main, nightly] paths: - agilerl/** - tests/** - .github/workflows/** - pyproject.toml pull_request: paths: - agilerl/** - tests/** - .github/workflows/** - pyproject.toml concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} cancel-in-progress: true permissions: contents: read jobs: tests: timeout-minutes: 30 runs-on: gha-runner-scale-set strategy: fail-fast: false max-parallel: 4 matrix: python-version: ['3.10', '3.11', '3.12', '3.13'] container: image: pytorch/pytorch:2.11.0-cuda13.0-cudnn9-devel options: --user root # Workspace (/__w) is ~1GB with little free space; root (/) has plenty. Put cache and venv on /. env: UV_CACHE_DIR: /tmp/uv-cache UV_PROJECT_ENVIRONMENT: /tmp/agilerl-venv HF_HOME: /tmp/hf-cache TORCHINDUCTOR_CACHE_DIR: /tmp/inductor-cache steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v7 with: enable-cache: true python-version: ${{ matrix.python-version }} - name: Cache HuggingFace models uses: actions/cache@v4 with: path: /tmp/hf-cache key: hf-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} restore-keys: hf-${{ matrix.python-version }}- - name: Cache torch inductor compilations uses: actions/cache@v4 with: path: /tmp/inductor-cache key: inductor-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} restore-keys: inductor-${{ matrix.python-version }}- - name: Install dependencies # swig is needed to build box2d-py from source (no pre-built wheels for py3.10+). run: | uv sync --locked --all-groups --extra all echo "$UV_PROJECT_ENVIRONMENT/bin" >> $GITHUB_PATH - name: Reset coverage data run: rm -f .coverage .coverage.* # Single phase: `-n auto --dist loadgroup` from pyproject gives 8 # workers on the gha-runner-scale-set node. `vllm`- and `gpu`-marked # tests share the 4 `gputest0..gputest3` xdist groups defined in # `tests/conftest.py`, which caps GPU-touching concurrency at 4 # workers regardless of -n; the remaining ~4 workers fan out across # CPU-only tests. See the `pytest_collection_modifyitems` docstring # for the GPU-memory and port-race rationale behind the 4-group cap. # # Single invocation = single coverage run; pytest-cov auto-combines # the per-worker `.coverage.*` shards before writing `coverage.xml`, # so we don't need a manual `coverage combine` step (which was # tripping over corrupted shards under the old two-phase setup). - name: Run tests run: uv run pytest --exitfirst --cov=agilerl --cov-report=xml --durations=0 --durations-min=1.0 - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
What changed
- Add a job timeout so a hung step cannot burn hours of runner time.
2 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
This workflow runs 1 job (4 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.