Keyboard-first GitHub pull request client for macOS and Linux, with a review queue, local cache, and CLI for coding agents.
43
stars
196
commits
TypeScript
primary language
Sep 5, 2026
updated
GitHub pull requests at local speed.
PR Cockpit is a keyboard-first macOS app that keeps pull requests, diffs, threads, checks, and images warm on your Mac. Reads feel immediate, while comments, reviews, edits, and merges sync through your existing gh login. GitHub remains the source of truth.
Website · Install · CLI · Self-host relay · Shortcuts
The local server serves the queue and open pull request from SQLite instead of rebuilding every screen from GitHub. Webhook markers trigger targeted refreshes, WebSocket invalidations update the UI, and a poller repairs missed events.
Warm-cache opens of the large private pull request scape-app/scape#8132:
| Product | p50 | p95 | p99 |
|---|---|---|---|
| PR Cockpit | 0.082 s | 0.112 s | 0.121 s |
| Cursor Origin | 1.738 s | 3.702 s | 5.606 s |
| GitHub | 3.381 s | 4.880 s | 5.678 s |
A separate 12-run comparison of the common interactions, each a cold first open:
| Interaction | PR Cockpit p50 | GitHub p50 | Faster |
|---|---|---|---|
| Open a PR | 0.020 s | 1.421 s | 71.8× |
| Open a diff | 0.041 s | 1.487 s | 36.2× |
| Search PRs | 0.049 s | 0.839 s | 17.1× |
At p99, PR Cockpit painted the same pull request 47× faster than GitHub. Methodology and reproduction.
Press ⌥⌘K from any app, type, enter. The full pull request opens from the local cache.

Ready to merge, your move, and waiting are separate lanes, already sorted by what needs attention. Stacked pull requests stay together. Checks, conflicts, unresolved threads, and review state are available without tab-hopping.

Press x to fold test files out of the diff. In graphql/graphql-js#4692, that leaves the one-line fix on screen.

The review stays in one context:
| Agent | Edit |
|---|---|
![]() | ![]() |
| Revert hunk | History |
|---|---|
![]() | ![]() |
The installer adds the open-source pr-cockpit CLI. It reads the same local cache as the app, returns compact agent-shaped output, and revalidates only when that cache is stale.
pr-cockpit owner/repo#123 # state, checks, unresolved threads
pr-cockpit owner/repo#123 --diff # cached diff
pr-cockpit owner/repo#123 --file src/app.ts # full file at the PR head
pr-cockpit owner/repo#123 --jobs # cached queued, running, and completed jobs
pr-cockpit owner/repo#123 --logs [check] # cached failed and cancelled logs
pr-cockpit resolve owner/repo#123 HANDLE # resolve a review thread
pr-cockpit update # fast-forward and rebuild
Waiting on CI, review, or a new comment? Block on the local fingerprint instead of polling GitHub:
pr-cockpit listen owner/repo#123
listen blocks until substantive cached state changes — a push, check result, review, or comment — then prints only what changed. --ci-only and --comments-only narrow the wake signal.

