Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dd6b01b
docs(roadmap): plan v0.12 Quorum and sprints; renumber later milestones
hazeliscoding Sep 29, 2026
b133fa2
docs(agents): release notes follow Quorum's voice, no emoji
hazeliscoding Sep 29, 2026
36949df
test(fixtures): canned sweeps for every UI state and isolated screens…
hazeliscoding Sep 29, 2026
627aee7
feat(ui): Quorum tokens, bundled fonts and icons, and AA and asset ch…
hazeliscoding Sep 29, 2026
4255bea
docs(roadmap): record the v0.12 foundation and its AA fixes
hazeliscoding Sep 29, 2026
6837721
feat(sprints): computed sprint schedules per profile, resolved in the…
hazeliscoding Sep 29, 2026
4511f35
feat(ui): Quorum top bar with the sprint picker, freshness, loading b…
hazeliscoding Sep 29, 2026
2572540
fix(ui): color body text with text-1, since Quorum's --text-body name…
hazeliscoding Sep 29, 2026
7f731cf
feat(ui): Quorum board with a health strip, filter chips, dense table…
hazeliscoding Sep 29, 2026
da996d6
docs(roadmap): tick the v0.12 board
hazeliscoding Sep 29, 2026
8561695
feat(sprints): preview a schedule's sprints around today from the mai…
hazeliscoding Sep 29, 2026
bf0e6a0
fix(ui): show the board's loading skeleton only while a sweep is loading
hazeliscoding Sep 29, 2026
962747e
feat(ui): Quorum settings with a sprint schedule editor, and the onbo…
hazeliscoding Sep 29, 2026
461ff7c
build(checks): fail on raw colors outside the Quorum tokens
hazeliscoding Sep 29, 2026
42c37fe
docs(roadmap): tick the v0.12 settings and onboarding
hazeliscoding Sep 29, 2026
ce78599
fix(copy): plainer setup errors and a clearer next step for old drafts
hazeliscoding Sep 29, 2026
acca6ad
test(e2e): render the README screenshots from the busy fixture at 2x
hazeliscoding Sep 29, 2026
b8f6cb1
docs(readme): sprints in the features and first launch, and new scree…
hazeliscoding Sep 29, 2026
04c0824
docs(agents): a Design section for Quorum tokens, contrast, status an…
hazeliscoding Sep 29, 2026
e2e887a
docs(roadmap): tick the v0.12 voice pass, Design section and README s…
hazeliscoding Sep 29, 2026
a462839
fix(renderer): reloading the window (Ctrl+R) no longer leaves it blank
hazeliscoding Sep 29, 2026
6941a53
fix(a11y): the Sprints and Custom switch is a pair of toggle buttons,…
hazeliscoding Sep 29, 2026
a5c34ca
docs(roadmap): tick the v0.12 review and note the unused font fallbacks
hazeliscoding Sep 29, 2026
58567a8
build: npm install at the root also installs the desktop and renderer…
hazeliscoding Sep 29, 2026
b98f5ef
docs: npm install is the one install step, rerun after pulling
hazeliscoding Sep 29, 2026
72b3c2e
build(desktop): allow Electron's install script under npm 11
hazeliscoding Sep 29, 2026
b29802c
style(roadmap): apply the editor's Markdown formatting
hazeliscoding Sep 29, 2026
1c7c6cb
docs(roadmap): rejoin list items the formatter split, and restore two…
hazeliscoding Sep 29, 2026
7e8dae7
docs(readme): status v0.12
hazeliscoding Sep 29, 2026
49e7de0
chore(release): v0.12.0
hazeliscoding Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ jobs:
node-version: 22
- name: Install dependencies
run: |
npm ci
# --ignore-scripts: the root postinstall would npm install the folders below a
# second time, without their lockfiles' exact versions.
npm ci --ignore-scripts
(cd desktop && npm ci)
(cd desktop/renderer && npm ci)
# Renderer AOT build + main-process tsc together are the typecheck.
- name: Build
run: npm run build
- name: Test
run: npm test
# WCAG AA on the Quorum tokens, and no remote assets or stray fonts in the renderer.
- name: Design checks
run: npm run check
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ jobs:
- name: Install dependencies
shell: bash
run: |
npm ci
# --ignore-scripts: the root postinstall would npm install the folders below a
# second time, without their lockfiles' exact versions.
npm ci --ignore-scripts
(cd desktop && npm ci)
(cd desktop/renderer && npm ci)
- name: Build
Expand Down
58 changes: 49 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ organization. It ships for Windows and Linux.
"needs attention". `prs:fetch` runs it over every open row after every sweep, cached rows
included. The Sweep section, the tray line and the sprint summary read its output; the
renderer never decides on its own whether a PR needs attention.
- Sprints are computed, never stored: a profile keeps a schedule (`sprints`) and a `period`
(`'current'`, a pinned `{ sprint }` or `'custom'`), and `core/sprints.ts` resolves them against
today through `period:resolve`. The renderer never does sprint date math itself.
- Workflow health, not human performance: no per-person counts, leaderboards or review stats.
- No AI features before 1.0.
- Windows and Linux only. macOS is not planned.
Expand All @@ -77,29 +80,65 @@ organization. It ships for Windows and Linux.
- The assets are in `docs/brand/`. `mark.svg` is the source of the app icon. `lockup.svg` is for
light backgrounds and `lockup-dark.svg` for dark ones.
- The mark: a gold (`#d1a249`) main branch and a blue (`#98c6ff`) feature branch merging, on a
navy (`#001740`) tile. These are the app's light primary, gold and dark accent.
navy (`#001740`) tile. These colors belong to the icons and the lockup; inside the app, the
accent is Quorum's teal.
- The wordmark is Manrope ExtraBold (800) with -0.02em tracking, converted to vector paths. It is
navy `#001740` on light and white on dark. Use the SVGs; don't re-typeset it with a web font.
- `desktop/build/icon.png` (512px) is rendered from `docs/brand/mark.svg`. `tray.png` and
`tray-alert.png` (256px) are the same mark, and the alert one adds a red badge. Re-render the
PNGs whenever the mark changes.

