CI Perf Lint

Rule documentation

Rules

Current explainers for workflow and repository-wide findings. These docs describe what gets flagged, why it matters, and how to verify improvements.

249Total rules

Repository-wide and workflow findings. Open a rule to see what gets flagged, suggested action, and verification guidance.

async-test-uses-sync-testclient

async-test-uses-sync-testclient

Detects `async def test_*` functions under `tests/` that instantiate `TestClient(...)`.

avoid-brew-update-on-hosted-macos

avoid-brew-update-on-hosted-macos

Flags GitHub-hosted macOS jobs that run `brew update` or `brew upgrade` during CI.

avoid-broad-upload-artifact

avoid-broad-upload-artifact

Detects `actions/upload-artifact` steps that upload very broad paths (`.`, `./`, `*`, or `**`) without an error-condition guard.

avoid-c-drive-on-windows-runner

avoid-c-drive-on-windows-runner

Avoid hardcoding `C:\` drive paths on Windows runners.

avoid-docker-image-via-uses

avoid-docker-image-via-uses

Steps using `uses: owner/repo` without `@ref`, `docker://`, or `./` qualifier.

avoid-eslint-plugin-prettier

avoid-eslint-plugin-prettier

Flags repositories whose visible ESLint config appears to wire Prettier into ESLint.

avoid-lucide-angular-icons-registry

avoid-lucide-angular-icons-registry

Flags `icons` registry imports from `lucide-angular`.

avoid-lucide-dynamic-icon

avoid-lucide-dynamic-icon

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect `lucide-react/dynamic`.

avoid-mui-barrel-imports

