What the agent does
The agent reads the site's own testing conventions first. In a Wagtail site like wagtail/bakerydemo it finds wagtail>=8.0,<8.1 and Django>=6.0,<6.1 in requirements/base.txt, Python 3.12 in .python-version, and an AGENTS.md that says render tests live in bakerydemo/<app>/tests/, that the test settings bakerydemo.settings.test avoid manifest static file errors, and that focused page setup is preferred over loading the full bakerydemo.json fixture. The site has two test files, both in base: test_home_page.py, a WagtailPageTestCase that builds the page tree in setUpTestData with Page.get_first_root_node() and a Site, publishes a HomePage and checks it renders base/home_page.html, and test_seo.py for canonical and Open Graph tags. The blog, breads, locations, people and recipes apps have no tests at all.
It lists the page models and their rules from each models.py. BlogPage, BreadPage, LocationPage, PersonPage and RecipePage each name a single parent_page_types entry, their index pages name them as the only subpage_types, and BlogPage, RecipePage and GalleryPage allow no children (subpage_types = []). StandardPage and HomePage set no rules. For every model it writes assertAllowedParentPageTypes and assertAllowedSubpageTypes from WagtailPageTestCase, so a change to those lists fails a test, and assertCanCreateAt and assertCanNotCreateAt for the pairs that matter, such as a BreadPage under HomePage.
Then it checks that each page can be created through the admin form and renders. It uses assertCanCreate with nested_form_data and streamfield from wagtail.test.utils.form_data, the helpers the home page test already imports, filling the fields each model declares: a BreadPage with its optional origin and bread_type foreign keys pointing at snippets the test creates, so the template shows them, a LocationPage with a lat_long in the 64.144367, -21.939182 form its RegexValidator accepts, and one with a value it must reject with invalid_lat_long. It publishes each page under its index and checks the response with assertPageIsRenderable and assertTemplateUsed. BlogIndexPage uses RoutablePageMixin, so it also requests tags/<slug>/ for a tag that has posts and for one that does not, which tag_archive redirects back to the index with a message.
It runs the suite the way CI does, with DJANGO_SETTINGS_MODULE=bakerydemo.settings.test: ./manage.py check, ./manage.py makemigrations --check --noinput so the tests add no model drift, and ./manage.py test. Without DATABASE_URL, settings/base.py uses SQLite, so no database server is needed. A rule the tests find surprising, such as HomePage being creatable anywhere, is kept as the current behaviour and called out in the pull request for a maintainer to decide.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Write tests with wagtail.test.utils.WagtailPageTestCase for this site's page models: creation rules, parent and child page types, and that each page renders. Read AGENTS.md, the requirements, the test settings and the existing tests first and follow their conventions: tests in each app's tests/ package, the page tree built in setUpTestData, focused setup rather than the full demo fixture. For every page model assert its allowed parent and subpage types, check creation through the admin form with nested_form_data, including one invalid value for each field with a validator, and publish a page and check it renders with the expected template. Cover routable sub-URLs where a page defines them. Run python manage.py test with the test settings, plus manage.py check and makemigrations --check. Do not change models or templates. Open a pull request that lists each page model and what is now tested.",
"resources": [
{
"url": "https://github.com/your-org/your-wagtail-site"
}
]
}- 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
The pull request adds a tests/ package to each app that had none, for bakerydemo bakerydemo/blog/tests/, breads/tests/, locations/tests/, people/tests/ and recipes/tests/, each with an __init__.py and a test_pages.py, plus tests for StandardPage and GalleryPage beside the existing ones in base/tests/. It changes no model, template or fixture. The description is a table of page models with their parent and child rules as tested, the form cases, and the render check.
The checks are the evidence. bakerydemo's ci.yml runs manage.py check, makemigrations --check and manage.py test under the test settings on the pull request, and the session keeps the agent's own runs of the same three commands from its sandbox, with every test name and result.
A reviewer checks that each assertAllowedParentPageTypes set matches what editors are meant to be able to do rather than only what the code allows today, that the snippets and images the tests create are minimal and not a second copy of the demo fixture, and that any behaviour called out as surprising gets a decision before it is locked in by a test.
Run it on every new page model
When a pull request adds or changes a Page subclass, its parent_page_types or its subpage_types, have a GitHub pull_request webhook send this request with the pull request URL in resources. The agent works on that branch, adds the tests for that model, and runs the suite in its own session and sandbox, so a page that editors cannot create where they expect is caught in review.
A webhook URL on the API key receives run.completed or run.failed when the turn ends, with the session URL, which your server can post back on the original pull request.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
Page tests in Wagtail need a working site: a page tree, a default Site, images and snippets for the required fields, and a settings module that does not trip over static files. Setting that up on a laptop means a virtualenv, a database and migrations, and keeping them in step with the branch. On Rush the agent installs requirements/development.txt in its own sandbox, builds the tree inside each test class, and runs the suite there, and none of it touches your environment.
The result shows its work. Every manage.py command the agent ran stays in the session with its output, so the table in the pull request can be checked against the run that produced it. The same request can go to several Wagtail sites at once, each in its own sandbox, each with a pull request someone reviews.
Frequently asked questions
Does it load my full demo or production fixture?
No, unless the fixture itself is what you want tested. Each test class builds the pages it needs in setUpTestData, as bakerydemo's AGENTS.md asks, so tests stay fast and a fixture change in another pull request does not break them.
What does WagtailPageTestCase give me over Django's TestCase?
Assertions written for page models: assertCanCreateAt, assertAllowedParentPageTypes, assertAllowedSubpageTypes, assertCanCreate for posting the admin create form, and assertPageIsRenderable and assertPageIsPreviewable. It also logs in a superuser for the admin checks, so the tests exercise the same forms editors use.
Does it need Postgres?
Not for bakerydemo, which falls back to SQLite when DATABASE_URL is unset. If your site's settings require Postgres, or your search backend needs it, the agent starts Postgres in its sandbox and sets DATABASE_URL for the run.
Will it test StreamField blocks?
It fills StreamField bodies with the streamfield form helper so creation works with real block data, and checks that the rendered page contains each block's content. Ask in the prompt for block-level tests and it adds tests that render each block from blocks.py on its own.