PR Review Cockpit #
A small standalone Electron desktop app that hosts many GitHub PRs as a grid of live webviews, lets you focus one, and drive it.
It replaces a flaky window-tiling script (open-prs) that hit Chrome's
~500px minimum-window-width limit (tiles overlapped) and couldn't use iframes
(GitHub sends X-Frame-Options: DENY). Electron <webview> tags are real
browser contexts, so they load github.com fine and we size them freely with no
minimum — panes can go far below Chrome's window minimum with zero overlap.
Run #
cd /Users/jas/pr-cockpit
npm install
npm start
Requires the gh CLI authenticated on this machine
(gh auth login). The first time a PR webview loads you may need to sign in to
github.com inside the app; the login persists (shared persist:github
session partition) across tiles and restarts.
Configure #
Copy the example config and edit it (it is gitignored, so your repo/author never gets committed):
cp cockpit.config.example.json cockpit.config.json
{
"repo": "owner/repo",
"author": "your-login",
"me": "your-login",
"state": "open",
"limit": 100,
"onlyToday": false
}
author: "" fetches all open PRs. Environment variables override the file
(COCKPIT_REPO, COCKPIT_AUTHOR, COCKPIT_ME, COCKPIT_STATE,
COCKPIT_LIMIT, COCKPIT_ONLY_TODAY).
On launch (and on Refresh) the main process shells out to:
gh pr list --repo <repo> --author <author> --state <state> \
--json number,title,url,reviewDecision,isDraft,statusCheckRollup --limit <limit>
Each PR gets a derived CI status from statusCheckRollup:
- red — any check FAILURE / timed-out / cancelled
- yellow — any check queued / in-progress / pending
- green — checks present and all passing
- neutral — no checks
Features #
Grid mode #
- CSS grid of tiles, one
<webview>per PR. - Slim header per tile:
#<num> · <title>, colored by CI status (green/yellow/red/neutral), plusdraft/✓ approvedbadges. - Cols control (2–6) — resize panes freely, no overlap.
- Sort: Newest (desc PR number) / CI status / Draft-last.
Focus mode #
- Click a tile header (or its
#numplaceholder) to focus. - Focused PR expands to the large right pane; other PRs collapse to a thin scrollable left rail of header-only mini-strips.
- Focused tile gets a blue highlighted border.
- Esc or the ⤺ Grid button exits. Click any mini-strip to switch focus.
Drive the focused PR #
Focus-mode toolbar:
- Open in browser —
shell.openExternal(pr.url)in your real browser. - Reload —
webview.reload(). - Run JS — text field that runs arbitrary JS in the focused PR page via
webview.executeJavaScript(...)and shows the result. This is the seam for future CDP/automation.
Performance / lazy-loading choice #
10+ live Chromium webviews are heavy, so:
- Every PR gets a tile, but each tile's
<webview>srcis lazy — attached only when the tile first becomes live. Unloaded tiles show a clickable#numplaceholder. - In grid mode the first
EAGER_LOAD_COUNT(default 6) tiles auto-load for instant usefulness; the rest load on click. - In focus mode only the focused webview is live; other PRs are
header-only mini-strips (their
<webview>body is CSS-hidden but the element and its loaded state persist, so re-focusing an already-loaded PR is instant).
Tune EAGER_LOAD_COUNT at the top of renderer/renderer.js.
Files #
package.json— deps +startscript.main.js— main process: window,ghIPC, external-open, CI-status derivation.preload.js— context-isolated bridge (window.cockpit).renderer/index.html/style.css/renderer.js— the UI.
TODO / v2 ideas #
- Deeper CDP automation off the Run JS seam (scripted review flows).
- Review actions via the GitHub API/
gh(approve / request-changes / comment) from the focus toolbar. - Auto-refresh on an interval; desktop notifications on CI status change.
- Per-PR screenshot thumbnails in the rail instead of header-only strips.
- Persist column/sort/focus preferences between runs.