--- a
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,140 @@
+name: 'Tests'
+concurrency:
+  group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }}
+  cancel-in-progress: true
+on:  # yamllint disable-line rule:truthy
+  push:
+    branches: ["main", "maint/*"]
+  pull_request:
+    branches: ["main", "maint/*"]
+
+permissions:
+  contents: read
+
+jobs:
+  style:
+    name: Style
+    runs-on: ubuntu-latest
+    timeout-minutes: 3
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+      - uses: actions/setup-python@v5
+        with:
+          python-version: '3.12'
+      - uses: pre-commit/action@v3.0.1
+      - run: pip install mypy numpy scipy vulture
+      - run: mypy
+      - run: vulture
+
+  bandit:
+    name: Bandit
+    needs: style
+    runs-on: ubuntu-latest
+    steps:
+      - uses: davidslusser/actions_python_bandit@v1.0.1
+        with:
+          src: "mne"
+          options: "-c pyproject.toml -ll -r"
+          pip_install_command: "pip install bandit[toml]"
+
+  pytest:
+    name: '${{ matrix.os }} / ${{ matrix.kind }} / ${{ matrix.python }}'
+    needs: style
+    timeout-minutes: 80
+    runs-on: ${{ matrix.os }}
+    defaults:
+      run:
+        shell: bash -el {0}
+    env:
+      PYTHON_VERSION: '${{ matrix.python }}'
+      MKL_NUM_THREADS: '1'
+      OPENBLAS_NUM_THREADS: '1'
+      PYTHONUNBUFFERED: '1'
+      MNE_CI_KIND: '${{ matrix.kind }}'
+      CI_OS_NAME: '${{ matrix.os }}'
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - os: ubuntu-latest
+            python: '3.13'
+            kind: pip
+          - os: ubuntu-latest
+            python: '3.12'
+            kind: pip-pre
+          - os: ubuntu-latest
+            python: '3.12'
+            kind: conda
+          - os: macos-latest  # arm64 (Apple Silicon)
+            python: '3.12'
+            kind: mamba
+          - os: macos-13  # latest Intel release
+            python: '3.12'
+            kind: mamba
+          - os: windows-latest
+            python: '3.10'
+            kind: mamba
+          - os: ubuntu-latest
+            python: '3.10'
+            kind: minimal
+          - os: ubuntu-22.04
+            python: '3.10'
+            kind: old
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+          persist-credentials: false
+      - run: ./tools/github_actions_env_vars.sh
+      # Xvfb/OpenGL
+      - uses: pyvista/setup-headless-display-action@v3
+        with:
+          qt: true
+          pyvista: false
+          wm: false
+      # Python (if pip)
+      - uses: actions/setup-python@v5
+        with:
+          python-version: ${{ matrix.python }}
+        if: startswith(matrix.kind, 'pip')
+      # Python (if conda)
+      - name: Fixes for conda
+        run: |
+          # For some reason on Linux we get crashes
+          if [[ "$RUNNER_OS" == "Linux" ]]; then
+            sed -i "/numba/d" environment.yml
+          elif [[ "$RUNNER_OS" == "macOS" ]]; then
+            sed -i "" "s/  - PySide6 .*/  - PySide6 <6.8/g" environment.yml
+          fi
+        if: matrix.kind == 'conda' || matrix.kind == 'mamba'
+      - uses: mamba-org/setup-micromamba@v2
+        with:
+          environment-file: ${{ env.CONDA_ENV }}
+          environment-name: mne
+          create-args: >-
+            python=${{ env.PYTHON_VERSION }}
+        if: ${{ !startswith(matrix.kind, 'pip') }}
+      - run: bash ./tools/github_actions_dependencies.sh
+      # Minimal commands on Linux (macOS stalls)
+      - run: bash ./tools/get_minimal_commands.sh
+        if: startswith(matrix.os, 'ubuntu') && matrix.kind != 'minimal' && matrix.kind != 'old'
+      - run: bash ./tools/github_actions_infos.sh
+      # Check Qt
+      - run: bash ./tools/check_qt_import.sh $MNE_QT_BACKEND
+        if: env.MNE_QT_BACKEND != ''
+      - name: Run tests with no testing data
+        run: MNE_SKIP_TESTING_DATASET_TESTS=true pytest -m "not (ultraslowtest or pgtest)" --tb=short --cov=mne --cov-report xml -vv -rfE mne/
+        if: matrix.kind == 'minimal'
+      - run: ./tools/get_testing_version.sh
+      - uses: actions/cache@v4
+        with:
+          key: ${{ env.TESTING_VERSION }}
+          path: ~/mne_data
+      - run: bash ./tools/github_actions_download.sh
+      - run: bash ./tools/github_actions_test.sh  # for some reason on macOS we need to run "bash X" in order for a failed test run to show up
+      - uses: codecov/codecov-action@v5
+        with:
+          token: ${{ secrets.CODECOV_TOKEN }}
+        if: success() || failure()