wdm0006/python-skills/github-actions
Claude Code and agent skill by wdm0006/python-skills
- community
Checking that the SKILL.md file is still in the repository.
Cut GitHub Actions minutes and wall-clock time without losing coverage — the OS billing multiplier (macOS 10x / Windows 2x / Linux 1x), trigger hygiene that stops push+pull_request double-firing, concurrency that cancels superseded runs, dependency caching keyed on lockfiles, matrix discipline, and auditing scheduled crons that bill 24/7. Use when CI is burning included minutes, when runs feel slow, when setting up a new repo's workflows, or when reviewing an existing workflow for waste.
Install
npx vskill@latest install wdm0006/python-skills/github-actionsSKILL.md
Running GitHub Actions Efficiently
Actions minutes on private repos bill against a monthly included quota; public repos are free. So cost concentrates in private repos, and a handful of workflows usually dominate the bill. This skill is the checklist for finding and fixing that waste. Every fix below preserves what CI actually verifies — none of them trade away coverage.
First, know the one number that dominates everything
Minutes are billed per job, rounded up to the minute, times a runner-OS multiplier:
| Runner | Multiplier | |
|---|---|---|
Linux (ubuntu-*) | 1x | |
Windows (windows-*) | 2x | |
macOS (macos-*) | 10x |
A one-minute macOS job costs the same as ten Linux minutes. This single fact reorders every optimization: a repo with a few macOS jobs can outspend a repo with ten times as many Linux jobs. Before anything else, find your macOS jobs and ask of each: does this step genuinely need macOS?
- Xcode / Apple-platform builds and tests (
xcodebuild): yes, macOS is required. - Linters and formatters (even Swift ones like SwiftLint/SwiftFormat), pure
unit tests with no Apple frameworks, packaging, doc builds: usually no — move them to ubuntu-latest and cut that job's cost ~10x.
Split the must-be-macOS work into its own job and push everything else to Linux. If a single macOS job does both (e.g. runs SwiftLint and an Xcode build), split it: a cheap Linux lint job plus the macOS build job. The tools only parse source, so the Linux job just checks out and runs them — no toolchain build.
SwiftLint and SwiftFormat both ship self-contained prebuilt Linux binaries, so "Swift means macOS" is a myth for the linting half of the pipeline:
Use SwiftLint's `swiftlint-static` (not the dynamically linked swiftlint, which needs a Swift runtime the bare runner lacks) and SwiftFormat's swiftformat_linux — both are statically linked and run on plain ubuntu-latest. Pin versions in the URL, curl -f to fail on a bad download, and reference the exact binary names rather than a fragile find.
What genuinely can't move. A SwiftPM target only builds on Linux if its code and its dependencies do. Two reliable signals it's macOS-pinned: the package declares platforms: [.macOS(...)] only, or it depends on an Apple-focused library (e.g. SQLite.swift, anything importing AppKit/SwiftUI/CloudKit). Don't gamble a repo's only build job on a Linux move — if swift build there depends on such a package, keep it on macOS. grep -rE 'import (AppKit|SwiftUI| Cocoa|CloudKit|CoreData)' over the target's sources is a fast pre-check.
Trigger hygiene: stop paying for the same commit twice
The most common silent waste is a workflow that runs twice on every change:
When you push a feature branch that has an open PR, the push event and the pull_request event both fire a full run of the same commit. On a 10x macOS runner that doubles the most expensive thing you have.
Fix — scope `push` to the branches you actually gate on:
Now branch work is validated once (by the PR) and main is validated once (post-merge). No commit is ever built twice for the same reason.
Add path filters so unrelated changes don't spin a runner at all:
(Note: a required status check gated on paths can block PRs that legitimately change nothing in-scope — prefer paths-ignore for docs, or make the check non-required, rather than paths on a required job.)
Concurrency: kill superseded runs automatically
Without a concurrency block, pushing three commits in quick succession starts three full runs and lets all three finish. You only care about the last one.
This cancels any in-progress run on the same ref when a newer one starts. It is the single highest-leverage line for anyone who pushes iteratively or force-pushes during review. Put it at the top level of every workflow.
One caveat: don't set cancel-in-progress: true on workflows that must run to completion once started — deploys, releases, anything that writes external state. Scope those with a distinct group and leave cancellation off (or queue them).
Cache dependencies — keyed on the lockfile
Re-downloading and re-resolving dependencies on every run is pure waste. Cache the dependency directory, keyed on the lockfile so the cache invalidates exactly when dependencies change, with a restore-keys fallback for partial hits.
Most setup-* actions have caching built in — prefer it over hand-rolled actions/cache where it exists:
For ecosystems without built-in caching, use actions/cache directly:
Cache the dependency graph (downloaded/resolved packages), not fragile machine-specific build state. Caching compiler-derived artifacts with absolute paths (e.g. all of Xcode's DerivedData) can produce flaky or wrong builds — the dependency cache is the safe, high-ROI target.
Two speed wins on macOS runners specifically:
Matrix discipline
A matrix multiplies job count: os: [ubuntu, macos, windows] × python: [3.10, 3.11, 3.12, 3.13] is 12 jobs per run, and the macOS/Windows cells carry the 10x/2x multipliers. Test broadly, but deliberately:
- Run the full matrix on
main/ nightly, and a minimal matrix (one OS,
min+max version) on PRs. if: github.event_name == 'push' gates the expensive cells.
fail-fast: true(the default) stops the whole matrix on the first failure —
keep it unless you specifically need every cell's result.
- Test the versions you actually support. Dropping an EOL runtime is free minutes.
- Prefer Linux cells; add macOS/Windows cells only for genuinely OS-specific code.
Preserve the required check when splitting jobs
Branch protection and rulesets require check names, not the work a job used to do. Turning a required test job into matrix checks such as test (3.12) and test (3.13) can leave the original test requirement waiting forever. Inspect the configured requirements before renaming or splitting jobs; preserve the exact required name with a small aggregate job:
always() makes the aggregate run after a failed dependency; the explicit result check rejects failure, cancellation and skipping. A bare success step would publish a green gate even when the matrix failed. Include every job the old gate promised to verify in needs, and check each result. Do not put workflow-level path filters on this required gate: a workflow that never starts cannot publish its aggregate check.
Verify both a passing matrix and a deliberately failing cell on a disposable branch, then confirm the PR reports the original required check name. See GitHub's required-check troubleshooting guidance for dependency and workflow-skipping behavior.
Scheduled workflows bill around the clock
A schedule: cron runs whether or not anyone touched the repo — so it bills continuously, forever, and is the easiest thing to forget. Audit every one:
- Uptime / health checks do not belong on Actions — a
*/5or*/15cron is
a runaway meter. Use a purpose-built external monitor (many have free tiers).
- Daily rebuilds of static content that hasn't changed (e.g. redeploying a
site on a timer) are wasted runs — deploy on push instead, and keep a workflow_dispatch: for manual rebuilds.
- DST/timezone hacks that register two crons and gate one out still pay the
runner spin-up (checkout + toolchain setup) for the run that no-ops. Gate before the setup steps, or compute the schedule so only one fires.
- Genuinely periodic jobs (a real nightly build) are fine — just right-size the
frequency to how often the input actually changes.
Find them all across a repo:
Failures and long runs still bill
- A job that fails at minute 9 of 10 bills all 9. Order steps cheap-to-expensive
and lint/typecheck before the long build, so bad commits die fast.
- Add a
timeout-minutes:to every job so a hung step can't burn the max 6-hour
runner allotment.
- Flaky tests that auto-retry the whole workflow multiply cost — fix the flake
rather than papering over it with reruns.
Measure before and after
Don't guess which workflow is expensive — measure:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/common/github-actions/SKILL.md
Popularity
- Repository stars
- 95
- Repository forks
- 14
- 7-day trend score
- 23
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/wdm0006/python-skills/github-actions)