# BerryBox > GitHub Actions runners built for agents. Change one runs-on line and every job gets a fresh AMD VM, billed for actual runtime. BerryBox Playbooks are agent-readable guides to making any GitHub Actions setup faster and cheaper, on any runner. Every page has a Markdown version at its URL plus .md. ## Playbooks - [BerryBox Playbooks](https://berrybox.io/playbooks.md): the copy-paste prompt and the full index - [Measure a CI baseline](https://berrybox.io/playbooks/baseline.md): Pull recent GitHub Actions history with the gh CLI, find the critical path and the minutes it burns, and keep the numbers you will compare against. - [Stop paying for runs nobody needs](https://berrybox.io/playbooks/wasted-runs.md): Cancel runs a newer push replaced, run each commit once, skip jobs whose inputs didn't change and put a ceiling on runaway jobs, without losing a required check. - [Get setup off the clock](https://berrybox.io/playbooks/slow-setup.md): Cache downloads on lockfile keys, fetch only the history a job reads, install only what it runs and bake stable tools into an image, so each job reaches its real work in seconds. - [Build less, and build it faster](https://berrybox.io/playbooks/slow-builds.md): Carry compiler, build tool and Docker layer caches between runs, build each architecture natively, move lint and type checks to native tools and link faster, guided by a profile of where build time goes. - [Make the test suite finish sooner](https://berrybox.io/playbooks/slow-tests.md): Run tests on every core without shared state, replace sleeps, real services and repeated setup with cheaper equivalents, then split what remains across shards balanced by recorded timings. - [Run only what a change can affect](https://berrybox.io/playbooks/test-selection.md): On pull requests, run only the tests and packages a change can reach and reuse results for inputs that already passed, while the merge queue, the default branch or a nightly run still runs everything. - [Shorten the path that ends the run](https://berrybox.io/playbooks/critical-path.md): Find the chain of jobs that decides when a run finishes, then remove waits that aren't dependencies, build once, move independent work off the longest job and keep the full matrix where it pays off. - [Give the long pole the right machine](https://berrybox.io/playbooks/runners.md): Cut the time jobs wait for a runner, benchmark CPU-bound long poles on more cores, move disk-heavy steps to faster storage and put light jobs on the smallest runner that fits, judging each change by wall time and cost per run. - [Make a red build mean something broke](https://berrybox.io/playbooks/flaky-tests.md): Retry only what failed and record it, quarantine tests that keep flaking, stop new flaky tests in review, and remove the outside changes and network stalls that fail runs without a code change. - [Keep CI ahead of a growing pull request queue](https://berrybox.io/playbooks/pr-volume.md): When people and coding agents open more pull requests than CI can absorb, test merges together in a queue, keep the required gate short and catch cheap failures before they reach a runner. ## Plays - [Build once and pass the output to the jobs that need it](https://berrybox.io/playbooks/critical-path/build-once.md): Compile, bundle or build the image in one job, upload the result as an artifact, and have test shards, end-to-end jobs and packaging download it instead of repeating the same build on every runner. - [Combine short checks whose setup takes longer than the work](https://berrybox.io/playbooks/critical-path/merge-tiny-jobs.md): Run lint, format, type and other short checks as steps of one job that checks out and installs once, so each check stops paying for its own runner, setup and rounded-up minute. - [Run independent steps at the same time inside a job](https://berrybox.io/playbooks/critical-path/overlap-setup.md): In the long-pole job, start independent steps such as image pulls, dependency installs, per-target builds and packaging together, wait for them before the step that needs their results, and keep every failure visible. - [Start independent jobs together by dropping needs they don't use](https://berrybox.io/playbooks/critical-path/parallelize-independent-jobs.md): Keep a needs edge only where the later job uses the earlier job's artifact, output or side effect, let every other job start when the run starts, and gate merges on one aggregate job. - [Split independent work out of the long-pole job](https://berrybox.io/playbooks/critical-path/split-the-long-pole.md): When one job sets the run's wall time, move steps that don't use the rest of its output into a parallel job, keep the required check name on an aggregate job, and split only when the moved work dwarfs a job's setup. - [Run a reduced matrix on pull requests and the full matrix later](https://berrybox.io/playbooks/critical-path/trim-the-matrix.md): Test pull requests on the few platforms and versions that catch most breakage, run every combination in the merge queue, on the default branch or on a schedule, and require one aggregate check so the legs can change. - [Run new and changed tests many times before they can block merges](https://berrybox.io/playbooks/flaky-tests/gate-new-tests.md): When a pull request adds or edits tests, run just those tests 20 to 50 times with retries off, report the result as its own check, and fix any failure before the tests join the suite everyone waits on. - [Pin service images and tools to exact versions](https://berrybox.io/playbooks/flaky-tests/pin-service-images.md): Replace floating tags such as latest in services, containers, runner labels and tool installs with exact versions or digests, so a run changes only when a commit changes it, and take updates through reviewed pull requests. - [Quarantine flaky tests with an owner and an exit date](https://berrybox.io/playbooks/flaky-tests/quarantine-flaky-tests.md): Collect tests that fail and pass again without a code change, move them out of the blocking job into a reviewed list with an owner, an issue and an expiry date, and keep running them where they can't block a merge. - [Put stall limits and bounded retries on every network fetch](https://berrybox.io/playbooks/flaky-tests/resilient-network.md): Make checkout, submodules, downloads and package installs give up on a stalled transfer within about a minute and retry it two or three times with backoff, so a bad connection costs seconds instead of a failed or hung job. - [Retry only the test or step that failed, and record the retry](https://berrybox.io/playbooks/flaky-tests/retry-narrowly.md): Rerun failed tests, or a failed download or service start, inside the same job two or three times at most, report every pass on retry as a flaky test, and never retry whole workflows, timeouts or steps with side effects. - [Make CI failures short and easy for agents to act on](https://berrybox.io/playbooks/pr-volume/agent-readable-output.md): Agents read CI logs to decide what to change. Print failures instead of passes, keep each error on one line with its file and reason, and save the full output as an artifact, so the cause fits in the agent's context. - [Catch lint, format and type errors before they reach CI](https://berrybox.io/playbooks/pr-volume/check-before-push.md): Run the repository's fast checks in a pre-push hook so lint, format and type failures cost seconds on the author's machine instead of a CI run, and keep the same checks in CI for pushes that skip the hook. - [Use a merge queue instead of requiring up-to-date branches](https://berrybox.io/playbooks/pr-volume/merge-queue.md): A merge queue tests each ready pull request on top of the base branch and the pull requests ahead of it, so authors stop updating branches and rerunning CI before every merge. Required workflows must also run on merge_group. - [Keep required checks fast and run heavy suites after merge](https://berrybox.io/playbooks/pr-volume/minimal-required-checks.md): Every merge waits on the slowest required check. Require only fast, reliable checks on pull requests, and run the slow suites in the merge queue, on the default branch after merge or as optional pull request jobs. - [Have coding agents run the checks before they open a pull request](https://berrybox.io/playbooks/pr-volume/verify-before-pr.md): Give agents one command that runs what CI requires, make them pass it before opening or updating a pull request, and cap CI rounds, so agent pull requests arrive green instead of using CI as a test runner. - [Benchmark the long pole on a bigger runner](https://berrybox.io/playbooks/runners/bigger-runner.md): Run the same long-pole job on the same commit at two or three runner sizes, two or three times each, and switch only when the wall-time gain is worth the change in cost per run. - [Cut the time jobs wait for a runner](https://berrybox.io/playbooks/runners/cut-queue-time.md): Measure queue time per runner label, find out whether a concurrency cap, a cold pool or a burst of jobs causes it, and fix that cause with higher limits, split runner groups, warm capacity or fewer jobs. - [Move IO-heavy work onto faster storage](https://berrybox.io/playbooks/runners/fast-disk.md): When unpacking, installing or database writes dominate a job, put the workspace, package caches, build outputs and test data on the fastest storage the runner has, such as a Windows Dev Drive, a local NVMe disk or tmpfs. - [Run light jobs on the smallest runner that fits](https://berrybox.io/playbooks/runners/right-size-down.md): Move short, single-threaded jobs such as lint, format, labeling and gate checks to the smallest runner that keeps their wall time, such as GitHub's 1-vCPU ubuntu-slim, and confirm with an A/B run on the same commit. - [Keep compiler and build caches between runs](https://berrybox.io/playbooks/slow-builds/compiler-cache.md): Restore the compiler's and build tool's caches on every run and save them only from the default branch, so a small change recompiles only the units it touched. - [Reuse Docker layers across runners](https://berrybox.io/playbooks/slow-builds/docker-layer-cache.md): Export BuildKit's layer cache to the GitHub Actions cache or a registry, and order the Dockerfile so a source change rebuilds only the layers that come after it. - [Link with LLD or mold, and keep heavy LTO out of CI test builds](https://berrybox.io/playbooks/slow-builds/faster-linker.md): Link Rust and C/C++ builds with LLD or mold instead of the platform's default linker, and save full link-time optimization for release builds, where the runtime gain pays for the minutes. - [Build each architecture on a native runner instead of under QEMU](https://berrybox.io/playbooks/slow-builds/native-arch-builds.md): Build the amd64 and arm64 images in parallel on matching runners and merge them into one multi-arch tag, instead of compiling arm64 under QEMU on an x86 runner. - [Move lint and type checks to native tools without losing rules](https://berrybox.io/playbooks/slow-builds/native-tools.md): Type-check with TypeScript 7's native compiler and lint with Oxlint or Ruff, after you map every rule you run today and prove the new setup still fails on the problems the old one caught. - [Profile the build before you optimize it](https://berrybox.io/playbooks/slow-builds/profile-the-build.md): Record where build time goes with the compiler's and build tool's own profilers on a CI runner, then fix the crate, header, type or dependency that costs the most instead of guessing. - [Cache package downloads, keyed on the lockfile](https://berrybox.io/playbooks/slow-setup/cache-dependencies.md): Restore the package manager's download store from a key that hashes the lockfile, check out before you hash, and let only trusted default-branch runs write the cache that every pull request reads. - [Cache browsers, toolchains and CLI downloads](https://berrybox.io/playbooks/slow-setup/cache-tool-downloads.md): Keep downloaded browsers, compilers and CLIs between runs in a cache keyed on the exact tool version, or swap a compile-from-source step for a prebuilt binary, when the download is slow, flaky or rate-limited. - [Remove caches that take longer than the work they skip](https://berrybox.io/playbooks/slow-setup/drop-slow-caches.md): Time each cache's restore and save against the work it skips, delete the ones that lose, save from the default branch only, and keep pull request and merge queue writes from evicting the entries main relies on. - [Install only the packages and tools each job uses](https://berrybox.io/playbooks/slow-setup/install-only-what-runs.md): Scope each job's install to the workspace packages and dependency groups it actually runs, and skip the full install in jobs that only need one small tool. - [Bake stable dependencies into the runner or container image](https://berrybox.io/playbooks/slow-setup/prebake-images.md): Move the tools and system packages that every job installs and that rarely change into a prebuilt container or runner image, rebuilt on a schedule and whenever its inputs change. - [Fetch only the history and files a job needs](https://berrybox.io/playbooks/slow-setup/shallow-checkout.md): Keep actions/checkout at its default single commit, give the few jobs that diff or version just the history they read, and use blobless or sparse checkouts for jobs that need commit history or a few folders but not every file. - [Balance shards by recorded test timings](https://berrybox.io/playbooks/slow-tests/balance-shards.md): Assign tests to shards by how long they took on the default branch instead of by count, give every shard the same timings file and refresh it after each merge so no shard trails the others. - [Keep unit tests off real networks and services](https://berrybox.io/playbooks/slow-tests/fake-slow-services.md): Give unit tests in-process fakes for databases, caches, HTTP APIs and subprocesses, block outbound connections so a missing mock fails at once instead of after a timeout, and run real-service tests in a separate integration job. - [Isolate test state so tests can run in parallel](https://berrybox.io/playbooks/slow-tests/isolate-test-state.md): Give each test worker its own database, ports, files and environment, find order dependencies by shuffling, and run the few tests that must share a resource in a serial lane, so more workers stop meaning more flakes. - [Match test workers to the runner's cores and memory](https://berrybox.io/playbooks/slow-tests/match-workers-to-cores.md): Set the test runner's worker count from the CPUs and memory the CI runner actually has, instead of running serially or copying a laptop setting, and cap it where memory or a shared service runs out first. - [Wait for readiness, not for a fixed sleep](https://berrybox.io/playbooks/slow-tests/poll-dont-sleep.md): Replace fixed sleeps in tests and workflows with polls for the condition you need, such as a health check, a page marker or a signal from the code, so each wait ends as soon as it can and never too early. - [Build shared fixtures and test databases once](https://berrybox.io/playbooks/slow-tests/setup-once.md): Run migrations, seed data, logins and compilation once per run or once per image, then give each worker a cheap copy, instead of repeating the same setup in every worker, test file or container. - [Split a long test suite across parallel jobs](https://berrybox.io/playbooks/slow-tests/shard-tests.md): Run the suite as a matrix of shards with the test runner's own shard flag, gate merges on one aggregate job, merge the shard reports and confirm that every test ran exactly once. - [Build and test only the affected packages in a monorepo](https://berrybox.io/playbooks/test-selection/affected-packages.md): Let the workspace tool map a change to the packages it touches and every package that depends on them, run tasks for that set only, and run everything when root config, lockfiles or CI files change. - [Select the tests each change needs, and keep a full-suite backstop](https://berrybox.io/playbooks/test-selection/affected-tests.md): On pull requests, run only the tests that depend on what a change touched, fall back to the full suite when shared inputs change, and keep running everything in the merge queue, on the default branch and nightly. - [Reuse a passing result when a check's inputs haven't changed](https://berrybox.io/playbooks/test-selection/reuse-unchanged-results.md): Key each slow, deterministic check on a hash of everything it reads, record a pass when it succeeds, and skip the work when the same inputs already passed, while the check still reports under its usual name. - [Cancel runs a newer push replaced](https://berrybox.io/playbooks/wasted-runs/cancel-stale-runs.md): Group each workflow's runs by pull request so a new push cancels the run it made obsolete, and leave default-branch, release and deploy runs alone. - [Hold expensive checks until a draft pull request is ready for review](https://berrybox.io/playbooks/wasted-runs/hold-draft-prs.md): Skip the slow jobs while a pull request is still a draft and start them when it is marked ready, so pushes of unfinished work get quick checks instead of the full suite. - [Don't start a runner for comments, labels and edits your jobs ignore](https://berrybox.io/playbooks/wasted-runs/ignore-noise-events.md): Comment, label, review and description-edit events can start full workflow runs and cancel real ones. Keep them out of the workflow that reports required checks, and gate the workflows that need them with job-level conditions. - [Give every job a timeout that fits its normal runtime](https://berrybox.io/playbooks/wasted-runs/job-timeouts.md): A job without timeout-minutes can hang for six hours before GitHub stops it. Set each limit from the job's recorded p95 with about 2x headroom, so hangs fail in minutes and healthy runs never hit the limit. - [Run CI once per commit instead of on both push and pull_request](https://berrybox.io/playbooks/wasted-runs/one-run-per-commit.md): A workflow that triggers on every push and on pull_request runs each pull request commit twice. Limit push to the default branch so each commit gets one run. - [Skip jobs whose inputs didn't change, without stranding required checks](https://berrybox.io/playbooks/wasted-runs/skip-unchanged-paths.md): Detect changed paths in a first job, skip unaffected jobs with job-level if conditions and require one aggregate job, so small pull requests stop running everything while required checks keep reporting. ## Product - [BerryBox docs](https://docs.berrybox.io/llms.txt): runners, migration, billing and the API - Agent skill: `npx skills add strawberry-labs/berrybox-skills`