avoid-mui-barrel-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` with Material UI's recommended top-level package restriction.

avoid-mypy-production-bundle

avoid-mypy-production-bundle

Detects mypy declared in production dependency sections or bundled into CDK deployment assets.

avoid-prettier-eslint

avoid-prettier-eslint

Flags repositories whose visible dependencies or config still indicate `prettier-eslint`, or workflows that call `prettier-eslint` directly.

avoid-svg-component-imports

avoid-svg-component-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect SVG imports that turn asset files into React, Vue, or similar framework components.

avoid-xcode-install-on-hosted-macos

avoid-xcode-install-on-hosted-macos

Flags GitHub-hosted macOS jobs that visibly install or download Xcode during CI.

bundler-external-subpath-leak

bundler-external-subpath-leak

Rollup/Vite and webpack literal external entries match module IDs exactly. An external `"react"` does not necessarily externalize an imported `"react/jsx-runtime"`. Uncovered subpaths can add dependency code and build work to artifacts.

cache-terraform-providers

cache-terraform-providers

Detects jobs that run `terraform init` without caching the downloaded provider plugins.

cargo-build-before-test

cargo-build-before-test

Detects redundant `cargo build` steps that immediately precede `cargo test` with identical build conditions.

cdk-asset-waste-files

cdk-asset-waste-files

CDK assets contain unnecessary files that inflate deployment package size.

cdk-bucket-deployment-memory-unconfigured

cdk-bucket-deployment-memory-unconfigured

CDK code that uses `BucketDeployment` without setting the `memoryLimit` property, on projects where the memory default is still relevant.

CDK Duplicate Asset Hash

cdk-duplicate-asset-hash

Detects multiple CDK assets with the same `sourceHash` in `cdk.out/manifest.json`.

circleci-checkout-uses-full-clone

circleci-checkout-uses-full-clone

CircleCI defaults to a blobless clone (`method: blobless`), which fetches only the reachable objects for the current commit. This is equivalent to `git clone --filter=blob:none` and is faster and uses less data than a full clone.

collapse-multiple-go-builds-in-job

collapse-multiple-go-builds-in-job

Detects CI jobs that run multiple separate `go build` commands.

consider-caching-os-packages-or-using-a-custom-image

consider-caching-os-packages-or-using-a-custom-image

Flags jobs that repeatedly install OS packages at runtime without visible package caching or a prebuilt image strategy.

consider-filter-blob-none-for-release-metadata

consider-filter-blob-none-for-release-metadata

Flags history-aware metadata jobs that may be able to use checkout `filter: blob:none`.

consider-msw-3-upgrade

consider-msw-3-upgrade

MSW version evidence uses the root lockfile dependency where available, and ignores unrelated aliases and unresolved package protocols.

consider-mypy-2-upgrade

consider-mypy-2-upgrade

Suggests planning a mypy 2.x upgrade for repositories still on mypy 1.x.

consider-rust-nightly-parallel-frontend

consider-rust-nightly-parallel-frontend

Cargo compiles independent crates in parallel already. When a large crate remains on the critical path, parallel work inside rustc's frontend may use otherwise idle cores. This is a benchmark candidate, not a guaranteed speedup: CPU availability, cache state, and memory pressure affect results.

consider-slim-over-alpine-for-ci

consider-slim-over-alpine-for-ci

Flags CI jobs that run inside a visible Alpine or musl-based container image.

cuda-torch-install-on-cpu-runner

cuda-torch-install-on-cpu-runner

Flags standard Ubuntu x64 GitHub-hosted jobs that install PyTorch directly without a CPU-only index, pulling the CUDA build and its NVIDIA dependencies onto a runner that has no GPU.

cypress-github-action-uses-npm-run

cypress-github-action-uses-npm-run

A repository pins a package manager through its lockfile or `packageManager` field. When a `cypress-io/github-action` step still builds or starts the app through `npm`, the test run depends on a second, unpinned toolchain: npm may not be installed in CI, and even when it is, it adds an inconsistent startup path next to the package manager the rest of the pipeline uses.

db-io-reduce

db-io-reduce

Database service containers and ad-hoc `docker run` commands in CI write to disk by default. On GitHub Actions hosted runners, this causes unnecessary I/O overhead that can significantly slow down test suites.

deep-checkout-excessive-depth

deep-checkout-excessive-depth

Detects `actions/checkout` configured with `fetch-depth >= 1000` when the job does not appear to need that much history.

deep-checkout-without-need

deep-checkout-without-need

Detects `actions/checkout` configured with `fetch-depth: 0` when the job does not appear to need full git history.

detected-large-barrel-file

detected-large-barrel-file

This repository-wide finding comes from an embedded `oxlint` scan using `oxc/no-barrel-file`.

detected-large-files

detected-large-files

This repository-wide finding flags excessive large data and binary files that bloat git clone and checkout operations.

docker-bake-file-unused-in-ci

docker-bake-file-unused-in-ci

Detects repositories that have a Docker bake file while CI bypasses it with direct Docker image builds.

Docker build cache disabled in CI

docker-build-cache-disabled-in-ci

Routine Docker builds should reuse cache whenever possible. `--no-cache` and build action `no-cache: true` force every layer to rebuild, even when the Dockerfile and copied files are unchanged.

Docker build loads image into daemon unnecessarily

docker-build-load-true-unnecessary

`docker/build-push-action` with `load: true` loads the built image into the local Docker daemon. This adds serialization overhead and is only needed when a subsequent step in the same job uses the image locally (e.g., `docker run`, `docker compose`, `docker tag`, `docker save`).

docker-build-without-layer-cache

docker-build-without-layer-cache

Detects `docker/build-push-action` steps that do not configure `cache-from` and `cache-to`.

docker-cache-copy-path-mismatch

docker-cache-copy-path-mismatch

Detects Dockerfiles that COPY a Gradle or Maven build configuration file that does not exist in the repository, when an alternative with a different extension does exist.

docker-gha-cache-scope-collision

docker-gha-cache-scope-collision

Docker's GHA exporter defaults to `scope=buildkit`. If an API image and a worker image each export to that scope, the later export replaces the earlier cache record. Different image tags or job names do not create separate scopes automatically. This can reduce cache reuse for the next build of the other image, whether the exports run sequentially or concurrently.

Dockerfile local ADD without clear need

dockerfile-add-without-clear-need

`ADD` has extra behavior for remote URLs and archive extraction. For ordinary local files and directories, `COPY` is more explicit and avoids accidentally doing extra work in the Docker build.

dockerfile-apk-add-without-no-cache-or-cache-mount

dockerfile-apk-add-without-no-cache-or-cache-mount

Detects direct `apk add` commands in shell or JSON-form Dockerfile `RUN` and `ONBUILD RUN` instructions that do not use `--no-cache` or a BuildKit cache/tmpfs mount covering the effective apk cache directory.

dockerfile-apt-install-without-cleanup-or-cache-mount

dockerfile-apt-install-without-cleanup-or-cache-mount

apt lists retained in an output image increase layer storage and transfer work. Deleting files in a later `RUN` does not remove them from the earlier layer. BuildKit cache mounts can preserve repeated package-manager work without baking metadata into the image.

Dockerfile apt install without no-install-recommends

dockerfile-apt-install-without-no-install-recommends

`apt-get install` installs recommended packages by default. In CI-built Docker images, those extra packages often increase layer size without improving the runtime image.

Dockerfile apt install without version pin

dockerfile-apt-install-without-version-pin

Without version constraints, an apt install may select different package versions when an image layer is rebuilt. Constraints can limit dependency drift and make rebuild behavior more predictable. Pinning alone does not guarantee cache hits, faster builds, or reproducibility of the entire image.

Dockerfile base image uses floating tag

dockerfile-base-image-uses-floating-tag

Untagged base images and `:latest` can move to new content independently of the repository. That makes rebuilds less predictable and can invalidate Docker cache layers even when application code has not changed.

Dockerfile Bun install without cleanup or cache mount

dockerfile-bun-install-without-cleanup-or-cache-mount

Bun's global registry cache is separate from installed dependencies but can persist in image layers. Externalizing it can retain rebuild reuse without packaging the download cache.

dockerfile-bun-install-without-frozen-lockfile

dockerfile-bun-install-without-frozen-lockfile

Detects Node Dockerfiles that run Bun dependency installation without frozen lockfile behavior while a Bun lockfile is available in the Docker build context.

dockerfile-bundle-install-without-cache-mount

dockerfile-bundle-install-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-cargo-build-release-without-cache-mount

dockerfile-cargo-build-release-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-cargo-install-without-locked

dockerfile-cargo-install-without-locked

Detects Rust Dockerfiles that install external Rust tools with `cargo install` without `--locked`.

Dockerfile compiled build copies source layer

dockerfile-compiled-build-copies-source-layer

Build inputs used only to produce artifacts do not need their own persisted source layer. A read-only bind mount can reduce intermediate snapshot and cache-export costs, including on disposable CI builders. Input changes still invalidate the build RUN. A final image already containing only artifacts may be unchanged, and the same source files still need to be transferred as build context.

Dockerfile consecutive RUN instructions

dockerfile-consecutive-run-instructions

Separate `RUN` instructions create separate filesystem layers. Downloading a file in one layer and deleting it in another does not remove the file from the earlier layer. Separating package index updates from installs can also reuse stale metadata.

dockerfile-copies-all-before-deps

dockerfile-copies-all-before-deps

Detects Dockerfiles that copy broad source context before dependency installation.

dockerfile-copy-link-without-cache-benefit

dockerfile-copy-link-without-cache-benefit

Detects `COPY --link` instructions whose cache benefit is unlikely to beat their build graph overhead.

dockerfile-extracts-copied-archive

dockerfile-extracts-copied-archive

Copying an archive into a layer, then extracting and deleting it in a later RUN, still stores the archive in the earlier COPY layer. A temporary extraction input can avoid that snapshot and its cache-export work. Output image bytes only decrease when the COPY layer belongs to the output stage's rootfs ancestry; artifact-only builders may only benefit in intermediate build storage/export.

dockerfile-final-stage-copies-broad-context

dockerfile-final-stage-copies-broad-context

Detects Dockerfiles where the final image stage copies the broad build context.

dockerfile-go-build-without-cache-mount

dockerfile-go-build-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-go-mod-download-without-cache-mount

dockerfile-go-mod-download-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-gradle-build-without-cache-mount

dockerfile-gradle-build-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-gradle-dependencies-without-cache-mount

dockerfile-gradle-dependencies-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-maven-build-without-cache-mount

dockerfile-maven-build-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

dockerfile-maven-go-offline-without-cache-mount

dockerfile-maven-go-offline-without-cache-mount

Warnings require a CI-discovered build with a [recognized persistent builder path](../docker-cache-mount-persistence.md): Depot, configured Blacksmith, or repository-visible Buildkite local Docker state persistence. Unknown/disposable builders are not flagged for missing cache mounts.

Dockerfile npm install without cleanup or cache mount

dockerfile-npm-install-without-cleanup-or-cache-mount

npm's download cache is separate from installed `node_modules` and can persist in image layers. Keeping it outside the layer preserves rebuild reuse without packaging the cache.

Dockerfile pip install without no-cache or cache mount

dockerfile-pip-install-without-no-cache-or-cache-mount

pip's download and wheel caches can remain in Docker image layers, adding storage and transfer costs. Docker layer caching does not require those files to be stored inside the image. A BuildKit cache mount preserves package-cache reuse outside the layer.

Dockerfile pnpm install without cleanup or cache mount

dockerfile-pnpm-install-without-cleanup-or-cache-mount

pnpm's content-addressable package store may persist in image layers alongside installed dependencies. An external store can reduce intermediate storage and transfer work while retaining rebuild reuse.

dockerfile-pnpm-install-without-frozen-lockfile

dockerfile-pnpm-install-without-frozen-lockfile

Detects Node Dockerfiles that run `pnpm install` without `--frozen-lockfile` while `pnpm-lock.yaml` is available in the Docker build context.

dockerfile-rpm-install-without-cleanup-or-cache-mount

dockerfile-rpm-install-without-cleanup-or-cache-mount

yum, dnf, microdnf and zypper can retain repository metadata and package caches in image layers. Removing them in a later `RUN` cannot reclaim the bytes in the earlier layer. Retained data adds storage, export, push, pull and extraction work.

Dockerfile RUN cd instead of WORKDIR

dockerfile-run-cd-instead-of-workdir

Each shell-form `RUN` starts a new shell. A leading `cd` changes only that shell's directory; it does not affect later Dockerfile instructions. `WORKDIR` makes a persistent directory explicit and can avoid accidental builds in the wrong directory. It does not inherently reduce layer count or guarantee faster builds.

dockerfile-runtime-copies-builder-rootfs

dockerfile-runtime-copies-builder-rootfs

`COPY --from=build / /` copies the builder's merged filesystem, including any compiler, source and build-only files still present. If the output image only needs the compiled application and runtime assets, this creates avoidable snapshot, export, push, pull and extraction work.

dockerfile-runtime-image-uses-heavy-base

dockerfile-runtime-image-uses-heavy-base

Full language images and SDK images carry development tools and system packages that may not be needed to run the application. A smaller runtime image can reduce cold pulls, extraction, pushes, and storage. It does not necessarily improve application execution or cached rebuild speed.

dockerfile-runtime-inherits-build-environment

dockerfile-runtime-inherits-build-environment

Building an executable and running it in the same stage ancestry ships the compiler base and build layers with the application. An independent runtime stage can reduce final image size, cold pulls, extraction, and pushes. Merely writing `FROM builder AS runtime` keeps the builder's layers.

dockerfile-useradd-high-uid-without-no-log-init

dockerfile-useradd-high-uid-without-no-log-init

`useradd` normally initializes lastlog/faillog entries. With a large UID, these can become logically large sparse files. Docker documents a sparse-file export issue that can expand `/var/log/faillog` in a container layer, increasing image storage and export/transfer work. The effect depends on the base image's account tools, configuration and exporter.

dockerfile-uses-npm-install-with-lockfile

dockerfile-uses-npm-install-with-lockfile

Detects Node Dockerfiles that run project-level `npm install`-style commands while `package-lock.json` is available in the Docker build context.

Dockerfile uv install without no-cache or cache mount

dockerfile-uv-install-without-no-cache-or-cache-mount

uv downloads and build artifacts can remain in image layers. BuildKit cache mounts retain rebuild reuse outside the layer.

dockerfile-uv-sync-without-frozen-lockfile

dockerfile-uv-sync-without-frozen-lockfile

Detects Python Dockerfiles that run project-level `uv sync` without frozen or locked lockfile behavior while `uv.lock` is available in the Docker build context.

Dockerfile Yarn install without cleanup or cache mount

dockerfile-yarn-install-without-cleanup-or-cache-mount

Yarn Classic's download cache can remain in image layers alongside `node_modules`. Modern Yarn PnP and zero-install archives may instead be runtime dependencies and must not be treated as disposable downloads.

dockerfile-yarn-install-without-immutable-lockfile

dockerfile-yarn-install-without-immutable-lockfile

Detects Node Dockerfiles that run Yarn dependency installation without a lockfile-immutable flag while `yarn.lock` is available in the Docker build context.

dockerignore-misses-noisy-build-context-paths

dockerignore-misses-noisy-build-context-paths

Detects Docker build contexts where a `.dockerignore` file exists but still allows noisy root paths into the build context.

duplicate-checkout-in-same-workflow

duplicate-checkout-in-same-workflow

Detects multiple non-matrix jobs that each perform checkout before similar install-heavy work inside one workflow.

duplicate-install-or-lint

duplicate-install-or-lint

Detects non-matrix jobs that repeat the same dependency install and lint combination within one workflow.

elixir-otp-version-performance

elixir-otp-version-performance

Detects outdated Elixir and OTP (Erlang) versions across your CI configuration, Dockerfiles, and `.tool-versions` files.

go-build-before-race-test

go-build-before-race-test

Detects broad `go build ./...` steps that run before broad race-enabled Go tests.

go-test-broad-package-serial-p-one

go-test-broad-package-serial-p-one

Detects broad Go test runs that serialize package execution with `-p 1`.

go-test-repeats-vet-after-go-vet

go-test-repeats-vet-after-go-vet

Detects Go CI jobs that run `go vet` and then run `go test` without `-vet=off`.

gradle-parallel-not-enabled

gradle-parallel-not-enabled

Detects multi-project Gradle repositories that do not have parallel build execution enabled.

hatch-without-uv-installer

hatch-without-uv-installer

Flags repositories and CI jobs that use Hatch without `installer = "uv"` configured.

jvm-cds-opportunity-for-repeated-startup

jvm-cds-opportunity-for-repeated-startup

Detects Java repositories where short-lived JVM startup likely dominates CI runtime and suggests evaluating CDS/AppCDS or related startup amortization techniques.

jvm-production-image-uses-jdk-runtime

jvm-production-image-uses-jdk-runtime

Detects Dockerfiles where the final production/runtime stage uses a full JDK base image even though it only runs a Java application.

large-jest-snapshot

large-jest-snapshot

This repository-wide finding comes from an embedded `oxlint` scan using `jest/no-large-snapshots`.

matrix-test-job-without-test-sharding

matrix-test-job-without-test-sharding

Flags test jobs that use a shard-like matrix but do not visibly pass the matrix value into the test command.

maven-parallel-not-enabled

maven-parallel-not-enabled

Detects multi-module Maven repositories that run lifecycle goals in CI without parallel module execution.

missing-angular-cli-cache

missing-angular-cli-cache

Flags workflows that visibly run Angular CLI tasks while Angular CLI cache is not fully wired for CI.

missing-concurrency

missing-concurrency

Detects heavy workflows that do not define workflow-level or job-level `concurrency`.

missing-dependency-cache

missing-dependency-cache

Actions cache policy is respected: job-level `cache-mode` overrides workflow-level policy. `read` permits restore; `none`, `write-only`, and dynamic/unknown modes suppress cache-enablement advice. Disabled restore is not counted as working cache coverage. Existing event defaults remain unchanged; this rule does not recommend loosening cache access.

missing-dockerignore-for-build-context

missing-dockerignore-for-build-context

Detects Docker image builds that use a wide build context without a visible `.dockerignore` file.

missing-gradle-build-cache

missing-gradle-build-cache

Flags workflows that visibly run Gradle tasks while no repository-level Gradle build cache configuration is visible.

missing-make-j-flag

missing-make-j-flag

Detects workflow steps that run `make`, `gmake`, or `cmake --build` without any parallelization mechanism.

missing-next-build-cache

missing-next-build-cache

Flags workflows that visibly run `next build` while no cache step for `.next/cache` is visible.

missing-path-ignore-for-non-code

missing-path-ignore-for-non-code

Detects heavy workflows that do not ignore obviously non-code changes such as docs and markdown.

missing-paths-filter

missing-paths-filter

Detects heavy workflows that respond to `push` or `pull_request` without `paths` or `paths-ignore`.

missing-release-downstream-success-guard

missing-release-downstream-success-guard

Flags release-like downstream jobs that already use a status-based `if:` expression but do not also visibly guard on upstream success.

missing-test-worker-tuning-for-standard-runner

missing-test-worker-tuning-for-standard-runner

Flags direct test-runner commands on standard GitHub-hosted runners when no visible worker tuning is present.

missing-timeout-in-minutes-buildkite

missing-timeout-in-minutes-buildkite

Buildkite pipeline steps do not have a default timeout. Without `timeout_in_minutes`, a hung or degraded step can run indefinitely and consume agent capacity.

missing-timeout-in-minutes-gitlab-ci

missing-timeout-in-minutes-gitlab-ci

GitLab CI jobs use a project-level default timeout (60 minutes). Heavy jobs should use an explicit `timeout` to prevent runaway builds and wasted CI minutes.

missing-timeout-minutes

missing-timeout-minutes

Detects non-matrix jobs of interest that do not define job-level `timeout-minutes`.

missing-turbo-cache

missing-turbo-cache

Flags workflows that visibly run `turbo run ...` tasks while no local Turbo cache path or remote-cache wiring is visible.

native-dependency-may-fall-back-to-source-build

native-dependency-may-fall-back-to-source-build

Flags repositories that use native-heavy packages while the workflow also shows install conditions that may bypass wheels or prebuilt binaries.

nox-without-uv-backend

nox-without-uv-backend

Flags repositories and CI jobs that use nox without the `--uv` flag or `nox.options.uv = True`.

npm-audit-in-ci

npm-audit-in-ci

Flags `npm audit` steps in workflows triggered by `push` or `pull_request`.

`prefer-npm-ci` (`npm-ci-over-npm-install` explainer)

npm-ci-over-npm-install

Detects ordinary workflow dependency installs through `npm install`/`npm i`. The canonical ID is `prefer-npm-ci`; a single workflow rule owns detection and uses the install step's location. Switching requires a committed, current `package-lock.json`.

outdated-datadog-lambda-extension

outdated-datadog-lambda-extension

Detects Datadog Lambda Extension versions below v88 in GitHub Actions workflows and recommends upgrading to v88 or later.

outdated-husky-version

outdated-husky-version

Flags repositories that use Husky `< 9.1.2` and also have workflows that look relevant to local hook workloads such as lint, format, test, or TypeScript checks.

outdated-pydantic-v2

outdated-pydantic-v2

Pydantic's schema build happens at import/startup time and is a long-standing V2 cost. Several v2 releases made large improvements:

outdated-setup-action-without-cache

outdated-setup-action-without-cache

Detects older `actions/setup-*` majors when no cache configuration is visible.

pdm-without-use-uv

pdm-without-use-uv

Flags repositories and CI jobs that use PDM without `use_uv = true` configured.

playwright-config-uses-npm-run

playwright-config-uses-npm-run

A repository pins a package manager through its lockfile or `packageManager` field. When `playwright.config.*` still invokes package scripts through `npm run`, the test run depends on a second, unpinned toolchain: npm may not be installed in CI, and even when it is, it adds an inconsistent startup path next to the package manager the rest of the pipeline uses.

prefer-aws-cdk-cli-2-1125-for-hotswap

prefer-aws-cdk-cli-2-1125-for-hotswap

Flags CDK hotswap usage (`cdk deploy --hotswap`, `--hotswap-fallback`, or `cdk watch`) that runs on an `aws-cdk` CLI older than 2.1125.0.

prefer-aws-cdk-lib-2-267

prefer-aws-cdk-lib-2-267

Flags `aws-cdk-lib` versions from 2.262.0 up to (but not including) 2.267.0.

prefer-aws-cdk-lib-offline-validation

prefer-aws-cdk-lib-offline-validation

Flags `aws-cdk-lib` versions below 2.262.0, which do not include the built-in offline CloudFormation validation.

prefer-buildx-bake-for-multiple-images

prefer-buildx-bake-for-multiple-images

Detects CI jobs that build multiple Docker images or targets through separate Docker build invocations.

prefer-buildx-build-over-docker-build

prefer-buildx-build-over-docker-build

Detects CI jobs that run legacy `docker build` instead of `docker buildx build`.

prefer-cache-apt-pkgs-action-1-3-1

prefer-cache-apt-pkgs-action-1-3-1

cache-apt-pkgs-action v1.3.1 resolves package versions with one `apt-cache` call instead of repeated calls. Releases before v1.1.0 also lack its `apt-fast` installation optimization. These are setup improvements, not a guaranteed fixed speedup for every package list or cache state.

prefer-cargo-shear-in-ci

prefer-cargo-shear-in-ci

Suggests running an unused-dependency check (`cargo-shear` or `cargo-machete`) in CI for Rust workspaces.

prefer-ccache-action-1-2-20-on-windows

prefer-ccache-action-1-2-20-on-windows

The same Visual Studio compiler binary can have different modification times on different hosted Windows runner images. Older ccache-action defaults can therefore cause unnecessary compilation cache misses or duplicate entries. Version 1.2.20 sets `compiler_check=content` on Windows instead.

prefer-cdk-asset-build-concurrency

prefer-cdk-asset-build-concurrency

Flags CI `cdk deploy` commands that build multiple Docker image assets without `--asset-build-concurrency`.

prefer-cdk-express-mode-in-development

prefer-cdk-express-mode-in-development

Detects development and sandbox CDK deploy commands that omit CloudFormation express mode (`--express`), and flags older `aws-cdk` CLI pins that predate the flag.

prefer-cdk-method-direct-in-development

prefer-cdk-method-direct-in-development

Flags development `cdk deploy` commands that do not use `--method=direct`.

prefer-cdk-version-reporting-disabled

prefer-cdk-version-reporting-disabled

Flags CDK apps on `aws-cdk-lib` 2.178.0 or later that leave CDK usage data reporting enabled.

prefer-direct-angular-material-imports

prefer-direct-angular-material-imports

Flags top-level Angular Material imports that can expand the module graph for CI tooling.

prefer-direct-ant-design-icons-imports

prefer-direct-ant-design-icons-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@ant-design/icons` package root.

