Skip to content

LeRedTeam/cache-doctor

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

Cache Doctor

Your GitHub Actions caches are wasting money. You just can't see it.

Cache Doctor is a continuous linter and diagnostic tool for GitHub Actions cache. It finds the problems you didn't know you had -- orphan caches from deleted branches, bad key patterns that never hit, quota silently filling up -- and tells you exactly how to fix them.

Two lines of YAML. Zero infrastructure. Runs on every PR.

- uses: LeRedTeam/cache-doctor@v1
  with:
    mode: analyze

Why

GitHub Actions cache has no dashboard, no hit/miss analytics, no quota alerts, and no eviction notifications. When your 10 GB quota fills up, GitHub silently evicts caches via LRU. Your builds go from 3 minutes to 15 minutes and nobody knows why.

You've been there:

  1. Notice builds are slow
  2. Wonder if it's cache-related
  3. Read raw workflow logs line by line
  4. Guess at the fix
  5. Wait for next builds
  6. Repeat

Cache Doctor replaces that loop with a single command.

What It Looks Like

cache-doctor analyze

Cache Health Report
==================================================

Quota: 7.2 GB / 10.0 GB (72%)
Total caches: 31
  Active: 18 (3.8 GB)
  Stale:  8 (2.1 GB) -- not accessed recently
  Orphan: 5 (1.3 GB) -- from deleted branches

Issues found: 3
----------------------------------------
1. [HIGH] Quota pressure: 72% used
   Cache quota at 72%. LRU eviction may be active.

2. [MEDIUM] 5 orphan caches from deleted branches waste 1.3 GB
   These caches belong to branches that no longer exist.

3. [LOW] 8 stale caches not accessed recently waste 2.1 GB
   These caches have not been accessed within the stale threshold.

Recommendations
----------------------------------------
1. [MEDIUM] Orphan caches from deleted branches
   Found 5 orphan caches wasting 1.3 GB.
   Action: cache-doctor cleanup --delete-orphans
   Impact: Reclaim 1.3 GB

2. [LOW] Many stale caches
   Found 8 stale caches wasting 2.1 GB.
   Action: cache-doctor cleanup --stale-days 7
   Impact: Reclaim 2.1 GB

cache-doctor cleanup --delete-orphans

Cache Cleanup Report
==================================================

Deleted 5 caches (1.3 GB reclaimed)

Orphan (1.3 GB):
  - node-modules-Linux-feature/old-thing-abc123 (800.0 MB, branch: feature/old-thing)
  - build-cache-feature/old-thing-def456 (200.0 MB, branch: feature/old-thing)
  - deps-feature/experiment-ghi789 (300.0 MB, branch: feature/experiment)

Quota: 5.9 GB / 10.0 GB (55%) -- was 72%

cache-doctor lint

Linting .github/workflows/ci.yml...

CD001 [WARNING] Line 24: No restore-keys defined. Cache is all-or-nothing.
  > - uses: actions/cache@v4
  Fix: Add restore-keys with a prefix fallback for partial cache matches.

CD011 [WARNING] Line 31: Cache key uses github.sha. This is unique per commit
  so the cache will never hit.
  > - uses: actions/cache@v4
  Fix: Use hashFiles() on input files instead of github.sha.

CD016 [WARNING] Line 18: This job already uses a setup action with built-in npm
  caching. This manual cache step may be redundant.
  > - uses: actions/cache@v4
  Fix: Remove this actions/cache step or disable built-in caching in the setup
  action (cache: false).

CD017 [WARNING] Line 36: Restore-keys don't share a prefix with the cache key.
  Key starts with "v2-build-" but no restore-key matches.
  > - uses: actions/cache@v4
  Fix: Ensure restore-keys use the same prefix as the cache key.

Found 8 issues (0 errors, 6 warnings, 2 info)

Quick Start

Run on every PR (recommended)

name: Cache Health
on: pull_request

permissions:
  actions: read

jobs:
  cache-doctor:
    runs-on: ubuntu-latest
    steps:
      - uses: LeRedTeam/cache-doctor@v1
        with:
          mode: analyze

Results appear in the Job Summary tab of the workflow run.

Scheduled cleanup

name: Cache Cleanup
on:
  schedule:
    - cron: '0 2 * * 1'  # Monday 2am
  workflow_dispatch:

permissions:
  actions: write

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - uses: LeRedTeam/cache-doctor@v1
        with:
          mode: cleanup
          stale-days: '7'
          delete-orphans: 'true'

CLI

# Install
go install github.com/LeRedTeam/cache-doctor@latest

# Analyze
export GITHUB_TOKEN=ghp_...
cache-doctor analyze --repo your-org/your-repo

# Cleanup (always dry-run first)
cache-doctor cleanup --dry-run --delete-orphans --repo your-org/your-repo
cache-doctor cleanup --delete-orphans --repo your-org/your-repo

# Lint (Pro)
cache-doctor lint .github/workflows/

19 Lint Rules

Cache Doctor encodes the tribal knowledge that lives in scattered blog posts and Stack Overflow answers into automated checks.

