What the agent does
In remix-run/react-router-templates the agent reads pnpm-workspace.yaml first: five packages, the four templates default, node-custom-server, unstable_rsc-data-mode-vite and unstable_rsc-framework-mode plus a .tests package, with allowBuilds turned off for esbuild, sharp and workerd and a minimumReleaseAge of 10800 minutes that excludes react-router and @react-router/*. That last setting matters for an upgrade run: pnpm will not pick a version published in the last week and a half except for React Router itself, so the pull request can say why a package stayed one release behind. .nvmrc says 24 and ci.yml installs pnpm 10 on Node 22.
Then it reads each template's package.json. default declares react-router, @react-router/node, @react-router/serve and @react-router/dev as *, with react ^19.2.8, vite ^8.0.3, typescript ^5.9.3 and tailwindcss ^4.2.2, and pnpm-lock.yaml resolves React Router to 8.4.0. node-custom-server adds express ^5.2.1, @react-router/express, compression, morgan and cross-env, and its typecheck is react-router typegen followed by tsc -b. The RSC templates pin exact versions: vite 8.0.3, typescript 5.9.3, @vitejs/plugin-rsc ~0.5.34 and @remix-run/node-fetch-server 0.13.0. A star range moves to whatever is newest, a caret range moves within its major, and a pinned version only moves if the agent edits package.json, and the pull request treats those three cases differently.
The checks come from the repository's own suite. .tests/playwright.config.ts runs the test.*.ts files on Chromium; test.default.ts copies the template into a temporary directory, runs pnpm typecheck, starts pnpm dev on a free port and loads the page, expects the title New React Router App and the React Router Docs and Join Discord links, asserts no page errors and an empty stderr, then runs pnpm build and pnpm start and repeats the page check. test.node-custom-server.ts does the same for the Express server. The agent runs pnpm install, then in .tests runs pnpm playwright install --with-deps chromium and pnpm test --project=chromium for a baseline before touching anything.
It runs pnpm outdated across the workspace, applies pnpm update to move every caret and star range to its newest allowed version, and runs the typecheck, build and Playwright suite again. For a failure it restores the lockfile entries half at a time until one package remains, pins that package back and records the error. Majors outside a caret range, such as a new Vite or Express, are listed with their versions but not applied, and the pinned RSC versions are only raised when the same version passes in the other templates.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Upgrade the npm dependencies to the latest compatible versions with pnpm. Read pnpm-workspace.yaml and .nvmrc first and respect the minimumReleaseAge setting. Before changing anything run pnpm install, then in .tests run pnpm playwright install --with-deps chromium and pnpm test --project=chromium for a baseline. Run pnpm update so each package in every template moves within its declared range, then run pnpm typecheck and pnpm build in each template and the Playwright suite in .tests again. Leave out any upgrade that breaks the typecheck, build or tests and say why with the error. List newer majors outside the current ranges without applying them. Open a pull request with one line per bump.",
"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 changes pnpm-lock.yaml, and a template's package.json only where a range had to be raised. The description has one line per package with its old and new version, grouped by template, then the upgrades left out with the command and error that failed, and a short list of majors available outside the current ranges so the team can plan those on purpose. A package held back by minimumReleaseAge is named as such rather than reported as current.
A reviewer checks that the CI workflow's Playwright job passes on the pull request, reads the React Router line first because its star range means a new major arrives without warning, and looks at the changelog for any Vite or Tailwind minor that moved. The session record holds the baseline run, each pnpm command and the bisection, so an excluded package can be re-tried in a follow-up message to the same session.
Run it on every Monday morning
A scheduled workflow sends POST /o/{org}/sessions with this request and your repository in resources, with the org key as the bearer token and an Idempotency-Key built from the repository and the week, so a re-run returns the run already started instead of a second pull request.
Put a webhook URL on the key. When the turn finishes your endpoint receives run.completed with session_url, reads the pull request link from the session and posts it where the team reviews, ready before the first meeting.
The use case this job follows, with its automation and trigger: Upgrade dependencies weekly.
Why run it on Rush?
A template repository with four apps and a Playwright suite that boots each one in dev and in production mode takes several minutes per pass, and a bisection needs many passes. On a laptop that blocks the person running it. In a Rush sandbox the agent gets its own install, its own Chromium and as many passes as the bisection needs, with every command's output kept in the session.
A per-package bot opens a pull request for each bump and lets the team find the one that broke the start test. The agent opens one pull request, already tested, with the broken bumps taken out and named, and the same request can run against every repository that started from these templates at once, up to the key's concurrency limit.
Frequently asked questions
What does the minimumReleaseAge setting change?
pnpm skips any version published less than 10800 minutes ago, except react-router and the @react-router packages, which the workspace excludes. A package whose newest release is younger than that stays on the previous one, and the pull request says so instead of calling it up to date.
Will it move React Router to a new major?
It can, because the templates declare react-router as * rather than a caret range, so pnpm update takes the newest version there is. The pull request puts that line first and names the major so the reviewer can decide whether to keep it.
Does it upgrade the RSC templates too?
Only where their pinned versions can be raised to a version that passes in the other templates. The unstable templates pin vite, typescript and @vitejs/plugin-rsc exactly, and the agent reports those as pinned rather than silently editing them.
Can it run the Playwright suite without a display?
Yes. The suite runs Chromium headless, and the sandbox installs the browser with pnpm playwright install --with-deps chromium as the CI workflow does. The dev and start tests bind free ports with get-port, so several templates can be tested in the same sandbox.