Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci-status-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Runs the ci-status skill's tests. They need only pytest: the script under test
# calls gh, and the tests stand a fake in its place.
name: ci-status tests

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

jobs:
ci-status:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2

- name: Install pytest
run: uv pip install --system pytest

- name: Run the tests
run: python -m pytest tests/ci-status
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Superpowers planning artifacts and subagent-driven-development scratch
docs/superpowers/
.superpowers/

# Bytecode from running the Python skills and their tests
__pycache__/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Offworld Labs' org-wide Claude Code resource: a **plugin marketplace** (`offworl
plus **shared reference docs** used across every repo in the organisation.

- `plugins/core` — the `core` plugin; its `setup-repo` skill bundles the shared rules, `.claude/settings.json`, `CLAUDE.md`, and CI workflow templates used to scaffold new repos.
- `plugins/core/skills/ci-status`: reports a pull request's real CI state, where `gh pr checks` and `gh run watch` misreport it.
- `docs/` — on-demand org-wide reference docs (see [Documentation](#documentation)).

## Install
Expand Down
2 changes: 1 addition & 1 deletion plugins/core/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "core",
"version": "0.6.0",
"version": "0.7.0",
"description": "Core Offworld Labs skills, commands, agents, and hooks shared across all repos.",
"author": {
"name": "Offworld Labs"
Expand Down
64 changes: 64 additions & 0 deletions plugins/core/skills/ci-status/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
name: ci-status
description: Use whenever you need to know whether a pull request's CI passed, to wait for CI after a push, or to judge the run a merge to main started. Replaces `gh pr checks`, `gh pr checks --watch` and `gh run watch`, whose exit codes and tables report skipped, superseded and not-yet-started runs as passes.
---

# ci-status

Reports a PR's real CI state from the runs for its head commit, and exits
non-zero unless every gate passed. The script's docstring lists the traps it
handles; the short version is that `gh pr checks` and `gh run watch` have each
reported green for a PR that was untested, conflicting, failed or unreviewed.

`CI_STATUS="${CLAUDE_PLUGIN_ROOT}/skills/ci-status/scripts/ci_status.py"`

## Use

```
python3 "$CI_STATUS" <pr> -R <owner>/<repo> # one reading
python3 "$CI_STATUS" <pr> -R <owner>/<repo> --watch # poll until it settles
python3 "$CI_STATUS" --commit <sha> -R <owner>/<repo> # a merge's push run
```

- Inside a clone of the repo, `-R` and the PR number can be left out; the PR
defaults to the current branch's. A fork's clone resolves to whichever repo
`gh` is set to there (often the upstream), so pass `-R` in one.
- `--watch` polls every 30 s for up to 60 min. Run it in the background (it
outlives a foreground command's limit) and act on its exit status.
- `-v` lists every job rather than only those not passing.
- `--no-review` drops the Claude review from the gate. Use it only when a human
has reviewed the PR instead.

## Reading the answer

| Exit | Meaning | What to do |
|------|---------|------------|
| 0 | Every gate passed on the PR's head | Read the review it links, if any: green is not "no findings" |
| 1 | Failed, or will not run until someone acts | Act on the reason it prints (below) |
| 2 | The question was wrong: no such PR, no PR for this branch, not a GitHub repo, or no access | Fix the arguments |
| 3 | Not settled: runs still going, or something not arrived yet (a run, the review, the head following its branch) | Ask again, or `--watch`, which calls a wait final after a few minutes |
| 4 | GitHub could not be read, so there is no verdict | Ask again; it says nothing about CI |

Checks from other apps and commit statuses count as gates beside the Actions
runs.

The reasons that need action:

- **A job failed.** Fix it, or report it as a flake. Do not rerun silently: the
rerun overwrites the run's conclusion (ci-status still lists the failed
attempt).
- **The PR conflicts.** GitHub makes no merge ref, so no CI will run. Rebase.
- **Every run skipped all its jobs.** Nothing was tested, usually because the
PR is a draft or a filter excluded the change.
- **The PR's head has not followed its branch.** No CI runs for the new commit.
Amend to a new SHA (`git commit --amend --no-edit`) and push with
`--force-with-lease`.
- **The review bot did not review.** The PR edits the review workflow (review it
by hand), the branch carries an older copy of that workflow than the default
branch (rebase onto it), or the workflow did not trigger for this head. Report
any of them as "not reviewed", never as a clean review.
- **The review stopped partway.** Rerun it with the command it prints,
`gh run rerun <run id>`. `--failed` reruns nothing when the job itself passed,
which it does unless the repo's workflow checks the review finished.

Skipped jobs inside a run that ran are neutral: deploy jobs skip on every PR.
Loading
Loading