## Design

- The UI is the **Quorum Design System**. Its tokens are copied into
`desktop/renderer/src/styles/quorum/`, each file naming its source. The only edits are marked
`/* AA */`. Don't edit those files otherwise: if Quorum changes, copy the file again and
reapply the marked edits.
- App styles live in `styles/app/` and use tokens only. `npm run check` fails on a raw color
outside `styles/quorum/`, a font not set through a token, or any remote URL.
- Every text color on every surface the UI uses is a pair in
`renderer/scripts/check-contrast.mjs`, which must reach 4.5:1 in both themes (3:1 for focus
rings and status dots). A text color on a new surface needs a new pair. Don't fade rows with
opacity; tag them.
- Status is never color alone: a dot or a colored word sits next to words (Pass, Fail, a
reason), and pressed chips show a check.
- Fonts (Manrope, IBM Plex Mono, from Fontsource) and icons (Lucide, copied into
`app/ui/icons.ts`) are bundled, with their licenses in `renderer/licenses/`. The app loads
nothing from a CDN.
- Mono is for evidence: PR refs, counts, ages, sizes, dates, logins and error details. Status
tables are `data-density="dense"` (26px rows); the Sweep and Settings tables are `compact`.
- Voice, release notes included: sentence case, plain words, no emoji, no exclamation marks. A
headline says what happened ("Couldn't refresh"), with the evidence under it in mono.
- Quorum names both a color and a font `--text-body`, and the font wins. Color body text with
`--text-1`.
- Review a UI change with the fixture screenshots, in both themes.

## Commands

Run these from the repo root unless noted.

- `npm install && npm run setup` installs root, desktop and renderer dependencies.
- `npm install` installs root, desktop and renderer dependencies: its postinstall runs
`npm run setup`. Run it again after pulling, since `npm run dev` installs nothing.
- `npm run dev` runs the Angular dev server on :4301 and Electron with live reload.
- `npm run build` runs the renderer AOT build and the main-process `tsc`. Together they are the
typecheck.
- `npm test` runs the Node tests in `desktop/src/main/core/*.test.mjs`. They import the compiled
`desktop/dist/`, so build first.
- `npm run check` runs the design checks (contrast in both themes, then assets). CI runs it.
- `npm run package:win` builds the installer and portable exe. `npm run package:linux` builds
the AppImage and has to run on Linux. Local packages are unsigned unless the Azure env vars
are set.
- From `desktop/` after a build, `GH_TOKEN=$(gh auth token) node e2e/screenshot.mjs` writes
screenshots to `desktop/e2e/shots/`. `PRSWEEP_DEMO=1` points it at a public org for README
images.
- From `desktop/` after `npm run build`, `node e2e/screenshot.mjs --fixtures [busy,calm,…]`
shoots every fixture state in both themes to `desktop/e2e/shots/`, with no token or network.
`GH_TOKEN=$(gh auth token) PRSWEEP_ORG=<org> node e2e/screenshot.mjs` shoots the live board.
`node e2e/screenshot.mjs --readme` renders the README images (`docs/screenshots/`) from `busy`.
Every run uses a throwaway `--user-data-dir` and aborts unless the app really uses it; never
point a UI script at the real data folder (Chromium ignores `%APPDATA%` overrides).
- `PRSWEEP_FIXTURE=<name>` makes an unpackaged build serve canned sweeps from
`desktop/e2e/fixtures/<name>.json` instead of GitHub, still judged by the real attention
engine. Fixture times are relative (`"-3d"`, `"+2d"`); rows list only what matters and the
loader (`core/fixture.ts`) fills the rest. `busy` must keep triggering all nine attention
reasons (its test checks).
- `PRSWEEP_DEBUG=1` makes the main process log GraphQL variables and response bodies, plus one
`[sweep]` line per sweep with its mode, duration, requests and retries.
- From `desktop/` after `npm run build:main`,
Expand All @@ -121,11 +160,12 @@ Run these from the repo root unless noted.
version bump. The release workflow publishes that file as the release body and fails before
building if it's missing. Write them for a reader skimming on a phone:
- Open with one bold **TL;DR:** line saying what changed and why it matters.
- Then short sections, in this order, only when they have something: `## ✨ New`,
`## ⚡ Faster`, `## 🐛 Fixed`, `## 👀 Heads up` (anything a user might trip over), and
`## ⬆️ Getting it`.
- Then short sections, in this order, only when they have something: `## New`,
`## Faster`, `## Fixed`, `## Heads up` (anything a user might trip over), and
`## Getting it`.
- One line per bullet, starting with a **bold** phrase. Plain words, user-visible effects,
real numbers when there are some. No commit hashes, no internals, no paragraphs.
real numbers when there are some. No commit hashes, no internals, no paragraphs, and no
emoji: Quorum's voice applies to release notes too.
- Pushing a `v*` tag runs `.github/workflows/release.yml`. It builds the signed Windows installer,
the portable exe and the Linux AppImage, then publishes one GitHub release. The `latest*.yml`
files and blockmaps must ship with every release, because the auto-updater reads them.
Expand Down
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ long. The share of diffs waiting more than three days for review dropped 12 perc
Most teams don't have a Nudgebot. Their stuck PRs are spread across a dozen repos, and GitHub's
own dashboard shows what's waiting on *you*, not on the team. PR Sweep puts the whole team's PRs
on one board, sorted by GitHub's own review state, so nobody maintains labels or a project board.
Set the org, the team and the sprint's dates once. It refreshes every five minutes from the tray.
Set the org, the team and your sprint schedule once. It refreshes every five minutes from the tray.

