What the agent does
The agent reads the repository's own declarations first. In wallabag/wallabag, composer.json asks for PHP 8.2 or newer and symfony/framework-bundle 5.4, with phpunit/phpunit 9.6, phpstan/phpstan 1.12 and friendsofphp/php-cs-fixer 3.70 in require-dev. phpunit.xml.dist defines three suites, unit under tests/unit, integration under tests/integration and functional under tests/functional, and loads the dama/doctrine-test-bundle extension so each test runs inside a rolled-back transaction. The Makefile wraps them as make test, make test-unit, make test-integration and make test-functional, each running bin/phpunit with memory_limit=-1.
The entry API lives in src/Controller/Api/EntryRestController.php: GET /api/entries with its filters, GET /api/entries/exists, POST /api/entries, PATCH /api/entries/{entry} and its reload variant, DELETE /api/entries/{entry}, the bulk POST /api/entries/lists and DELETE /api/entries/list, and the tag routes under /api/entries/{entry}/tags. Its tests are in tests/functional/Controller/Api/EntryRestControllerTest.php, 69 test methods on a base class, WallabagApiTestCase, that logs the admin fixture user in with loginUser and skips a test when the fixture database has no entry to read.
After composer install the agent runs the suites. tests/bootstrap.php drops and recreates the test database and runs the Doctrine migrations before the integration and functional suites, using the DATABASE_URL from .env, which is SQLite by default; the matrix in .github/workflows/continuous-integration.yml also runs MySQL and PostgreSQL across PHP 8.2, 8.3 and 8.4, with RabbitMQ and Redis services and a yarn build:dev of the assets on the Node 24 that .nvmrc names. The agent reports which of those it reproduced in the sandbox and which it did not.
Then it reads the diff against the surrounding code: a new filter on getEntriesAction that the repository query never applies, a PATCH handler that changes a field without dispatching through the EventDispatcherInterface it receives, a tag route that bypasses TagsAssigner, a test that passes only because markTestSkipped fired. It also runs bin/phpstan analyse at the configured level 5 and bin/php-cs-fixer fix --dry-run, the same checks as coding-standards.yml, after the bin/console cache:clear --env=test that PHPStan's Symfony extension needs. Every finding cites file and line.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "codex",
"input": "Review this pull request. Check it out, install dependencies with Composer, run `make test-unit` and `make test-functional`, then `bin/console cache:clear --env=test`, `bin/phpstan analyse --no-progress` and `bin/php-cs-fixer fix --dry-run`. Read the diff with the surrounding code in the entry API controller, its repository queries and the functional tests that cover it. Post one GitHub review that cites file and line for every finding, separates blocking issues from suggestions, and quotes each command's result, including tests that were skipped. Do not push commits.",
"resources": [
{
"url": "https://github.com/your-org/your-app/pull/42"
}
]
}- 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.
- 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.
- 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 review on the pull request. The summary quotes the PHPUnit result per suite, with the counts of passed, failed and skipped tests exactly as the runner printed them, then the PHPStan and PHP CS Fixer output. The findings follow with file and line, blocking issues first.
Inline comments sit on the cited lines in EntryRestController.php or its test, so a note about an unvalidated parameter sits on the line that reads it. The session's transcript keeps the install, the database bootstrap, each suite and every file the agent opened, which is how a reviewer confirms that a finding came from reading the repository method and not from the diff alone.
Before merging, a reviewer reruns the failing or skipped tests on the branch, checks each cited line against its comment, and decides on the database question: a change that passes on SQLite in the sandbox still has the MySQL and PostgreSQL legs of CI to clear.
Run it on every pull request opened
Create an automation with a GitHub trigger on pull_request.opened and pull_request.synchronize, branch_patterns set to master and the 2.** release branches the CI workflow watches, and this prompt. Each pull request gets its own sandbox, its own database bootstrap and its own review, and a new push gets a fresh review of the new diff.
Set a webhook URL on the API key and Rush POSTs run.completed with the session URL when each run finishes, so your server can post the review link where the maintainers read. max_runs_per_hour on the automation caps how many runs a burst of pull requests can start, and the key's max_concurrent, 4 by default, caps how many run at once.
The use case this job follows, with its automation and trigger: Review every pull request.
Why run it on Rush?
A wallabag review on a laptop starts with a Composer install, a Yarn build of the assets and a bootstrap that drops and migrates a test database, before the first PHPUnit suite can run. On Rush that happens in a sandbox that is thrown away afterwards, and every command and its output is kept, so the review says what the functional suite did on this branch rather than what the diff suggests it would do.
The entry API has 69 functional tests that depend on fixture data and skip themselves when it is missing, which is exactly the kind of result a diff-only review never sees. An agent that ran the suite can say which tests were skipped and why, and several pull requests get that treatment in parallel while the maintainers' own checkouts stay untouched.
Frequently asked questions
Does it need MySQL or PostgreSQL?
No. .env points DATABASE_URL at SQLite and tests/bootstrap.php creates and migrates that database before the integration and functional suites. The review says it ran on SQLite; the MySQL and PostgreSQL legs remain CI's job. Start the session in a Project with a DATABASE_URL secret to run against another engine.
Why run PHPStan when CI already does?
So the review can quote it alongside the findings and point at the line. phpstan.neon is level 5 over src and tests with a baseline, and its Symfony extension needs the test container dumped first, which is why the prompt clears the test cache before analysing.
What if tests were skipped?
The entry API tests call markTestSkipped when the fixture database holds no matching entry. The review lists skipped tests separately from failures and says whether the behaviour the pull request changes is covered by a test that actually ran.
Can it review the JavaScript side too?
The repository runs yarn lint:js and Stylelint in coding-standards.yml. Add them to the prompt and the review quotes their output; the Node version comes from .nvmrc, which is 24.