Skip to documentation

Put your panel to work.

Install the relay, choose your reviewers, and get a scored review on your next pull request.

Quick start

You need Git, the GitHub CLI, a local clone of each watched repo, and at least one supported coding agent. Sign in to your agents or configure their API keys before starting.

1. Connect GitHub

Your GitHub account needs permission to manage repository webhooks and, when publishing is enabled, write PR comments.

Terminal
gh auth login
gh extension install cli/gh-webhook
gh auth status

2. Install review-relay

$ curl -fsSL https://github.com/Tyru5/review-relay/releases/latest/download/install.sh | bash

Standalone binaries for macOS and glibc Linux on x64/arm64, and Windows x64. No Bun or Node installation required. Alpine/musl is not supported.

3. Choose your repos and start

Terminal
review-relay setup
review-relay start -d
review-relay status

setup finds GitHub clones under your home directory and agent CLIs on your PATH. Choose the repos, reviewers, models, and effort. It saves ~/.review-relay/config.json.

Review an open PR
review-relay run --repo acme/widget --pr 42

Use start without -d for foreground logs. The machine and daemon must stay running to receive events.

Install locations, updates, and pinned versions

Unix installs to ~/.local/bin/review-relay. Add ~/.local/bin to your PATH if needed. Windows installs to %LOCALAPPDATA%\review-relay\bin and adds it to your user PATH by default.

The installers verify the binary’s SHA-256 checksum and preserve an existing config. Run the installer again to update, then restart the daemon. To pin a release, pass --version x.y.z to the Unix installer, or -Version x.y.z to the PowerShell script.

Unix also accepts --bin-dir. PowerShell accepts -BinDir and -NoModifyPath. See environment variables for equivalent settings.

Configuration

Configuration is JSON. The CLI uses --config <path> first, then REVIEW_RELAY_CONFIG, then ~/.review-relay/config.json. Restart the daemon after editing it.

~/.review-relay/config.json · example
{
  "reviewers": [
    "codex",
    "claude"
  ],
  "repos": [
    {
      "fullName": "acme/widget",
      "localPath": "~/code/widget",
      "trigger": "github",
      "postToPr": false
    }
  ]
}

This example watches a fictional repo through GitHub events and keeps reports local. Replace fullName and localPath, then set postToPr to true when you want comments.

Top-level options

Top-level configuration options
OptionDefaultWhat it does
reposRequiredNon-empty list of GitHub repositories and their local clones.
port9988Local webhook server port. Listens on 127.0.0.1 only.
graceMs120000In auto mode, wait this many milliseconds for Greptile before the GitHub fallback runs.
timeoutMs1800000Per-reviewer timeout in milliseconds. The default is 30 minutes.
reviewers["codex","claude"]Fallback panel when no route matches. At least one reviewer ID is required.
modelsBuilt-in entriesModel, effort, provider, and display label per reviewer. Custom entries also name a harness.
routes[]Ordered rules that select reviewers or skip an automatic review.
dataDir~/.review-relayReports, state, logs, and temporary worktrees. Does not change the config file location.

Repository options

Each object in repos accepts these settings. Use an absolute path, or ~/, so the clone resolves consistently.

Repository configuration options
OptionDefaultWhat it does
fullNameRequiredGitHub owner/name, for example acme/widget.
localPathRequiredExisting local clone with an origin remote for this repository. ~/ expands to your home. Relative paths resolve from the process working directory.
triggerautoauto, greptile, or github. Mentions work in every mode.
postToPrtruePublish the report as a PR comment. Set false for local reports only; reviewers still run.
github.onPushfalseAlso handle pull_request.synchronize when new commits are pushed. Applies to github and auto modes.
github.mention@review-relayCase-insensitive text that requests a review in a new PR comment. Use a non-empty mention.
Use a different config
review-relay info --config ./relay.json
review-relay start -d --config ./relay.json

Use the same --config for status, stop, and other commands targeting that daemon. info --json and config show resolved values, including defaults.

Environment variables and installer overrides
Environment variables
OptionDefaultWhat it does
REVIEW_RELAY_CONFIG~/.review-relay/config.jsonConfig path for the CLI and installers. --config takes precedence in the CLI.
REVIEW_RELAY_DEBUGNot setAny non-empty value logs why webhook events were ignored. Set before starting the daemon.
NO_COLORNot setA non-empty value disables CLI color, even if FORCE_COLOR is set.
FORCE_COLORNot setA non-empty value other than 0 enables CLI color.
REVIEW_RELAY_INSTALL_VERSIONlatestInstaller release version. Unix --version and PowerShell -Version take precedence.
REVIEW_RELAY_INSTALL_BIN_DIRPlatform defaultInstaller destination. Unix --bin-dir and PowerShell -BinDir take precedence.
REVIEW_RELAY_INSTALL_URLhttps://downloads.reviewrelay.devAlternate download origin. Only use an origin you trust.
REVIEW_RELAY_INSTALL_NO_MODIFY_PATHNot setWindows only. Any non-empty value prevents PATH changes; equivalent to -NoModifyPath.

