All jobs

Review Pull Requests on a Wagtail Site

Yes. An agent checks out the pull request, runs manage.py check, the migration check, manage.py test and make lint in its sandbox, and posts one review.

Run this on RushIn a Project that has your repository.

What the agent does

The agent reads the repository's own instructions before the diff, because wagtail/bakerydemo has an AGENTS.md written for this. It names the commands, make lint, make format, ./manage.py check and ./manage.py test, says render tests belong in bakerydemo/<app>/tests/, prefers focused page setup over loading the full fixture in bakerydemo/base/fixtures/bakerydemo.json, and tells the agent to run tests with DJANGO_SETTINGS_MODULE=bakerydemo.settings.test to avoid manifest-staticfiles errors from the dev settings. CONTRIBUTING.md adds the fixture export command and a policy the review respects: purely AI-generated contributions are not welcome and AI assistance must be disclosed, so the review posts as what it is, an agent's findings for a human reviewer to weigh.

Then it runs what .github/workflows/ci.yml runs. The test-server job installs requirements/development.txt with uv, which pins Django>=6.0,<6.1, wagtail>=8.0,<8.1 and ruff==0.15.15, then runs ./manage.py check, ./manage.py makemigrations --check --noinput and ./manage.py test under the test settings; lint-server runs make lint-server, which is ruff format --check, ruff check, curlylint --parse-only bakerydemo and djhtml --check over every tracked .html file; lint-client runs npm ci under Node 24 from .nvmrc and make lint-client for stylelint, eslint and prettier. ruff.toml selects B, BLE, C4, E, F, I, RUF100, T20, UP and W at line length 88 for Python 3.12, so a stray print or a bare except is a lint failure, not a style note. settings/test.py swaps in a local-memory cache, the immediate task backend and the MD5 password hasher, and the database is SQLite at bakerydemodb unless DATABASE_URL is set.

The tests that exist are the agent's model for what a new one should look like. bakerydemo/base/tests/test_home_page.py extends WagtailPageTestCase, builds the page tree once in setUpTestData, publishes a HomePage with save_revision().publish(), asserts the base/home_page.html template and its hero text, and uses nested_form_data with streamfield([...]) to prove a second home page can be created through the admin form. test_seo.py creates a Wagtail Image from a generated JPEG, checks the canonical link and Open Graph tags, and reads /robots.txt. A pull request that adds a page model or a block without a test in that shape gets a finding that names the file to add.

The diff is read with the three questions the prompt names. Page model migrations: every page app has a migration chain, base up to 0027, blog to 0008, breads to 0010, locations to 0011, recipes to 0004 and people to 0003, and makemigrations --check fails when a model change has none; a renamed field or a changed StreamField definition needs its migration in the same pull request. StreamField changes: bakerydemo/base/blocks.py defines BaseStreamBlock with heading_block, paragraph_block, image_block, block_quote and embed_block, each with a template under bakerydemo/templates/blocks/ and a preview_value, and CaptionedImageBlock overrides get_api_representation to add a fill-600x338 rendition; a new block needs its template, its preview, and, if the model exposes body through api_fields as BlogPage does, an API representation that still serialises. Template output: the agent renders the touched page in a test rather than reading the template, since search/views.py hard-codes BlogPage, BreadPage, LocationPage and RecipePage for the database search backend and a new page type will not appear in results until it is added there. One GitHub review is posted per run with file and line on every finding, and the agent pushes nothing.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Review this pull request on a Wagtail site. Read AGENTS.md and CONTRIBUTING.md first. Check the branch out, install requirements/development.txt, and with DJANGO_SETTINGS_MODULE=bakerydemo.settings.test run ./manage.py check, ./manage.py makemigrations --check --noinput and ./manage.py test, then make lint-server, and npm ci with make lint-client if the diff touches CSS or JavaScript. Read the diff with the page models, bakerydemo/base/blocks.py, the block templates under bakerydemo/templates/blocks, the app's migrations and bakerydemo/search/views.py. Look for model or StreamField changes without a migration, new blocks without a template or preview_value, api_fields that no longer serialise, page types missing from the hard-coded search view, and tests that load the full fixture where AGENTS.md asks for focused setup. Where a finding is about rendered output, write a short WagtailPageTestCase in the sandbox to confirm it, but do not add it to the branch. Post one GitHub review that quotes the check, migration, test and lint results, separates blocking issues from suggestions, and cites file and line for every finding. Do not push commits.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app/pull/42"
    }
  ]
}
  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 review on the pull request. Its summary quotes manage.py check, the makemigrations --check result, the test run under the test settings, and make lint-server with any ruff, curlylint or djhtml line it printed. Findings follow with file and line in the app they belong to, marked blocking or suggestion, and a StreamField finding names the block, its template and the migration it is missing.

