Languages: English · 中文
A compact macOS desktop app for watching open GitHub pull requests across multiple repositories — without context-switching to github.com a dozen times a day.
Built for developers who keep a small browser-window-shaped app pinned in a corner and just want to know: which of my PRs need review, which are green, which are blocked.
- Multi-repo watch list — track any subset of your personal/org repos, persisted locally.
- Live PR list — title, status glyph, CI/review state,
+/-line counts, branches, author avatar, age. Polls every 60s. - Inline filter — full-text match on title/author, no round-trip.
- PR detail in its own window (×ばつ700) — opens any PR in a separate macOS window so you can keep the launcher visible.
- Conversation — unified timeline of commits, reviews, comments; commits and reviews link out to GitHub.
- Files — parsed unified diff with line numbers and
+/-highlighting. Binary files (images, archives, fonts, lockfiles, etc.) are detected and silently skipped. - Commits — clean list view.
- Close / Merge actions — confirmation dialog; merge button is automatically disabled and labeled
Conflictwhen GitHub reports the PR as unmergeable. Dynamic poll cadence: when GitHub's mergeable status is stillUNKNOWN, refetch every 5s until resolved, then drop back to 60s.
- Always-on-top pin — toggle the main window to stay above other apps. Useful while reviewing in your editor.
- PAT auth via macOS Keychain — token stored using
keyring-rs, never on disk in plaintext. Sign-out wipes the entry. - System theme follow — dark/light follows macOS, no toggle.
- Native traffic-light positioning — the title bar is overlaid (no chrome) but
close/min/maxsit where macOS expects them on both main and detail windows.
| Layer | Tech |
|---|---|
| App shell | Tauri 2.11 (Rust, multi-window) |
| Frontend | React 19 + Vite 7 + TypeScript |
| Styling | Tailwind v4 + shadcn/ui (radix-nova) |
| Fonts | Geist Variable + Geist Mono |
| Data fetching | SWR (poll + dedupe) |
| GitHub | GraphQL v4 (PR list / detail) + REST (files, close, merge) |
| Secrets | macOS Keychain via keyring-rs |
| Persistence | tauri-plugin-store (JSON) |
- Grab the latest
Plotter_<version>_aarch64.dmgfrom the Releases page. - Open the DMG and drag Plotter.app into
/Applications. - First launch will be blocked by Gatekeeper ("Apple cannot check it for malicious software") because the app isn't notarized — it's a personal tool, not paid through Apple's developer program. Bypass once with either of:
- Right-click
Plotter.app→ Open → click Open again in the confirmation dialog, or - From a terminal:
xattr -dr com.apple.quarantine /Applications/Plotter.app
- Right-click
Then jump to First-time setup.
Use this if you want to hack on Plotter, or you trust your own toolchain more than a binary off the internet.
bun install bun tauri dev
The frontend dev server runs on :1420; Tauri launches the native window automatically.
bun tauri build
The .app (and DMG) will land under src-tauri/target/release/bundle/. It is not signed or notarized — Gatekeeper will treat it the same as the prebuilt DMG above, so the same quarantine bypass applies if you copy it to another machine.
Whether you installed via DMG or built from source, the first launch is the same:
- Open Settings (gear icon in the header).
- Paste your GitHub Personal Access Token and click Save. The token is verified against
GET /userbefore being stored in the macOS Keychain. - Add at least one repository. Accepts any of:
owner/repohttps://github.com/owner/repogit@github.com:owner/repo.git
- Select the repo from the dropdown to start polling.
You need a PAT (classic or fine-grained) — create one at https://github.com/settings/tokens.
Scopes:
repo— read access is enough for browsing; fullrepo(write) is needed for the Close / Merge actions.- For org-owned repos, the token must also be authorized for the org at https://github.com/settings/tokens → "Configure SSO" / "Authorize" under the org name.
plotter/
├── src/ # React app
│ ├── App.tsx # Main window (repo selector + PR list)
│ ├── pr-detail/
│ │ └── PrDetailWindow.tsx # Detail window (tabs, diff, close/merge)
│ ├── components/
│ │ ├── settings-sheet.tsx # PAT + repo management
│ │ └── ui/ # shadcn primitives
│ ├── lib/
│ │ ├── auth-store.tsx # PAT context
│ │ ├── repo-store.tsx # watch-list context (tauri-plugin-store backed)
│ │ ├── use-pull-requests.ts
│ │ ├── use-pr-detail.ts
│ │ ├── use-pr-files.ts
│ │ └── open-pr-detail.ts # invokes Rust to spawn detail window
│ └── App.css # Tailwind v4 theme tokens
└── src-tauri/
├── src/lib.rs # All Tauri commands (auth, list_prs, get_pr_detail, get_pr_files, close_pr, merge_pr, open_pr_detail)
├── tauri.conf.json # productName=Plotter, identifier=app.plotter.dev
├── capabilities/ # Per-window permissions (main + pr-*)
└── icons/ # Generated from a ×ばつ1024 macOS-template source
- Multi-window is implemented in Rust (
open_pr_detail) rather than the JS API so traffic-light positioning is reliable. The capability whitelist (src-tauri/capabilities/default.json) coversmainandpr-*windows. - All numeric/identifier text in the UI uses
font-mono(Geist Mono) with tabular numerals to keep columns aligned across PR rows. - The icon source lives at
public/gh-logo-icon.png; the bundled app icon is composited onto a ×ばつ1024 macOS-template canvas (824 squircle, 185px corner radius) beforetauri iconregenerates the full icns/ico/PNG set.
Personal tool, alpha-quality. No public release; clone and build for yourself if you find it useful.