Open-source project
prontolabs/pronto avatar
prontolabs/pronto

Pronto: running linters only on the lines a branch changes

Quick automated code review of your changes

2,672 stars251 forksRubyMIT

At a glance

What is it?
Pronto is a Ruby gem that diffs a branch against a commit-ish and runs its analysis only over the changed files. It is aimed at teams that want style and security feedback posted on GitHub, GitLab or Bitbucket pull requests without paying for a full-repository scan on every push.
Who is it for?
Adopt Pronto if your team already runs RuboCop, Flay or Brakeman and you want that feedback attached to the pull request rather than buried in CI logs; the runner model means you keep your existing linter configuration. Skip it if you need whole-repository analysis on every run, if your default branch is not master and you will not pass -c, or if nobody on the team is willing to maintain a Ruby toolchain in CI.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 32 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The diff-scoped review problem Pronto was built for

A linter that runs over an entire repository on every push reports the same hundred pre-existing offenses every time. The signal a reviewer needs is narrower: which of the lines this branch touched are wrong. Pronto's stated purpose in the README is exactly that, "runs analysis quickly by checking only the relevant changes", and the audience is teams that already have linters configured and want their output attached to the review rather than dumped into a build log.

The project was created for GitHub pull requests, and the README says it also works locally and integrates with GitLab and Bitbucket. That ordering matters. The local mode is the debugging path, the hosted integrations are the product. Pronto itself ships no analysis rules. It is a diff engine plus a formatter layer, and the actual checks come from separate gems such as pronto-rubocop, pronto-flay and pronto-brakeman. If you install only the main gem, you get a working command that has nothing to say.

How the diff, the runners and the formatters fit together

The mechanism has three parts. First, Pronto computes a diff between the current HEAD and a commit-ish, and the README states the default is master. Second, each installed runner receives that diff and returns messages only for the changed lines, which is why a runner gem is a separate install rather than a bundled rule set. Third, a formatter decides where those messages go: the console for local runs, or the provider's API for CI runs.

The default branch note in the README is the part that trips people up. If your default branch is not master, the README instructs you to invoke pronto run -c=<branch> or set the default_commit config value. A CI job that skips this will diff against a branch that does not exist in the checkout and quietly produce nothing useful.

Formatters are selected with -f and can be combined. The GitHub family alone covers five behaviours: github for commit comments, github_pr for comments on the pull request diff, github_pr_review for grouped reviews, github_status for a commit status per runner, and github_combined_status for one status covering all runners. The PR review formatter splits a large number of pending comments into several reviews, with the count governed by PRONTO_WARNINGS_PER_REVIEW, the warnings_per_review config value, or a default of 30. The README explains this is to avoid provider rate limits, which is a practical admission that a noisy run can otherwise be throttled.

Installing Pronto and running it on a local branch

Installation is a standard Ruby gem install, followed by whichever runners you want. The README shows the plain gem command and then the runner gems:

bash
gem install pronto
gem install pronto-rubocop
gem install pronto-flay

With bundler the README shows the same gems declared in the Gemfile, with require: false on the runners because they are only needed when Pronto loads them:

ruby
gem 'pronto'
gem 'pronto-rubocop', require: false
gem 'pronto-flay', require: false

For a first real run, check out the branch you want reviewed and let Pronto diff it against the default commit-ish. The README's local example is:

bash
git checkout feature/branch
pronto run

That compares committed changes on the current branch against master. Two variants cover work that is not committed yet: pronto run --staged analyzes the git staging area, and pronto run --unstaged analyzes changes made but not staged. Running the bare command with no arguments prints the available options, which is the fastest way to confirm which runners were actually detected.

If your default branch is not master, pass the base explicitly. In CI the base is usually the pull request target, which is why the README's GitHub Actions example uses origin/${{ github.base_ref }}.

Wiring Pronto into a GitHub pull request workflow

The CI path needs an OAuth token with access to the repository, supplied either as the PRONTO_GITHUB_ACCESS_TOKEN environment variable or as a value in .pronto.yml. The README's minimal invocation pairs a formatter with an explicit base commit:

bash
PRONTO_GITHUB_ACCESS_TOKEN=token pronto run -f github_pr -c origin/master

The README also documents a GitHub Actions workflow that installs the gems, fetches the base refs, and runs two formatters at once. The checkout step is shallow, so the workflow adds an explicit fetch of the origin refs before running:

