All jobs

Fix a Failing CI Build in a Python Project

Yes. A failed workflow run starts an agent that reads the log, reruns the same pytest command in a sandbox and opens a pull request that turns it green.

Run this on RushIn a Project that has your repository.

What the agent does

The run starts from a GitHub workflow_run.failure event on the default branch. The event the agent reads names the workflow, the head branch, the head commit and the check runs that failed, so it knows whether it is looking at the test matrix, the lint job or the type check before it opens a single file. It clones the repository at that commit into its own sandbox and reads the failed job's log with gh run view --log-failed.

In a library like psf/requests, the agent finds three workflows that can go red for different reasons. run-tests.yml runs make and then make ci, which is python -m pytest tests --junitxml=report.xml, across Python 3.10 to 3.14, 3.14t, 3.15-dev and PyPy 3.11 on Ubuntu, macOS and Windows, plus a no_chardet job that uninstalls charset_normalizer and chardet and a job pinned to urllib3<2. lint.yml runs pre-commit run --all-files. typecheck.yml runs pyright src/requests/ in strict mode on 3.10 and 3.14.

It reproduces the failing job, not a nearby one. For a test failure it installs requirements-dev.txt (an editable install with the socks extra, pytest-httpbin==2.1.0, httpbin and trustme) on the same Python minor the log names and runs the one failing test by node id, such as pytest tests/test_requests.py::TestRequests::test_.... pyproject.toml adds --doctest-modules, so a docstring example in src/requests/ can fail the suite too. A failure only in the urllib3<2 or no_chardet job is reproduced by making the same change to the environment first.

With the failure on screen, the agent fixes the cause: the code in src/requests/, a test that depended on something the commit changed, or the workflow itself when the break is an action or a Python version that moved. It reruns the failing test, then make ci and pre-commit run --all-files, so the fix does not trade a test failure for a lint failure.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "The GitHub Actions run on the default branch failed; the event follows this prompt. Read the failed job's log and name the job, the Python version and the failing test or step. Recreate that job's environment in the sandbox, reproduce the failure with the same command, fix the cause, and run the full test suite and the pre-commit hooks. Open a pull request that quotes the failing log lines and explains the fix. Do not skip, mark flaky or delete a failing test.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is a pull request against the default branch. Its description names the job that failed (for example the 3.12 Ubuntu leg of run-tests.yml), quotes the traceback from the log, and shows the same test failing and then passing in the sandbox. The diff is the fix; a change to a workflow file or to requirements-dev.txt is listed apart from the code change.

GitHub runs the full matrix on the pull request, so the checks a reviewer reads are the real ones, including the macOS and Windows legs the sandbox cannot run. They check that the failing job is green, that no test gained a skip or xfail marker, and that a fix in src/requests/ still satisfies pyright in strict mode.

When the failure only reproduces on a platform the sandbox does not have, such as a Windows path issue, the run says so plainly. It reports what it read in the log, what it tried on Linux and its best reading of the cause, so the person who takes it over starts from the evidence.

Run it on every failed workflow run on main

In the console, add an automation to the Project for this repository with the prompt above and a github trigger on workflow_run.failure, with main in its branch patterns. Every workflow run that ends in failure on that branch then starts one run, with the workflow name, head commit and failing checks given to the agent as data under the prompt.

A redelivered GitHub event does not start a second run, and the automation's runs-per-hour limit (1 to 30) caps a burst when one bad merge breaks every workflow at once. Runs from forks are never picked up.

The use case this job follows, with its automation and trigger: Fix a bug from an alert.

Why run it on Rush?

A red matrix on a Python library usually means someone downloads the log, works out which of a dozen interpreter and OS legs failed, builds a matching virtualenv and reruns one test. A Rush run does that in its own sandbox with the commands and their output kept, so the reviewer sees the traceback before the fix and the passing test after it, not a summary.

Failures come in groups: a dependency release can break the urllib3<2 job on one repository and the strict type check on another in the same hour. Each failure gets its own run on its own branch, they run at the same time, and the result is a pull request whose own checks prove the fix or a report that says what is still unknown.

Frequently asked questions

Which Python version does it use?

The one the failing job used, read from the log or the workflow matrix. For psf/requests that can be anything from 3.10 to 3.15-dev or PyPy, and a fix that works on one minor is rerun on the oldest supported one before the pull request opens.

Will it mark the test as flaky to make CI pass?

No. The prompt forbids skipping, marking or deleting a failing test, and the diff shows any change to a test file. When a test really is nondeterministic, the run says what makes it so and fixes that cause instead.

Does it work with tox, nox, uv or Poetry?

Yes. It runs whatever the failing workflow step runs, whether that is make ci, tox -e py312, uv run pytest or poetry run pytest, so the sandbox installs dependencies the way CI does.

What if the failure is in the workflow file, not the code?

Then the fix is in .github/workflows/, such as a Python version that is no longer available or an action pinned to a removed tag. The pull request says the change is to CI, and its own checks show whether the new workflow runs.