What the agent does
In a Wagtail project like wagtail/bakerydemo, the agent starts from the pinned stack: .python-version says 3.12 and requirements/base.txt declares Django>=6.0,<6.1 and wagtail>=8.0,<8.1, with development tooling in requirements/development.txt pinning ruff 0.15.15, curlylint and djhtml. There is no mypy configuration yet and no mypy in the requirements, so the first commit adds the tool and its Django plugin alongside the stubs Django projects need: django-stubs for the ORM and wagtail-stubs where the Wagtail API lacks inline annotations. The agent records the baseline test run, DJANGO_SETTINGS_MODULE=bakerydemo.settings.test with ./manage.py test, before annotating anything.
The code to cover is spread across the feature apps: bakerydemo/base/models.py alone defines fifteen page and block classes, and blog/, breads/, locations/, recipes/, people/ and search/ each carry their own models, views and templatetags. bakerydemo/search/views.py:11-47 hard-codes the searchable page models, and bakerydemo/urls.py wires the Wagtail admin, the search view and the v2 API router, all of which benefit from explicit request and response types. The agent works app by app, adding annotations to every function signature, and configures mypy in strict mode with a settings module so the ORM plugin resolves model fields instead of guessing.
Strict mode on a Django codebase surfaces real bugs, and the prompt asks the agent to fix those it finds and list them. Typical findings in a demo site of this shape: a view returning an HttpResponse in one branch and a redirect in another without a declared union, template tags whose returned types disagree with what the templates assume, and block value types in base/blocks.py that the StreamField code treats too loosely. Each fix stays behavior-preserving; where strictness forces a judgment call, the agent narrows the type rather than casting it away. The project's own lint contract is held to: make lint-server runs ruff format --check, ruff check, curlylint and djhtml, and annotated code must stay ruff-clean.
The run ends with proof: ./manage.py test in the test settings, then mypy across the project with its output captured. Only two test modules exist today, bakerydemo/base/tests/test_home_page.py and test_seo.py, so the agent treats the strict-mode run itself as the regression net and says so in the pull request. The diff also adds the mypy configuration and, where a third-party package ships no stubs, the ignore_missing_imports entries with a comment naming each package.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Add type hints to every function in this project and configure mypy in strict mode. Install stubs where packages lack them, fix real bugs mypy finds and list them, run the tests, and open a pull request with mypy's output.",
"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
The pull request contains the annotations app by app, the mypy configuration with its Django settings module, the added tool and stub dependencies in requirements/development.txt, and a captured mypy run ending with zero errors in strict mode. Its description lists the real bugs strict mode exposed and how each was fixed, and notes the packages that needed missing-imports entries. The ruff, curlylint and djhtml steps from make lint-server pass unchanged.
A reviewer reads the bug list first, since those are the behavior-adjacent hunks, then samples annotated views and model methods against their call sites. The mypy output file is the acceptance evidence: strict mode with zero errors, attached to a run that also ran ./manage.py test in bakerydemo.settings.test. The session read returns the repository and pull request information, and the transcript holds the mypy invocations and their full output.
Run it on every new app added
When a pull request adds a new app or a sizable module to the Django project, your automation sends POST /o/{org}/sessions with the repository URL and this prompt scoped to the new code, so annotations land while the code is fresh instead of becoming a later migration. Install the Rush GitHub App on the repository first and authenticate with an API key; an Idempotency-Key header keeps a retried submission from starting two runs.
Keep the returned execution_id and read the session when the run settles, or receive the key's completion webhook. If mypy flags something you disagree with, send a follow-up on the finished turn with the hunk; the messages endpoint wakes the parked sandbox where it left off. A follow-up while the turn is running is refused with a conflict, so check status first.
The use case this job follows, with its automation and trigger: Hand off from your terminal.
Why run it on Rush?
Strict-mode typing on a Django project is hours of mypy output triage, and it is exactly the kind of work that should not occupy your machine or your attention span. On Rush the agent works through the apps in its own sandbox and the run keeps going after your terminal closes; the transcript preserves every mypy invocation, so the zero-error claim is backed by output you can reread. A follow-up on the finished turn can push the strictness further, per-app, without a new setup.
For several Django services, submit one repository per run within your key's concurrency allowance and each gets the same strict-mode baseline. You review the bug lists independently, which is where the value sits. The useful proof is the mypy output at zero errors with the test suite still passing in the project's test settings.
Frequently asked questions
What does strict mode mean for a Django project?
Every function gets full annotations, untyped definitions are disallowed, and the django-stubs plugin resolves ORM queries against the real model fields. bakerydemo had no mypy at all, so the run adds the tool, the plugin configuration and a settings module, then works app by app until the strict run reports zero errors.
Will the agent change how my code behaves?
Annotations do not change runtime behavior, but strict mode often finds real bugs: branches with inconsistent return types, wrong argument types at call sites, block values treated too loosely. The prompt asks the agent to fix those and list each one, so the behavior-adjacent hunks are exactly what you review first.
What about packages with no stubs?
The agent installs django-stubs and wagtail-stubs where they exist, and for packages that ship no stubs adds a missing-imports entry naming the package. Those entries are visible in the configuration and can be removed package by package as stubs appear.
Only two test modules exist. Is that enough proof?
The run executes ./manage.py test under bakerydemo.settings.test and holds the project's lint contract, ruff format and check, curlylint and djhtml. With a test suite that thin, the strict mypy run is the real net, and its full output is attached to the pull request.
Can I leave it running and check later?
Yes. Save the execution_id the API returns and read the session when you are back, or receive the key's completion webhook. Once the turn finishes, a follow-up wakes the parked sandbox for another round; it is kept for 7 idle days.