prefer-direct-antd-imports

prefer-direct-antd-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `antd` package root.

prefer-direct-date-fns-imports

prefer-direct-date-fns-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `date-fns` package root.

prefer-direct-effect-imports

prefer-direct-effect-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from top-level Effect package entries.

prefer-direct-font-awesome-imports

prefer-direct-font-awesome-imports

Flags top-level Font Awesome icon pack imports that can expand the module graph for CI tooling.

prefer-direct-headlessui-float-react-imports

prefer-direct-headlessui-float-react-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@headlessui-float/react` package root.

prefer-direct-headlessui-react-imports

prefer-direct-headlessui-react-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@headlessui/react` package root.

prefer-direct-heroicons-imports

prefer-direct-heroicons-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect grouped Heroicons imports.

prefer-direct-lodash-es-imports

prefer-direct-lodash-es-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `lodash-es` package root.

prefer-direct-material-ui-v4-imports

prefer-direct-material-ui-v4-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from Material UI v4 package roots.

prefer-direct-mui-core-imports

prefer-direct-mui-core-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `mui-core` package root.

prefer-direct-ramda-imports

prefer-direct-ramda-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `ramda` package root.

prefer-direct-react-bootstrap-imports

prefer-direct-react-bootstrap-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `react-bootstrap` package root.

