GitHub Projects, bulk-edited the way it should work.
Bulk edit, close, delete, duplicate, transfer, and sprint-manage your project items — all from the table view, no backend required.
Inspired by refined-github — the gold standard for browser extensions that fix what GitHub won't.
⚡ 90% built with multiple AI agents. By fathiraz.
- Why This Exists
- Features
- Installation
- Usage Guide
- Architecture
- Tech Stack
- Roadmap
- Contributing
- License
GitHub Projects V2 is a solid board — but editing items in bulk is painful. You update one field at a time. You close one issue at a time. You drag items to the next sprint one by one. That's not how teams move.
Refined GitHub Projects adds the bulk operations and sprint tooling that should have shipped with GitHub Projects V2 — running entirely in your browser, with your token never leaving your machine.
| Problem | What RGP adds |
|---|---|
| Can't edit N items at once | Bulk Edit Wizard — select fields, set values, apply to all |
| GitHub's duplicate only copies the title | Deep Duplicate — clones all fields, assignees, labels, body |
| Closing a sprint takes many clicks | End Sprint — moves incomplete items to next iteration in one action |
| No visibility into background API calls | Live Queue Tracker — real-time progress, rate-limit safe |
| Dangerous operations have no guardrail | Every destructive action requires a confirmation modal |
| Feature | What it does |
|---|---|
| Bulk update fields | Change Status, Assignee, Iteration, Priority, Labels, and any custom field across N items at once |
| Bulk close issues | Mark issues as Completed or Not Planned in a single click |
| Bulk reopen issues | Restore closed items back to active work |
| Bulk lock / unlock | Lock conversations with a reason (off-topic, too heated, resolved, spam) |
| Bulk pin / unpin | Promote or demote important issues at the repository level |
| Bulk transfer | Move issues to another repository, history intact |
| Bulk delete | Permanently remove items from your project |
| Bulk rename titles | Update issue or PR titles across multiple items |
| Export to CSV | Download selected items with all fields, assignees, labels, and custom properties |
| Sprint management | End a sprint with one click; incomplete items auto-assign to the next iteration |
| Task completion tracker | Live task counters in sprint group headers, updated in real time |
| Deep duplicate | Clone any item with all custom fields, assignees, labels, and sub-issue relationships |
Select items with ⌘A / Ctrl+A — the floating bar appears. Hit Actions (⌘⇧B) to open the full menu.
Available bulk operations:
| Category | Action | Shortcut |
|---|---|---|
| Fields | Edit Fields | ⌘⇧E |
| Content | Rename Titles | ⌘⇧R |
| Content | Reorder Items | ⌘⇧J |
| Status | Close Issues | ⌘⇧X |
| Status | Reopen Issues | ⌘⇧O |
| Status | Lock Conversations | ⌘⇧L |
| Status | Unlock Conversations | — |
| Visibility | Pin Issues | ⌘⇧F |
| Visibility | Unpin Issues | — |
| Move | Transfer Issues | ⌘⇧M |
| Export | Export to CSV | ⌘⇧V |
| Danger | Delete Items | ⌘⇧⌫ (admin only) |
- Select Fields — choose which standard and custom fields to update
- Set Values — pick new values: Status, Priority, Sprint, Size, Estimate, Assignees, Labels, dates…
- Review & Apply — see a clean diff of every change before a single API call fires
GitHub's native duplicate copies only the title. Deep Duplicate clones the full issue — all project fields, assignees, labels, body, and sub-issue links — and lets you edit everything before confirming.
End a sprint with one click. The Sprint widget (top-right on any Projects page) shows the active iteration and task completion. Hit End Sprint, pick the target iteration for incomplete items, and the background queue moves them automatically — no manual re-assignment.
Every bulk operation runs through a sequential background queue with 1-second delays between mutations. The live tracker shows real-time percentage progress and automatically backs off on 403 / 429 errors — keeping your PAT safe on large projects.
- No backend — all calls go directly from your browser to
api.github.com - Token stays local — the PAT is stored in browser extension storage, never sent to any external server
- Shadow DOM isolated — injected UI never clashes with GitHub's own styles
| Browser | Engine | Status |
|---|---|---|
| Arc | Chromium | ✅ Tested |
| Microsoft Edge | Chromium | ✅ Tested |
| Zen | Firefox (Gecko) | ✅ Tested |
| Chrome | Chromium | ✅ Tested |
| Firefox | Gecko | ✅ Tested |
- Go to Releases and download the latest browser build package (not the source archive).
- Extract the archive on your machine.
- Open your browser's extension page:
- Chrome / Edge:
chrome://extensions - Firefox:
about:debugging#/runtime/this-firefox
- Chrome / Edge:
- Load the extension:
- Chrome / Edge: enable Developer mode → Load unpacked → select the extracted folder
- Firefox: Load Temporary Add-on → select the manifest file in the extracted folder
- Click the extension icon, paste your GitHub PAT, and click Validate and save.
Done. The extension is live on every GitHub Projects table you open.
Paste this into Cursor, Claude Code, or any coding agent:
Install Refined GitHub Projects from the latest GitHub release at:
https://github.com/fathiraz/refined-github-projects/releases
Steps:
1. Download the latest browser build package (not the source archive)
2. Extract the archive
3. Load as unpacked extension:
- Chrome/Edge: chrome://extensions → Developer mode → Load unpacked → select extracted folder
- Firefox: about:debugging#/runtime/this-firefox → Load Temporary Add-on → select manifest.json
4. Click the extension icon → paste your GitHub PAT (scopes: repo, read:org, project) → Validate and save
Or fetch these instructions directly:
curl -sL https://raw.githubusercontent.com/fathiraz/refined-github-projects/main/README.md# Prerequisites: Node.js 18+, pnpm
git clone https://github.com/fathiraz/refined-github-projects.git
cd refined-github-projects
pnpm install
# Dev server with hot reload
pnpm dev
# Production build
pnpm buildLoad .output/chrome-mv3 in Chrome/Edge or the Firefox output in about:debugging.
- GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Generate new token (classic)
- Name it
Refined GitHub Projectsand select the required scopes:
| Scope | Reason |
|---|---|
repo |
Read/write issues, labels, assignees |
read:org |
Read organization membership for assignee search |
project |
Read/write GitHub Projects V2 fields |
- Copy the token and paste it into the extension popup → Validate and save.
- Open any GitHub Projects table view
- Check item checkboxes — or press
⌘A/Ctrl+Ato select all - The Bulk Actions Bar appears at the bottom
- Click Actions (
⌘⇧B) and choose your operation - Follow the wizard; review changes before confirming
- The Sprint widget appears top-right on your Projects page
- Click End Sprint
- Choose the target iteration for incomplete items
- Click End Sprint — incomplete items move automatically
| Shortcut | Action |
|---|---|
⌘A / Ctrl+A |
Select all visible items |
⌘⇧B |
Open Actions menu |
Esc |
Clear selection |
┌─────────────────┐ sendMessage ┌──────────────────────────┐ ┌──────────────────────┐
│ Content Script │ ──────────────────→ │ Background Service │ ──→ │ GitHub GraphQL API │
│ (DOM / UI) │ │ Worker │ │ api.github.com │
│ │ ←────────────────── │ - PAT storage │ │ │
│ - Shadow DOM │ response / │ - Sequential queue │ │ │
│ - Row observer │ queueStateUpdate │ - 403/429 backoff │ │ │
└─────────────────┘ └──────────────────────────┘ └──────────────────────┘
↑
│ WXT Storage API
↓
┌─────────────────┐
│ Extension │
│ Popup │
│ - PAT config │
└─────────────────┘
Data flow:
- The Content Script observes the GitHub Projects DOM via
MutationObserverand injects UI into a Shadow DOM container — invisible to GitHub's own styles. - On a bulk operation, the content script sends a typed message to the Background Service Worker.
- The Background Worker retrieves the stored PAT, builds a sequential task queue, and fires GraphQL mutations with 1 s delays between each write.
Promise.all()is never used for mutations — it will 403-ban your token. - Progress is broadcast back as
queueStateUpdatemessages, driving the live tracker widget.
| Layer | Technology |
|---|---|
| Extension framework | WXT with Manifest V3 |
| UI | React 18, TypeScript, Primer CSS |
| Messaging | @webext-core/messaging |
| Storage | WXT browser storage APIs |
| API | GitHub Projects V2 GraphQL via fetch |
| DOM isolation | WXT CSUI with Shadow DOM |
| Background | WXT Background Service Workers |
- Bulk update fields (Status, Assignee, Sprint, Priority, Labels, custom fields)
- Bulk close / reopen issues
- Bulk lock / pin / unpin issues
- Bulk transfer issues to another repository
- Bulk delete project items
- Bulk rename titles
- Reorder items
- Export selected items to CSV
- Deep duplicate with all fields, assignees, labels, body, sub-issues
- Sprint management — end sprint with auto-assignment of incomplete items
- Task completion tracker in sprint group headers
- Live queue tracker with real-time progress
- Chrome Web Store release
- Firefox Add-ons release
- Safari support
Contributions are welcome. Please follow these rules — they exist to keep the extension safe for everyone.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes and run
pnpm typecheck - Commit with a conventional message:
git commit -m 'feat: my feature' - Push and open a pull request
Critical rules (strictly enforced):
- Never use
Promise.all()for GraphQL mutations — GitHub will 403-ban your PAT - All mutations must run sequentially through the background queue with
sleep(1000)between each - Never call GitHub's API directly from a Content Script — always use
sendMessageto the Background Worker - Anchor injected UI to
data-testidattributes or ARIA labels, not volatile CSS class names
MIT © fathiraz
- refined-github — the gold standard for browser extensions that meaningfully improve GitHub's UX
- WXT — made cross-browser Manifest V3 development actually enjoyable
- Primer CSS / @primer/react — GitHub's own design system, so the injected UI feels native
- GitHub GraphQL API — the Projects V2 API that makes all of this possible
fathiraz · github.com/fathiraz · Project repository




