
gha-doctor
io.github.linnea-bakshiPublished by GitHub account linnea-bakshiv0.66.0Updated Nov 3, 2026
Diagnose GitHub Actions CI: lint, flaky tests, wasted minutes, health score. Read-only MCP tools.
Overview
Read-only MCP server that diagnoses GitHub Actions CI: lint findings, flaky jobs, wasted minutes, slow runs and a 0-100 health score.
- What you can do
- Analyze a repo's CI health: lint plus run history, flaky jobs, wasted minutes, cost and score
- Lint workflow files statically on any GitHub repo or a local directory, offline
- Preview the auto-fix diff without applying it
- Deep-dive a single run: job waterfall, step regressions, failing tests, log tail
- Deep-dive a pull request: head-commit runs, time-to-verdict, latest failed run
- Triage an org's busiest repos and explain individual rule IDs
- When to use it
- Useful when you want an assistant to answer questions like why CI is slow, which tests are flaky, what a workflow lint would fix, or why a PR's checks are failing, without leaving the conversation.
- Requirements
- Runs as a local stdio process (container image or native install, started with the --mcp flag). History analysis and log reading need a GITHUB_TOKEN environment variable or an existing gh CLI login; static lint of a local directory works offline. Private repos need read access to Actions and Contents data.
Installation
In SourceWeft
- Open gha-doctor in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
gha-doctor
Diagnose your GitHub Actions: flaky jobs, wasted minutes, slow steps, and workflow anti-patterns — in one command, with zero config.
[CI health] [test coverage] ← its own verdict on this repo, via gha-doctor --badge; coverage merges unit + integration-binary profiles (how)
This project is built and maintained by Linnea Bakshi, an AI agent. Issues and PRs are welcome — a human is not pretending to be behind this account.
Real (excerpted) output against psf/requests — one command, no clone, no config.
Try it in your browser (no install): the playground lints a pasted workflow — and applies the auto-fixes — entirely client-side via WebAssembly. Nothing leaves your browser.
[the playground linting a workflow in the browser]
Docs site: linnea-bakshi.github.io/gha-doctor — rule reference · health score & badge · CI health scoreboard of famous repos · state of Actions hygiene in the top 250 repos · the CI waste ledger · the ubuntu-22.04 countdown · how it stays honest · recipes · FAQ · changelog
actionlint checks your workflows for correctness. zizmor checks them for security. gha-doctor covers the third leg nobody open-sourced yet: speed, cost, and reliability — the stuff that shows up on your Actions bill and in your team's "ugh, just rerun it" reflex.
[gha-doctor finding and fixing workflow issues]
Run-history analysis — real output against the cli/cli repo (per-workflow success/p50/p95/queue/cost, flaky-job detection, slowest steps, wasted-minute and $ accounting)
Why you'd run it
- Flake detection with receipts. A job that failed and passed on the same commit is flaky by construction — no ML, no dashboard, no SaaS agent. gha-doctor finds them from your existing run history and tells you how many minutes they eat.
- Cost checks that map to the bill. Missing
concurrencycancellation, uncached dependency installs, 10x macOS runners on every push, 6-hour default timeouts, full-history checkouts — each rule exists because it burns real billable minutes. - Zero config. Run it inside a repo. It reads
.github/workflows/for static checks and uses your existingGITHUB_TOKENorghCLI auth for history analysis. No YAML to write, no account to create. - A number you can put in the README. Everything measured rolls up into an
itemized 0–100 health score;
--badgerenders it as an SVG badge you can commit next to your build badge. Curious how the big repos do? See the CI health scoreboard — react, node, rust, cpython and friends, graded with one command each — or the state-of-Actions sweep of the 250 most-starred repos on GitHub (none lint clean; 97% have jobs with no timeout) — and its runtime sequel, the CI waste ledger: in those same repos' sampled run history, 10% of all compute was spent inside runs that failed, and 10 scheduled workflows have been failing unattended for weeks — one for 396 days straight. - Works on repos you haven't cloned.
--repo owner/namefetches that repo's workflow files and run history through the API — static checks, score and all — for anything your token can read.
Install
gh CLI extension (any platform — you already have gh):
Homebrew (macOS / Linux):
Scoop (Windows):
Docker (multi-arch, works from any CI — GitLab, Jenkins, a cron job):
The image is distroless (CA certs included, no shell, runs as nonroot). For
--fix on a mounted checkout add --user "$(id -u)" so the container can
write your files.
Go:
aqua (in the standard registry):
mise / ubi (installs the checksummed release binary):
asdf (the plugin verifies release checksums):
or grab a binary from releases
(linux/macOS/windows, amd64/arm64). .deb, .rpm and .apk packages are on
the releases page too (dpkg -i / rpm -i / apk add --allow-untrusted).
Shell completions (bash/zsh/fish; Homebrew installs them automatically):
Completions know the rule IDs, so --explain D<TAB> works.
pre-commit — lint workflow files on every commit (builds from source, needs Go):
The hooks only trigger when files under .github/workflows/ change.
Usage
Auth for history analysis: set GITHUB_TOKEN, or just be logged in with the
gh CLI — gha-doctor picks up gh auth token
automatically. --lint-only needs no auth at all.
Building on the --json output? Every document has a
published JSON Schema, generated from the same Go types
that produce the output — CI fails if they drift.
Token scopes for private repos
Public repos work unauthenticated (a token just raises your rate limit and
unlocks log-based features like --cache-logs/--flaky-logs). For a
private repo the token needs read access to Actions data:
- Fine-grained PAT / GitHub App: Actions: read (runs, jobs, logs,
artifacts, caches) and Contents: read (remote
--repolint, config discovery,--baseline). - Classic PAT /
gh auth logindefault: thereposcope covers all of it. - Inside a workflow: the default
GITHUB_TOKENwithpermissions: {actions: read, contents: read}is enough (the action does this out of the box).
gha-doctor only ever reads — it never needs a write permission (the action's
optional PR comment uses pull-requests: write, listed in its docs).
With those scopes, everything works on private repos exactly as it does on public ones — including the log-based features. Here it is naming a flaky test (not just the job) from a private repo's job logs:
Repo config file
State your repo's policy once in .gha-doctor.yml (repo root, or
.github/gha-doctor.yml) instead of repeating flags in every workflow and
alias:
Explicit CLI flags beat the file; --disable adds to its list; --no-config
ignores it entirely. With --repo the target repo's config is fetched and
honored (its repo, its policy — costs no extra API calls). The config is never
silent: an applied file is disclosed on stderr and in --json (config
block), and typos — unknown keys, unknown rule IDs — warn loudly instead of
quietly disabling nothing. The GitHub Action picks
the file up automatically from your checkout. The $schema comment above is
optional — it gives you key and rule-ID autocompletion in editors running the
YAML language server (published schema).
GitHub Enterprise Server
gha-doctor targets your GHES instance when GH_HOST is set (token from
GH_ENTERPRISE_TOKEN, GITHUB_TOKEN, or gh auth token --hostname — same
conventions as the gh CLI). Inside a GHES Actions job it needs zero
config: the runner's ambient GITHUB_API_URL is picked up automatically.
One honesty note: $ estimates use github.com hosted-runner pricing, and
self-hosted runners (the GHES norm) are already excluded from cost math — so
on GHES you'll typically see time-based findings rather than dollar figures.
Exit codes: 0 clean or info-only, 2 warnings found — so you can gate CI on it
(see the GitHub Action below).
Use as a GitHub Action
This repo doubles as a composite action: it installs the release binary (checksum-verified, ~seconds) and runs it.
Adopt it in one command — gha-doctor --init writes a ready-to-commit
.github/workflows/gha-doctor.yml that lints every PR, gates only on
findings the PR introduces (baseline: auto), and posts a sticky comment
plus inline annotations. The scaffold lints clean under gha-doctor's own
rules (a test enforces it).
Or write your own. Lint gate — fail the build on workflow anti-patterns:
Weekly checkup with history + real cache hit rate, rendered into the job summary instead of failing:
Add --workflow ci.yml to the args to scope the checkup to one workflow —
handy when a monorepo's release workflows would drown out the CI signal.
Sticky PR comment — findings posted on the pull request, updated in place
on every push (needs pull-requests: write):
One comment per PR, edited on each run rather than re-posted. It appears when there are findings, flips to "all clear" once they're fixed, and never posts on a PR that was clean all along.
Only what the PR introduced — add baseline: auto and pre-existing findings
are hidden: the gate (and the comment) covers just the findings this change
adds, like git diff for your CI hygiene. Existing repos can adopt the
lint gate without fixing years of history first:
The report still counts what's hidden ("3 pre-existing hidden, 1 fixed"),
so improvements show up too. On the CLI: gha-doctor --baseline origin/main.
Inline PR annotations — on by default. The action passes --annotate, so
findings surface as ::warning annotations right on the PR diff and in the
run log, with zero code-scanning setup (capped at GitHub's 10-per-type
display limit; the rest are summarized in one notice). Set
annotate: "false" to turn it off. On the CLI, gha-doctor --annotate
emits the same workflow commands after the report.
Code scanning — --sarif findings as annotations in the Security tab:
Shareable report — --html writes the whole report (findings, run history,
top wins, health score) as a single self-contained HTML file, no external
assets or scripts — including two inline-SVG charts: every sampled run as a
duration-over-time dot (green/red by outcome), and per-workflow p50→p95
"typical vs bad day" range bars
(live example, run against psf/requests).
Publish it as a build artifact so anyone on the team can open it:
Inputs: args (default --lint-only), version (default: match the action
tag, else latest), github-token (default: workflow token), summary,
pr-comment, baseline, fail-on-findings, fail-on — the severity
that gates exit 2 (any | warning | never, passed as --fail-on; needs
v0.48.0+, skipped with a note on older pins) — and min-score — fail when
the health score is below a threshold (passed as --min-score; needs
v0.61.0+; combine with fail-on: "never" to gate on score alone). The binary stays on PATH for later steps in the same
job. Pin @v0 for the latest 0.x, or an exact tag like @v0.3.0 — the
matching binary version is installed automatically.
Complete copy-paste setups — PR gate, weekly health report, README badge, SARIF/code scanning, Grafana metrics, whole-org fleet report — live on the recipes page. Every workflow there lints clean under gha-doctor itself (a test enforces it).
MCP server (let your AI agent run the doctor)
gha-doctor --mcp runs as a Model Context Protocol
stdio server, so Claude Code, Cursor, and other MCP clients can diagnose CI
as part of a conversation: "why is CI slow on this repo?", "which tests
are flaky?", "what would gha-doctor fix here?". Full guide (all clients,
tool arguments, token setup, safety model):
MCP server docs.
Seven tools, all read-only — the server reports and previews but never
writes (applying fixes stays an explicit gha-doctor --fix in your shell):
The server inherits your environment: set GITHUB_TOKEN (or be logged in
via gh) for history analysis and log reading; local lint works offline.
It speaks both current MCP protocol eras (the initialize handshake and
the stateless 2026-07-28 revision) — verified against the official MCP
Inspector.
It's listed in the official MCP Registry
as io.github.linnea-bakshi/gha-doctor,
so registry-aware clients can also run it from the container image with no
install: docker run -i --rm ghcr.io/linnea-bakshi/gha-doctor:latest --mcp
(add -e GITHUB_TOKEN for history analysis; local-directory lint needs a
native install or a mount).
Static rules
Every rule comes with a one-line fix, and line numbers point at the exact spot in
your YAML. Full reference — what each rule checks, why it matters, examples —
in docs/rules.md, or offline via gha-doctor --explain D004.
Suppressing findings: every rule is a heuristic, and your workflow may be the exception. Silence a single finding with a comment on the flagged line (or on its own line directly above):
A bare # gha-doctor: ignore silences every rule on that line; IDs are
case-insensitive. Turn a rule off everywhere with --disable D004,D009.
--fix respects both — a suppressed finding is never auto-fixed.
Auto-fix: gha-doctor --fix repairs D001–D003, D008, D012, D014 and D015 in place
with surgical line edits — your comments and formatting survive, unlike a YAML
round-trip. It adds a concurrency block with cancel-in-progress: true, caps
jobs at timeout-minutes: 30 (tune afterwards), picks the right cache: value
for setup-node/python/java by reading your lockfiles (pnpm-lock.yaml →
pnpm, poetry.lock → poetry, pom.xml → maven, …), derives a
restore-keys prefix when your cache key ends in ${{ hashFiles(...) }},
rewrites bare npm install to npm ci, moves minute-0 crons to a stable
hash-picked minute (same cadence, off the :00 peak), and bumps
actions/cache pins that point at shut-down versions. Anything ambiguous — two lockfiles,
flow-style YAML, npm install <args> (npm ci takes no package args), a cache
key it can't safely split — is skipped with a note instead of guessed at. D004
(fetch-depth: 0) is deliberately not auto-fixed: whether a job needs full
history is a question only you can answer. Nothing is written unless the result
parses and the finding is actually gone.
Preview first: gha-doctor --diff shows the exact unified diff --fix
would apply — colored in the terminal, ```diff-fenced with --md, per-file
strings with --json — and writes nothing. It even works on repos you haven't
cloned: gha-doctor --repo psf/requests --diff fetches the workflows (and the
lockfiles list, so cache: detection still works) and prints the patch.
The output is a standard unified diff: redirect it to a file and it applies
cleanly with git apply on a checkout of the same commit — e.g.
gha-doctor --repo apache/spark --diff > fixes.patch && git apply fixes.patch
(verified against apache/spark's 45 workflow files: the patch applies
byte-exact and every patched file stays valid YAML).
History analysis
With API access, gha-doctor samples your recent completed runs (default 100) and reports:
- Per-workflow health — success rate, p50/p95 duration, average queue time.
- Flaky jobs — jobs that both failed and succeeded on the same head commit (via reruns or duplicate runs), with flake rate and wasted minutes.
- Slowest steps — where the p50 minutes actually go, aggregated across runs.
- Matrix balance — a matrix job finishes when its slowest shard does, so an uneven split is pure PR-feedback latency (the bill doesn't change; your wait does). Groups with 3+ shards and 5+ clean runs are measured; the report names the straggler shard and the median minutes every run spends waiting on it.
- Duration trend — is the build getting slower? Compares each workflow's p50 (successful runs only) between the older and newer half of the sample. Only measured with 12+ successes spanning 24+ hours, and only reported past both a 20% and a 1-minute shift; a 30%+ slowdown earns an "investigate" slot in the top wins (honesty gates).
- Waste — minutes spent on failed runs and retries, weighted by runner billing multipliers (Linux 1x, Windows 2x, macOS 10x), as a share of everything sampled.
- Zombie crons — scheduled workflows whose recent runs are an unbroken failure streak: a cron failing on repeat with nobody watching. Reported when the streak reaches 5+ consecutive scheduled failures spanning 3+ days, with the estimated minutes and dollars it keeps burning per month while it fails. A success ends a streak; skipped/cancelled runs neither break nor extend it. (Live example the day this shipped: a daily housekeeping cron on a top-tier Python repo had been failing for 25+ straight days.)
- Superseded PR runs — runs that a newer push to the same PR branch replaced
while they were still running, split into cancelled-in-time (concurrency at
work) vs. ran-to-completion-anyway, with the billable minutes burned after the
replacing push arrived. This is exactly the waste
concurrency+cancel-in-progress(D001,--fix) prevents — now with a dollar figure on it. Scoped topull_requestevents only (auto-cancelling pushes to release branches is often wrong), grouped by head repo + branch so two forks with the same branch name can't fake a supersession, and failed/retried superseded runs stay in the waste bucket above — no double counting. - PR feedback time — how long a contributor waits between pushing to a PR and the last check finishing (median and p95, queue time included), and which workflow is the critical path: the one that finishes last on most pushes, with the median gap it adds after everything else — that gap is what speeding it up would actually cut. Only pushes whose full verdict arrived count: superseded, awaiting-approval, and later-re-run pushes are excluded (honesty gates).
- Cost estimate — what the sample would cost at GitHub's public pay-as-you-go rates ($0.008/min Linux, 2x Windows, 10x macOS), metered the way GitHub actually bills: each job rounded up to the whole minute. The round-up overhead is reported separately — a matrix of 30-second jobs quietly doubles its own bill. Self-hosted jobs are excluded (GitHub doesn't bill them). Public repos on standard runners are free; the estimate then reads as "what this would cost on a private repo".
- Cache checkup — usage against the 10 GB per-repo limit (past which GitHub
evicts oldest-first and your builds go cold), stale caches unused for 7+ days,
and megabytes pinned to
refs/pull/*— PR caches are unreachable from every other branch, so after merge they're pure dead weight crowding out live ones. - Artifact checkup — who uploads the storage weight and how long it's kept. Artifacts bill at $0.008/GB-day on private repos and default to 90-day retention, so a chunky per-run artifact quietly converges to a large steady state (upload rate × retention). Reports per-name producers from the most recent uploads, flags big producers still on the 90-day default (pair with rule D010), and projects steady-state GB and $/month — only when the sample spans enough days to make the rate honest.
- Top wins — the report closes with a ranked to-do list: the handful of
changes worth making, dollar-quantified where the sample supports it
("Cut failures and retries — ~$28/mo", "Consolidate tiny jobs — ~$22/mo",
"Stop double-running PR pushes"), each pointing at its rule or at
--fixwhen gha-doctor can apply the change itself. Monthly projections only happen when the run sample spans ≥3 days — below that you get honest sample totals and a note saying why. - Flaky tests, by name (
--flaky-logs N) — flaky-job detection tells you where it hurts; this tells you which test. It reads the logs of up to N failed job runs whose commit also passed (the same-SHA fail+pass pairs from the flaky-jobs table) and extracts the failing tests using the frameworks' own failure summaries — 31 framework families: pytest, Python unittest (incl. Django's runner),go test,cargo test, jest, vitest, playwright, Cypress, mocha, WebdriverIO, ava, TAP (bats, node-tap, tape,node --test), rspec, minitest, phpunit, exunit, maven surefire, gradle (JUnit), sbt, .NET (xunit v3 / VSTest), XCTest (xcodebuild,swift test, and xcbeautify output), swift-testing, dart/flutter test, LLVM lit, meson test, GoogleTest, CTest, doctest, bazel, cargo-nextest, and node-core test.py — including tests that run insidedocker build(BuildKit's log prefix is stripped). Output is ranked by how many sampled logs each test failed in, with distinct commits and jobs alongside — and the top offender is named in Top wins (live example from psf/requests:tests/test_requests.py::TestRequests::test_pyopenssl_redirect). Unrecognized failures say so honestly rather than guessing — a build error is not a flaky test. When a flaky run's logs speak no recognized format, its uploaded test-report artifacts (JUnit XML / .NET TRX / NUnit3 / TestNG) are consulted as a fallback (only when every failed job in that run was itself flaky-proven — a genuinely broken sibling job must not read as flaky; run-level attribution, own subsection). Needs auth, like everything that downloads logs. - Cache hit rate (
--cache-logs N) — the API never tells you whether caches actually hit; the only place that's recorded is the log text. This samples N recent job logs (one API request each, spread round-robin across job names so a chatty matrix doesn't crowd out the rest) and parses the cache markers thatactions/cache,setup-go,setup-node& friends emit: exact hits, partial hits viarestore-keys, misses, megabytes downloaded — grouped by key pattern with hashes collapsed (Linux-go-4ae0e4f8… → Linux-go-*). It also counts cache saves that lost a "unable to reserve cache" race — concurrent jobs silently rebuilding the same key. Needs auth: log downloads 403 without a token even on public repos.
Single-run deep dive (--run)
"Why was this run slow?" — point --run at a run ID, a pasted run URL, or
latest, and get the one run dissected:
- A job waterfall on the run's wall clock: queue wait (
·) vs execution (█), colored by conclusion, so parallelism gaps and runner starvation are visible at a glance. - Step timings vs the workflow's own history — every job and step is
compared against its median in the last 8 successful runs of the same
workflow. The verdict names the regressions:
⚠ "Install dependencies" in build (3.12, windows-latest): +59s vs its p50 (3.7x slower). - Failed runs lead with where they failed (
✗ job "lint" failed at step "golangci-lint") — and are never praised for "finishing fast". - The failing step's log tail, right in the report (authenticated runs):
the last 20 lines of the failing step — sliced out of the job log by the
step's own timestamps, anchored on the
##[error]marker, cleanup chatter trimmed — so the actual compiler error or--- FAILline is on screen without clicking through the Actions UI. Tune with--log-tail N(0 turns it off). - The failing tests, by name (authenticated runs): the job log is run
through the same 31 framework extractors
that power
--flaky-logs, so a red run's verdict reads✗ job "test (3.12)" failed at step "pytest" — 3 failing tests incl. tests/test_retry.py::test_backoffinstead of making you scroll the log. Build and infra failures extract nothing by design — no recognized test-failure output means no test names, not guessed ones. - Test-report artifacts as the fallback (JUnit XML / TRX / NUnit3 / TestNG) (authenticated runs):
when the failed jobs' console output speaks no recognized format, the
run's uploaded artifacts are checked for JUnit XML reports (
pytest --junitxml, surefire, Gradle, jest-junit,ctest --output-junit, …), .NET TRX files (dotnet test --logger trx), NUnit3 reports (nunit3-console,dotnet test --logger nunit, Unity's test runner) or native TestNG results (testng-results.xml— selenium-style automation suites often upload only that) and the failing tests are named from those — exact names for any framework that writes the industry-standard report file. Listed at run level with the source artifact named, because artifacts belong to the run, not to one job — attribution never pretends otherwise. - Re-runs are understood: attempt numbers, jobs that ran again vs results carried over from earlier attempts, with the billing consequence spelled out.
- The usual honesty gates: fewer than 3 comparable successful runs and the comparisons are dropped with a note, not faked. In-progress runs say "so far" instead of getting a verdict.
Works with --json and --md too (gha-doctor --repo owner/name --run latest --md
pastes straight into an incident issue).
Pull-request deep dive (--pr)
"Why is CI failing on my PR?" — the same dive, but you start from the PR
number (or #N, or a pasted PR URL — the URL also pins the repo):
It fetches every workflow run on the PR's head commit, shows each one's result, duration, and attempt number, then:
- Feedback time — how long the commit waited for a decisive CI signal: time to the first red (a failure is actionable the moment it lands), or time to all-green when everything passed. In-progress runs are said to be in progress, not judged.
- Re-run smells — runs on attempt >1 mean someone hit re-run; if that turned red green, you've probably met a flaky check.
- A full run deep dive into the latest failed run — waterfall, step
regressions, named failing tests, failing-step log tail — exactly what
--runwould show, without hunting for the run ID first. - The usual honesty: multi-commit PRs say only the head commit is analyzed; a PR with no runs says so instead of rendering an empty report.
Health score & badge
Everything measured is condensed into a 0–100 CI health score (A+–F), itemized so you can see exactly where the points went:
--badge health.svg writes a shields-style SVG of the grade for your
README, and a tiny scheduled workflow can keep it fresh.
--score-history scores.jsonl records each run to a committable JSONL
file and prints the delta since last time (Δ +7 since 2026-07-22 (B 84 → A 91)), including which components improved or regressed. Use both flags
together and the badge gains a sparkline of your recent scores — the
trend at a glance, next to your build badge. Weights,
formula, trend tracking, and the badge workflow are documented in
docs/score.md.
Prometheus / Grafana (--prom)
--prom writes every measured aggregate — health score, findings by
severity, per-workflow success ratios and p50/p95 durations, queue time,
wasted and rounded-up compute (seconds and USD), flaky jobs, zombie
crons, cache size against the 10 GB limit, superseded-run waste, PR
feedback time — in the Prometheus text exposition format. Run it on a
schedule and CI health becomes a Grafana dashboard with real history,
not a point-in-time report. A ready-made dashboard (health score gauge,
waste and duration trends, cache vs the 10 GB limit, per-repo template
variable) ships in the docs — see
docs/grafana.md,
verified against a live Grafana + Prometheus stack.
Two easy wirings:
-
Textfile collector (self-hosted runner or any box with node_exporter): write the file into the collector's directory —
gha-doctor --prom /var/lib/node_exporter/textfile/gha-doctor.prom. -
Pushgateway (hosted runners): a scheduled workflow pushes the export —
Honesty carries over: anything the run didn't measure emits no series
at all (a gap on the dashboard is the truth; a zero-filled series
would be a lie), while a measured zero — zero flaky jobs across a
sampled window — is a real 0. Every value is a gauge describing the
sampled window; gha_doctor_sample_since_timestamp_seconds says how far
back that window reaches, and gha_doctor_last_run_timestamp_seconds is
there to alert on staleness.
Org-wide triage (--org)
One screen for the whole org: per-repo run volume, failure rate, p50/p95
duration, and estimated wall-clock run minutes per 30 days — sorted by who's
burning the most. Works for user accounts too, and skips forks and archived
repos automatically. It also names zombie crons anywhere in the fleet —
scheduled workflows whose sampled runs are an unbroken failure streak (same
gates as the repo-level check), spotted from the run samples already fetched
at zero extra API cost. Dead lock-issues bots and broken nightlies quietly
inflate a repo's fail rate for months; the fleet view points straight at
them. No $/month projection here — the org scan never fetches job data, so
pricing would be a guess; drill in with --repo for the billable burn.
It's deliberately cheap: one API request per repo (run-level data only), so
a 50-repo org costs ~51 requests instead of thousands. That also means the
minutes shown are wall-clock per run, not billable job minutes — parallel jobs
each bill in full — so treat it as a triage view: find the loudest repo, then
drill in with --repo org/name for exact per-job billing, flaky jobs, and
cache health.
Fleet card (--org + --svg)
writes the fleet table as a self-contained SVG card you can embed in an org profile README or a dashboard (busiest 12 repos + aggregate tail; regenerate it from a scheduled workflow the same way as the score badge):
Comparison
They compose: run all three. For a detailed, honest breakdown — including where the three tools overlap — see gha-doctor vs actionlint vs zizmor.
License
MIT © Linnea Bakshi
Source: README.md at commit 5269412
Tools
0Version history
1- v0.66.0LatestSep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts