---
name: github-actions-failed-runs
description: "Each weekday morning: workflow runs that failed on the default branch in the last 24 hours, the job and step that broke, the error and the commit behind it. Use when the user asks for this, or when it runs on a schedule."
---

# GitHub Actions failed runs on main

Each weekday morning: workflow runs that failed on the default branch in the last 24 hours, the job and step that broke, the error and the commit behind it.

Main goes red at 18:00, and the first person to notice is whoever tries to merge at 10:00 the next morning. Actions emails the person who triggered the run, which on main is whoever merged last, and only if they kept those notifications on.

The agent checks the default branch every morning, opens each failed run, finds the job and step that broke and pulls the first real error line out of the log. It also says whether the workflow is still failing or a later run already went green, and whether a failure looks flaky.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- Read access to Actions on the repo; on a fine-grained token, the Actions read permission.
- The `gh` CLI signed in, or a GitHub MCP server or connector that can list workflow runs and read job logs.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **Find the default branch** (GitHub): `gh repo view acme/acme-web --json defaultBranchRef --jq .defaultBranchRef.name`, so the same skill works on repos that use `main`, `master` or `trunk`.
2. **List failed runs** (GitHub Actions): `gh run list --repo acme/acme-web --branch main --status failure --created ">=2026-10-15" --json databaseId,workflowName,headSha,displayTitle,createdAt,url`, with the date set to 24 hours ago.
3. **Find the failing job and step** (GitHub Actions): `gh run view <id> --json jobs` lists each job with its `conclusion` and `steps`; keep the first step whose conclusion is `failure`. Then read `gh run view <id> --log-failed` and take the first line that is a real error (`Error`, `FAIL`, `exit code`), skipping setup noise.
4. **Check whether it is still red** (GitHub Actions): Read the newest run of each workflow on the branch (`gh run list --workflow <name> --branch main --limit 3`). Mark it recovered if that run passed, failing since the first of its consecutive failures if not, and flaky if the same commit both failed and passed.
5. **Report**: One row per workflow with job, step, error line, commit and author. Post with `work_state: failed` while any workflow is still red, and `done` once all have recovered.

## Route B: the browser

### What you need

- Signed in to GitHub with read access to the repository; the Actions tab must be visible to that account.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://github.com/. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **Open the repository's Actions tab**: Go to `github.com/<owner>/<repo>` and click **Actions**. In the filter bar set **Branch** to the default branch (`main` on most repos) and **Status** to **Failure**, or type `branch:main is:failure` into the "Filter workflow runs" box. Keep only runs whose time, shown on each row, is within the last 24 hours.
2. **Find the failing job and step**: Open each run. The left pane lists its jobs with a red mark on the failed ones; click one and the failed step opens with its log. Copy the first line that is a real error (`Error`, `FAIL`, `exit code`), skipping setup output. **Search logs** at the top helps on long jobs.
3. **Check whether it is still red**: In the Actions sidebar click the workflow's name and filter by the branch: if the newest run is green the failure has recovered; if several in a row are red, note the first failing commit and author from its row. The same commit both red and green means a flaky job.
4. **Report**: One row per workflow with job, step, error line, commit and author, and whether it is still failing, recovered or flaky.

Note: The Actions filter has no date field, so the 24-hour window is read off the run times by eye; the list is newest first, so stop at the first older row. Logs older than 90 days are gone by default, which never matters here.

## The report

- **Still failing**: workflows whose latest run on the default branch is red.
- For each: job, step, the first error line, the commit that broke it and its author.
- **Recovered**: workflows that failed in the window but have passed since.
- **Flaky**: jobs that failed and passed on the same commit.

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "github-actions-failed-runs/<date of this run, e.g. 2026-10-16>",
  "item_key": "github-actions-failed-runs",
  "project": "acme-web",
  "source": "GitHub Actions failed runs on main skill",
  "kind": "update",
  "title": "Main is red: e2e failing since yesterday evening",
  "summary": "**e2e** has failed on the last 3 runs, starting at `a41c9e2` (#1297). **lint** failed once overnight and passed on the next run.",
  "work_state": "failed",
  "widget": [
    {
      "type": "Table",
      "props": {
        "columns": [
          "Workflow",
          "Job / step",
          "Error",
          "Status"
        ],
        "rows": [
          [
            "e2e",
            "playwright / Run tests",
            "settings.spec.ts:42 timed out waiting for the Save button",
            "Failing since 18:12"
          ],
          [
            "lint",
            "eslint / Lint",
            "no-unused-vars in app/billing/plan.ts",
            "Recovered at 02:30"
          ]
        ]
      }
    },
    {
      "type": "KeyValue",
      "props": {
        "items": [
          {
            "key": "Broken by",
            "value": "a41c9e2 Move settings to the app router (#1297)"
          },
          {
            "key": "Author",
            "value": "mo"
          },
          {
            "key": "Failed runs",
            "value": "4 in 24 hours: e2e 3, lint 1"
          }
        ]
      }
    },
    {
      "type": "Links",
      "props": {
        "items": [
          {
            "label": "Latest e2e run",
            "url": "https://github.com/acme/acme-web/actions/runs/11873450912"
          }
        ]
      }
    }
  ]
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Weekdays at 8:00 (`0 8 * * 1-5`). From cron, with the agent signed in on that machine:

```bash
0 8 * * 1-5 claude -p "Run the github-actions-failed-runs skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/github-actions-failed-runs#schedule

Source: https://briefkin.dev/skills/github-actions-failed-runs