Rule What It Catches
CD001 Missing restore-keys -- cache is all-or-nothing, no partial matches
CD002 Hardcoded cache key -- never invalidates, serves stale content forever
CD003 Missing OS in key -- matrix jobs on different OS share incompatible caches
CD004 Missing matrix vars in key -- Node 18 and Node 20 share the same cache
CD005 Caching node_modules directly -- huge, platform-specific; use ~/.npm instead
CD006 Overly broad hashFiles -- **/*.json changes constantly, busting cache
CD007 No version prefix -- can't bulk-invalidate when cache format changes
CD008 Path too broad -- caching ~ or . wastes quota on everything
CD009 Duplicate cache steps -- same key twice in one job, wasting API calls
CD010 Outdated actions/cache@v3 -- v4 has better performance
CD011 github.sha in key -- unique per commit, cache never hits
CD013 Restore-key too short -- bu matches ancient, irrelevant caches
CD014 Reusable workflow cache without inputs -- callers collide
CD015 Large paths (target/, .gradle, vendor/) -- wrong thing cached
CD016 setup-node with cache: 'npm' plus manual actions/cache -- double caching
CD017 Restore-key prefix mismatch -- v2-build-* key with build- restore, never matches
CD018 Dynamic key without hashFiles -- ${{ runner.os }} alone never invalidates
CD019 actions/cache/save without restore -- uploads every run, never downloads
CD020 6+ cache steps in one job -- caching strategy needs rethinking

Configuration

Action Inputs

Input Default Description
token ${{ github.token }} GitHub token
mode analyze analyze, lint, or cleanup
stale-days 7 Days without access to consider stale
delete-orphans false Delete caches from deleted branches
dry-run false Show what would be deleted
path .github/workflows/ Path to lint
format summary summary, json, human, sarif
top 5 Number of largest caches to show

Action Outputs

Output Description
quota-pct Current quota usage %
total-caches Total caches
stale-count Stale caches
orphan-count Orphan caches
findings-count Issues found
deleted-count Caches deleted
reclaimed-bytes Bytes reclaimed

Exit Codes

Code Meaning
0 Success, no issues
1 Issues found (useful for CI gates)
2 Invalid arguments
3 GitHub API error

How It Works

Cache Doctor reads cache metadata from the GitHub REST API (key, size, branch, last access time). It never reads cache content. It never stores your token. It has no backend, no database, no telemetry.

GitHub REST API          cache-doctor           Your workflow
      │                       │                       │
      │  GET /actions/caches  │                       │
      │◄──────────────────────│                       │
      │  cache metadata       │                       │
      │──────────────────────►│                       │
      │                       │  analyze/lint/cleanup  │
      │  GET /branches/{name} │                       │
      │◄──────────────────────│                       │
      │  exists? 404?         │                       │
      │──────────────────────►│                       │
      │                       │  Job Summary / JSON    │
      │                       │──────────────────────►│

Required permissions:

  • actions: read for analyze and lint
  • actions: write for cleanup (needs delete permission)

Free vs Pro

Feature Free Pro
Analyze (quota, stale, orphan detection) Yes Yes
Cleanup (delete stale/orphan caches) Yes Yes
Job Summary output Yes Yes
JSON output Yes Yes
Lint (19 static analysis rules) Yes
SARIF output (GitHub Code Scanning) Yes
PR comment output Yes
Hit/miss analysis (log parsing) Yes

Pro: $15/month or $119/year per organization. Get a license →

The free tier gives you full visibility into your cache health and automated cleanup. Pro adds preventive checks that catch bad patterns before they ship.

Get a License

Pro licenses are per-organization and cover all repos in the org.

1. Choose a plan

Plan Price Link
Pro Monthly $15/month Subscribe →
Pro Annual $119/year (2 months free) Subscribe →
Commercial (AGPL exemption) $149/year Purchase →

2. Receive your license key

After payment, you'll receive a license key by email. It looks like this:

eyJlbWFpbCI6InlvdUBjb21wYW55LmNvbSIsInRpZXIiOiJwcm8iLC...

3. Add it to your GitHub repo or org

Go to Settings > Secrets and variables > Actions and create a secret:

  • Name: CACHE_DOCTOR_LICENSE_KEY
  • Value: the license key from step 2

For org-wide coverage, create it as an organization secret and grant access to all repos that use cache-doctor.

4. Use Pro features

- uses: LeRedTeam/cache-doctor@v1
  with:
    mode: lint
  env:
    CACHE_DOCTOR_LICENSE_KEY: ${{ secrets.CACHE_DOCTOR_LICENSE_KEY }}

Or via CLI:

export CACHE_DOCTOR_LICENSE_KEY="eyJlbWFpbCI6..."
cache-doctor lint .github/workflows/

License FAQ

What happens when my license expires? There's a 7-day grace period. After that, Pro features (lint, SARIF, PR comments) stop working. Analyze and cleanup always work (free tier).

Can I use one license across multiple repos? Yes. Pro licenses are per-organization. One license covers all repos in the org.

Is there a free trial? The free tier includes full analyze and cleanup functionality. Try those first -- if you want lint rules to prevent future problems, upgrade to Pro.

License

AGPL-3.0. See COPYING.

Commercial licenses (AGPL exemption) available at the link above or contact leredteam@gmail.com

About

Diagnose and optimize GitHub Actions cache health. Continuous linter for cache behavior.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages