Skip to content
Latchkey

Linux workflow (AgileRL/AgileRL)

The Linux workflow from AgileRL/AgileRL, explained and optimized by Latchkey.

B

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 →
Source: AgileRL/AgileRL.github/workflows/linux-tests.ymlLicense Apache-2.0View source

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

workflow (.yml)
---
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

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.

Actions used in this workflow