Agent authentication belongs to each agent CLI. review-relay does not store API keys in its config.

Reviewers & models

reviewers names the default panel. Every ID selects a built-in CLI or a custom entry in models. Selected reviewers run in parallel; they do not need to use different CLIs.

Supported reviewers
Reviewer IDProductRelay defaults
claudeClaude Codeclaude-opus-5-5, effort max
codexCodex CLIgpt-6-astra, effort high
auggieAugment AuggieCLI default model; effort supported
copilotGitHub Copilot CLICLI default model; effort supported
droidFactory DroidCLI default model; effort supported
geminiGemini CLICLI default model; no per-run effort option
grokGrok BuildCLI default model; effort supported
hermesHermes AgentCLI default model; effort supported
kiloKilo Code CLICLI default model; effort supported
opencodeopencodeCLI default model; effort supported
pipiCLI default model; effort supported
qwenQwen CodeCLI default model; no per-run effort option
vibeMistral VibeCLI default model; no per-run effort option

The executable normally matches the ID. Kilo also accepts kilocode. Install and authenticate each selected CLI separately; review-relay does not install agents.

Model entry options

Model entry options
OptionDefaultWhat it does
harnessRequired for custom IDsOne of the supported CLI IDs below. A built-in ID always uses its own CLI.
labelCLI label or custom IDName shown in the PR comment. Active reviewer labels must be unique, ignoring case.
modelHarness defaultModel identifier accepted by the CLI. Omit to use the relay default below, or the CLI default when none is set.
effortHarness defaultReasoning setting for CLIs that support it. Model and CLI versions determine which values work.
providerNot setHermes only. Provider identifier, separate from the model name.

For example, models.codex changes the built-in Codex reviewer. To run two Codex models, create two custom IDs with harness: "codex" and put both IDs in reviewers.

Custom IDs use up to 32 lowercase letters, digits, and dashes, starting with a letter or digit. Omitted settings inherit the harness defaults, not another entry’s overrides. Add or remove custom entries in JSON; setup can edit existing entries.

Unknown custom-entry fields are errors. Invalid legacy built-in settings may warn and be ignored. Unsupported model or effort values can still be rejected by the agent CLI at runtime.

Routing rules

Routes choose a panel from the PR’s diff and trigger. The first matching, applicable route wins. If none matches, the global reviewers and timeoutMs apply.

Routed config · example
{
  "reviewers": [
    "codex",
    "claude"
  ],
  "models": {
    "codex-deep": {
      "harness": "codex",
      "label": "Codex deep",
      "model": "gpt-6-astra",
      "effort": "high"
    }
  },
  "routes": [
    {
      "name": "docs-only",
      "when": {
        "onlyPaths": [
          "docs/**",
          "**/*.md"
        ]
      },
      "skip": true
    },
    {
      "name": "sensitive",
      "when": {
        "wideImpact": true
      },
      "reviewers": [
        "codex-deep",
        "claude"
      ],
      "timeoutMs": 2400000
    },
    {
      "name": "small",
      "when": {
        "maxLines": 100,
        "maxFiles": 5
      },
      "reviewers": [
        "codex"
      ]
    }
  ],
  "repos": [
    {
      "fullName": "acme/widget",
      "localPath": "~/code/widget",
      "trigger": "auto",
      "postToPr": false
    }
  ]
}

This example skips documentation-only automatic reviews, sends sensitive changes to a larger panel, and sends small changes to Codex. Everything else uses the default panel.

Route options

Route options
OptionDefaultWhat it does
nameRequiredUnique ID, up to 32 lowercase letters, digits, and dashes; starts with a letter or digit.
whenRequiredNon-empty object of conditions below. All conditions must match.
reviewersEither reviewers or skipNon-empty list of known reviewer IDs, without duplicates. Replaces the fallback panel.
skipOmit for review routesSet true instead of reviewers to skip. Skip routes cannot set timeoutMs.
timeoutMsGlobal timeoutMsPositive integer in milliseconds. Overrides the timeout for each reviewer on this route.

Match conditions

All conditions in when must hold. Lists match any listed value or glob. Path globs use repository-relative paths and are case-sensitive. Use ** to span directories.