prefer-direct-react-icons-imports

prefer-direct-react-icons-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect grouped `react-icons` icon-set imports.

prefer-direct-react-use-imports

prefer-direct-react-use-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `react-use` package root.

prefer-direct-recharts-imports

prefer-direct-recharts-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `recharts` package root.

prefer-direct-rxjs-imports

prefer-direct-rxjs-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `rxjs` package root.

prefer-direct-tabler-icons-imports

prefer-direct-tabler-icons-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@tabler/icons-react` package root.

prefer-direct-tremor-imports

prefer-direct-tremor-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@tremor/react` package root.

Use direct upload for already-compressed artifacts

prefer-direct-upload-for-compressed-artifacts

`actions/upload-artifact` steps that upload a single already-compressed or binary file without using `archive: false`, or that use a version older than v7 which does not support direct uploads.

prefer-direct-visx-imports

prefer-direct-visx-imports

This repository-wide finding comes from an embedded `oxlint` scan using `eslint/no-restricted-imports` to detect imports from the `@visx/visx` package root.

prefer-dorny-paths-filter-for-scoped-jobs

prefer-dorny-paths-filter-for-scoped-jobs

Detects workflows where multiple heavy component-scoped jobs run on broad PR or branch push triggers without a visible `dorny/paths-filter` gate.

