An extremely fast GitHub for pull request review. PRs open in 20 ms instead of 1.4 s (benchmark).
PR Cockpit is a desktop app for GitHub pull requests on macOS and Linux. A local mirror, kept current by webhooks, holds every PR you care about, so the queue, the diff, the failed check logs and the review threads paint from disk. Keyboard for everything; GitHub stays the source of truth.
Install · See the workflow · CLI for humans and agents · Website
The queue separates ready to merge, your move, and waiting. Failed merge attempts appear under FAILED TO MERGE above pinned PRs in every grouping mode, until retried, dismissed, merged, or closed. Checks, conflicts, unresolved threads, and review state give you the context to decide what to open next. Stacked pull requests stay together.
Run this in your terminal as your normal user, not with sudo:
curl -fsSL https://raw.githubusercontent.com/theolundqvist/pr-cockpit/main/scripts/bootstrap | bashRead the installer first. It checks prerequisites, installs the desktop app and pr-cockpit CLI, and opens setup. On macOS it offers to install missing tools where supported; on Linux it checks system prerequisites and installs missing Bun and GitHub CLI tools into the managed installation. Both install and update paths use private Bun 1.4.3, verified against official SHA-256 checksums, without replacing your own Bun.
Supported platforms: macOS and Linux, both with Git 2.38 or newer; the installer stops with the found version when Git is older. Linux also requires systemd and the desktop libraries listed by the installer; x64 and arm64 are supported. X11 is supported directly; Wayland uses XWayland, and global shortcuts depend on compositor policy. Windows is not supported.
- Connect GitHub in the app. Cockpit reuses your GitHub CLI (
gh) login. If you need to sign in or grant additional access, setup opens the GitHub authorization flow in your browser. - Choose a repository you work in. Start with an open PR you've authored or participated in. Open follows PRs involving you; All PRs shows every open PR in your selected repositories. You can enter
owner/repoif it is not in the suggested list. - Enable live updates, or continue with polling. Live updates use a GitHub App installation with access to your selected repositories. An organization may require an owner's approval; that need not block your first review.
- Open the queue and pick that PR. Read the conversation, press d to switch to Files, and inspect a change. Press ? whenever you want the shortcut guide.
The first sync fetches PRs involving you. All PRs loads on demand without expanding background polling. Press Tab to cycle Open, All PRs, and Recently merged. Repository and live-update configuration live in Settings.
Press r to filter repositories. Use arrows to highlight one, Enter to toggle it, or Shift+Enter to select only that repository.
Enable Date filters and sorting in Settings → Workspace for Opened and Order controls in the main PR lists, plus Grouping in Your queue. Switch grouping between Status, Feature area, PR type, and Manual without leaving the queue. Opened, Order, Grouping, and Repository selections survive refreshes and app updates; only applied custom date bounds are saved. Filter to the last 24 hours, 7 days, 30 days, or a custom local date-and-time range; custom bounds apply when you press Apply. Order by newest or oldest opened, or most or least recently updated. Queue order keeps the usual priorities. Grouped queues keep their sections, manual pin order, and stacks; the Whiteboard is unchanged. PRs with an unknown opened date appear in All time but not an active date range.
Press ⌥⌘K on macOS or Super+Alt+K on Linux X11 to search from another app. Move the pointer or use the arrow keys to select a result; Enter opens that highlighted result in Cockpit, with the cached PR ready to read. Typing a number such as 51 or #51 lists that exact PR first, then PRs whose numbers contain it, open before closed and highest first, so 51 also finds #10051.
The search panel uses its own connection pool, so pending main-window requests cannot queue ahead of its page load. Shell updates take effect after relaunching the desktop app.
Diffs, threads, checks, and file history live in the same review workspace. The header shows Closed or Merged even if the PR retains its draft flag. The PR check summary uses the latest workflow run and job attempt; earlier runs remain in Actions history. Press x to fold tests and generated files when you want to see the implementation first; press it again to bring them back. Generated files include .generated. names and committed .gitattributes rules marked linguist-generated; nested rules and overrides follow the reviewed revision. The same group can be hidden by default in Settings.
PR images are prefetched into each machine's persistent cache, including SSH replicas; opening an image reuses that local download.
When the review needs a change, stay in context: e edits the open file and commits the patch to the PR; p opens the PR in your configured coding agent with review context. You can also revert a focused hunk or press h to inspect file history. A failed merge immediately requests fresh PR details to reveal conflicts or other blockers, while keeping the original error available to retry or dismiss.
Enable Full-file finder in Settings → Review preferences to read whole files from ⌘P (files) and ⌘⇧F (code search); use Ctrl on Linux. Results highlight the matched characters. Enter opens the whole file with syntax highlighting, at the matching line for a search hit, and ⌘F finds within it. From the PR list, the same shortcuts first ask for a tracked repository and then a branch, default branch first, and search that branch's latest mirrored commit. Escape steps back one level at a time.
Reviewer badges show scores explicitly posted in reviews or comments, parsed without launching a scoring agent.
Enable Pending reviews in Settings → Workspace to save inline comments as a native GitHub draft and submit them together as one review. Drafts survive reloads and remain editable; if the PR head changes, submission stops until the stale draft is discarded. Comment now still posts a single comment immediately.
Enable Mark changed descriptions in Settings → Workspace to show a small blue dot to the left of the avatar, vertically centered on it, when the PR description differs from the one you last read. It is off by default. A description counts as read while it is on screen in the Conversation tab of a foreground window; PRs you have never read stay unmarked, and a description reverted to the version you read clears the dot.
Task-list checkboxes (- [ ], - [x]) in a PR description can be ticked in the Conversation tab; comments stay read-only. Each tick is queued as a description edit that rewrites only that checkbox in the description GitHub currently holds, so text republished since you loaded the PR, such as a regenerated report, is kept. A task is matched by the PR number that starts it (#123), otherwise by its text; if it is gone or ambiguous the edit fails and you reload. Checkboxes stay disabled while a description edit is open, queued, or failed.
Right-click an open PR and choose Close PR to close it without opening the review. Cockpit asks for confirmation before queuing the close on GitHub.
Enable Approve PRs for safe merge in Settings → Workspace, then right-click a PR and choose Approve for safe merge. It appears above ordinary pins, below failed merges, without launching an agent. Approval covers that PR through fixes and base updates until revoked; closing it or disabling the feature clears approval. Ordinary pins remain bookmarks.
Enable Rename and move PRs between groups in Settings → Workspace to rename a PR from its right-click menu or move it onto another section or row. Rename edits the title inline: Enter saves and Escape cancels. Type grouping changes the title's conventional-commit type; feature grouping changes its scope; manual grouping changes only your assignment. Dragging preserves the summary, draft prefix, and breaking-change marker. Status sections remain read-only. Dropping into Approved for safe merge grants approval; dropping out revokes it.
Press ⌘Z (Ctrl+Z on Windows/Linux) to undo a title change from Rename or a group move, including while it is saving. Undo restores the exact previous title on GitHub, not revoked merge approval. Title changes and Set Aside share undo order; text fields and the whiteboard keep their own undo.
Desktop notifications are off by default. In Settings → Notifications, choose events and combine rules for human or bot authors, comment text, repositories, and review requests. GitHub bot accounts and configured review bots count as bots; unknown authors match neither human nor bot filters.
Turn on PRs I merge in Settings -> Notifications to get a desktop notification when a PR you merged lands and a Merged by me filter in the Kitchen Notifications list; it works whether or not the custom rules are on. A PR counts as yours when you merged it, or when a merge-queue bot merged it after you last added its order label. Bot merges read that label history from GitHub only while the setting or an I merged it rule is on.
Repositories can add quick actions to the PR sidebar and the PR-row Quick actions submenu by committing .github/pr-cockpit.json. Each action posts a fixed comment or adds a label. Cockpit reads it from the repository's default branch and shows the actions on every open PR there:
{
"quickActions": [
{ "label": "Preview", "comment": "@preview", "key": "P" },
{ "label": "Order", "addLabel": "order", "key": "O" }
]
}Each entry needs exactly one of comment or addLabel; key is optional, and keys Cockpit already uses are ignored. Settings → Agents & merging → Quick actions shows the format and copies a prompt that asks your coding agent to write the file. Your quick actions in the same place apply only to your Cockpit, on top of each repository's file: an entry with a matching label changes only the fields it sets or hides that action with "hidden": true, other entries add buttons, and "repos": ["owner/repo"] limits an entry to those repositories.
Everyday shortcuts
| Key | Action |
|---|---|
| j / k | Move |
| enter / esc | Open / back |
| ⌘[ / ⌘] | Back / forward (macOS) |
| d | Conversation / Files |
| c / r | Comment / reply |
| p | Open in the configured agent |
| e | Edit the open file |
| x | Hide / show tests and generated files |
| h | File history |
| m | Merge |
| ⌘z / Ctrlz | Undo a group-move rename or Set Aside action |
| ? | Full shortcut guide |
Enable Whiteboard (Experimental) in Settings → Workspace to add the final review-queue tab. It is off by default. One personal canvas is saved in this installation's SQLite database; disabling the setting keeps it and stops board activity in every connected window. Unsaved work stays protected in its window with a visible export/re-enable banner; keep that window open until recovered. Board actions never change GitHub, manual queue groups, or queue order.
Open PRs, including drafts, start in sections based on your queue grouping, arranged to fit the canvas proportions. Arrange refreshes inbox-generated groups from the current queue, removes empty sections, and reflows the board; Undo restores the previous grouping and positions. Custom sections and their cards stay personal. Rename a generated section to make it personal. Cards outside the current queue remain under On this board. Ordinary refreshes and window resizing preserve your layout. Drag cards on the 16 px grid, Shift-click or drag empty space to select several objects, and move a section to carry its contents. Add personal notes, pen strokes and connectors with the toolbar. Double-click a card to open its real PR; returning keeps your location and selection. New PRs arrive below existing objects without rearranging them. New commits flag cards for another look; missing cached PRs keep clearly marked last-known metadata. Live metadata refreshes do not create personal saves. Clean windows adopt newer saved boards; unsaved edits require explicit conflict resolution.
Scroll zooms at the pointer; hold Space and drag to pan. Tool shortcuts are V select, H pan, F section, P pen, T note, and C connector, also shown beside each tool. 1 fits the board, 0 restores 100%, and / finds and locates objects. Arrows nudge the selection; Delete removes only board objects. Ctrl/⌘ Z and Shift Ctrl/⌘ Z undo/redo within the current session, without rolling back live PR metadata. Text editors retain their native text shortcuts. Clear completed removes closed/merged cards from the board only; it is undoable and those cards stay excluded on refresh. Export downloads a board backup. Failed saves and conflicting windows keep local edits and offer explicit retry/recovery controls.
The included pr-cockpit CLI reads the same local cache as the app. Use it yourself, or give your coding agent a way to inspect a PR without repeatedly fetching it from GitHub. Set up the app first; the CLI needs the local Cockpit server.
Replace owner/repo#123 with your pull request:
pr-cockpit owner/repo#123 # state, checks, and review threads
pr-cockpit owner/repo#123 --diff # cached unified diff
pr-cockpit owner/repo#123 --file src/app.ts # file contents at the PR head
pr-cockpit owner/repo#123 --jobs # queued, running, and completed jobs
pr-cockpit owner/repo#123 --logs # cached failed and cancelled job logs
pr-cockpit owner/repo#123 --logs verify --run 987 --attempt 2--run selects a cached run even after the PR head advances; --attempt selects its rerun attempt. Without these selectors, jobs and logs use the current head.
Waiting on CI or a review? Listen instead of polling.
pr-cockpit listen owner/repo#123listen waits for substantive cached state changes—a push, check result, review, comment, or merge conflict—then prints what changed and exits. It returns at once when the PR already has failing checks, open comments, or merge conflicts, but never from a snapshot older than known webhook activity: it waits for revalidation first. --ci-only, --comments-only, and --conflicts-only narrow the wake signal.
pr-cockpit listen owner/repo#123 --run 987 waits for a specific run and reconciles it about every 30 seconds at the default interval, so missed webhooks cannot leave completion unobserved. A failed reconciliation exits with an error.
CI completeness is durable for the observed head; an expired Actions viewing lease does not turn settled jobs back into pending work. Checks use the latest result per job name within each workflow/App, so metadata-only workflows with different names do not erase earlier required checks on that head. Skipped and neutral jobs retain their displayed state but satisfy required checks, as on GitHub; missing checks, incomplete pages, and unobserved jobs remain pending.
The CLI also supports comments, reviews, thread resolution, edits, and merges through Cockpit's mutation queue. Run pr-cockpit --help for commands and options, including --body-file for exact multiline text and --json for machine-readable status. The installer separately asks before adding Cockpit instructions to supported coding assistants.
Built-in agents launch from Cockpit's cached PR brief without spending GitHub API quota, and clone through Git rather than GitHub's API. They use pr-cockpit for PR reads and mutations; remote API operations still need available quota. With OMP, Opus uses the opus alias and Sonnet uses anthropic/claude-sonnet-5-5.
Arming auto-merge approves the feature and delegates safely landing it to the merger. It follows your global and repository instructions, addressing comments, conflicts, and CI failures caused by the PR; known unrelated failures need no rerun or post-merge proof. OMP loads global instructions automatically, and the agent reads repository instructions after cloning. A direct prompt can also authorize merging explicitly. In either case, Cockpit refreshes the PR and merges only the head the agent checked. Bypassing required GitHub checks or approvals still needs the repository's force-merge opt-in; conflicts, unresolved threads, and changes-requested reviews remain blockers.
Safe-merge approval is also visible in CLI output and as approvedForSafeMerge in --json; listen wakes when it changes. Agents must re-read approval immediately before merging and still satisfy the safety checks above. Approval is granted or revoked in the app, never by an agent approving itself.
The PR detail’s Agents tab renders Markdown answers and expandable tool activity, shows an identical final-answer echo only once, and keeps available tool inputs, errors, and log tails inspectable.
Enable Agent conversations in Settings → Agents & merging for a conversation-first Agents workspace beside the inbox tabs. Search sessions grouped into Working, Needs attention, and Recent, including closed PRs. Read Conversation, expand longer tasks in place, inspect Log tail, or open an older attempt from run history. Run links support Back/Forward; each run and view remembers its reading position. New output follows only when you’re at the end; otherwise Jump to latest signals unread output. Transcripts and logs contain the recent output available from the cache, not complete logs. PR filters and grouping sit below the inbox tabs.
Enable Quick Generate in Settings → Agents & merging to draft text from anywhere with ⌥⌘J on macOS or Super+Alt+J on Linux X11. Choose an API key and model, write a prompt, then press ⌘Enter to generate. Results render Markdown with Cockpit’s syntax-highlighted code blocks; Copy keeps the original Markdown. Closing the prompt keeps its draft and result. Updating an older desktop shell requires a normal relaunch for the global shortcut.
Keys are detected from $XDG_CONFIG_HOME/.env (or ~/.config/.env), then ~/.env, then the Cockpit server's environment; the first nonempty value wins. API key file selects a different file and accepts absolute paths, ~/, $HOME, or $XDG_CONFIG_HOME. A missing selected file shows an error instead of falling back. Supported names are CEREBRAS_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, and GROQ_API_KEY; suffixes such as CEREBRAS_API_KEY_WORK provide additional choices. Credentials stay on the Cockpit host and go only to their provider, including in replica mode. Models come from the provider's catalog, with Cerebras Qwen preferred by default.
Settings → Usage shows REST core and GraphQL quota separately, including exhausted balances and reset times. Optional REST request attribution is off by default; turn on Record REST requests there to record this Cockpit server's actual outbound attempts by source and endpoint, with a 72-hour history. On a replica, the switch controls its authoritative source rather than the viewing machine. Other-client usage stays unknown until uninterrupted recording covers the whole quota window with authoritative headers and known charges, and while responses remain in flight. Turning recording off or on, account changes, failed ledger writes and restarts start coverage over. Automatically followed redirects have unknown charges. While Cockpit runs a gh command that can call GitHub's API (sign-in checks, and webhook forwarding for as long as it runs), Cockpit's own requests are still recorded but other-client usage stays unknown. Reading quota status remains available when the primary REST limit is exhausted; GitHub's secondary cooldowns still apply.
Cockpit is a client for your existing GitHub workflow, not a second place to maintain pull requests.
- On your machine: a Bun server caches PR state in SQLite and serves the desktop UI and CLI. In replica mode, cached lists stay local; GitHub searches and keyed PR title lookups use the connected source.
- Mirror storage: Git mirrors compact automatically and evict the oldest unprotected caches toward a 20 GiB target. Active reads, recent use, and linked worktrees are protected, so the target is not a hard limit.
- Back to GitHub: comments, reviews, file edits, thread resolution, and merges use your GitHub CLI authentication. GitHub remains authoritative.
- Keeping it current: the hosted relay is enabled by default. It receives GitHub webhooks and delivers compact change markers and Actions run/job state, including runner assignment—not full PR contents or job logs—to Cockpit. Cockpit never sends the relay your GitHub token; it proves read access to each repository with commit data only readers can look up, and that proof rotates daily. Branch pushes refresh open PRs whose head or base matches, including recently viewed PRs outside the inbox. A direct GitHub poller repairs missed events.
- Your relay, if you prefer: you can configure a different relay URL. See Self-hosting for deployment and connection instructions.
Local caching does not mean the app makes no external connections. Besides GitHub and the relay, the backend has Sentry error reporting enabled by default.
Updates, diagnostics, and configuration
In Settings → Workspace → Developer, choose Check for updates to fetch the latest main revision from GitHub. If an update is available, Install update runs the existing updater; the page reloads when the server reports the new revision. Installations with updates disabled reject both actions.
If the installed backend cannot start, the desktop launcher automatically tries an update before opening the app. Recovery is limited to once every five minutes, respects disabled updates, and leaves local edits and non-main branches untouched. It restarts only the backend, never an already-running desktop window. If no working update is available, startup reports the failure.
pr-cockpit update # update and reconcile the installed app
pr-cockpit status # identify the process supervising the local serverThe installer manages the background server and desktop integration. On Linux, $HOME/.pr-cockpit/scripts/uninstall removes a default installation; adding --purge also removes its local data.
Use Settings for day-to-day configuration. Optional shell overrides live in ~/.config/pr-cockpit/config (Linux respects XDG_CONFIG_HOME).
| 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 |
Custom webhook relay URL |
COCKPIT_TAILSCALE_SERVE |
Set to 1 to publish Cockpit privately through Tailscale Serve |
COCKPIT_TAILSCALE_HTTPS_PORT |
Tailscale HTTPS port; defaults to 443 |
Found friction in a real review? Open an issue with what you were trying to do and what got in the way. Keep reports and screenshots free of private repository data.
Fixes, functionality, themes, and UI polish are welcome. Read the contributor and agent guide for development setup and repository conventions. New functionality must default off; styling must be opt-in unless it is minor polish that preserves the default appearance. Pull requests must include before-and-after screenshots showing their effect in the app.


