https://github.com/cesarferreira/needle
TUI that highlights the GitHub PRs that need you
https://github.com/cesarferreira/needle
pr prs pull-requests rust
Last synced: 5 months ago
JSON representation
TUI that highlights the GitHub PRs that need you
- Host: GitHub
- URL: https://github.com/cesarferreira/needle
- Owner: cesarferreira
- License: mit
- Created: 2025-12-12T15:06:48.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-19T02:20:40.000Z (6 months ago)
- Last Synced: 2026-01-13T22:52:47.282Z (5 months ago)
- Topics: pr, prs, pull-requests, rust
- Language: Rust
- Homepage: https://crates.io/crates/needle-cli
- Size: 4.04 MB
- Stars: 100
- Watchers: 0
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
needle
TUI that shows the few PRs that need you: review requests, failing CI, and long-running checks.
## Install
```bash
cargo install needle-cli
```
This installs the `needle` binary.
## Quick start
Demo mode (no GitHub token required):
```bash
needle --demo
```
Real mode (requires `NEEDLE_GITHUB_TOKEN` or `GITHUB_TOKEN`):
```bash
export NEEDLE_GITHUB_TOKEN=ghp_...
# or
export GITHUB_TOKEN=ghp_...
needle
```
## Options
- `--days `: only include PRs updated in the last `N` days (default: `30`)
- `--demo`: run with diverse fake data
- `--org `: only show PRs in these orgs/users (repeatable or comma-delimited)
- `--include `: only show these repos (repeatable or comma-delimited)
- `--exclude `: 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`)
```bash
needle --days 7
```
## Configuration File
Needle automatically creates a config file at `~/.config/needle/config.toml` on first run. All CLI options can be set as defaults in this file:
```toml
# 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 = 15
```
CLI arguments always override config file values.
## Pinned PRs
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.
## Desktop Notifications
Needle shows desktop notifications for important events like CI failures, review requests, and PRs ready to merge.

On macOS, install [terminal-notifier](https://github.com/julienXX/terminal-notifier) for click-to-open support:
```bash
brew install terminal-notifier
```
With `terminal-notifier` installed, clicking a notification opens the PR in your browser. Without it, notifications still work but won't be clickable.
## Requirements
- Rust (stable)
- A GitHub Personal Access Token in `NEEDLE_GITHUB_TOKEN` or `GITHUB_TOKEN`
## Get a GitHub token
Needle uses the GitHub API, so you’ll need a Personal Access Token.
1. Go to https://github.com/settings/tokens?type=beta and create a **Fine-grained** token.
2. Choose the account/organization that owns the repos you want to scan.
3. Set **Repository access** to “All repositories” (or select specific repos).
4. Add **Pull requests: Read-only** permissions.
5. Copy the token and export it:
```bash
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.
## What it shows
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
## Controls
List view:
- `↑ / ↓`: move selection
- `Enter`: open selected PR in default browser
- `Tab`: open details view
- `p`: pin/unpin selected PR
- `/`: filter mode (type to filter by repo/title/author/#)
- `Esc`: exit filter mode + clear filter text
- `Ctrl+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 check
- `Enter`: open selected CI check page (falls back to PR URL)
- `f`: open first failing CI check (falls back to PR URL)
- `Tab`: back to list
- `r`: refresh now
- `q`: quit
### Details view CI checks
In details view you get a list of CI steps (check runs / status contexts):
- âś… success
- ❌ failed
- 🟡 running (shows “running for …” when `startedAt` is available)
## Refresh behavior
- 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.
## Scoring
- 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
## Troubleshooting
- **Missing token**: set `GITHUB_TOKEN`.
- **Not a TTY**: run in an interactive terminal (not a non-tty runner).
## License
MIT. See `LICENSE`.