Pruefer

Pruefer is a self-hosted pull-request review daemon. It watches the repositories its GitHub App is installed on, reviews open pull requests by running the claude CLI (backed by a Claude Code subscription, not metered API billing), and submits a formal pull_request_review pinned to the head commit it reviewed. It lives in this repository under cmd/pruefer/.

This page is a short overview. The Pruefer README is the full reference and the authority on every setting and default. If the two ever disagree, the README wins.

What it does

It exists so a repo can satisfy Fabrik’s wait_for_reviews: true gate (or simply have a review bot) without depending on a hosted third-party reviewer’s quota.

Install

You need Go, a working claude CLI on the host with a valid Claude Code subscription (a credential separate from the GitHub App), and a GitHub account that will own the App.

# in a checkout of this repository
go build -o bin/pruefer ./cmd/pruefer
./bin/pruefer

On the first run, with no local App credentials, Pruefer walks you through GitHub’s App Manifest flow: it opens a browser page, you confirm the App’s name, and GitHub hands the credentials back to a temporary local listener. Pruefer saves the private key to .pruefer/app-private-key.pem and the rest to .pruefer/app-state.json (neither is committed or logged). It then prints a link to install the App. Install it on the repos or the account you want reviewed. No restart is needed, because Pruefer picks up new installations on its own.

Minimal configuration

Pruefer reads .pruefer/config.yaml from its working directory. This is enough to start:

# .pruefer/config.yaml
poll_interval_seconds: 120
model: sonnet

Which repos get reviewed is decided by where you install the App. There is no repo list to maintain.

Main operator settings

Precedence is flag, then environment variable, then YAML, then default. The defaults below are from the README’s Configuration reference, which lists every setting with its flag and environment variable.

YAML key Default What it does
poll_interval_seconds 120 How often Pruefer polls for PRs.
model sonnet Claude model used for reviews.
effort medium low, medium, high or max.
concurrency_cap 3 Maximum simultaneous claude reviews.
max_diff_bytes 500000 Diff size above which Pruefer trims the largest files and reviews the rest.
watched_repos none Optional filter that narrows the installed repos to a subset.
served_accounts none Optional allowlist of account logins. An installation outside it is removed.
excluded_authors, excluded_labels, excluded_paths none Skip PRs by author or label, and exclude files by glob from the review.
request_changes_threshold off low, medium, high or critical. When a finding meets it, the review is REQUEST_CHANGES.
cadence every-push every-push, once or on-request.
catch_up_marker_authors none Needed to skip reviews of pure merge-train catch-ups. See below.
auto_upgrade false Self-upgrade at the poll boundary.

Review behaviour can be extended with review_guidance, review_skill, plugins and review_tools, and a reviewed repo can adjust some settings in its own .pruefer/config.yaml. The README covers these in depth.

Working with Fabrik’s review gate

Declare Pruefer on the stage that waits for reviews, using your own App’s handle (the App slug, written bare, with no @ and no [bot] suffix):

wait_for_reviews: true
expected_reviewers: [<your Pruefer app's handle>]

Fabrik then knows a review is coming even though Pruefer is never formally requested as a reviewer. The User Guide’s Declaring Expected Reviewers section explains the semantics, and its Pruefer review notes list the behaviours that matter at the gate. In short:

Full reference

For everything else, including the config reference, review plugins, coded review tools, severity-gated REQUEST_CHANGES, review cadence and logging, read the Pruefer README.

Pruefer is one of the companion tools used alongside Fabrik.