The transcript keeps the install, every command with its output, and the short page-render tests the agent wrote to confirm a finding, so when the review says a new block renders without its caption, the response body the test asserted on is there.

Before merging, a reviewer runs the touched app's tests on the branch, reads the migration the pull request added, and checks anything the review marked as needing visual or editorial review, which AGENTS.md asks pull requests to call out. A missing migration or a failing render is blocking by default; a lint finding in a file the pull request did not change is not.

Run it on every pull request opened

Create an automation in the Project with a github trigger on pull_request.opened and pull_request.synchronize, branch_patterns set to main, and this prompt. Each fire adds the pull request after the prompt, so every pull request and every push to it gets its own sandbox, its own SQLite database and its own review. Mark the automation read_only so its runs comment and never push.

The review is the result and appears on the pull request; the run is listed in the Project. max_runs_per_hour, 1 to 30, keeps a sprint's worth of pushes to a bounded number of test runs, and a fire past the cap is skipped as rate_limited until the next push. The repository's own CI still runs the Docker build and the Postgres leg, which the sandbox does not replace.

The use case this job follows, with its automation and trigger: Review every pull request.

Why run it on Rush?

A Wagtail change is only half visible in the diff: the migration, the block template, the API representation and the search view all live elsewhere, and the way to know the page still renders is to publish one in a test and request it. The repository's AGENTS.md says exactly how to do that, and doing it takes a Python environment, the dev requirements, Node for the client lint and the test settings. On Rush the agent sets that up in its own sandbox, runs the same sequence as ci.yml and keeps every command's output, so the review rests on a rendered page rather than a reading of the template.

One sandbox per pull request keeps reviews parallel and the author's checkout untouched. The reviewer gets findings with the test output attached, and the author gets the lint and migration results before CI reports them, in a form that discloses the agent's part as the contributing guide asks.

Frequently asked questions

Does it respect the repository's AI policy?

The review is an agent's reading and test run, posted as such, and it changes nothing on the branch. CONTRIBUTING.md says AI assistance must be disclosed and purely AI-generated contributions are not welcome, which applies to the pull request's author; the review makes it easy to disclose by quoting what it ran and found.

Which database do the tests use?

SQLite, the default in settings/base.py when DATABASE_URL is unset, which is what ci.yml's test-server job uses too. The Docker workflow runs the suite against the compose stack; if a change depends on PostgreSQL features, save DATABASE_URL as a Project secret and the agent runs against that instead.

Does it load the demo fixture?

Not by default. AGENTS.md prefers focused model and page setup, and both existing test files build their own pages in setUpTestData. The agent follows that, and only loads bakerydemo.json when the pull request changes the fixture itself, in which case it also checks that the export was formatted with prettier as CONTRIBUTING.md requires.

What does it check in the frontend?

make lint-client runs stylelint with @wagtail/stylelint-config-wagtail, eslint and a prettier check over the CSS, JavaScript, JSON and YAML files. AGENTS.md notes that theme tokens and fixed visual-effect tokens must stay separate, so a CSS diff that makes an overlay or gradient token theme-dependent is a finding even when the lint passes.