prefer-download-artifact-v8-for-archives

prefer-download-artifact-v8-for-archives

download-artifact v8 introduced `skip-decompress: true`. Retaining a ZIP instead of extracting it avoids CPU and disk I/O when the next step publishes the archive itself. Updating the action alone does not disable decompression.

prefer-elixir-parallel-deps-compile

prefer-elixir-parallel-deps-compile

Detects GitHub Actions jobs that use Elixir 1.19+ and run `mix` without enabling parallel dependency compilation.

prefer-eslint-concurrency

prefer-eslint-concurrency

ESLint v9.34.0 added multithread linting through the `--concurrency` CLI flag. Files are processed on several worker threads instead of a single main thread, and ESLint reports roughly 1.30x to 3.01x faster linting on large projects. The flag is **opt-in**: the default is `off`, equivalent to `--concurrency=1`, so existing configurations stay single-threaded until they ask for more.

prefer-eslint-plugin-import-x

prefer-eslint-plugin-import-x

Flags repositories whose visible ESLint setup appears to use `eslint-plugin-import` without visible `eslint-plugin-import-x` usage.

prefer-explicit-import-extensions

prefer-explicit-import-extensions

Large Vite-family repositories should prefer explicit file extensions for relative JavaScript and TypeScript imports.

prefer-frozen-lockfile

prefer-frozen-lockfile

Frozen installs keep dependency resolution aligned with the committed lockfile. Explicit flags are unnecessary when the package manager already enables equivalent CI behavior.

prefer-install-action-2-38-for-nextest

prefer-install-action-2-38-for-nextest

install-action v2.38.0 adds a dedicated manifest for `cargo-nextest`, replacing `cargo-binstall` in its normal installation path. Upstream explicitly describes performance and robustness improvements. This speeds tool installation, not nextest's execution of tests; unsupported binary versions/platforms can still need fallback work.

prefer-jest-30-for-jest-29

prefer-jest-30-for-jest-29

Root lockfile versions take precedence over declared lower bounds for Jest, TypeScript and JSDOM. An unresolved `^30.0.0` does not prove Jest is below 30.5.

