Skip to main content
Glama

didrun

Did your scheduled GitHub workflows run when they should have? didrun reads GitHub's own record of a repo's workflows and scheduled runs and lists the runs that came late, the runs that never came, the runs that failed, the green runs that did nothing, and the schedules GitHub has quietly disabled.

npx --allow-git=root github:agentwares/didrun

Run it inside a clone, or name the repo (… didrun octo-org/nightly-jobs). No account, no change to your repo, no code to add. It uses your own GitHub token (GITHUB_TOKEN, GH_TOKEN or the GitHub CLI's login), and with none it reads public repos.

GitHub's own documentation (read 9 October 2026) says scheduled runs "can be delayed during periods of high loads", that under enough load "some queued jobs may be dropped", and that in a public repository "scheduled workflows are automatically disabled when no repository activity has occurred in 60 days". None of that sends an alert. A dropped run leaves no trace in the Actions tab, and a disabled schedule simply stops.

What it prints

Recorded over a synthetic repo shipped with the package (npx --allow-git=root github:agentwares/didrun demo, regenerated by node scripts/sample.mjs), not anyone's real runs:

Synthetic repo, written for this demo: not anyone's repo or runs.

didrun 0.1.0 · synthetic-org/nightly-jobs · Fri 2 Oct 13:00 UTC to Fri 9 Oct 13:00 UTC (7 days) · recorded synthetic fixtures

4 scheduled workflows: 36 runs due, 34 ran (32 on time, 2 late), 2 missed; 1 failed, 1 green but did
nothing and 1 workflow disabled.

Nightly backup  ·  .github/workflows/backup.yml
  schedule     0 3 * * * (UTC)
  runs due     7: 6 ran, 1 late, 1 missed; 1 failed, 1 did nothing
  missed       Sun 4 Oct 03:00 UTC  no run was created
  did nothing  Mon 5 Oct 03:00 UTC  green in 6 s; its usual success takes 4 min 8 s
  late         Tue 6 Oct 03:00 UTC  the run was created 2 h 17 min late
  failed       Thu 8 Oct 03:00 UTC  the run failed after 1 min 30 s
  last run     Fri 9 Oct 03:04 UTC, success
  next due     Sat 10 Oct 03:00 UTC
  fix          GitHub delays and drops scheduled runs under high load, which includes the start of
               every hour: move the minute off :00 (e.g. 17 instead of 0)
               open the green runs that were short: usually every job or step was skipped by an
               `if:`, or the job found nothing to do and exited 0

Sync prices  ·  .github/workflows/sync.yml
  schedule     0 */6 * * * (UTC)
  runs due     28: 27 ran, 1 late, 1 missed
  missed       Sun 4 Oct 06:00 UTC  no run was created
  late         Wed 7 Oct 18:00 UTC  the run was created 47 min late
  last run     Fri 9 Oct 12:03 UTC, success
  next due     Fri 9 Oct 18:00 UTC
  fix          GitHub delays and drops scheduled runs under high load, which includes the start of
               every hour: move the minute off :00 (e.g. 17 instead of 0)

Close stale issues  ·  .github/workflows/stale.yml
  schedule     0 0 * * * (UTC)
  state        disabled by GitHub: no repository activity in 60 days (public repositories only)
  last run     Sun 9 Aug 00:07 UTC, success (61 days ago)
  fix          gh workflow enable stale.yml -R synthetic-org/nightly-jobs
               then keep the repo active: GitHub disables a public repo's scheduled workflows again
               after 60 days without activity

Weekly report  ·  .github/workflows/report.yml
  schedule     30 8 * * 1 (America/New_York)
  runs due     1: on time
  last run     Mon 5 Oct 12:41 UTC, success (4 days ago)
  next due     Mon 12 Oct 12:30 UTC

Not scheduled: 1 workflow (ci.yml).

This repository is public and its last push was 48 days ago. GitHub disables a public repo's
scheduled workflows after 60 days without activity: around 20 Oct 2026 (in 12 days), unless there is
activity first.

An hourly watch for scheduled runs is not built.
Would you pay for one that emails you when a run is late, missed or did nothing? One click counts:
  https://agentwares-agentcheck.vercel.app/didrun?ref=didrun#watch

A real one: on 9 October 2026, read without a token, both of actions/stale's own Sunday 03:00 UTC schedules had run on 4 October, but 1 h 4 min and 1 h 18 min late.

Related MCP server: TaskBounty Check

Usage

npx --allow-git=root github:agentwares/didrun                          # the current checkout's origin, last 7 days
npx --allow-git=root github:agentwares/didrun owner/repo --days 30     # another repo, up to 30 days back
npx --allow-git=root github:agentwares/didrun --workflow nightly.yml   # one workflow, by file name, path or name
npx --allow-git=root github:agentwares/didrun --late 60                # count a run as late after 60 minutes (default 30)
npx --allow-git=root github:agentwares/didrun --json                   # the report as JSON
npx --allow-git=root github:agentwares/didrun --fail-on missed         # exit 1 if a run never came or a schedule is disabled
npx --allow-git=root github:agentwares/didrun demo                     # the synthetic repo above; no network

How a run is matched to its time. For every workflow with an on.schedule on the default branch, didrun lists the times its cron lines fire over the window, in UTC or the line's timezone (with GitHub's rule for the hour clocks skip). It counts only from when the file last changed, so a new schedule is not blamed for runs before it existed. GitHub's run list does not say which scheduled time a run answered, so a run belongs to the latest time due at or before it was created. When two runs land between the same two times, the earlier one counts as a late run of the time before. A time with no run is missed once it is more than --late minutes old, and pending until then. For schedules more frequent than GitHub's delay, a late run and a missed one cannot be told apart from the record. The count of runs that never came is right either way.

