All jobs

Review Pull Requests on an Electron App

Yes. An agent checks out the pull request, runs package, lint, tsc, jest and the Electron smoke test in its sandbox, and posts one review on IPC and preload.

Run this on RushIn a Project that has your repository.

What the agent does

The agent reads the two-package layout before the diff, because in electron-react-boilerplate most review mistakes come from putting a dependency or a file on the wrong side of it. The root package.json has main set to ./release/app/dist/main/main.js, and build.directories.app points electron-builder at release/app, whose own package.json is at version 4.6.0 with an empty dependencies map that electron.vite.config.ts reads to decide which native modules to externalize. postinstall runs npm --prefix .erb/tooling ci, install-electron and electron-builder install-app-deps; .erb/tooling/package.json holds typescript, ts-jest, ts-node and the TypeScript ESLint plugins apart from the app, and both jest.config.js and eslint.config.js resolve them through createRequire on that package. devEngines and engines require Node 24 and npm 10 or newer.

The checks the repository runs are in .github/workflows/test.yml: on macOS, Windows and Ubuntu with Node 24 it does npm ci, then npm run package, npm run lint, npm exec tsc -- --noEmit and npm test, and on Linux xvfb-run --auto-servernum npm run test:smoke. package is npm run build && electron-builder build --publish never, with build being electron-vite build into release/app/dist/{main,preload,renderer}. test is Jest 30 with testEnvironment: 'jsdom', identity-obj-proxy for stylesheets, mocks for .svg?react and binary assets, and setupFiles pointing at .erb/scripts/check-build-exists.ts. The two tests are src/__tests__/App.test.tsx, which renders App and expects the electron-react-boilerplate heading and the docs and donate links, and src/__tests__/updates.test.ts, which mocks electron, electron-updater and electron-log under a node environment and checks that startAutoUpdates does nothing unpackaged, runs once when packaged and logs a rejected checkForUpdatesAndNotify. The agent runs that whole sequence in the sandbox, with xvfb-run for the smoke test.

Then it reads the diff with the questions the prompt names. IPC boundaries: src/main/main.ts registers one handler, ipcMain.on('ipc-example'), which replies IPC test: pong, and src/main/preload.ts exposes electron.ipcRenderer through contextBridge.exposeInMainWorld with sendMessage, on and once typed against Channels = 'ipc-example'; src/renderer/preload.d.ts declares window.electron from that type. A new channel must be added to Channels, handled in main.ts and reached only through the bridge, and a removeListener must still be returned from on. Context isolation and preload exposure: the BrowserWindow in createWindow sets only preload under webPreferences, so it relies on Electron's defaults for contextIsolation and nodeIntegration; a diff that adds nodeIntegration: true, turns contextIsolation off, or exposes ipcRenderer itself instead of a wrapper is blocking. The agent also checks setWindowOpenHandler, which denies new windows and hands the URL to shell.openExternal, and the activate handler, which only creates a window when mainWindow is null so the updater is not started twice.

The smoke test is the strongest evidence the repository offers, so the agent reads .erb/scripts/smoke-test.cjs before quoting it. It starts npm start with --remoteDebuggingPort, finds the renderer page over the DevTools protocol, waits for the h1 and a loaded image, asserts there is no vite-error-overlay, that exactly two anchors exist, that window.electron.ipcRenderer.sendMessage('ipc-example', ...) round-trips to IPC test: pong, and that no Runtime.exceptionThrown arrived. A pull request that changes the home route, the preload surface or the IPC channel usually shows up here first. One GitHub review is posted per run: the summary quotes package, lint, tsc, jest and the smoke test, separates blocking issues from suggestions, and every finding cites file and line. 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 an Electron app built on electron-react-boilerplate. Check it out, run npm ci, then npm run package, npm run lint, npm exec tsc -- --noEmit, npm test and xvfb-run --auto-servernum npm run test:smoke, the same sequence as .github/workflows/test.yml. Read the diff with src/main/main.ts, src/main/preload.ts, src/renderer/preload.d.ts, electron.vite.config.ts and release/app/package.json. Look for IPC channels used in the renderer that are not in the Channels type or not handled in main.ts, anything exposed through contextBridge that hands the renderer a raw ipcRenderer or Node API, webPreferences that enable nodeIntegration or disable contextIsolation, native modules added to the root package.json instead of release/app/package.json, and listeners registered in on() without a matching removal. Post one GitHub review that quotes each command's result including the smoke test, 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 the result of npm run package, npm run lint, tsc --noEmit, the Jest run with its two suites, and the smoke test's final line or the assertion it failed on. Findings follow with file and line in src/main, src/renderer or the config files, each marked blocking or suggestion, and a finding about the preload names the property that was exposed and what the renderer could reach through it.

The transcript keeps the install with its postinstall steps, every command and its output, and the smoke test's console including anything Electron printed on the way up, so when the review says the renderer threw on load, the exception text is in the record.

Before merging, a reviewer runs npm run test:smoke on the branch on their own platform, since the sandbox covers Linux only, opens each cited line, and dismisses suggestions that do not hold. A new webPreferences flag or an unguarded IPC handler is blocking by default; an ESLint warning about import order 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 push gets its own sandbox, its own npm ci and electron-builder run, and its own review. Set read_only so the runs can comment but never push.

The review appears on the pull request as the result, and the run is listed in the Project. The automation's max_runs_per_hour, 1 to 30, keeps a day of Dependabot bumps to a bounded number of packaging runs; a fire past the cap is skipped as rate_limited and that pull request is reviewed on its next push.

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

Why run it on Rush?

An Electron review that stops at the diff misses the failures that matter: a preload that exposes too much, a channel the main process never handles, a native module that electron-builder cannot rebuild. Proving those means installing Electron, packaging the app and starting it under a virtual display, which is why most reviews skip it. On Rush the agent does that in its own sandbox and keeps every command and its output, so the review quotes the smoke test's IPC round-trip rather than asserting that IPC still works.

One sandbox per pull request means several contributors' changes are packaged and reviewed at the same time, each with its own release/build output, and none of it touches a developer's machine or the branch. The reviewer gets findings with the evidence attached and the author gets the same sequence CI would run, before CI runs it.

Frequently asked questions

Does the sandbox cover macOS and Windows too?

No. test.yml runs on all three, and the sandbox runs the Linux leg, including the smoke test under xvfb-run. The review says so, and a change to build.mac, build.win, assets/entitlements.mac.plist or the notarize script in .erb/scripts is reviewed by reading, labelled as such.

Will it catch a native module in the wrong package.json?

Yes. electron.vite.config.ts externalizes exactly the names in release/app/package.json dependencies, and postinstall rebuilds them with electron-builder install-app-deps. A native module added to the root package.json gets bundled instead, which the agent confirms by reading the build output and flags with the line to move.

What does it make of the updater code?

src/main/updates.ts returns early unless app.isPackaged, guards against a second start, sets log.transports.file.level and catches a rejected checkForUpdatesAndNotify. updates.test.ts pins all of that, so a diff that changes it is checked against those tests, and a change that lets the updater run in development is a finding.

Does it run the lint with the repository's ESLint config?

Yes, npm run lint uses eslint.config.js, a flat config with the react, react-hooks, jsx-a11y, import, promise, compat and prettier plugins, loading the TypeScript parser from .erb/tooling. The review quotes the error count and treats a new error as blocking only if the pull request introduced it.