A small macOS menu bar app for tracking GitHub pull requests that need your review.
It uses the locally authenticated gh CLI, polls for open review requests, shows them in a popover, and can send native notifications for newly surfaced PRs.
The popover has two tabs, My Pull Requests (the PRs you authored) and My Review Needed (PRs requesting your review); swipe horizontally with two fingers, or click the segmented control, to switch between them. A toolbar above the list filters by repo or tag and changes the sort order (created, updated, repo, or CI state). The popover footer has a button to pause and resume notifications without opening Settings.
Each PR row shows compact review status metadata:
- total comment count, combining issue comments and review-thread comments
- unresolved review-thread count, with a hover tooltip grouped by author
- CI rollup state, with a hover tooltip listing failed check runs/status contexts when CI fails
- labels, diff stats, author, age, repo, and PR number in a single-line row layout
Status hover details use a short-delay cached tooltip panel anchored to the hovered badge, so CI and unresolved-comment details remain available while the popover refreshes and are not clipped by the row layout.
Each PR row exposes quick actions. The set depends on the tab:
- Approve submits an approval review with
gh pr review --approve(review tab only). - Close closes the PR without merging with
gh pr close. - Ignore hides the PR locally by repo and number; it stays hidden until you clear it from Settings -> Ignored PRs.
- Nudge / Urgent nudge run your configured local commands (see Nudge commands). They appear only when a command is set.
Approve and Close prompt for confirmation and drop the PR from the list on
success. Launch with --debug-actions to exercise the action UI in dry-run
mode: prompts and progress states render, but no GitHub mutation, local ignore,
or command is performed.
- Make sure the GitHub CLI is installed and authenticated:
gh auth statusIf that fails, run:
gh auth login- Build and launch the app:
swift build
swift run PruefstandFor safe UI testing with mock data, use preview mode:
swift run Pruefstand --preview-
Open Settings from the menu bar popover and choose which PRs to watch.
- Set the Polling interval (1-120 minutes) for how often Pruefstand refreshes.
- Under Which PRs, set the review scope: My teams (includes direct requests), Directly requested to me, or Mentioned me.
- Under Notifications, toggle native notifications on/off, or pause them temporarily (also available from the popover footer).
- Use Watched repos to scope the list to one or more repositories.
- Use Watched contributors to check one or more active authors, or add a login manually, to include PRs even when you are not requested as a reviewer.
- Toggle Include drafts when draft PRs should be shown too.
- Use Hidden authors to suppress PRs from specific logins; bot accounts
(
renovate,dependabot,github-actions, and any[bot]login) are hidden by default. - Ignored PRs shows the locally ignored count and a Clear button to un-hide them all.
-
Optional: configure Nudge commands so each PR row can run your own local reminder workflow. For example, this asks Codex to draft a review nudge and copies it to the clipboard:
codex "Draft a concise, friendly PR review reminder. PR: $PR_TITLE. Repo: $PR_REPO. Open for $PR_AGE_DAYS days. Link: $PR_URL." | pbcopyPruefstand only runs the command with PR context. The command decides whether to copy text, open another app, call a local agent, or hand off to one of your own scripts.
swift buildTo assemble a local .app bundle:
./scripts/bundle.shRebuild the bundle after code changes before reopening Pruefstand.app; swift build updates the SwiftPM binary, while the bundle script copies the release
binary into the app bundle.
For UI iteration, launch the app in preview-window mode with mock PR data:
swift run Pruefstand --previewTo test action UI against real PR data without approving or closing anything:
swift run Pruefstand --debug-actionsOr, after bundling:
open Pruefstand.app --args --previewopen Pruefstand.app --args --debug-actionsRun the lightweight repository checks before committing:
./scripts/check-launch-mode.shThe script compiles focused Swift checks for launch/action behavior, settings, filters, nudge command interpolation, PR status metadata decoding, GraphQL query budget guardrails, popover layout invariants, and status tooltip interaction behavior.
Pruefstand can run local commands for a PR from the row actions:
- Nudge runs the configured default reminder command.
- Urgent nudge runs the configured escalation command.
Configure them in Settings -> Commands. Empty commands hide their buttons. Commands
run through /bin/zsh -lc with a GUI-safe PATH prefix:
/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin
Pruefstand does not authenticate Slack, email, or any other delivery channel. The command decides what happens. For example:
codex "Draft a concise, friendly PR review reminder. PR: $PR_TITLE. Repo: $PR_REPO. Open for $PR_AGE_DAYS days. Link: $PR_URL." | pbcopyor:
~/bin/pr-nudge {url}Every nudge command receives these variables:
| Variable | Description |
|---|---|
PR_TITLE |
Pull request title |
PR_URL |
Browser URL for the pull request |
PR_REPO |
Repository name with owner |
PR_NUMBER |
Pull request number without # |
PR_AUTHOR |
GitHub login of the PR author |
PR_CREATED_AT |
ISO-8601 creation timestamp |
PR_UPDATED_AT |
ISO-8601 update timestamp |
PR_AGE_DAYS |
Whole days since creation, minimum 0 |
PR_REVIEW_DECISION |
GitHub review decision when available |
PR_COMMENT_COUNT |
Total PR issue comment count |
PR_CI_STATE |
success, failure, pending, or none |
PR_ADDITIONS |
Added line count |
PR_DELETIONS |
Deleted line count |
PR_CHANGED_FILES |
Changed file count |
PR_LABELS |
Comma-separated label names |
Placeholders are replaced before the command is passed to the shell. They are POSIX shell-quoted, so use them as standalone shell words:
~/bin/pr-nudge {url}For natural-language prompts, prefer environment variables inside a quoted string:
codex "Write a review nudge for $PR_TITLE: $PR_URL" | pbcopy| Placeholder | Environment variable |
|---|---|
{title} |
PR_TITLE |
{url} |
PR_URL |
{repo} |
PR_REPO |
{number} |
PR_NUMBER |
{author} |
PR_AUTHOR |
{created_at} |
PR_CREATED_AT |
{updated_at} |
PR_UPDATED_AT |
{age_days} |
PR_AGE_DAYS |
{review_decision} |
PR_REVIEW_DECISION |
{comment_count} |
PR_COMMENT_COUNT |
{ci_state} |
PR_CI_STATE |
{additions} |
PR_ADDITIONS |
{deletions} |
PR_DELETIONS |
{changed_files} |
PR_CHANGED_FILES |
{labels} |
PR_LABELS |
Unknown placeholders are left unchanged.
You can ask a local agent to write a command:
Write me a Pruefstand Nudge command.
It can use these variables:
PR_TITLE, PR_URL, PR_REPO, PR_AUTHOR, PR_AGE_DAYS, PR_CHANGED_FILES, PR_LABELS.
I want it to ask Codex to draft a short friendly PR review reminder and copy the
result to my clipboard. Do not hardcode PR-specific values.