Skip to main content

PRonto

PRonto logo: a dog in profile with a green dot

Never look at an out-of-date pull request again.

PRonto runs quietly on your computer and keeps every open GitHub pull request you've authored up to date with its base branch. Whenever GitHub would show the Update branch button on one of your PRs, PRonto presses it for you, using the default "merge commit" option. When you open your PRs, they're already current.

$ pronto
updated    acme/webapp#412
updated    acme/api#88
skipped    acme/api#85: There are no new commits on the base branch.
skipped    acme/infra#1205: merge conflict between base and head

Contents


Features

  • Automatic "Update branch". Merges the base branch into each of your open PRs that's behind, exactly as the GitHub button does.
  • Safe by design. PRs that are already up to date, or that have merge conflicts, are left alone. PRonto never force-pushes, rebases, or resolves conflicts.
  • Runs in the background. One command registers PRonto with your operating system's scheduler (launchd on macOS, Task Scheduler on Windows, cron on Linux). It keeps running across reboots, with no terminal window left open.
  • Menu-bar / system-tray icon. Turn PRonto on or off, change how often it checks, limit it to recent PRs, run it on demand, and open the log, all from an icon.
  • Ignore old PRs. Limit PRonto to PRs opened in the last N days, so that a forgotten PR from two years ago doesn't get a merge commit every 15 minutes.
  • Dry-run mode. See which PRs PRonto would touch without changing anything.
  • Cross-platform. macOS, Windows and Linux.
  • Small and auditable. About 350 lines of Python. The only dependencies are for the tray icon.

How it works

Each run, PRonto:

  1. Searches GitHub for open pull requests authored by you (is:pr is:open author:@me archived:false). If you set a max age, it adds created:>=<date>.
  2. Calls GitHub's update-branch API for each one. This is the same action as clicking Update branch → Update with merge commit.
  3. GitHub decides the outcome:
    • Branch is behind: GitHub merges the base branch into it → updated
    • Already up to date: nothing happens → skipped … no new commits
    • Has conflicts: nothing happens → skipped … merge conflict

PRonto doesn't use git and never touches your local clones. Everything happens on GitHub's side.

