All jobs

Fix Failing GitHub Actions Checks in a Laravel App

Yes. When a Laravel build fails, an agent reads the failed job's log, reruns php artisan test on the same PHP and database, fixes the cause and opens a PR.

Run this on RushIn a Project that has your repository.

What the agent does

The agent starts with the log of the job that failed. It receives the workflow_run event, runs gh run view <run id> --log-failed, and reads which matrix entry broke. In a Laravel app like monicahq/monica that matters, because .github/workflows/tests.yml does not list steps itself: it calls the reusable workflow monicahq/workflows/.github/workflows/laravel.yml@v2 with php-versions: "['8.3', '8.4']" and connections: "['sqlite', 'mysql', 'pgsql']", defaulting to PHP 8.3 on SQLite. A test that fails only on pgsql is a different problem from one that fails everywhere, so the agent names the PHP version and connection from the job name and quotes the PHPUnit failure, then opens the reusable workflow file to see the exact commands it runs.

Then it sets up the same PHP and database. composer.json requires PHP ^8.3, laravel/framework ^12.0 and phpunit/phpunit ^11.0, and the agent runs composer install from composer.lock on the PHP version the failing entry used. phpunit.xml sets DB_CONNECTION=testing, QUEUE_CONNECTION=sync, CACHE_STORE=array, MAIL_MAILER=array and SCOUT_DRIVER=collection, and config/database.php points the testing connection at env('DB_TEST_DRIVER', 'sqlite') with database/database-test.sqlite as the default file. For a SQLite failure the agent creates that file and runs the migrations against it; for MySQL or Postgres it starts that database and sets the DB_TEST_* variables the workflow sets.

It runs the failing test alone with php artisan test --filter, such as php artisan test --filter=CreateContactTest. Monica's domain tests sit beside the domain code: app/Domains/Contact/ManageContact/Services/CreateContact.php is covered by tests/Unit/Domains/Contact/ManageContact/Services/CreateContactTest.php, which uses DatabaseTransactions and helpers like createUser, createVault and setPermissionInVault(..., Vault::PERMISSION_MANAGE, ...), and expects NotEnoughPermissionException, ValidationException or ModelNotFoundException for the wrong caller or input. The agent reads the service's validation rules and permission checks against the failing assertion and fixes the code the failing commit changed.

A query that works on SQLite and fails on Postgres, such as a case-sensitive LIKE or a string compared to an integer column, is fixed in the query, not by skipping the connection. After the fix the agent runs the full php artisan test on the failing connection and on the default SQLite, so the pull request does not move the failure to another matrix entry.

Start it with one API call

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

{
  "agent": "claude",
  "input": "The GitHub Actions workflow on this branch failed; the workflow_run event is at the end of this prompt. Read the failed job's log with gh run view <run id> --log-failed, name the PHP version and database connection of the failing matrix entry, and quote the PHPUnit failure. If the workflow calls a reusable workflow, read that file for the exact steps. Install with composer from the lockfile on the same PHP version, set up the same test database and migrate it, and reproduce the failure with php artisan test, filtered to the failing test first. Fix the cause in the application code (change a test only if the test is wrong, and say so; never skip a database connection), run the full php artisan test on the failing connection and on the default one until they pass, and open a pull request against the failing branch that quotes the error it fixed.\n\nEvent: <workflow_run payload>",
  "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

A pull request against the failing branch with the fix in the service, model, policy or controller the PHPUnit trace named. Its description quotes the failing test and assertion from the GitHub log, names the PHP version and connection, and lists every command the agent ran in its sandbox: the composer install, the migration, the filtered test and the full suite on each connection it tried. The workflow's full matrix reruns on the pull request, and the trajectory keeps each command with its output.

When the log shows a failure outside the code, such as a MySQL service that never became healthy, a Composer package that could not be downloaded, or a SonarCloud step failing on its token, the agent opens no pull request and its answer says what failed and where. That answer arrives on your webhook with the run.

A reviewer checks that permission checks such as Vault::PERMISSION_MANAGE were not loosened to make a test pass, that a query fix behaves the same on all three databases, and that any edited test was wrong rather than inconvenient.

Run it on every failed Laravel test matrix

Send GitHub's workflow_run webhook to your server and, for each run that completes with conclusion: failure, send this request with the event in input and https://github.com/<owner>/<repo>/tree/<head_branch> as the resource. A matrix across PHP versions and databases produces one workflow_run, so one run handles every failing combination; exclude the agent's own branches so its fixes do not trigger it again.

Rush POSTs run.completed or run.failed to the webhook URL on your API key when the run finishes, with its answer and session URL, so your server can comment the pull request link on the contributor's pull request. Keep each workflow_run.id with the execution_id to drop redelivered events.

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

Why run it on Rush?

A failure on one PHP version and one database is slow to chase on a laptop: you need that PHP, that database server, a migrated test database and a clean vendor/ before the test even runs. The agent builds that in its own sandbox with its own clone, so your local PHP, your Valet or Sail setup and your current branch are untouched, and it starts as soon as the matrix goes red.

The fix comes with proof a reviewer can follow: the quoted PHPUnit failure, the trajectory with every Composer, migration and test command and its output, and the full matrix rerunning on the pull request. When several branches fail together, each one gets its own run in parallel, and a person merges each fix.

Frequently asked questions

Can it reproduce a failure that happens only on Postgres or MySQL?

Yes. It starts the database the failing matrix entry used and points the testing connection at it through the DB_TEST_* variables, then runs the same test. The pull request says which connections it ran the suite on.

Does it work with Pest instead of PHPUnit?

Yes. php artisan test runs Pest suites too, and the agent filters to the failing test the same way. It writes any test changes in the style your suite already uses.

Our workflow calls a reusable workflow in another repository. Can it read that?

It reads it when the file is public, as Monica's monicahq/workflows is, or when the Rush GitHub App can reach that repository. If it cannot read it, it works from the commands the job log shows and says so.

Will it change my phpunit.xml or skip tests?

The prompt rules out skipping a connection or a test, and any change to phpunit.xml or the workflow shows in the diff for the reviewer. Its fixes go in application code unless a test is shown to be wrong.