prefer-knip-in-ci

prefer-knip-in-ci

Suggests running knip, the JavaScript/TypeScript unused-code and unused-dependency checker, in CI.

prefer-lefthook-for-complex-git-hooks

prefer-lefthook-for-complex-git-hooks

Flags repositories whose Git hook setup looks moderately complex and may be easier to maintain with Lefthook.

Prefer mise over asdf for tool version management

prefer-mise-over-asdf

asdf uses shims and plugin hooks that can add overhead to every tool invocation and introduce subtle environment inconsistencies. mise is designed as a drop-in replacement that reads `.tool-versions` directly, avoids shims where possible, and typically provides faster setup in both CI and local development.

prefer-mypy-2-performance-milestone

prefer-mypy-2-performance-milestone

Detects mypy versions below known performance milestones in the 2.x series and suggests incremental upgrades within the major version.

prefer-mypy-num-workers

prefer-mypy-num-workers

Detects repositories that install mypy 2.0 or newer but run it without parallel workers.

prefer-mypy-performance-milestone

prefer-mypy-performance-milestone

Detects mypy versions below known performance milestones in the 1.x series and suggests incremental upgrades.

prefer-native-arm-runner-over-qemu

prefer-native-arm-runner-over-qemu

Detects Docker image builds that target ARM through QEMU emulation in GitHub Actions.

prefer-nextest-for-heavy-rust-tests

prefer-nextest-for-heavy-rust-tests

Flags heavy-looking Rust test jobs that still run `cargo test` without visible `cargo-nextest` adoption.

prefer-nextjs-12-minor-performance-milestone

prefer-nextjs-12-minor-performance-milestone

Both workflow and repository findings use root dependency version evidence. Unresolved ranges crossing the milestone are not treated as old installed versions.

prefer-nextjs-13-minor-performance-milestone

prefer-nextjs-13-minor-performance-milestone

Both workflow and repository findings use root dependency version evidence. Unresolved ranges crossing the milestone are not treated as old installed versions.

prefer-nextjs-14-minor-performance-milestone

prefer-nextjs-14-minor-performance-milestone

Both workflow and repository findings use root dependency version evidence. Unresolved ranges crossing the milestone are not treated as old installed versions.

prefer-nextjs-16-minor-performance-milestone

prefer-nextjs-16-minor-performance-milestone

Workflow findings use root dependency version evidence. Unresolved ranges crossing 16.3 are not treated as old installed versions.

prefer-node-run-over-npm-run

prefer-node-run-over-npm-run

Detects simple GitHub Actions steps and package.json scripts that run package scripts through `npm run` when `node --run` may be a lower-overhead replacement.

prefer-oxfmt-over-prettier

prefer-oxfmt-over-prettier

Flags repositories that appear to use Prettier without visible Oxfmt adoption.

prefer-oxlint-over-eslint

prefer-oxlint-over-eslint

Flags repositories that appear to use ESLint without visible Oxlint adoption.

prefer-oxlint-type-check-over-tsc

prefer-oxlint-type-check-over-tsc

Oxlint's type-aware mode runs the TypeScript type checker (tsgolint) inside the same TypeScript program it uses for linting. That means one pass can both lint and report type errors, replacing a separate `tsc --noEmit` step and avoiding the duplicate program setup and analysis.

Prefer pnpm 12.10 or later

prefer-pnpm-12-10

pnpm 12 is a stable Rust rewrite. Version 12.10 adds faster cached registry metadata reads, prevents metadata requests from waiting behind tarball downloads, and avoids recreating correct dependency links in large macOS workspaces.

prefer-pnpm-setup-for-store-only-cache

prefer-pnpm-setup-for-store-only-cache

pnpm's dependency store and metadata cache are separate. Restoring only the store does not restore `lockfile-verified.jsonl`, so pnpm 11+ can repeat registry-backed lockfile verification even when dependencies are already cached.

prefer-pulumi-actions-4-2

prefer-pulumi-actions-4-2

pulumi/actions v4.2.0 checks whether an installed Pulumi CLI satisfies the requested version. If so, it skips downloading the CLI and querying available versions. Repeated setup and persistent runners can save installation time. A missing or incompatible CLI still requires installation; resource deployment speed is separate.

prefer-pydantic-v2

prefer-pydantic-v2

Detects Python dependency files that pin or request Pydantic v1.

prefer-python-3-11

prefer-python-3-11

Python 3.11 is the "Faster CPython" milestone. Compared with 3.10 it is 10-60% faster (about 1.25x on the pyperformance suite), and interpreter startup is 10-15% faster. Both directly shorten Python CI jobs, and short-running scripts benefit most from the startup win. Python 3.12 and 3.13 continue the work.

prefer-rails-performance-milestone

prefer-rails-performance-milestone

Detects repositories that use Rails 7.0.x or 7.1.x with an active CI pipeline and recommends upgrading to Rails 7.2.x for CI performance improvements.

prefer-ruby-3-yjit

prefer-ruby-3-yjit

Detects repositories that use Ruby 3.2.x in CI and recommends upgrading to Ruby 3.4+ for faster YJIT.

prefer-ruff-format-over-black

prefer-ruff-format-over-black

Detects repositories that appear to use `black` without visible Ruff formatting adoption.

prefer-ruff-import-sorting-over-isort

prefer-ruff-import-sorting-over-isort

Detects repositories that appear to use `isort` without visible Ruff import-sorting adoption.

prefer-rust-cache-2-9-2

prefer-rust-cache-2-9-2

rust-cache 2.9.2 fixes cleanup of build/fingerprint artifacts for library targets whose names differ from package names, including cdylib, rlib, dylib and staticlib. Older cleanup can remove reusable dependency artifacts before saving the cache, causing unnecessary compilation after an otherwise successful cache restore.

prefer-sccache-action-0-0-6

prefer-sccache-action-0-0-6

sccache-action v0.0.6 checks the local tool cache before downloading the sccache archive and checksum. Earlier releases download them even with a cached binary. Persistent self-hosted runners can save setup work on subsequent jobs. This is binary installation overhead, not compilation-cache effectiveness.

prefer-setup-bun-for-lightweight-node-tooling

prefer-setup-bun-for-lightweight-node-tooling

Flags jobs that:

prefer-setup-gradle-6-2-for-enhanced-cache

prefer-setup-gradle-6-2-for-enhanced-cache

