What the agent does
The agent reads how the site is run before it adds a route. In a site shaped like wagtail/bakerydemo, requirements/base.txt pins Django to the 6.0 line and Wagtail to 8.0, with WhiteNoise and dj-database-url; requirements/production.txt adds uWSGI, psycopg, django-redis and django-basic-auth-ip-whitelist; and runtime.txt and the Dockerfile both fix Python 3.12. bakerydemo/settings/base.py reads DATABASE_URL and falls back to SQLite, production.py builds a Redis cache from REDIS_URL when it is set and reads ALLOWED_HOSTS from DJANGO_ALLOWED_HOSTS, and test.py swaps in a local-memory cache. docker-compose.yml runs postgres:18.1, redis:8.4 and the app on port 8000; docker-entrypoint.sh waits for Postgres with a psql loop and migrates; and the image's CMD is uwsgi /code/etc/uwsgi.ini with two workers and four threads on $(PORT), which the Dockerfile sets to 8000.
bakerydemo/urls.py is where the route goes. It mounts the Django admin, the Wagtail admin, documents, image serving, search, sitemap.xml, the API routers and the debug toolbar, then Wagtail's page URLs last. AGENTS.md asks for tests under bakerydemo/<app>/tests/, run with DJANGO_SETTINGS_MODULE=bakerydemo.settings.test, and CONTRIBUTING.md asks that AI assistance be disclosed in the pull request with the steps taken to verify the code, which the agent does.
The change uses django-health-check, whose current 4.10 release requires Django 5.2 or newer. The agent adds it to requirements/base.txt with a bound on the 4 line, adds health_check, health_check.db and health_check.cache to INSTALLED_APPS in base.py, and appends health_check.contrib.redis in production.py inside the existing if REDIS_URL: block, next to the cache it configures, with REDIS_URL as its target. In urls.py the route path("health/", include("health_check.urls")) is placed before the Wagtail catch-all so a page with the slug health can never shadow it. The view answers HTML by default and JSON with ?format=json, which is what a load balancer or an uptime probe reads.
The test follows the repository's own pattern. bakerydemo/base/tests/test_health.py sits beside test_home_page.py, requests /health/?format=json, asserts a 200 and that the DatabaseBackend and CacheBackend entries read working, and then patches the cache to raise and asserts a 500 with the failing entry named, so the route proves something rather than always answering OK. For the container the agent adds a HEALTHCHECK to the Dockerfile that runs a short Python urllib request against http://localhost:8000/health/?format=json, since the slim image carries no curl. It runs uv pip install -r requirements/development.txt, ./manage.py check, ./manage.py makemigrations --check --noinput, ./manage.py test under the test settings and make lint-server, the steps .github/workflows/ci.yml runs, and brings up docker compose to read the route through uWSGI once.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Add health checks to this Wagtail site. Read requirements/base.txt, requirements/production.txt, bakerydemo/settings/base.py, bakerydemo/settings/production.py, bakerydemo/settings/test.py, bakerydemo/urls.py, Dockerfile, docker-compose.yml, docker-entrypoint.sh, AGENTS.md and .github/workflows/ci.yml first. Add django-health-check with database and cache checks, add the Redis check only in the production settings where REDIS_URL is configured, mount it at /health/ before the Wagtail catch-all, add a Django test under bakerydemo/base/tests that reads /health/?format=json and covers a failing cache, add a Dockerfile HEALTHCHECK that uses Python rather than curl, run manage.py check, makemigrations --check, the test suite under bakerydemo.settings.test and make lint-server, confirm the route through docker compose, and open a pull request that discloses the agent's work and how it was verified.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- 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 pull request on its own branch. The diff touches requirements/base.txt for the package, bakerydemo/settings/base.py and bakerydemo/settings/production.py for the apps and the Redis target, bakerydemo/urls.py for the route, bakerydemo/base/tests/test_health.py for the test and the Dockerfile for the HEALTHCHECK. No migration is created, because the package's checks keep no models of their own, and makemigrations --check proves it. The description lists the checks by name, shows the JSON the route answers, and discloses the AI assistance and the verification steps as CONTRIBUTING.md asks.
The checks are the proof. The CI workflow runs on the pull request: lint-server runs Ruff, curlylint and djhtml, and test-server runs manage.py check, makemigrations --check and manage.py test under the test settings with uv. The session's trajectory at GET /o/{org}/sessions/{id}/messages keeps every one of those commands with its output, and the docker compose request that shows the route answering through uWSGI, so a reviewer reads the evidence rather than a claim.
Before merging, a reviewer checks that /health/ is reachable by the probe that needs it and not indexed or linked anywhere public, that the Redis check is added only where REDIS_URL exists so a deployment without Redis does not report itself down, and that the HEALTHCHECK interval suits the platform, since Heroku ignores it and Compose honours it. Nothing reaches main until the pull request merges.
Run it on every new Wagtail site
Start one run per site that has no health route from your own server: POST /o/{org}/sessions with this prompt and that repository in resources, one call each. GET /o/{org}/github lists every repository the Rush GitHub App installation can reach, so a script can find the ones with wagtail in a requirements file and no health_check in their settings and start a run for each. A request_id built from the repository name makes a retried call return the run it already started.
Give the key a webhook_url and each run POSTs run.completed with its session_url when the turn finishes, so the pull request links collect on your side without polling. A key has at most max_concurrent runs in progress at once, 4 by default, and a further start is 429, so a sweep over many sites should feed them in as earlier runs finish.
The use case this job follows, with its automation and trigger: Hand off from your terminal.
Why run it on Rush?
A health route is small, but proving it means running the site the way production runs it: Postgres and Redis up, uWSGI in front, the route read through the container, and then a failing backend to see the status flip. On a laptop that is a Compose stack and a uv environment for a ten-line change. On Rush the agent does that in its own sandbox with Docker, runs the Django suite under the test settings and the lint target, and pushes only when the CI steps pass locally.
The pull request is also the disclosure the project asks for. It names the checks, shows the JSON, says what the agent ran, and the trajectory keeps each command and its output for anyone who wants to look. A sweep over several sites becomes several sandboxes and several pull requests at once, each with its own record, rather than an afternoon per site.
Frequently asked questions
What does the route check?
The database, through health_check.db, which writes and deletes a row; the cache, through health_check.cache; and in production, Redis at REDIS_URL through health_check.contrib.redis. Each check reports working or an error, and the HTTP status is 200 only when all pass. The test covers the passing case and a failing cache.
Why is the Redis check only in production.py?
Because that is the only settings module that configures Redis: production.py builds the cache from REDIS_URL when it is set, and test.py uses a local-memory cache. Adding the Redis check in base.py would make the test suite and a local SQLite setup report themselves unhealthy for a service they do not use.
Does the health view need authentication?
No, and it is not given any, because a load balancer or uptime probe cannot sign in. The route exposes the names of the checks and their status, not credentials or configuration. If the site runs behind django-basic-auth-ip-whitelist from requirements/production.txt, the reviewer decides whether the probe's address needs to be on the whitelist.
Why use Python instead of curl in the HEALTHCHECK?
The image is built from python:3.12-slim and the Dockerfile installs only the runtime packages the site needs, which do not include curl. A one-line python -c with urllib.request is already available, and the check targets port 8000, which the Dockerfile sets as PORT and etc/uwsgi.ini binds.
Will a page with the slug health break the route?
No. The route is added to urlpatterns before the include(wagtail_urls) entry that serves pages, so /health/ resolves to the view first. The test requests the path and asserts a JSON response, which a Wagtail page would not return.