Route match conditions
ConditionValueMatches when
reposGlob listMatch owner/name, ignoring case. Each pattern must match at least one configured repo.
baseBranchesGlob listMatch the target branch, not the PR head branch. Case-sensitive.
sourcesValue listgreptile, github, mention, or manual.
pathsGlob listAt least one changed path matches. Includes the old path of a renamed file.
onlyPathsGlob listEvery changed path must match at least one pattern, including both sides of renames. Empty diffs do not match.
minLinesInteger ≥ 0Minimum additions + deletions, inclusive, excluding recognized lockfiles.
maxLinesInteger ≥ 0Maximum additions + deletions, inclusive, excluding recognized lockfiles.
minFilesInteger ≥ 0Minimum number of changed non-lockfiles, inclusive.
maxFilesInteger ≥ 0Maximum number of changed non-lockfiles, inclusive.
wideImpactBooleanMatch changes to recognized dependency manifests, CI, migrations, schemas, SQL, environment files, and other sensitive paths. False matches their absence.

Size conditions exclude recognized lockfiles; path conditions still see them. Binary files count as files with zero added or deleted lines. Renames consider both old and new paths.

Request a named panel

PR comment
@review-relay sensitive

A trusted commenter can name a non-skip route after the mention. That route runs even if its conditions do not match. Unknown names and skip-route names fall back to normal routing.

Route names must be unique. Unknown fields, duplicate reviewers, empty conditions, and a minimum above its maximum stop config loading.

Triggers & review flow

Trigger modes
ModeStarts onBehavior
autoGreptile or GitHubDefault. Greptile starts immediately. A GitHub PR event waits graceMs, then runs if Greptile has not started for that commit.
githubGitHub PR eventsRuns immediately on opened, reopened, and ready_for_review. Add github.onPush: true for synchronize events.
greptileGreptile check startOnly the Greptile start triggers automatic reviews. No GitHub fallback.

Mentions work in all three modes. Only new PR comments by an OWNER, MEMBER, or COLLABORATOR qualify. Bot comments and ordinary issues do not.

  1. Receive an event. Each repo has a temporary webhook forwarded through gh webhook forward to the local signed endpoint. No public relay URL is needed.
  2. Resolve and deduplicate. The scheduler keys automatic reviews by repository and head commit. Completed, skipped, and in-progress jobs suppress duplicates. Failed jobs can retry on another trigger.
  3. Choose the route. Fetch the PR and base branch, inspect the diff, and select reviewers. A skip stops before a worktree is created.
  4. Run the panel. Create a detached worktree, remove executable project-level agent config, and run the selected CLIs concurrently against the same rubric.
  5. Save and publish. Remove the temporary worktree, save reports, and create or update a PR comment if enabled.

GitHub PR events ignore drafts and closed PRs. Explicit mentions and manual runs require an open PR but can review a draft. They bypass completed-job deduplication, but not an already-running job in the same scheduler.

Greptile matching requires app greptile-apps, check name Greptile Review, and a created check that is queued or in progress. Completed checks only log a result. Fork checks without an associated PR are ignored; use auto for the GitHub fallback.

CLI commands

Run review-relay help <command> or review-relay <command> --help for command help. Global options are --config <path>, -h / --help, and -v / --version.

CLI commands
CommandArguments / optionsPurpose
setupNo required flagsInteractive repo and reviewer selection. Writes the config and preserves settings it does not ask about.
start-d, --detachWatch repos. Foreground by default; -d runs in the background and writes daemon.log.
stopNo flagsStop the background daemon. Attempts graceful shutdown, then forces exit after 20 seconds.
restartNo flagsStop, then start in the background. Use after editing config.
status--limit <n>Daemon, endpoint, forwarders, and recent jobs. Default 20 jobs; exits 3 when the daemon is not running.
logs[N], -f, --followRead the last N log lines, default 50. Use -f to follow new output.
run--repo <owner/name> --pr <n> [--route <name>]Review an open PR now, including a previously reviewed commit. Can publish a comment.
route--repo <owner/name> --pr <n> [--source <source>]Explain matching rules without running reviewers or posting. Fetches the PR and base refs. Default source: github.
replay<events.jsonl> --dry-run --grace <ms>Process recorded deliveries. --dry-run logs would-run jobs; --grace overrides the auto-mode wait for this replay.
info--jsonResolved configuration and diagnostics. --json prints machine-readable output.
configNo flagsPrint the resolved configuration as JSON.
help[command]List commands, or show a command’s options and examples.

Preview or force a route