setup-gradle 6.2 improves **Enhanced caching**: post-build cleanup inspects the filesystem directly instead of starting Gradle/JVM. The local build cache is stored separately from other Gradle User Home state, and transient housekeeping files are excluded to reduce cache size and improve stability.

prefer-setup-java-v6

prefer-setup-java-v6

setup-java v6 contains concrete setup-performance changes:

prefer-setup-miniconda-v4

prefer-setup-miniconda-v4

setup-miniconda v4 reduces setup work independently of its Node/ESM migration:

prefer-setup-uv-for-lightweight-python-tooling

prefer-setup-uv-for-lightweight-python-tooling

Flags jobs that:

prefer-setup-uv-v9-for-version-resolution

prefer-setup-uv-v9-for-version-resolution

Known `astral-sh/setup-uv` releases before v9 resolving `latest` or a common semver/PEP 440 range using the standard manifest and highest resolution. Findings are warnings in strict mode, consolidated per job.

prefer-sparse-checkout-for-scoped-workflow

prefer-sparse-checkout-for-scoped-workflow

Flags build or release jobs that use only a narrow working tree and may still benefit from sparse checkout.

prefer-standard-arm-runner-for-api-cli

prefer-standard-arm-runner-for-api-cli

Flags API-bound CLI jobs that run on standard x64 Ubuntu GitHub-hosted runners and may be good candidates for the matching standard arm64 Ubuntu runner.

prefer-standard-arm-runner-for-portable-tooling

prefer-standard-arm-runner-for-portable-tooling

Flags lightweight lint or format tooling jobs that run on standard x64 Ubuntu GitHub-hosted runners and may be good candidates for the matching standard arm64 Ubuntu runner.

prefer-storybook-6-minor-performance-milestone

prefer-storybook-6-minor-performance-milestone

Both workflow and repository findings use root dependency version evidence. Unresolved ranges crossing the milestone are not treated as old installed versions.

prefer-storybook-7-minor-performance-milestone

prefer-storybook-7-minor-performance-milestone

Both workflow and repository findings use root dependency version evidence. Unresolved ranges crossing the milestone are not treated as old installed versions.

prefer-storybook-test-flag

prefer-storybook-test-flag

Detects CI jobs that build Storybook for tests (Storybook Test Runner or Chromatic) without the `--test` flag.

prefer-tailwind-v4-upgrade-tool

prefer-tailwind-v4-upgrade-tool

Tailwind CSS v3 projects should usually start a v4 migration with the official upgrade tool, but only when the visible compatibility signals look reasonable.

prefer-test-reporter-2-3-for-xml

prefer-test-reporter-2-3-for-xml

test-reporter v2.3.0 updates sax.js to fix expensive parsing of large XML CDATA sections. Upstream cites a 50 MB log requiring about 5 GiB of memory and several seconds of parsing before the fix. Small XML files may see little benefit; JSON reporters and test execution itself are unaffected by this parser change.

prefer-turborepo-over-npm-workspaces

prefer-turborepo-over-npm-workspaces

Flags repositories that appear to rely primarily on npm, use more than two workspace patterns, and do not use Turborepo.

prefer-typescript-5-performance-milestone

prefer-typescript-5-performance-milestone

Root lockfile versions take precedence over declared lower bounds. A range that crosses the next minor milestone does not prove an older installed version.

prefer-typescript-7-native-compiler

prefer-typescript-7-native-compiler

TypeScript version evidence uses the root lockfile dependency where available, and ignores unrelated aliases and unresolved package protocols.

prefer-uv-0-12

prefer-uv-0-12

uv ships performance work continuously, and the 0.11 and 0.12 lines carried large batches that directly affect CI:

prefer-uv-pip-over-pip

prefer-uv-pip-over-pip

Flags `pip install` commands in jobs that already have `setup-uv` available. If uv is already installed (via `astral-sh/setup-uv`), plain `pip install` should be replaced with `uv pip install` for faster installs.

prefer-vitest-performance-milestone

prefer-vitest-performance-milestone

Suggests moving a Vitest project to the next notable speed milestone, one step at a time.

prefer-workflow-dispatch-run-details

prefer-workflow-dispatch-run-details

Suggests replacing sleep-based run-ID discovery after a workflow dispatch with the ID returned by the dispatch API.

prefer-zstd-compression-for-pushed-docker-images

prefer-zstd-compression-for-pushed-docker-images

Detects pushed BuildKit Docker image builds that do not request zstd layer compression.

pyramid-config-scan-unrestricted

pyramid-config-scan-unrestricted

Detects Pyramid `config.scan()` calls that do not specify an `ignore=` filter when the scan target contains directories that are unlikely to contain runtime application code.

pytest norecursedirs is explicitly set, overriding defaults

pytest-norecursedirs-override

The project has `norecursedirs` explicitly set in a pytest config file **and** does not have `testpaths` configured. The check also verifies that directories corresponding to pytest's default `norecursedirs` entries exist in the repository but are missing from the custom list.

pytest testpaths is not configured

pytest-testpaths-unconfigured

The project uses pytest but has not configured `testpaths` in any pytest config file (`pytest.ini`, `pyproject.toml`, `setup.cfg`, `tox.ini`), and CI workflow steps do not pass explicit test paths either.

pytest-xdist-installed-but-not-used

pytest-xdist-installed-but-not-used

Detects CI pytest commands that run without parallel workers despite `pytest-xdist` being installed.

python-top-level-heavy-client-init

python-top-level-heavy-client-init

Detects heavy client, connection, or model initialization at module top level in `src/**/*.py` for FastAPI, Django, and Flask repositories.

rails-db-schema-load-over-migrate

rails-db-schema-load-over-migrate

Detects GitHub Actions jobs that initialize an ephemeral Rails test database by replaying all migrations with `rails db:migrate`, and recommends loading the schema directly instead.

recommend-modern-test-runner

recommend-modern-test-runner

Suggests evaluating a modern JavaScript test runner for repositories still on a legacy runner.

recommend-rspack-over-webpack

recommend-rspack-over-webpack

This rule detects repositories using webpack 5.x that could benefit from migrating to rspack.

recommend-swc-over-babel

recommend-swc-over-babel

This rule detects repositories using Babel that could benefit from migrating to SWC.

recommend-webpack-4-latest-patch

recommend-webpack-4-latest-patch