curl -fsSL https://raw.githubusercontent.com/theolundqvist/pr-cockpit/main/scripts/bootstrap | bash
The installer checks macOS prerequisites, asks before installing anything, shows each stage, and opens the four-step setup. Only after installation succeeds does it optionally offer to teach local coding assistants to use the cache-aware CLI. Run pr-cockpit update to upgrade. A legacy private installation is replaced while local pull-request data and settings are preserved.
From a clone on the Linux host, install the loopback-only systemd user service:
./scripts/install-linux
Edit ~/.config/pr-cockpit/server.env, then run systemctl --user restart pr-cockpit.service. To update the checkout and rebuild the UI without replacing that file, run git pull && ./scripts/install-linux again.
For SSH access, leave TCP port 4820 closed and tunnel it instead:
ssh -N -L 4820:127.0.0.1:4820 user@host
Then open http://127.0.0.1:4820.
For phone access, keep the loopback binding and put a mesh VPN in front of it. A VPN whose agent runs on the same host reaches 127.0.0.1:4820 directly, so nothing has to listen on a public address. With Twingate, install a Connector on the host and define a Resource with address 127.0.0.1, an alias, and TCP restricted to port 4820; Tailscale Serve and Cloudflare Access work the same way. Add each exact browser origin to the comma-separated COCKPIT_ALLOWED_ORIGINS value in server.env (for example, COCKPIT_ALLOWED_ORIGINS="http://cockpit.example.internal:4820") and restart the service, because unsafe requests and the event socket reject untrusted origins. Never bind PR Cockpit publicly or open port 4820.
Run Settings → Run setup again whenever you want to change repositories or live updates.
| Key | Action |
|---|---|
| ⌥⌘K | Search pull requests from any app |
| j / k | Move |
| enter / esc | Open / back |
| d | Conversation / Files |
| c / r | Comment / reply |
| p | Open in the configured agent |
| e | Edit the open file |
| x | Hide / show test files |
| h | File history |
| m | Merge |
| ? | Full cheatsheet |
Settings live in the app. Optional shell overrides live in ~/.config/pr-cockpit/config.
| Variable | Purpose |
|---|---|
COCKPIT_REPOS | Comma-separated owner/repo list |
COCKPIT_PORT | Local HTTP port; defaults to 4820 |
COCKPIT_DEFAULT_REPO | Repository assumed when a PR number is passed alone |
COCKPIT_REPO_ROOTS | Paths containing local checkouts |
COCKPIT_RELAY_URL | Self-hosted webhook relay |
Functionality, themes, visual polish, and fixes for rough UI edges are all welcome.
New functionality must default off. Styling must be opt-in unless it is minor polish that preserves the default appearance.
Every pull request must attach before-and-after screenshots showing its effect in the app.
TypeScript
45.5%
Svelte
32.6%
JavaScript
17.6%
Shell
3.5%
Keyboard-first GitHub pull request client for macOS and Linux, with a review queue, local cache, and CLI for coding agents.
43
stars
196
commits
TypeScript
primary language
Sep 5, 2026
updated
GitHub pull requests at local speed.
PR Cockpit is a keyboard-first macOS app that keeps pull requests, diffs, threads, checks, and images warm on your Mac. Reads feel immediate, while comments, reviews, edits, and merges sync through your existing gh login. GitHub remains the source of truth.
Website · Install · CLI · Self-host relay · Shortcuts
The local server serves the queue and open pull request from SQLite instead of rebuilding every screen from GitHub. Webhook markers trigger targeted refreshes, WebSocket invalidations update the UI, and a poller repairs missed events.
Warm-cache opens of the large private pull request scape-app/scape#8132:
| Product | p50 | p95 | p99 |
|---|---|---|---|
| PR Cockpit | 0.082 s | 0.112 s | 0.121 s |
| Cursor Origin | 1.738 s | 3.702 s | 5.606 s |
| GitHub | 3.381 s | 4.880 s | 5.678 s |
A separate 12-run comparison of the common interactions, each a cold first open:
| Interaction | PR Cockpit p50 | GitHub p50 | Faster |
|---|---|---|---|
| Open a PR | 0.020 s | 1.421 s | 71.8× |
| Open a diff | 0.041 s | 1.487 s | 36.2× |
| Search PRs | 0.049 s | 0.839 s | 17.1× |
At p99, PR Cockpit painted the same pull request 47× faster than GitHub. Methodology and reproduction.
Press ⌥⌘K from any app, type, enter. The full pull request opens from the local cache.

Ready to merge, your move, and waiting are separate lanes, already sorted by what needs attention. Stacked pull requests stay together. Checks, conflicts, unresolved threads, and review state are available without tab-hopping.

Press x to fold test files out of the diff. In graphql/graphql-js#4692, that leaves the one-line fix on screen.