> **Status:** v0.11, in daily use. Windows and Linux builds are on [Releases](../../releases) and
> **Status:** v0.12, in daily use. Windows and Linux builds are on [Releases](../../releases) and
> update themselves. Next is a sprint summary with a standup you can paste into chat. See
> [ROADMAP.md](ROADMAP.md).

<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/board-dark.png">
<img alt="The board for the electron org: counts for My queue, Needs review, Changes requested, Approved and Merged in range, author filter chips, then one table per section with each PR's title, author, comments, size, pending reviewers and last update" src="docs/screenshots/board.png">
<img alt="The board for a sample team in Sprint 24: a strip of counts for My queue, Needs review, Changes requested, Approved and Merged, author filter chips, the Sweep listing each stuck PR with its CI status, why it's stuck, for how long and a next-step button, then a table per section" src="docs/screenshots/board.png">
</picture>

## Install
Expand All @@ -51,7 +51,9 @@ Grab a build from [Releases](../../releases).
SAML SSO, choose **Configure SSO** on the token and authorize the org. An unauthorized token
gets empty results instead of errors, so PR Sweep checks for this and tells you.
3. In Settings, add your team's GitHub logins. Leave the list empty to see the whole org.
4. Set the sprint's From and To dates in the header. Leave To empty for an open-ended view.
4. In Settings, under **Sprints**, set when your first sprint starts and how long sprints run.
The board then opens on the current sprint. No sprints? Choose **Custom** in the top bar and
set From and To dates instead. Leave To empty for an open-ended view.

> **Private orgs:** the first time someone signs in to an org that restricts third-party OAuth
> apps, GitHub asks them to **request access to `<org>`**. An org owner approves the app once,
Expand All @@ -66,7 +68,10 @@ Grab a build from [Releases](../../releases).
step. PRs that are only waiting or stale, or untouched for a month, sit behind a toggle, and
you can snooze a row until it changes or tomorrow. In a sprint's last two days, it also says how
many open PRs aren't approved yet.
- **Sorts** every open PR your team has, plus what merged in the date range, into Needs review,
- **Knows your sprint.** Give it the first sprint's start and the sprint length, and the board
opens on the current sprint, moves on when it ends, and steps back and forward with the arrows.
Rename a sprint or make one longer, and the sprints after it follow.
- **Sorts** every open PR your team has, plus what merged in the sprint, into Needs review,
Changes requested, Approved and Merged, from GitHub's `reviewDecision`. There are no labels to
keep up.
- **Queues** the open PRs anywhere in the org that are waiting on *your* review, with how long
Expand All @@ -76,7 +81,7 @@ Grab a build from [Releases](../../releases).
- **Notifies** from the tray when a PR lands in your queue, or when one of yours is approved, gets
changes requested or starts failing CI. The tray menu also counts what the Sweep has for the
team. Closing the window keeps it watching.
- **Shares** a setup. Save org, team and date-range profiles, then export them as JSON for
- **Shares** a setup. Save org, team and sprint profiles, then export them as JSON for
teammates to import. Tokens are never exported.
- **Opens instantly.** The last sweep is cached on disk, so the board appears at once and
refreshes in the background.
Expand Down Expand Up @@ -133,8 +138,7 @@ GitHub search has quirks, all checked against the live API. PR Sweep works aroun
## Development

```sh
npm install # root orchestration deps
npm run setup # desktop + renderer deps
npm install # root, desktop and renderer deps (rerun after pulling)
npm run dev # Angular dev server (:4301) + Electron with live reload
npm run build # renderer AOT build + main-process tsc (the typecheck)
npm test # core service tests (build first)
Expand Down
Loading
Loading