Version evidence prefers the root lockfile dependency. A manifest range must stay entirely below 4.47 to prove an older version when no lockfile version is available.

recommend-webpack-5-latest-patch

recommend-webpack-5-latest-patch

Version evidence prefers the root lockfile dependency. A manifest range must stay entirely below 5.53 to prove an older version when no lockfile version is available.

redundant-bootstrap-in-husky-hook

redundant-bootstrap-in-husky-hook

Flags repositories whose `.husky/*` hook files still use deprecated Husky bootstrap or x-runner wrapping such as `npx`.

redundant-install-for-preinstalled-cli

redundant-install-for-preinstalled-cli

Flags GitHub-hosted Ubuntu, Windows, or macOS jobs that visibly install a CLI already present on the runner image and then use that CLI later in the same job.

redundant-manual-cache-with-setup-action

redundant-manual-cache-with-setup-action

Respects job/workflow `cache-mode`: restore-disabled and unknown policies suppress overlap advice. Under `read`, a manual save-only step is not counted as duplicate work; manual restore can still overlap built-in restore.

redundant-npx-or-bootstrap

redundant-npx-or-bootstrap

Detects jobs that already install dependencies and still invoke common local CLI tools through bootstrap runners such as `npx`, `pnpx`, `pnpm dlx`, `bunx`, `yarn dlx`, `uvx`, or `uv tool run`.

renovate-aws-sdk-grouping

renovate-aws-sdk-grouping

Renovate configuration does not group AWS SDK dependencies, and the repository uses multiple AWS SDK v3 packages.

renovate-cdk-deps-grouping

renovate-cdk-deps-grouping

Renovate configuration does not group CDK dependencies, and the repository uses multiple CDK packages.

renovate-rebase-when-unconfigured

renovate-rebase-when-unconfigured

Renovate configuration does not explicitly set `rebaseWhen` locally.

repeated-bootstrap-setup

repeated-bootstrap-setup

Detects multiple non-matrix jobs within a workflow that share an identical bootstrap fingerprint (checkout + install + cache pattern).

repeated-build-in-same-workflow

repeated-build-in-same-workflow

Detects the same build family running in multiple non-matrix jobs within one workflow.

repeated-install-in-same-job

repeated-install-in-same-job

Detects the same install command running multiple times within one job.

repeated-lint-in-same-workflow

repeated-lint-in-same-workflow

Detects the same lint tool family running in multiple non-matrix jobs within one workflow.

ruby-setup-ruby-missing-bundler-cache

ruby-setup-ruby-missing-bundler-cache

Detects workflows that use `ruby/setup-ruby` but still run `bundle install` manually without enabling the official `bundler-cache: true` option.

scheduled-heavy-workflow-without-throttling

scheduled-heavy-workflow-without-throttling

Flags heavy scheduled workflows that appear to run more often than every 3 hours.

setup-node-cache-dependency-path-unset

setup-node-cache-dependency-path-unset

Detects `actions/setup-node` steps that enable caching without specifying `cache-dependency-path` when lock files exist outside the repository root.

tailwind-content-config

tailwind-content-config

Tailwind CSS content configuration must be present and scoped to avoid unnecessary file scanning.

terraform-github-app-auth

terraform-github-app-auth

GitHub App authentication via `app_auth` provides significantly higher API rate limits compared to a personal access token (PAT). Higher rate limits reduce the risk of hitting API limits during large `terraform plan`/`apply` operations, concurrent plans, and provider refreshes. Rate limit pauses can delay CI workflows by up to an hour.

terraform-github-parallel-requests

terraform-github-parallel-requests

**Severity**: suggestion **Confidence**: high

terraform-github-slow-resources

terraform-github-slow-resources

These resources already have an implicit repository scope via the GitHub provider. Looking up `data.github_repository` triggers an extra GitHub API call **per resource**, which inflates `terraform plan` and `apply` duration. In repositories with many branch protections, environments, or secrets, this compounds significantly and can trigger API rate limits.

terraform-lockfile-missing

terraform-lockfile-missing

Terraform root modules initialized in CI without their own `.terraform.lock.hcl`. Step/job/workflow working-directory defaults, static `cd`, and `terraform -chdir` are considered. A lockfile in another module does not suppress the finding.

terraform-pagerduty-team-membership-version

terraform-pagerduty-team-membership-version

Repositories that use `pagerduty_team_membership` with a PagerDuty provider version constraint that allows versions below v3.32.2.

terraform-parallelism-unconfigured

terraform-parallelism-unconfigured

Terraform defaults to `parallelism=10`, which is slow for large configurations. Tuning parallelism to match runner capacity is one of the highest-leverage Terraform CI optimizations.

tox-without-tox-uv

tox-without-tox-uv

Flags jobs that run `tox` without `tox-uv` installed.

ts-loader-fork-ts-checker

ts-loader-fork-ts-checker

This rule detects webpack configurations using `ts-loader` with `transpileOnly: true` or `happyPackMode: true` but missing `fork-ts-checker-webpack-plugin`.

ungated-heavy-job

ungated-heavy-job

Detects heavy jobs with no visible `if` condition inside broadly triggered workflows.

unnecessary-app-install-for-lint-job

unnecessary-app-install-for-lint-job

Detects jobs that install full application dependencies but only run lint or check tools.

unnecessary-checkout-when-only-using-artifacts

unnecessary-checkout-when-only-using-artifacts

Detects `actions/checkout` steps in jobs that only use artifact actions (`actions/download-artifact@` or `actions/upload-artifact@`) without any visible dependency on repository files.

unnecessary-npm-global-upgrade-before-npm-install

unnecessary-npm-global-upgrade-before-npm-install

Some workflows run `npm install -g npm` to upgrade the npm CLI before running `npm ci` or `npm install`. This is usually unnecessary — the npm version bundled with the runner's Node.js is sufficient for dependency installation. The global upgrade step adds wall-clock time to every CI run without improving reproducibility or correctness.

wasteful-npm-global-install

wasteful-npm-global-install

Jobs that use yarn, pnpm, or bun for package management but still run `npm install -g npm@latest` (or similar npm global upgrade commands).

wasteful-package-install-in-container

wasteful-package-install-in-container

Jobs that run inside a Docker container (`container:`) but install OS packages (`apt-get install`, `apk add`, `brew install`, etc.) in workflow steps where the installed packages are not referenced in later steps.