cargo install needle-cliThis installs the needle binary.
Demo mode (no GitHub token required):
needle --demoReal mode (requires NEEDLE_GITHUB_TOKEN or GITHUB_TOKEN):
export NEEDLE_GITHUB_TOKEN=ghp_...
# or
export GITHUB_TOKEN=ghp_...
needle--days <N>: only include PRs updated in the lastNdays (default:30)--demo: run with diverse fake data--org <ORG>: only show PRs in these orgs/users (repeatable or comma-delimited)--include <owner/repo>: only show these repos (repeatable or comma-delimited)--exclude <owner/repo>: hide these repos (repeatable or comma-delimited)--include-team-requests: include PRs requested to teams you are in (default: user-only)--bell: ring terminal bell when a PR enters NEEDS YOU or when CI fails--no-notifications: disable desktop notifications (enabled by default)--hide-pr-numbers: hide PR numbers column--hide-repo: hide repository column--hide-author: hide author column--no-cache: start empty (skip cached PRs) and rely on fresh refresh--purge-cache: delete the cache DB before starting (also works with--demo)
needle --days 7Needle automatically creates a config file at ~/.config/needle/config.toml on first run. All CLI options can be set as defaults in this file:
# Only include PRs updated in the last N days
days = 14
# Only show PRs from these orgs/users
org = ["my-company", "my-username"]
# Exclude noisy repos
exclude = ["my-company/legacy-repo"]
# Ring terminal bell on important events
bell = true
# Auto-refresh intervals (seconds)
refresh_interval_list_secs = 120
refresh_interval_details_secs = 15CLI arguments always override config file values.
Press p in list view to pin/unpin a PR. Pinned PRs appear in a dedicated 📌 PINNED section at the top of the list, regardless of their score. Pin state persists across sessions.
Needle shows desktop notifications for important events like CI failures, review requests, and PRs ready to merge.
On macOS, install terminal-notifier for click-to-open support:
brew install terminal-notifierWith terminal-notifier installed, clicking a notification opens the PR in your browser. Without it, notifications still work but won't be clickable.
- Rust (stable)
- A GitHub Personal Access Token in
NEEDLE_GITHUB_TOKENorGITHUB_TOKEN
Needle uses the GitHub API, so you’ll need a Personal Access Token.
- Go to https://github.com/settings/tokens?type=beta and create a Fine-grained token.
- Choose the account/organization that owns the repos you want to scan.
- Set Repository access to “All repositories” (or select specific repos).
- Add Pull requests: Read-only permissions.
- Copy the token and export it:
export NEEDLE_GITHUB_TOKEN="ghp_..."
# or
export GITHUB_TOKEN="ghp_..."Note
If both are set, NEEDLE_GITHUB_TOKEN takes priority.
Add it to your bashrc/zshrc for future usage.
Included PRs:
- PRs authored by you
- PRs where you are explicitly requested as a reviewer (User)
(team review requests are ignored unless--include-team-requests)
For each PR it computes:
- Latest commit SHA
- CI state (success/failure/running/none)
- Review request state (requested/approved/none)
- A hard-coded score → sorted desc → grouped into categories
List view:
↑ / ↓: move selectionEnter: open selected PR in default browserTab: open details viewp: pin/unpin selected PR/: filter mode (type to filter by repo/title/author/#)Esc: exit filter mode + clear filter textCtrl+n: toggle "only NEEDS YOU"Ctrl+c: toggle "only failing CI"Ctrl+v: toggle "only review requested"Ctrl+x: clear all filters
?: help (explains what each section means)r: refresh now (shows shimmer while refreshing)q: quit
Details view:
↑ / ↓: select CI checkEnter: open selected CI check page (falls back to PR URL)f: open first failing CI check (falls back to PR URL)Tab: back to listr: refresh nowq: quit
In details view you get a list of CI steps (check runs / status contexts):
- ✅ success
- ❌ failed
- 🟡 running (shows “running for …” when
startedAtis available)
- Fetches on startup in the background (UI shows cached data immediately).
- Manual refresh:
r - Auto refresh in list view: every 3 minutes
- Auto refresh in details view: every 30s
- Manual refresh resets the auto-refresh timer.
- No background async tasks beyond the single refresh worker thread.
- Single-screen list, visually grouped by derived category:
- NEEDS YOU (score >= 40)
- READY TO MERGE (your PR, CI green, no blockers)
- DRAFT (draft PRs; shown separately and dimmed)
- NO ACTION NEEDED (0..39)
- WAITING ON OTHERS (< 0)
- Empty sections are hidden.
- Draft rows are dimmed.
- No scrolling beyond terminal height (truncates to fit).
- Uses cached SQLite data to render immediately, then refreshes in the background.
Each PR gets a score (higher = more urgent):
+50 review requested from user
+40 CI failed AND state changed since last_seen
+20 CI running longer than 10 minutes
+15 approved but unmerged for >24h
-20 waiting on others (no review requested, CI green, not approved)
-30 CI failed but unchanged since last_seen
Sort:
- Score desc
- Then by updated timestamp desc
- Missing token: set
GITHUB_TOKEN. - Not a TTY: run in an interactive terminal (not a non-tty runner).
MIT. See LICENSE.

