Fast, filterable PR review. Entirely client-side.
Warning
Pulldash is WIP. Expect bugs.
Browser: pr.jennings.io. Open pull requests at https://pr.jennings.io/<owner>/<repo>/pull/<number>.
-
Custom filters: Add repos and filter by review requests, authored PRs, or all activity.
-
Keyboard-driven:
j/kto navigate files, arrows for lines,cto comment,sto submit. -
Fast file search:
Ctrl+Kto fuzzy-find across hundreds of changed files.
- GitHub's review UI is slow (especially for large diffs)
- No central view to filter PRs you care about
- AI tooling has produced more PRs than ever before—making a snappy review UI essential
GitHub's API supports CORS, so Pulldash runs entirely client-side. No backend proxying your requests.
-
Web Worker pool: Diff parsing and syntax highlighting run in workers sized to
navigator.hardwareConcurrency. The main thread stays free for scrolling. -
Pre-computed navigation: When a diff loads, we index all navigable lines. Arrow keys are O(1)—no DOM queries.
-
External store: State lives outside React (
useSyncExternalStore). Focusing line 5000 doesn't re-render the file tree. -
Virtualized rendering: Diffs, file lists, and the command palette only render visible rows.
| App type | Flow | Server config | Token storage |
|---|---|---|---|
| PAT | — | Static | localStorage |
| OAuth App | Device | GITHUB_CLIENT_ID |
localStorage |
| Web | + GITHUB_CLIENT_SECRET |
localStorage |
|
| GitHub App | Device | GITHUB_CLIENT_ID |
Access token in memory, refresh token in localStorage |
| Web | + GITHUB_CLIENT_SECRET |
Access token in memory, refresh token in localStorage |
PAT — The user generates a classic GitHub PAT on github and paste it in the UI.
Use the repo scope for private repos, or public_repo for public repos only.
Only a static server is required.
Device flow — The user is presented with a code to copy/paste on github.
No client secret needed. The device flow is ideal for admins who don't want to manage a client secret.
Web flow — The user is redirected to github to authorize the application.
Requires a client secret on the server.
The token storage depends on the application type (OAuth App vs GitHub App), not on the flow.
PAT — No setup needed.
OAuth App (device flow)
- Go to GitHub Settings → Developer settings → New OAuth App
- Fill in:
- Application name:
pulldash(or any name) - Homepage URL: your pulldash URL (e.g.
http://localhost:3002) - Authorization callback URL:
{your-url}/api/auth/callback(e.g.http://localhost:3002/api/auth/callback) - Enable Device Flow: check this box
- Application name:
- Click Register application
- Copy the Client ID
OAuth App (web flow)
- Go to GitHub Settings → Developer settings → New OAuth App
- Fill in:
- Application name:
pulldash(or any name) - Homepage URL: your pulldash URL (e.g.
http://localhost:3002) - Authorization callback URL:
{your-url}/api/auth/callback(e.g.http://localhost:3002/api/auth/callback)
- Application name:
- Click Register application
- Copy the Client ID
- Generate a Client Secret and copy it
GitHub App (recommended)
Use the creation script:
bun run scripts/create-github-app.tsIt will ask for your pulldash URL, open a pre-configured GitHub App creation page, and print the environment variables to set on your server.
GitHub Apps also support the device flow — after creation, go to the app's settings page and check Enable Device Flow.
PAT
Just serve the files with you preferred web server.
Device flow
export GITHUB_CLIENT_ID=your_client_id
bun run src/node/main.tsWeb flow
export GITHUB_CLIENT_ID=your_client_id
export GITHUB_CLIENT_SECRET=your_secret
bun run src/node/main.tsThe frontend fetches the Client ID and available flows from the
server's GET /api/auth/config endpoint at runtime — no rebuild
needed when changing the OAuth App configuration.
bun install
bun devThen open http://localhost:3002 (or the next available port if 3002 is in use).
To run the server without the build watcher:
bun run build:browser
bun run src/node/main.tsBuild and run with Docker:
docker build -t pulldash .
docker run -p 3002:3002 \
-e GITHUB_CLIENT_ID=your_client_id \
-e GITHUB_CLIENT_SECRET=your_secret \
pulldash


