Run reviews on your own machine
The runner is open source (MIT) and connects to the MergeJudge hosted service. Source on GitHub · npm package.
The runner lets the hosted MergeJudge do the model step of a review on your own computer, with your own Claude Code or Codex (ChatGPT) login, or a GLM API key. The hosted app still handles GitHub events, lanes, the panel and posting the review. Your machine only takes a job, runs claude, and sends the result back.
What the runner does
- Connects out over HTTPS to MergeJudge and asks for review jobs. It opens no inbound ports.
- For each job it starts an engine CLI with no tools (or a read-only sandbox) and an empty temporary directory, gives it the review prompt on stdin, and returns the JSON answer.
- Supports the
diffandcontextmodes.deepjobs run on the runner only withrunner.code_source: local(see Privacy below). - Keeps a small config file (runner id and token) readable only by you.
Requirements
- Node.js 20 or newer.
- At least one engine: Claude Code signed in (run
claudeonce), and/or the Codex CLI signed in with ChatGPT (codex login; an API-key login is not accepted), and/or a z.ai API key for GLM. - macOS or Linux for auto-start. Other systems can run it by hand.
- The MergeJudge GitHub App installed on the account or organization whose repositories the runner will review, and you must administer that installation.
Set up
On the machine that will do the reviews:
npx mergejudge-runner setupIt prints a short code and a GitHub address. Open the address, enter the code and approve the sign-in. If you administer several installations, pick one (or pass --installation <id>). MergeJudge uses your GitHub sign-in once to check which installations you may administer and does not keep it.
Prefer the panel? Runners > Add runner shows a one-time code (valid 15 minutes); run npx mergejudge-runner setup <code> instead. Setup:
- registers the runner and writes the config to
~/.config/mergejudge-runner/config.json(file0600, folder0700); - checks that
claude(claude auth status) andcodex(codex login status) are installed and signed in, and warns with instructions if not (this is not an error). Signed-in engines are offered by the runner; - asks whether to also add a GLM (z.ai) API key, yes or no. The key is stored in the config file (
0600) and never printed; - asks whether to start the runner automatically at login;
- prints the runner status. It never prints the runner token or a key.
Flags: --yes (accept auto-start without asking), --no-autostart, --print-unit (print the launchd / systemd file and write nothing), --name <name>, --force (replace an existing registration), --engine <claude-code|codex|glm> (the runner's default engine), --model [engine=]<model> (repeatable: the first model of an engine is its default, more are offered to repos that ask for them, * offers any), --glm-key-env NAME (read the GLM key from that environment variable instead of asking) and --no-glm (do not ask). Set MERGEJUDGE_URL to point at a different MergeJudge Worker.
Engines and models
| Engine | Uses | Billing |
|---|---|---|
claude-code | your Claude subscription login (claude -p, no tools) | subscription |
codex | your ChatGPT login (codex exec --sandbox read-only) | subscription |
glm | Claude Code pointed at z.ai (https://api.z.ai/api/anthropic) with your z.ai API key | API key, billed per use |
The runner tells MergeJudge which engines and models it offers (when it registers and again each time it starts). Pick what a repo uses, strongest first:
the panel: Runners, then the repository's Engine and Model fields (shown when runner reviews are on);
runner:in.mergejudge.ymlon the base branch:yamlrunner: engine: codex model: gpt-5the runner's own default (
setup --engine/--model).
If a runner does not offer the engine or model a repo asks for, it hands the job back with a reason and the job stays queued for another runner (it expires after 24 hours like any queued job). Old runners (0.1.0) are treated as claude-code with its default model. The comment footer shows what ran, for example Mode: runner:codex · model: gpt-5; GLM shows runner:glm (API key).
Auto-start
- macOS: a LaunchAgent at
~/Library/LaunchAgents/si.mergejudge.runner.plist. If/etc/ssl/cert.pemexists andNODE_EXTRA_CA_CERTSis not set, it is added so Node trusts your system certificates. Logs go to~/Library/Logs/mergejudge-runner.log. - Linux: a systemd user unit at
~/.config/systemd/user/mergejudge-runner.service. To keep it running after you log out, runloginctl enable-linger $USER. Logs:journalctl --user -u mergejudge-runner.
Setup copies the runner to ~/.config/mergejudge-runner/runner.mjs, so the service keeps working after the npx cache is cleaned. Run setup again with --force to update it.
Without auto-start, start it by hand: npx mergejudge-runner run. Check on it with npx mergejudge-runner status.
Stopping and uninstalling
- macOS:
launchctl bootout gui/$(id -u)/si.mergejudge.runner && rm ~/Library/LaunchAgents/si.mergejudge.runner.plist - Linux:
systemctl --user disable --now mergejudge-runner.service && rm ~/.config/systemd/user/mergejudge-runner.service - Then delete
~/.config/mergejudge-runnerand revoke the runner in the panel so its token stops working.
A runner that is off simply takes no jobs.
Privacy: what MergeJudge's servers see
With deep-local mode, the AI review runs on your machine with your own AI login and reads your code from your own git clone. The AI step and code index run on your machine. Our servers still read the pull request diff from GitHub to run the rule checks, and don't store it. They keep only the review result: the lane, the reasons, the summary and the findings. Findings can quote short lines of code. This is the same text that's posted on your pull request.
In the default diff and context modes, the hosted service passes the PR diff, your policy files and related code snippets to your runner through its job queue, so they pass through and are held on our servers until the review finishes, and deleted within about 48 hours at the latest. Choose deep-local (review.mode: deep and runner.code_source: local) to run the AI step and code index on your machine instead. Your code is always sent to your own AI provider under your own account.
What stays on your machine
- Your Claude and ChatGPT logins never leave your machine. The runner does not read them; the CLIs use them locally.
- The runner passes each CLI a minimal environment and always removes
ANTHROPIC_API_KEY,OPENAI_API_KEYandCODEX_API_KEY, soclaude-codeandcodexreviews use your signed-in subscription and are never billed to an API key. - The GLM key is the one exception: it is set (as
ANTHROPIC_AUTH_TOKEN, withANTHROPIC_BASE_URL) only in the environment of the GLM child process, never on a command line, and is masked in logs. Those reviews are billed to your z.ai account. - In the default modes, MergeJudge sends the runner the diff and review context for the job. In deep-local mode the job carries no code. Either way, the runner sends back the review result only.
- Logs do not contain the token or the pull request content.
Personal use
The runner uses your own Claude subscription. Check your provider's conditions of use before using it: consumer subscriptions are generally meant for personal use, so do not share one login across a team or run it as a service for other people. For team or shared use, add a provider API key in the panel instead (see LLM providers).