mergejudge-runner 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gaurav Sharma
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,90 @@
1
- # Temporary Holding Version
1
+ # mergejudge-runner
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Runs the model step of a MergeJudge review on **your own machine**, with your own Claude Code or Codex (ChatGPT) login, or a GLM (z.ai) API key. MergeJudge Cloud keeps handling GitHub events, lanes, the panel and posting; the runner connects **out** over HTTPS (protocol `/runner/v1`), takes review jobs, and sends back a result. No inbound ports.
4
+
5
+ Status: MVP. Design: [docs/RUNNERS_DESIGN.md](../../docs/RUNNERS_DESIGN.md).
6
+
7
+ ## Quick start
8
+
9
+ ```sh
10
+ npx mergejudge-runner setup <code> # code from the panel: Runners > Add runner
11
+ ```
12
+
13
+ Registers the runner, detects which of `claude` and `codex` are installed and signed in (`claude auth status`, `codex login status`; Codex counts only when signed in **with ChatGPT**, an API-key login is warned about and codex is not offered), asks yes/no about a GLM (z.ai) API key, and offers to start it at login (launchd / systemd user unit). Flags: `--yes`, `--no-autostart`, `--print-unit`, `--engine <claude-code|codex|glm>`, `--model [engine=]<model>` (repeatable), `--glm-key-env NAME`, `--no-glm`; `MERGEJUDGE_URL` overrides the server. See the [guide](https://mergejudge.si/guide/run-on-your-machine).
14
+
15
+ ## Install (from source)
16
+
17
+ Needs Node >= 20 and the [Claude Code](https://code.claude.com) CLI (`claude`), logged in.
18
+
19
+ ```sh
20
+ git clone https://github.com/gauravsharmaGG/mergejudge && cd mergejudge
21
+ npm ci
22
+ npm run build --prefix packages/runner # writes packages/runner/dist/cli.js (git-ignored)
23
+ alias mergejudge-runner="node $PWD/packages/runner/dist/cli.js"
24
+ ```
25
+
26
+ The bundle includes the shared review code (`src/`), so the prompt, JSON parsing and result format are identical to the Worker and the Action.
27
+
28
+ ## Register
29
+
30
+ Create an enrollment code in the MergeJudge panel (valid 15 minutes, single use), then:
31
+
32
+ ```sh
33
+ mergejudge-runner register --code mjr_e_... --url https://app.mergejudge.si --name my-mac
34
+ ```
35
+
36
+ This stores the runner id and token in `$XDG_CONFIG_HOME/mergejudge-runner/config.json` (default `~/.config/...`). The directory is `0700`, the file `0600`, written atomically. The runner **refuses to start** if the file is readable by group or others. Only `https://` URLs are accepted (`http://` only for localhost). Use `--force` to replace an existing registration, `--claude-bin /path/to/claude` to pin the binary.
37
+
38
+ ## Engines and models
39
+
40
+ | Engine | What runs | Billing |
41
+ |---|---|---|
42
+ | `claude-code` | `claude -p --tools ""` on your subscription | subscription |
43
+ | `codex` | `codex exec --sandbox read-only --skip-git-repo-check --ephemeral --color never --ignore-user-config [-m MODEL] --output-schema <file> -o <file> -` (prompt on stdin, ChatGPT login) | subscription |
44
+ | `glm` | `claude -p` with `ANTHROPIC_BASE_URL=https://api.z.ai/api/anthropic` and `ANTHROPIC_AUTH_TOKEN=<your key>` set only in the child env | **API key (billed per use)** |
45
+
46
+ - The runner declares its engines, billing and models when it registers and on the runner heartbeat at every start. The config keeps `engine` (default), `engines: { name: { model, models } }` and, for GLM, `glmApiKey` (config is `0600`; `ZAI_API_KEY` in the environment works too). `models: ["*"]` offers any model.
47
+ - A repo can ask for an engine/model in the panel or in `.mergejudge.yml` (`runner.engine`, `runner.model`; the panel wins). If this runner does not offer it, the job is nacked with `code: "unsupported"` and a reason, no attempt is used, and it stays queued for other runners.
48
+ - A 0.1.0 config (no `engines`) keeps working as `claude-code` with the default model.
49
+ - Codex needs a ChatGPT sign-in: at startup the runner runs `codex login status` and drops codex from its capabilities on an API-key login or no login; a codex job that still arrives is nacked `unsupported` with that reason.
50
+ - Never passed to any engine: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `CODEX_API_KEY`, the runner token. The z.ai key is only in the GLM child's env and is masked in logs.
51
+
52
+ ## Run
53
+
54
+ ```sh
55
+ mergejudge-runner run # long-poll forever
56
+ mergejudge-runner run --once # handle one job (or exit if none is waiting), then exit
57
+ mergejudge-runner run --concurrency 2 # capped by the concurrency registered with the server
58
+ ```
59
+
60
+ - Heartbeats every <= 20 s while a job runs (lease is 60 s). If the server answers `cancel: true` (a newer push superseded the job) or the lease is lost, the `claude` process tree is killed and nothing is submitted.
61
+ - Per-job timeout 10 min (`--job-timeout-min`); on timeout the process tree is killed and the job is nacked.
62
+ - Errors (bad engine output, crash, unsupported job) are **nacked** with a short reason; the server retries up to its limit.
63
+ - Network errors, 5xx and 429 back off exponentially with jitter; `Retry-After` is honoured.
64
+ - `SIGINT`/`SIGTERM`: stop polling, give in-flight jobs 30 s to finish, then kill the engine and nack them ("runner shutting down") and exit. A second signal exits immediately.
65
+ - The access token is rotated through `/token/rotate` when it has < 14 days left (or when a response carries an `x-mergejudge-rotate` header). The new token is written to the config file (atomic rename) **before** it is used.
66
+ - Modes: `diff` and `context`. **`deep` is not supported** in this MVP: such a job is nacked with a clear reason (the runner advertises only `diff` and `context`, so the server should not lease it).
67
+
68
+ ## Status
69
+
70
+ ```sh
71
+ mergejudge-runner status
72
+ ```
73
+
74
+ Prints the config (token shown as its first 10 characters only), whether the Worker is reachable, and the result of a runner-level heartbeat (which also extends the leases the Worker holds for this runner).
75
+
76
+ ## Keep it running
77
+
78
+ - macOS: [examples/si.mergejudge.runner.plist](examples/si.mergejudge.runner.plist) (LaunchAgent, `KeepAlive`, logs to `~/Library/Logs`). It contains no secrets.
79
+ - Linux: a systemd user unit with `ExecStart=node /path/to/dist/cli.js run`, `Restart=always`, `TimeoutStopSec=45`.
80
+
81
+ Logs go to stderr.
82
+
83
+ ## Security notes
84
+
85
+ - **Subscription use is personal only.** The `claude-code` engine uses *your* Claude subscription login on *your* machine, reviewing *your own* repos. Do not share one subscription with a team, resell it, or run it for an org install; teams should use API-key engines (not in this MVP). Anthropic's terms were checked on 14 Oct 2026 and must be re-checked before launch; see [RUNNERS_DESIGN.md sections 9 and 10](../../docs/RUNNERS_DESIGN.md). Not legal advice.
86
+ - **`ANTHROPIC_API_KEY` must stay unset.** If it is set, Claude Code bills the API instead of your subscription. The runner never passes it (or `ANTHROPIC_AUTH_TOKEN`, any `MERGEJUDGE_*`, `OPENAI_*`, `GITHUB_*`, `AWS_*`, the runner token) to `claude`. The child gets a minimal allowlist copy of the environment (`PATH`, `HOME`, `USER`, `LANG`, `TMPDIR`, `XDG_*`, `CLAUDE_CONFIG_DIR`, proxy and CA variables, `CLAUDE_CODE_OAUTH_TOKEN` for `claude setup-token` logins). Unset `ANTHROPIC_API_KEY` in your own shell/service too, so `claude` is not confused by your global setup.
87
+ - **PR content is untrusted.** The prompt goes to `claude -p` on **stdin** (never argv, so it is not visible in `ps`), the CLI runs with `--tools ""` (no tools at all), an empty temp directory as cwd, no session persistence, and no slash commands. The model can only answer with text, which the shared parser validates; the Worker then applies its own floor (a runner can raise a lane, never lower it).
88
+ - **Token storage.** The runner token (`mjr_a_...`) is a bearer credential for your installation's review jobs. It lives only in the 0600 config file; it is never logged (logs hold job ids, repo/PR numbers, durations and sizes; a redaction filter masks token shapes as a safety net) and never passed to the engine. Revoke or rotate it in the panel if a machine is lost. The runner follows no redirects, so the token cannot be forwarded to another origin.
89
+ - **What the runner sees.** Job payloads contain the PR diff, title/body, the repo's policy files and (context mode) related files. Nothing is written to disk by the runner except the config file.
90
+ - The `claude` process runs as you. Run the runner under a dedicated OS user if you do not want PR text processed in your main account.