The review stays in one context:
| Agent | Edit |
|---|---|
![]() | ![]() |
| Revert hunk | History |
|---|---|
![]() | ![]() |
The installer adds the open-source pr-cockpit CLI. It reads the same local cache as the app, returns compact agent-shaped output, and revalidates only when that cache is stale.
pr-cockpit owner/repo#123 # state, checks, unresolved threads
pr-cockpit owner/repo#123 --diff # cached diff
pr-cockpit owner/repo#123 --file src/app.ts # full file at the PR head
pr-cockpit owner/repo#123 --jobs # cached queued, running, and completed jobs
pr-cockpit owner/repo#123 --logs [check] # cached failed and cancelled logs
pr-cockpit resolve owner/repo#123 HANDLE # resolve a review thread
pr-cockpit update # fast-forward and rebuild
Waiting on CI, review, or a new comment? Block on the local fingerprint instead of polling GitHub:
pr-cockpit listen owner/repo#123
listen blocks until substantive cached state changes — a push, check result, review, or comment — then prints only what changed. --ci-only and --comments-only narrow the wake signal.

curl -fsSL https://raw.githubusercontent.com/theolundqvist/pr-cockpit/main/scripts/bootstrap | bash
The installer checks macOS prerequisites, asks before installing anything, shows each stage, and opens the four-step setup. Only after installation succeeds does it optionally offer to teach local coding assistants to use the cache-aware CLI. Run pr-cockpit update to upgrade. A legacy private installation is replaced while local pull-request data and settings are preserved.
From a clone on the Linux host, install the loopback-only systemd user service:
./scripts/install-linux
Edit ~/.config/pr-cockpit/server.env, then run systemctl --user restart pr-cockpit.service. To update the checkout and rebuild the UI without replacing that file, run git pull && ./scripts/install-linux again.
For SSH access, leave TCP port 4820 closed and tunnel it instead:
ssh -N -L 4820:127.0.0.1:4820 user@host
Then open http://127.0.0.1:4820.
For phone access, keep the loopback binding and put a mesh VPN in front of it. A VPN whose agent runs on the same host reaches 127.0.0.1:4820 directly, so nothing has to listen on a public address. With Twingate, install a Connector on the host and define a Resource with address 127.0.0.1, an alias, and TCP restricted to port 4820; Tailscale Serve and Cloudflare Access work the same way. Add each exact browser origin to the comma-separated COCKPIT_ALLOWED_ORIGINS value in server.env (for example, COCKPIT_ALLOWED_ORIGINS="http://cockpit.example.internal:4820") and restart the service, because unsafe requests and the event socket reject untrusted origins. Never bind PR Cockpit publicly or open port 4820.
Run Settings → Run setup again whenever you want to change repositories or live updates.
| Key | Action |
|---|---|
| ⌥⌘K | Search pull requests from any app |
| j / k | Move |
| enter / esc | Open / back |
| d | Conversation / Files |
| c / r | Comment / reply |
| p | Open in the configured agent |
| e | Edit the open file |
| x | Hide / show test files |
| h | File history |
| m | Merge |
| ? | Full cheatsheet |
Settings live in the app. Optional shell overrides live in ~/.config/pr-cockpit/config.
| Variable | Purpose |
|---|---|
COCKPIT_REPOS | Comma-separated owner/repo list |
COCKPIT_PORT | Local HTTP port; defaults to 4820 |
COCKPIT_DEFAULT_REPO | Repository assumed when a PR number is passed alone |
COCKPIT_REPO_ROOTS | Paths containing local checkouts |
COCKPIT_RELAY_URL | Self-hosted webhook relay |
Functionality, themes, visual polish, and fixes for rough UI edges are all welcome.
New functionality must default off. Styling must be opt-in unless it is minor polish that preserves the default appearance.
Every pull request must attach before-and-after screenshots showing its effect in the app.
TypeScript
45.5%
Svelte
32.6%
JavaScript
17.6%
Shell
3.5%