Requirements

  • Python 3.9 or newer
  • A GitHub account on github.com (GitHub Enterprise Server isn't supported yet)
  • A GitHub personal access token (see below), or the gh CLI logged in

Installation

These install PRonto as a standalone command, in its own isolated environment:

uv tool install pronto-pr
# or
pipx install pronto-pr

Don't have either? Install uv with curl -LsSf https://astral.sh/uv/install.sh | sh (macOS/Linux) or winget install astral-sh.uv (Windows).

The package is called pronto-pr because pronto was already taken on PyPI. The command you run is still pronto.

Try it without installing

uvx --from pronto-pr pronto --dry-run

From source

git clone https://github.com/Zachary-Love/PRonto.git
cd PRonto
uv tool install -e .

-e (editable) means code changes take effect immediately. If you change dependencies in pyproject.toml, re-run with uv tool install -e . --reinstall.

Upgrading

uv tool upgrade pronto-pr     # or: pipx upgrade pronto-pr

If the background job is installed, it picks up the new version on its next run. To update the tray icon, quit it and run pronto tray.

Creating a GitHub token

PRonto needs a token that can read your PRs and push merge commits to their branches. Create one at https://github.com/settings/tokens.

Option A: Classic token (simplest)

  1. Go to Generate new token → Generate new token (classic).
  2. Give it a name like PRonto and pick an expiration.
  3. Check the repo scope.
  4. Generate it and copy it (it starts with ghp_).

Organizations with SAML SSO: after creating the token, click Configure SSO next to it on the tokens page and Authorize each organization. Without this, PRonto can't see or update PRs in those orgs.

Option B: Fine-grained token (tighter permissions)

  1. Go to Generate new token → Fine-grained token.
  2. Set Resource owner to the account or organization that owns the repos.
  3. Under Repository access, choose the repos (or All repositories).
  4. Under Repository permissions, set:
    • Contents: Read and write
    • Pull requests: Read and write
  5. Generate it and copy it (it starts with github_pat_).

A fine-grained token only covers one resource owner. If your PRs are spread across several orgs, or across your personal account and an org, use a classic token. Some orgs also require an admin to approve fine-grained tokens.

Giving the token to PRonto

PRonto looks for a token in this order:

  1. The GITHUB_TOKEN environment variable
  2. The GH_TOKEN environment variable
  3. The token saved by pronto install (~/.config/pronto/token)
  4. The gh CLI (gh auth token), if it's installed and logged in

For a first run, set the environment variable:

export GITHUB_TOKEN=ghp_yourtokenhere          # macOS / Linux
$env:GITHUB_TOKEN = "ghp_yourtokenhere"        # Windows PowerShell

pronto install checks the token with GitHub and saves it, so you only need to do this once.

Quick start

uv tool install pronto-pr
export GITHUB_TOKEN=ghp_yourtokenhere

pronto --dry-run      # 1. see which PRs it would look at (changes nothing)
pronto install        # 2. run it every 15 minutes in the background, plus the tray icon

That's it. PRonto runs once right away, then every 15 minutes, and comes back automatically after a reboot. A little dog appears in your menu bar or system tray.

Usage

One-off runs

pronto --dry-run               # list the open PRs PRonto would try; changes nothing
pronto                         # update all your out-of-date PRs once, then exit
pronto --max-age 30            # only PRs opened in the last 30 days
pronto --every 10              # keep running in this terminal, every 10 minutes (Ctrl+C to stop)

Each PR prints one line: updated, or skipped with GitHub's reason.

Running in the background

pronto install                            # every 15 minutes, all PRs, with the tray icon
pronto install --every 30 --max-age 60    # every 30 minutes, only PRs opened in the last 60 days
pronto install --no-tray                  # background job only, no icon (good for servers)

pronto install:

  1. Finds your token and checks it with GitHub (it fails right away if the token is bad).

  2. Saves the token to ~/.config/pronto/token, readable only by your user.

  3. Registers a background job with your OS:

    OS Mechanism Runs while
    macOS launchd user agent you're logged in
    Windows Task Scheduler task named pronto you're logged in
    Linux a line in your crontab the machine is on
  4. Starts the tray icon and sets it to open at login (unless you pass --no-tray).

Every run is logged to ~/.config/pronto/pronto.log.

While your computer is asleep, nothing runs. PRonto catches up at the next scheduled run after it wakes.

The menu-bar / tray icon

pronto install starts the icon for you. If you quit it, start it again with:

pronto tray

The icon is a black-and-white dog in profile with a green dot when PRonto is on, and no dot when it's off. On macOS it's a native template icon, so it turns white or black to match your menu bar. Its menu:

Menu item What it does
Enabled Turns the background job on or off.
Max PR age Only update PRs opened within: Any age, 7 days, 30 days, 90 days, or 1 year.
Check every How often the background job runs: 5 min, 15 min, 30 min, or 1 hour.
Run now Runs immediately and shows a notification with how many PRs were updated.
Open log Opens pronto.log in your default text viewer.
Quit Closes the icon. Updates keep happening in the background.

Notes:

  • The icon is a remote control for the background job, not the job itself. Quitting the icon doesn't stop updates; use Enabled or pronto uninstall for that.
  • The icon opens automatically at login, and only one copy runs at a time.
  • The menu and the command line share the same settings, so you can switch between them freely.
  • Linux: the icon needs a desktop with system-tray support. GNOME needs the AppIndicator extension.

Command reference

pronto [command] [options]
Command Description
run (default) Update your out-of-date PRs now.
install Save your token, set up the background job, and start the tray icon. Run it again to change settings.
uninstall Remove the background job and the tray icon's login entry, and delete the saved token and settings.
tray Start the menu-bar / tray icon in the background.
Option Applies to Description
--dry-run run List PRs without updating anything.
--max-age DAYS run, install Ignore PRs opened more than DAYS days ago.
--every MIN run, install Minutes between runs: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60, 120, 180, 240, 360, 480 or 720. These are the intervals every OS scheduler can run exactly. With run, PRonto keeps running in the terminal; without it, it runs once. With install, the default is 15.
--no-tray install Don't start the tray icon.
-h, --help all Show help.

Exit codes: 0 on success. 1 if a one-off run can't reach GitHub, or no token is found.

Changing settings

Use the tray menu, or re-run install with the options you want:

pronto install --every 60 --max-age 14

install replaces all settings with the ones you pass. Leaving out --max-age resets it to "any age", and leaving out --every resets it to 15 minutes.

To change your token, set GITHUB_TOKEN to the new one and run pronto install again.

Where PRonto keeps things

All PRonto files live in ~/.config/pronto/ (on Windows: C:\Users\<you>\.config\pronto\):

File Contents
token Your GitHub token (permissions 600: only you can read it).
settings.json Enabled, check interval, and max PR age.
pronto.log Output from every background run. Starts over once it passes 1 MB.
tray.lock Keeps a second tray icon from starting.

Background job and login entries:

OS Background job Tray icon at login
macOS ~/Library/LaunchAgents/pronto.plist ~/Library/LaunchAgents/pronto-tray.plist
Windows Task Scheduler → pronto Registry: HKCU\Software\Microsoft\Windows\CurrentVersion\Run → pronto
Linux crontab line ending in # pronto ~/.config/autostart/pronto.desktop

Uninstalling

pronto uninstall               # remove the background job, login entry, saved token and settings
uv tool uninstall pronto-pr    # remove the program (or: pipx uninstall pronto-pr)

If the tray icon is running, choose Quit from its menu. To remove the log too, delete ~/.config/pronto/.

You may also want to revoke the token at https://github.com/settings/tokens.

Troubleshooting

Start with the log: ~/.config/pronto/pronto.log, or Open log in the tray menu. Each run starts with a --- YYYY-MM-DD HH:MM line.

Set GITHUB_TOKEN (or log in with gh auth login) No token was found. Create one, export GITHUB_TOKEN=..., then run pronto install.

HTTP Error 401: Unauthorized The token is wrong, expired, or revoked. Create a new one and run pronto install again.

Some PRs (often in an org) never show up

  • Classic token: authorize it for the org via Configure SSO on the tokens page.
  • Fine-grained token: make sure the resource owner is that org and the repos are included. The org may also need to approve the token.

skipped … Resource not accessible by personal access token The token can see the PR but can't push to its branch. Give it Contents: Read and write and Pull requests: Read and write, or use a classic token with repo.

skipped … merge conflict between base and head Expected: GitHub can't merge automatically. Resolve the conflict yourself; PRonto picks the PR up again afterwards.

skipped … There are no new commits on the base branch Expected: the PR is already up to date.

Tray icon not available: No module named 'pystray' Your install is missing its dependencies. This usually happens with an editable (-e) install made before dependencies changed. Reinstall:

uv tool install pronto-pr --reinstall          # from PyPI
uv tool install -e . --reinstall               # from a source checkout

Tray icon not available (…); the background job is still installed. PRonto couldn't show an icon, usually because there's no desktop (for example a server or SSH session). Updates still run. Use pronto install --no-tray to skip the icon.

The icon doesn't appear on Linux Your desktop needs tray support. On GNOME, install the AppIndicator and KStatusNotifierItem Support extension.

No "Run now" notification on macOS Notifications are sent through macOS's built-in scripting tool, so they appear under Script Editor. Allow them in System Settings → Notifications → Script Editor.

Windows laptop: nothing runs on battery Task Scheduler's defaults skip tasks while on battery. Open Task Scheduler → pronto → Properties → Conditions and uncheck Start the task only if the computer is on AC power.

Check that the background job is registered

launchctl list | grep pronto          # macOS
schtasks /Query /TN pronto            # Windows
crontab -l | grep pronto              # Linux

Debug the tray icon Run it attached to your terminal so errors print directly:

pronto tray --foreground

FAQ

Does PRonto rebase my branches? No. It only uses the "merge commit" form of Update branch. It never rebases, force-pushes, or rewrites history.

Will this trigger CI on every update? Yes. Each update is a new commit on your PR branch, so CI runs just as it would after clicking the button. Use --max-age or a longer --every if that's too much.

Which PRs does it look at? Open PRs that you authored, in repositories that aren't archived, including drafts. It doesn't touch other people's PRs.

What about PRs from two years ago that I forgot about? Use --max-age, or Max PR age in the tray menu. For example, --max-age 30 only considers PRs opened in the last 30 days.

Does it work when my laptop is closed? No. It runs on your machine, so it only works while the machine is awake (and, on macOS and Windows, while you're logged in). It catches up at the next scheduled run.

Will it hit GitHub's rate limits? Unlikely. Each run makes one search request per 100 PRs, plus one request per PR. Even every 5 minutes, that's well within GitHub's limits for normal use.

Is my token safe? It's stored in a file only your user can read, sent only to api.github.com, and never logged. pronto uninstall deletes it. A classic token with repo scope is powerful, so set an expiration, or use a fine-grained token if your PRs live under one owner.

Does it work with GitHub Enterprise Server? Not yet: the API URL is fixed to api.github.com.

Development

git clone https://github.com/Zachary-Love/PRonto.git
cd PRonto
uv tool install -e .       # installs the `pronto` command from your checkout
python3 test_pronto.py     # prints "ok"

Project layout:

File Purpose
pronto.py CLI, GitHub API calls, background-job and login-item setup
pronto_tray.py Menu-bar / tray icon
test_pronto.py Scheduler and login-item tests (fakes OS calls; touches nothing real)
pyproject.toml Packaging metadata

A safe way to try changes end to end: create a throwaway repo, open a PR, then push a commit to main so the PR falls behind. pronto --max-age 1 should then report it as updated.

Publishing a release

  1. Bump version in pyproject.toml.
  2. uv build
  3. uv publish --token pypi-...

License

MIT © 2026 Zachary Love

Metadata

Release files for pronto-pr 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pronto-pr 0.1.0
File Size Uploaded
pronto_pr-0.1.0.tar.gz 22.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pronto-pr 0.1.0
File Interpreter ABI Platform
pronto_pr-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.1 kB

Release files / pronto_pr-0.1.0.tar.gz

Download URL pronto_pr-0.1.0.tar.gz
Size 22.2 kB
Tags Source
SHA-256 checksum
How to use checksums
cd246f8097c76f210f3f482259910f730868030989fc41559ca21a59f115723d
BLAKE2b-256 checksum
How to use checksums
bb51bef2e025c7975cb3e47c5579e183ef8e12ed4ab50b6103518c689fcd35c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pronto_pr-0.1.0-py3-none-any.whl

Download URL pronto_pr-0.1.0-py3-none-any.whl
Size 16.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea2caf1da300a6d62d81367e78097210c3b09b7d97eb751ccf16528a23f81575
BLAKE2b-256 checksum
How to use checksums
2fe07215c646f68749db0b28783e3bfb1e4d0ff897673f5b220bd39d090c2443
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page