Explain routing without running agents
review-relay route --repo acme/widget --pr 42 --source github

run --route sensitive forces that non-skip route. Unlike mentions, an unknown or skip route is rejected. route --source accepts github, greptile, mention, or manual. Route inspection also works on closed PRs.

Replay recorded deliveries

Use a JSONL file with one {"event":"pull_request","payload":{...}} object per line. body is accepted as an alternative to payload. The payload must contain the original GitHub fields.

Inspect triggers without running agents
review-relay replay events.jsonl --dry-run --grace 0

Dry-run uses fresh in-memory state and logs which jobs would be dispatched. It does not fetch diffs or evaluate routes. Without --dry-run, replay can run agents, write state, and publish comments.

Scores & reports

Each successful reviewer scores correctness, security, code quality, standards, blast radius, and testing from 1 to 5, plus an overall merge confidence.

  • A critical finding caps that reviewer at 2/5.
  • A major finding caps that reviewer at 3/5.
  • Overall confidence cannot exceed the weakest dimension by more than one point.
  • The published score is the lowest capped score among successful reviewers, never an average.

Findings from different reviewers at the same file and within three lines are merged, retaining the highest severity. The comment links findings to the reviewed commit and includes dimension notes.

One comment, local reports

Publishing edits the signed-in GitHub user’s latest comment carrying the relay marker, or creates one if none exists. Switching GitHub accounts can create a separate comment. Scores are advisory; review-relay does not install a merge gate.

Report directory
<dataDir>/reports/<owner__repo>/pr-<number>/<sha8>/
  comment.md
  <reviewer-id>.json
  meta.json

meta.json records the job, route, selected models, timeouts, durations, and scores. Reviewer JSON contains the verdict, or an error and raw output on failure. Re-running the same PR commit writes to the same directory.

One failed reviewer does not cancel the others. A partial result can publish with the failure noted. If all reviewers fail, local reports are saved but no comment is posted, and the job fails. A publishing failure also leaves the local report available.

Security & privacy

Reviews run on your machine, but your code goes to the providers used by your selected agents and models. postToPr: false disables GitHub comments, not provider requests.

The webhook server binds to 127.0.0.1. POST /hook requires an HMAC-SHA256 signature using a secret generated at daemon startup. GET /health returns a local health response.

Reviewers use each CLI’s read-only controls, restricted tools, sandbox, or no-shell mode. The runner removes recognized project configs that could load hooks, plugins, or MCP servers from the review worktree before starting agents. Your original clone is not stripped.

These controls depend on the agent CLI and its version. They are not a separate VM boundary. Keep CLIs updated, review their authentication and provider settings, and treat PR content and model output as untrusted.

Reports and daemon logs can contain source code and findings. Protect dataDir accordingly. Stop the daemon normally so the forwarders can remove their temporary repository webhooks.

Troubleshooting

Start with these checks
review-relay status
review-relay info
review-relay logs 100
gh auth status
No review appeared

Check that the daemon and repo forwarder are running, your machine is awake, and fullName matches. In auto mode, allow the two-minute default grace period. Push events require github.onPush: true. Check for a draft, already-reviewed commit, or skip route.

For mention triggers, use a new PR comment from a trusted collaborator. To see ignored-event reasons, set REVIEW_RELAY_DEBUG=1 in the daemon’s environment and restart it.

A reviewer failed or timed out

Confirm its executable is on the daemon’s PATH and that the CLI can authenticate outside review-relay. Check model and effort support. Read that reviewer’s JSON in the report directory for the error and raw output. Increase timeoutMs if needed, then restart.

A failed job can retry on a later trigger. A partial review is completed, so use a mention or run to request it again.

Config edits had no effect

Run info with the same --config as the daemon. It flags unapplied edits, missing binaries, and missing clones. The daemon does not hot-reload its config; use restart.

The report exists but there is no PR comment

Check postToPr, GitHub authentication, and permission to comment. If every reviewer failed, the relay saves the report without publishing. Read comment.md and the log before retrying.

Port conflict, stale daemon, or leftover webhooks

status distinguishes a live relay from a stale daemon record or a different listener. Do not stop an unrelated service. Choose another port or stop the correct relay before starting again.

Forced exits and Windows shutdown can leave temporary webhooks behind. Inspect the repository’s Settings → Webhooks and remove only hooks you can identify as stale relay forwarders.

Git cannot fetch the PR

Check that localPath is an existing clone with an origin remote pointing at the configured GitHub repository. Confirm Git authentication works for that remote. The relay fetches the base branch and refs/pull/N/head, including fork PRs.

Back to quick startBack to the landing page