yaml
- run: |
    git fetch --no-tags --prune --depth=10 origin +refs/heads/*:refs/remotes/origin/*
- name: Setup pronto
  run: gem install pronto pronto-rubocop
- name: Run Pronto
  run: pronto run -f github_status github_pr -c origin/${{ github.base_ref }}
  env:
    PRONTO_PULL_REQUEST_ID: ${{ github.event.pull_request.number }}
    PRONTO_GITHUB_ACCESS_TOKEN: "${{ github.token }}"

That fetch line is not decoration. A shallow checkout often lacks the base branch, and Pronto cannot diff against a ref it cannot see. If you adapt this workflow, keep the fetch and keep -c pointed at the target branch. The README also notes a rake-task alternative that requires each runner gem and calls Pronto.run with an array of formatters, which is the option to consider if you would rather not shell out from CI.

Where Pronto stops being the right tool

The diff scope is the limitation as much as the feature. A branch that touches three lines gets three lines analyzed, so a repository-wide problem that your branch does not touch will never appear in the Pronto output. If your goal is a periodic full sweep, or a gate that fails when the total offense count exceeds a threshold, Pronto is the wrong layer and you want the underlying linter run directly.

The README is also explicit that the README might be ahead of the latest release, pointing to the v0.11.5 copy for the released documentation. Anyone reading configuration keys from the master branch should check them against that tagged README before assuming they exist in the version they installed.

Provider-side constraints are real. The github_pr_review formatter exists to batch comments into reviews specifically because of rate limits, and the batching is a blunt instrument: the number of reviews is derived from the pending comment count divided by the warnings-per-review setting, so a run with many findings produces several reviews rather than one. The README does not document rollback or a dry-run mode, so there is no described way to preview what a CI run will publish before it publishes it. The exit code behaviour is opt-in through --exit-code, which means a default run reports without failing the build; teams expecting a hard gate must add that flag themselves.

How Pronto differs from running RuboCop directly

The obvious alternative is the linter itself. RuboCop run over a repository reports every offense it finds and can be pointed at changed files with its own tooling; it needs no token, no formatter layer and no separate gem per rule set. The difference in approach is what each one optimizes for. RuboCop answers "is this codebase clean", Pronto answers "did this branch make anything worse", and only the second question can be answered without a baseline.

That distinction has a cost. Pronto adds a Ruby dependency, a provider token, and a formatter choice to a workflow that a single RuboCop invocation would otherwise cover, and it inherits RuboCop's configuration anyway because pronto-rubocop reads your existing .rubocop.yml. If your team is not already on Ruby, the gem install and the runner gems are new infrastructure for feedback that a Node or Python linter could deliver natively. If your team is on Ruby and already runs RuboCop in CI, Pronto is mostly a delivery mechanism: it moves the same findings from a log to the pull request, filtered to the lines under review.

Maintenance cost, licensing and what to check before adopting

The repository is not archived and the last push was on 2026-08-30. Releases have been irregular rather than frequent: v0.11.5 on 2025-12-05, v0.11.4 on 2025-05-02, v0.11.3 on 2025-01-11. Expect to track the tagged README for your installed version rather than the master branch, since the project itself warns the two can diverge.

Upgrade cost is mostly in the runner gems. Pronto's own surface is small (a command, a handful of flags, a config file), but each runner tracks the upstream tool it wraps, so a RuboCop major version can move your findings even when Pronto's version does not change. Pin the runner gems alongside the linter they wrap.

The project is MIT licensed, which permits commercial use and modification; the LICENSE file is at the repository root. That is a statement about the licence text, not legal advice, and the runner gems are separate packages with their own licences that you should check individually.

Before adopting, verify that the diff base resolves in your CI checkout, which formatter matches your review style, and whether you need --exit-code to make the job fail. The README documents none of the provider-side token scopes beyond "access to the repository", so confirm the token's permissions against your provider's own documentation.

Editorial conclusion

Adopt Pronto if your team already runs RuboCop, Flay or Brakeman and you want that feedback attached to the pull request rather than buried in CI logs; the runner model means you keep your existing linter configuration. Skip it if you need whole-repository analysis on every run, if your default branch is not master and you will not pass -c, or if nobody on the team is willing to maintain a Ruby toolchain in CI. Before rolling it out, verify three things: that the diff base resolves correctly in your CI checkout, that your access token has the scope the chosen formatter needs, and which of the GitHub formatters (github, github_pr, github_pr_review, github_status, github_combined_status) matches how you want comments to appear.

Frequently asked questions

How do I install Pronto?

Install the main gem with gem install pronto, then add at least one runner such as pronto-rubocop or pronto-flay. With bundler, the README shows the same gems in the Gemfile with require: false on the runners.

How do I use Pronto on a local branch?

Check out the branch and run pronto run to diff committed changes against master. Use pronto run --staged for the staging area or pronto run --unstaged for changes that are not staged.

How do I set up Pronto for a GitHub pull request?

Set PRONTO_GITHUB_ACCESS_TOKEN to a token with access to the repository, then run pronto with a formatter and an explicit base, for example pronto run -f github_pr -c origin/master. The README also gives a GitHub Actions workflow that fetches the origin refs before running.

What should I do if my default branch is not master?

The README says to invoke pronto run -c=<branch> or set the default_commit config value. Without that, the diff base will not resolve correctly.

Does Pronto include its own linting rules?

No. Pronto computes the diff and formats the output; the checks come from separate runner gems such as pronto-rubocop, pronto-flay and pronto-brakeman, which must be installed alongside the main gem.

Official sources

  1. Issues
  2. License: MIT
  3. prontolabs/pronto on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/prontolabs-pronto.svg)](https://hysenlabs.com/projects/prontolabs-pronto)