Help us improve
Share bugs, ideas, or general feedback.
From finops-plugin
Analyzes GitHub Actions billing, workflow efficiency, and waste patterns in orgs and repos. Identifies wasted runs, trigger issues, and CI/CD costs using gh CLI.
npx claudepluginhub laurigates/claude-plugins --plugin finops-pluginHow this skill is triggered — by the user, by Claude, or both
Slash command
/finops-plugin:github-actions-finopshaikuThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Analyze GitHub Actions usage, costs, and efficiency across organizations and repositories.
Identifies GitHub Actions workflow waste patterns like skipped runs, bot triggers, missing concurrency, path filters, and cancel-in-progress. Suggests YAML fixes for optimization.
Creates, audits, and optimizes GitHub Actions workflows for CI/CD, matrix builds, reusable workflows, composite actions, caching, and security hardening like pinning and permissions.
Reference for GitHub Actions workflow best practices, including runner context, timeout-minutes, caching, concurrency, and security. Use when writing or debugging .yml workflows.
Share bugs, ideas, or general feedback.
Analyze GitHub Actions usage, costs, and efficiency across organizations and repositories.
| Use this skill when... | Use X instead when... |
|---|---|
| Analyzing CI/CD costs and billing | Debugging a specific failed workflow -- use gh-workflow-monitoring |
| Identifying wasted workflow runs | Setting up new workflows -- use github-actions-workflows |
| Investigating workflow trigger patterns | Managing cache keys -- use github-actions-cache-optimization |
| Comparing efficiency across repos | Monitoring a single run -- use gh-workflow-monitoring |
git remote get-url originfind .github/workflows -maxdepth 1 -name '*.yml' -o -name '*.yaml'gh workflow list --json id,name,stateExecute this GitHub Actions FinOps analysis:
Read the Context values above. Parse $OWNER and $REPO from the current repo URL (e.g., https://github.com/OWNER/REPO.git). Run gh api repos/$OWNER/$REPO --jq '.owner.type' to determine if the owner is an "Organization" or "User". If Organization, set $GITHUB_ORG to the repo owner for org-level billing queries.
If no repo context is available, ask the user for the target organization or repository.
Query the Actions billing API:
gh api /orgs/$GITHUB_ORG/settings/billing/actions \
--jq '{included_minutes, total_minutes_used, total_paid_minutes_used}'
If this returns a permissions error, note that admin access is required and skip to Step 3.
Optionally also check packages and storage billing:
gh api /orgs/$GITHUB_ORG/settings/billing/packages \
--jq '{included_gigabytes_bandwidth, total_gigabytes_bandwidth_used}'
gh api /orgs/$GITHUB_ORG/settings/billing/shared-storage \
--jq '{days_left_in_billing_cycle, estimated_paid_storage_for_month}'
Fetch recent runs and group by workflow:
gh api "/repos/$OWNER/$REPO/actions/runs?per_page=100" \
--jq '.workflow_runs | group_by(.name) |
map({workflow: .[0].name, runs: length,
conclusions: (group_by(.conclusion) | map({(.[0].conclusion // "unknown"): length}) | add)}) |
sort_by(-.runs)'
Calculate run durations:
gh api "/repos/$OWNER/$REPO/actions/runs?per_page=20&status=completed" \
--jq '.workflow_runs | group_by(.name) |
map({name: .[0].name, count: length,
total_seconds: (map(.run_started_at as $start | .updated_at as $end |
(($end | fromdateiso8601) - ($start | fromdateiso8601))) | add)}) |
sort_by(-.count) | .[] | "\(.name): \(.count) runs, ~\(.total_seconds/60|floor)min total"'
Check each waste indicator:
Skipped runs:
gh api "/repos/$OWNER/$REPO/actions/runs?per_page=100" \
--jq '[.workflow_runs[] | select(.conclusion == "skipped")] |
group_by(.name) | map({workflow: .[0].name, skipped: length}) |
sort_by(-.skipped)'
Bot-triggered runs:
gh api "/repos/$OWNER/$REPO/actions/runs?per_page=100" \
--jq '[.workflow_runs[] | select(.triggering_actor.type == "Bot")] | length'
High-frequency workflows (candidates for path filters):
gh api "/repos/$OWNER/$REPO/actions/runs?per_page=100" \
--jq '.workflow_runs | group_by(.name) | map(select(length > 50)) |
map({workflow: .[0].name, runs: length})'
Read each workflow file from .github/workflows/ and check for:
concurrency: groupspaths: filters on push/PR triggersif: github.event.sender.type != 'Bot')Print a summary with these sections:
Use these thresholds for flagging:
| Metric | Red Flag Threshold |
|---|---|
| Skipped runs | >10% of total runs |
| Bot triggers | Bot-to-bot chains detected |
| Long durations | >10min average |
| High frequency | >50 runs/month without path filters |
| Duplicate runs | Same commit triggers multiple runs |
For each waste pattern found, recommend the specific fix:
| Pattern | Fix |
|---|---|
| Bot-triggered waste | Add if: github.event.sender.type != 'Bot' to jobs |
| Missing concurrency | Add concurrency: { group: ${{ github.workflow }}-${{ github.ref }}, cancel-in-progress: true } |
| No path filters | Add paths: with relevant source directories |
| Duplicate runs | Add concurrency groups with cancel-in-progress: true |
| Endpoint | Purpose | Admin Required |
|---|---|---|
/orgs/{org}/settings/billing/actions | Minutes usage | Yes |
/orgs/{org}/settings/billing/packages | Package bandwidth | Yes |
/orgs/{org}/settings/billing/shared-storage | Storage billing | Yes |
/orgs/{org}/actions/cache/usage | Org cache stats | No |
/repos/{owner}/{repo}/actions/runs | Workflow runs | No |
/repos/{owner}/{repo}/actions/workflows | Workflow definitions | No |
| Context | Command |
|---|---|
| Org billing | gh api /orgs/$ORG/settings/billing/actions --jq '{included_minutes, total_minutes_used}' |
| List repos | gh repo list $ORG --json nameWithOwner --limit 100 |
| Workflow runs | gh api "/repos/$O/$R/actions/runs?per_page=100" --jq '.workflow_runs' --jq 'length' |
| Skipped count | `gh api "..." --jq '[.workflow_runs[] |
| Bot triggers | `gh api "..." --jq '[.workflow_runs[] |