Main is red: e2e failing since yesterday evening
e2e has failed on the last 3 runs, starting at a41c9e2 (#1297). lint failed once overnight and passed on the next run.
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.
What lands on your board
e2e has failed on the last 3 runs, starting at a41c9e2 (#1297). lint failed once overnight and passed on the next run.
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.
gh repo view acme/acme-web --json defaultBranchRef --jq .defaultBranchRef.name, so the same skill works on repos that use main, master or trunk.
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.
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.
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.
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.
With BRIEFKIN_TOKEN set, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.
Pick your agent, where the data comes from and how to schedule it; the commands below follow.
One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.
shellcurl -fsSL https://briefkin.dev/skills/github-actions-failed-runs/install | shAsk Claude Code:
promptRun the github-actions-failed-runs skillOr paste the prompt instead of installing:
promptFor the GitHub repo acme/acme-web, find GitHub Actions runs that failed on the default branch in the last 24 hours (gh run list --branch <default> --status failure --created ">=DATE"). For each failed run, find the failing job and step (gh run view <id> --json jobs) and the first real error line from gh run view <id> --log-failed. Check whether the latest run of each workflow on the branch has passed since. Report one line per workflow: job, step, error, the commit and author that started the failure, and whether it is still failing, recovered, or looks flaky (failed and passed on the same commit).Weekdays at 8:00, from cron on any machine where Claude Code is signed in:
crontab0 8 * * 1-5 claude -p "Run the github-actions-failed-runs skill"Add it with crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.
Connect Briefkin once with curl -fsSL https://briefkin.dev/install | sh and every run lands on your board as a report card. How setup works
SKILL.md---
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
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.
actions toolset, hosted at https://api.githubcopilot.com/mcp/x/actions; append /readonly for read tools only. It lists runs and jobs and fetches job logs.gh CLI. gh run list --branch main --status failure --json databaseId,workflowName,conclusion,createdAt finds red runs, and gh run view <run-id> --log-failed prints only the failing steps' output. Set GH_TOKEN for unattended runs.GITHUB_TOKEN, scoped to the repositories you watch, with Actions: Read and Metadata: Read.Actions: Read lets the agent list runs and download logs but not rerun, cancel or trigger workflows; grant write only if you want it to retry flaky jobs.
https://api.githubcopilot.com/mcp/. Sign in with OAuth or a personal access token; add /readonly to the URL, or use a toolset URL such as https://api.githubcopilot.com/mcp/x/pull_requests/readonly, to expose only read tools. It also runs locally (source).gh CLI. Run gh auth login once, or set GH_TOKEN for scheduled runs. gh pr list --search "review-requested:@me" --json number,title,url,createdAt and gh api repos/{owner}/{repo}/dependabot/alerts cover most reports.GITHUB_TOKEN, limit it to the repositories in the report, and grant Read on Metadata, Contents, Pull requests and Issues, plus Dependabot alerts if you report on them.With every permission on a fine-grained token set to Read, the agent can't push, merge, comment or close anything.
Yes, with a token that can read Actions on that repo. Logs are kept for 90 days by default (an org can set less), so a 24-hour window is always well inside that.
It can with gh run rerun <id> --failed, which needs write access to Actions. The skill leaves that off by default: rerunning a real failure only delays the fix, so it suggests a rerun only for jobs that look flaky.
No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a report card, so you can glance at it instead of asking again.
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.
Yes. Switch the data source to "Your browser" and the steps change to the GitHub Actions and GitHub pages themselves: the agent opens github.com in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.
Skills are free to use with any agent. Briefkin is where their results land: one board for every report, number and question your agents send, with a ping when something needs you.
Free during the open beta. No card.