Green but did nothing means a run whose conclusion is skipped, or a success shorter than a fifth of the workflow's usual (median) successful run, with at least three successes to compare.

What it reads, and where it sends it. Only GET requests to GitHub's API (api.github.com, or GITHUB_API_URL on a GitHub Enterprise runner):

  • the repo: visibility, default branch, last push;

  • its workflows and their state;

  • each workflow file on the default branch;

  • the file's last commit;

  • its event=schedule runs in the window.

The token goes in the Authorization header of those requests and nowhere else. It is never printed, logged or stored. A private repo needs Actions and Contents read access (the repo scope on a classic token). Without a token GitHub allows 60 requests an hour, enough for a few checks of a small repo.

Exit codes:

  • 0: the check ran (whatever it found, unless --fail-on says otherwise);

  • 1: an error, or --fail-on matched;

  • 2: a usage mistake.

With --json, an error is {"error": {"code", "cause", "fix", "retryable"}}.

What --json gives:

  • summary, verdict (ok, problems or nothing-scheduled), and inactivity (public repos: days_since_push, disables_on, days_left);

  • for each workflow: state, disabled, schedules, evaluated_from, counts, usual_success_seconds, last_run and next_due;

  • findings, each with kind (missed, late, pending, failed, cancelled, did_nothing), due and the run;

  • fix, then unscheduled, not_on_default_branch and handoff.

Why scheduled runs go missing

From GitHub's events that trigger workflows and workflow syntax pages, read 9 October 2026:

  • Load. Scheduled runs are delayed when GitHub Actions is busy, and "high load times include the start of every hour". Under enough load, queued jobs are dropped. didrun suggests moving a minute-0 line off the hour when it finds late or missed runs.

  • The default branch. A schedule runs only from the workflow file on the default branch.

  • 60 days. In a public repository, scheduled workflows are disabled after 60 days with no repository activity, and stay disabled until someone enables them (gh workflow enable). Forks start with them disabled.

  • UTC. A line runs in UTC unless it sets timezone, an IANA name. The shortest interval is every 5 minutes.

One page per cause, with how to check by hand: agentwares-agentcheck.vercel.app/didrun.

The GitHub Action

# .github/workflows/didrun.yml
on:
  schedule:
    - cron: "23 8 * * *"
  push:
    branches: [main]
  workflow_dispatch:
permissions:
  actions: read
  contents: read
jobs:
  didrun:
    runs-on: ubuntu-latest
    steps:
      - uses: agentwares/didrun@main
        with:
          fail-on: missed # or problem, or never (default)

It runs the committed dist/ on your runner, with no install, writes the report to the job summary, and sets missed, late, problems and report (the JSON's path) as outputs. Inputs: repo (default: this one), days, late-minutes, fail-on and token.

A check on GitHub's scheduler shares its delays and drops, and in a public repo its own schedule falls under the same 60-day rule. So run it on pushes and by hand too, as above. examples/github-workflow.yml has the whole file.

For agents: an MCP tool

didrun mcp serves one tool over stdio, didrun_check_schedules (repo, days, late_minutes, workflow; all optional). It returns the same report as --json. It is read-only and calls GitHub's API, and its annotations say so. Add it to Claude Code with:

claude mcp add didrun -- npx -y --allow-git=root github:agentwares/didrun mcp

Inside Claude Code

The repo is also a Claude Code plugin marketplace with one skill, /didrun:didrun. It runs the check and walks through each finding with what GitHub documents as the cause, and proposes fixes for you to approve:

/plugin marketplace add agentwares/didrun
/plugin install didrun@didrun

An hourly watch for scheduled runs is not built

didrun tells you what happened when you ask. A watch would ask for you, every hour, from outside GitHub's scheduler, and email you when a run is late, missed, or green with nothing done, with no change to your repo. It does not exist yet: agentcheck's free hourly watch covers MCP servers only. If you would pay for this one, say so with one click on agentwares-agentcheck.vercel.app/didrun. The click is counted, and nothing else is sent.

License

MIT, by agentwares. didrun is a free tool from agentcheck, which runs scheduled checks of your endpoints and MCP servers and alerts you when an answer changes.

Related MCP Connectors

Related MCP Servers