argus-review 0.1.0 → 0.2.1

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/README.md CHANGED
@@ -22,10 +22,11 @@ It runs four ways, from the same engine and settings:
22
22
  7. **Cross-file pass.** Catches contract changes whose callers were not updated.
23
23
  8. **Secret scan.** Deterministic detection of keys and tokens in added lines.
24
24
  9. **Verification.** A second model pass, also able to explore the repository, re-derives every finding from the code and discards speculation, already-handled cases and style noise. Each finding gets a 0-10 score. A skeptical second verifier must also confirm every critical finding. Verification fails closed: a finding without a usable verdict (verifier error, missing or unknown verdict) is suppressed, with the reason recorded.
25
- 10. **Proof.** In a Docker sandbox, Argus installs the dependencies (with network) and runs the test suite (without network). It detects vitest, jest, `node --test`, `npm test`, pytest and go test. A failing test that passes on the base branch is reported as a regression. For serious findings the model writes a test that should fail because of the bug. It is marked as reproduced only if the test fails and then passes once the suggested fix is applied (or there is no suggested fix).
25
+ 10. **Proof (opt-in, `execution.enabled: true`).** It runs pull request code, so it is off by default. In a Docker sandbox, Argus installs the dependencies (with network) and runs the test suite (without network). It detects vitest, jest, `node --test`, `npm test`, pytest and go test. A failing test that passes on the base branch is reported as a regression. For serious findings the model writes a test that should fail because of the bug. It is marked as reproduced only if the test fails and then passes once the suggested fix is applied (or there is no suggested fix).
26
26
  11. **Follow-up.** On every push, findings whose code changed are re-checked; fixed ones get a "✅ Fixed in abc123" reply and their thread is resolved. Fixes, 👍/👎 reactions and replies such as "false positive" are tracked per category, and categories a team keeps dismissing need more confidence.
27
27
  12. **Anchoring and dedupe.** Quoted code is relocated to the right lines and mapped onto the diff. Near-duplicates are merged, and findings posted in earlier reviews are not repeated.
28
28
  13. **Publish.** Inline comments go out with severity, category, the analyzers that confirm them, how many passes found them, a committable suggestion and a "prompt for AI agents". One persistent summary comment holds the walkthrough, a changes table, a sequence diagram, the review effort and findings outside the diff. The PR is optionally approved or marked as changes requested; approval is only given when the review ran to completion (no errors, no unverifiable findings, no files skipped for the size limits, at least one file reviewed).
29
+ 14. **Merge gate.** An `argus` commit status goes to pending when the review starts and ends as failure (a finding of at least `review.status.failOn`, default major), error (the review did not complete, timed out or crashed) or success. Make it a required check to block merges until Argus passes; see [Blocking merges](#blocking-merges).
29
30
 
30
31
  Every dropped candidate is kept with its reason, and the web UI shows it under **Filtered out**.
31
32
 
@@ -36,14 +37,32 @@ Every dropped candidate is kept with its reason, and the web UI shows it under *
36
37
 
37
38
  ## Install
38
39
 
40
+ Pick one:
41
+
42
+ ```sh
43
+ npm install -g argus-review # the `argus` CLI with the web UI, Node 22.12+
44
+ docker compose -f deploy/docker-compose.yml up -d # server in Docker (copy deploy/.env.example to deploy/.env first)
45
+ ```
46
+
47
+ The Docker image `ghcr.io/anevski-stefan/argus` is private. To pull it, the image owner adds you under the package's **Manage access** on GitHub, and you sign in once with a GitHub token that has the `read:packages` scope:
48
+
49
+ ```sh
50
+ echo "$GITHUB_TOKEN" | docker login ghcr.io -u <your-github-user> --password-stdin
51
+ ```
52
+
53
+ Without access, build the image from a checkout instead: `docker compose -f deploy/docker-compose.yml up -d --build`.
54
+
55
+ On a plain Ubuntu or Debian VM (x86 or ARM, for example Oracle Cloud Always Free), `deploy/install-server.sh` installs Node 22, `argus-review`, a systemd service and Caddy with HTTPS on `<public-ip>.sslip.io`: `sudo ARGUS_ADMIN_EMAIL=you@example.com bash install-server.sh`.
56
+
57
+ From source:
58
+
39
59
  ```sh
40
- git clone <this repository> argus && cd argus
41
- npm install # no .npmrc or --legacy-peer-deps needed
42
- npm run build
60
+ git clone https://github.com/anevski-stefan/argus.git && cd argus
61
+ npm install && npm run build
43
62
  npm link -w @argus/server # puts `argus` on your PATH
44
63
  ```
45
64
 
46
- For development without building, use `bin/argus` (it runs the TypeScript sources directly).
65
+ For development without building, use `bin/argus` (it runs the TypeScript sources directly). Releases are listed in [CHANGELOG.md](CHANGELOG.md).
47
66
 
48
67
  ## Server and web UI
49
68
 
@@ -52,7 +71,7 @@ argus serve # http://127.0.0.1:4747, data in ~/.argus
52
71
  argus serve --port 8080 --host 0.0.0.0
53
72
  ```
54
73
 
55
- In the UI:
74
+ On the first visit, create the admin with the setup token printed at start-up (see [Access and exposure](#access-and-exposure)). Then, in the UI:
56
75
 
57
76
  1. **Models & providers.** Add an API key, or log in to `claude` / `codex` / `copilot` in a terminal to use your plan. Pick a model for each stage (review, verification, summary, chat) and press **Test connection**.
58
77
  2. **Repositories.** Connect GitHub, GitLab, Bitbucket or Azure DevOps with a token (the dialog lists the exact permissions), then add repositories.
@@ -62,8 +81,8 @@ Tokens and API keys are encrypted at rest (AES-256-GCM, key in `~/.argus/secret.
62
81
 
63
82
  ### Access and exposure
64
83
 
65
- - **Loopback only, no users:** `argus serve` on `127.0.0.1` is open to requests made straight from the same machine: a loopback peer, a loopback `Host` header (`localhost`, `127.0.0.1`, `[::1]`, any port), no proxy headers (`X-Forwarded-For`, `Forwarded`, `X-Real-IP`, `X-Forwarded-Host`/`-Proto`, `Via`) and no public URL pointing elsewhere. Anything else is locked as below. A proxy or tunnel on the same host (nginx, `ssh -R`, socat, ngrok) must therefore not be relied on to look remote by itself: have it send `X-Forwarded-For` (nginx: `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`), or set a public URL in Settings → Server, which turns open mode off.
66
- - **Reachable from the network (or through a proxy), no users:** the API is **locked** (`401 {setupRequired: true}`) until the first admin is created. Whenever there are no users and no shared password, the server prints a one-time setup token at start-up, whatever address it listens on (all replicas print the same token, which is stored in the database); the web UI asks for it on the first visit. Alternatively set `ARGUS_ADMIN_EMAIL` and `ARGUS_ADMIN_PASSWORD`, and that admin is created at start-up. `ARGUS_ALLOW_OPEN=1` serves without sign-in on purpose, for example behind an authenticating proxy.
84
+ - **No users yet:** the API is **locked** (`401 {setupRequired: true}`) until the first admin is created, whatever address Argus listens on. The server prints a one-time setup token at start-up and the web UI asks for it on the first visit. Alternatively set `ARGUS_ADMIN_EMAIL` and `ARGUS_ADMIN_PASSWORD`, and that admin is created at start-up.
85
+ - **Without sign-in, on purpose:** `ARGUS_ALLOW_OPEN=1` serves every request as admin while there are no users, for example behind an authenticating proxy or for local development. Creating the first user turns it off.
67
86
  - **Host and Origin checks:** requests must use a loopback host, the public URL's host or a name in `ARGUS_ALLOWED_HOSTS` (comma-separated, `*.example.com` allowed, `*` turns the check off). State-changing API calls must not come from another origin and must send their body as `application/json`. Webhooks are exempt and authenticated by their own signatures.
68
87
  - **Behind a reverse proxy:** set `ARGUS_TRUST_PROXY=1` so `X-Forwarded-For`/`-Proto`/`-Host` are honoured (client IPs for login throttling, `Secure` cookies). Only set it when Argus is reachable exclusively through that proxy.
69
88
  - **Sessions:** signing out ends every session of that user, and a password or role change ends that user's other sessions. Failed sign-ins are throttled per email and per IP.
@@ -74,17 +93,13 @@ Boolean variables accept `1`/`true`/`yes` and `0`/`false`/`no`.
74
93
  |---|---|
75
94
  | `ARGUS_DATA_DIR` | Data directory (default `~/.argus`) |
76
95
  | `ARGUS_SECRET_KEY` | Passphrase for encrypting stored secrets (otherwise a key file is generated) |
77
- | `ARGUS_CONCURRENCY` | Reviews that run in parallel per process (default 2) |
78
- | `ARGUS_DATABASE_URL` | `postgres://…` to store everything in PostgreSQL instead of SQLite |
79
- | `ARGUS_WORKER=0` | Serve the UI and webhooks only; reviews run on `argus worker` processes |
96
+ | `ARGUS_CONCURRENCY` | Reviews that run in parallel, a whole number of at least 1 (default 2) |
80
97
  | `ARGUS_ADMIN_EMAIL`, `ARGUS_ADMIN_PASSWORD` | Create this admin at start-up if it does not exist |
81
- | `ARGUS_ALLOW_OPEN=1` | Serve without sign-in even on a network address (see above) |
98
+ | `ARGUS_ALLOW_OPEN=1` | Serve without sign-in while there are no users (see above) |
82
99
  | `ARGUS_ALLOWED_HOSTS` | Extra host names the dashboard is reached by |
83
100
  | `ARGUS_TRUST_PROXY=1` | Honour `X-Forwarded-*` headers from a reverse proxy |
84
- | `ARGUS_SHUTDOWN_GRACE_MS` | How long a stopping process lets running reviews finish before handing them back to the queue (default 25000). Heartbeats continue meanwhile, so it may exceed the 90-second staleness window; keep it below the orchestrator's kill timeout (Kubernetes `terminationGracePeriodSeconds`) |
101
+ | `ARGUS_SHUTDOWN_GRACE_MS` | How long a stopping process lets running reviews finish before handing them back to the queue (default 25000). Keep it below your process manager's kill timeout (Docker `stop_grace_period`) |
85
102
  | `ARGUS_GIT_TIMEOUT_MS` | Timeout for git operations on the local mirror (default 300000) |
86
- | `ARGUS_CHAT_RATE_LIMIT` | Chat comments handled per pull request per 10 minutes (default 10) |
87
- | `ARGUS_WEBHOOK_MAX_BYTES` | Largest accepted webhook body (default 5 MB) |
88
103
  | `ARGUS_EXEC_DIR` | Directory for test-sandbox workspaces (default: the system temp dir) |
89
104
  | `ARGUS_SANDBOX_NETWORK` | Docker network for the dependency install phase |
90
105
  | `OPENROUTER_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `OPENAI_COMPATIBLE_API_KEY` | Provider keys, used when none is stored in the UI. Vendor keys only go to the vendor's default endpoint |
@@ -94,13 +109,11 @@ Boolean variables accept `1`/`true`/`yes` and `0`/`false`/`no`.
94
109
 
95
110
  **People and roles.** Under **Settings → Team & access**, create the first admin; from then on everyone signs in with an email and password. Viewers see everything, maintainers also start, cancel and retry reviews and edit learnings and per-repository settings, admins manage integrations, models, keys, global settings and users. Listing and testing models, the GitHub App setup and listing an integration's remote repositories are admin-only too. In repository settings, maintainers cannot set the keys that only the operator may change (models, execution, analyzer configuration, ticket allow-lists, approvals, the cost cap; see [Trust model](#trust-model)); the server ignores them and the UI says which.
96
111
 
97
- **PostgreSQL and workers.** Set `ARGUS_DATABASE_URL` and every Argus process shares one database. The queue lives in it: `argus serve --no-worker` serves the UI and webhooks, and any number of `argus worker` processes claim reviews (`FOR UPDATE SKIP LOCKED`), send heartbeats and pick up cancellations. A review whose worker dies is marked failed after 90 seconds. All processes need the same `ARGUS_SECRET_KEY`.
98
-
99
- **Docker.** `docker build -t argus .` builds a small image that runs as a non-root user. `deploy/docker-compose.yml` starts PostgreSQL, the web process and two workers (copy `deploy/.env.example` to `deploy/.env` first; admin credentials are required). For the test sandbox, build with `--build-arg DOCKER_CLI=true` (adds only the static Docker client) and mount the Docker socket into the workers. The worker user then needs the socket's group (`group_add`), and because the daemon resolves bind mounts on the host, the workspace directory must exist at the same path on the host and in the container: point `ARGUS_EXEC_DIR` (and `TMPDIR`) at it. `docker-compose.yml` has the commented block. Socket access is root-equivalent on the host.
112
+ **Storage.** Everything lives in one SQLite database in the data directory, with a queue in it that survives restarts: a graceful shutdown hands unfinished reviews back to the queue, and a review left running by a process that crashed or was killed is marked failed at the next start. One Argus process serves one data directory; do not point several processes at the same one. To review more pull requests at once, raise `ARGUS_CONCURRENCY`.
100
113
 
101
- **Kubernetes.** The image is not published: build and push it (`docker build -t registry.example.com/argus:<version> .`) and set `image.repository`; `image.tag` defaults to the chart's `appVersion`. `helm install argus deploy/helm/argus --set secret.secretKey=… --set postgres.password=… --set secret.adminEmail=… --set secret.adminPassword=…` deploys the web process, the workers and (optionally) PostgreSQL; the chart refuses to render without admin credentials unless `allowOpen=true`. Point `secret.databaseUrl` at a managed database with `postgres.enabled=false`. `web.replicas` can be raised: sessions, the setup token and the GitHub App setup state are signed or stored in the database. With the ingress enabled, `ARGUS_ALLOWED_HOSTS` and `ARGUS_TRUST_PROXY` are set from it. `worker.dind.enabled` adds a privileged Docker-in-Docker sidecar for the test sandbox; it needs a worker image built with `--build-arg DOCKER_CLI=true` (`worker.image`), shares the exec directory with the sidecar, and cannot be combined with `worker.runtimeClassName`. `web.extraEnv` and `worker.extraEnv` pass further variables.
114
+ **Docker.** `docker build -t argus .` builds a small image that runs as a non-root user. `deploy/docker-compose.yml` starts Argus with its data in a volume (copy `deploy/.env.example` to `deploy/.env` first; admin credentials are required). For the test sandbox, build with `--build-arg DOCKER_CLI=true` (adds only the static Docker client) and mount the Docker socket into the container. The container user then needs the socket's group (`group_add`), and because the daemon resolves bind mounts on the host, the workspace directory must exist at the same path on the host and in the container: point `ARGUS_EXEC_DIR` (and `TMPDIR`) at it. `docker-compose.yml` has the commented block. Socket access is root-equivalent on the host.
102
115
 
103
- **Upgrading from an earlier version.** All sessions are invalidated, so everyone signs in again; stored secrets still decrypt. Repository settings saved before the upgrade are not known to be admin-written, so their admin-only keys are ignored until an admin saves that repository's settings again. The test sandbox's old shared cache volumes (`argus-deps`, `argus-cache-*`) are no longer used and can be removed with `docker volume rm`. The upgrade folds duplicate queued reviews of the same pull request into one; during a rolling upgrade, processes still on the old version may briefly answer 500 when a second review of a pull request is queued while one is already waiting (that request is dropped; the queued review still runs), so upgrade all processes together where possible. Argus now recognises its own comments by its account (the token's user, or `<app-slug>[bot]` for a GitHub App); if that lookup fails, the review fails before posting anything and the next one tries again, rather than posting duplicate comments or a second summary. A loopback-bound server that has a public URL set, or is reached through a proxy, now requires sign-in (see [Access and exposure](#access-and-exposure)).
116
+ **Upgrading.** Stop Argus, back up the data directory (the database and `secret.key`, or keep `ARGUS_SECRET_KEY`), install the new version and start it again; database migrations run at start-up. Coming from 0.1.0, the shared dashboard password is gone: create an admin with the setup token printed at start-up (or `ARGUS_ADMIN_EMAIL`/`ARGUS_ADMIN_PASSWORD`).
104
117
 
105
118
  **npm.** `npm run pack:npm` produces `argus-review-<version>.tgz`: one bundled CLI with the web UI, installable with `npm install -g` on any machine with Node 22.
106
119
 
@@ -133,11 +146,11 @@ argus hook install # run on every commit; ARGUS_FAIL_ON=major blocks
133
146
 
134
147
  ## CI
135
148
 
136
- `argus ci` detects GitHub Actions, GitLab CI merge request pipelines, Bitbucket pull request pipelines and Azure Pipelines pull request builds, and it answers `@argus` comments in GitHub Actions. Ready-made workflow files are in the web UI under **Server & CI**. They pin `argus-review` to the server's version, and the GitHub workflow only reacts to comments whose `author_association` is `OWNER`, `MEMBER` or `COLLABORATOR`. They call `npx argus-review`, which needs the package published to npm or a private registry. Until then, switch on **Build Argus from source**, which clones the repository (`main`; there are no version tags yet), runs `npm ci` and calls `bin/argus ci`. In CI, `.argus.yml` is read from the target branch like on the server, and API keys only go to endpoints configured outside the repository.
149
+ `argus ci` detects GitHub Actions, GitLab CI merge request pipelines, Bitbucket pull request pipelines and Azure Pipelines pull request builds, and it answers `@argus` comments in GitHub Actions. Ready-made workflow files are in the web UI under **Server & CI**, and for each repository added as reviewed in CI (see [Connecting CI to the dashboard](#connecting-ci-to-the-dashboard)). They pin `argus-review` to the server's version, and the GitHub workflow only reacts to comments whose `author_association` is `OWNER`, `MEMBER` or `COLLABORATOR`. They call `npx argus-review`, which needs the package published to npm or a private registry. Until then, switch on **Build Argus from source**, which clones the repository (`main`; there are no version tags yet), runs `npm ci` and calls `bin/argus ci`. In CI, `.argus.yml` is read from the target branch like on the server, and API keys only go to endpoints configured outside the repository.
137
150
 
138
151
  | Platform | Token |
139
152
  |---|---|
140
- | GitHub | `GITHUB_TOKEN` (provided by Actions; needs `pull-requests: write`) |
153
+ | GitHub | `GITHUB_TOKEN` (provided by Actions; needs `pull-requests: write` and `statuses: write`) |
141
154
  | GitLab | `GITLAB_TOKEN`: a token with the `api` scope (the built-in job token cannot post comments) |
142
155
  | Bitbucket | `BITBUCKET_TOKEN`: a repository access token with pull request write |
143
156
  | Azure DevOps | `SYSTEM_ACCESSTOKEN` (the pipeline's `$(System.AccessToken)`; allow the build service to contribute to pull requests) |
@@ -155,8 +168,49 @@ The generator on **Server & CI** has a provider and a model field (free text; th
155
168
 
156
169
  Codex logins refresh, so Argus writes the new login back to the CI secret after each run, also when the job is cancelled or times out. It can only update the current repository's own secret, so use **one ChatGPT login per repository**: run `codex login` and `argus codex-secret` separately for each repository and store the value as a repository-level (GitLab: project-level) secret, not an organization, group or workspace one. Two repositories sharing one login break each other: every refresh rotates the login, and the repository that did not refresh is left with a dead one. `ARGUS_CODEX_AUTH` is only used when a model in the review runs on Codex; with another provider it is ignored. `ARGUS_SECRET_WRITE_TOKEN` needs: GitHub, a fine-grained PAT with "Secrets: write"; GitLab, a project access token with `api` (Maintainer); Bitbucket, a repository access token with "Pipelines: Edit variables"; Azure, a PAT with "Variable Groups (Read, create, & manage)". Limits: Codex runs on private repositories only, one run at a time (the generated file serialises runs: `queue: max` on GitHub, `resource_group` on GitLab, `concurrency-group` on Bitbucket, `lockBehavior: sequential` plus an Exclusive lock check you add to the `argus-codex` environment on Azure), and on Azure the secret lives in a dedicated variable group (`ARGUS_AZURE_VARIABLE_GROUP_ID`) that holds nothing else.
157
170
 
171
+ ### Connecting CI to the dashboard
172
+
173
+ A CI run can pull its settings from an Argus dashboard and send each review back to it, so the reviews show up next to the ones the server ran. Under **Repositories → Add → Reviewed in CI**, enter the platform, host and `owner/name` (or the repository URL). Argus adds the repository and shows its **repository token** once, together with a pipeline generated for it (it points at the dashboard's public URL: the one set under **Server & CI**, else `ARGUS_PUBLIC_URL`, else the page's own address). A repository added through an integration has no CI token; to connect its CI, remove it and add it again as **Reviewed in CI**. Add two things to the repository's CI settings:
174
+
175
+ | Name | Kind | Value |
176
+ |---|---|---|
177
+ | `ARGUS_URL` | Variable (the generated file sets it in the job's environment; with your own file, set it there or as a CI variable) | The dashboard's public URL, for example `https://argus.example.com`. It must be `https://`; `http://` is accepted only for `localhost` (any other `http://` URL prints a warning, because the token and the results would travel unencrypted) |
178
+ | `ARGUS_TOKEN` | Secret | The token shown when you added the repository (`argus_…`) |
179
+
180
+ `argus ci` talks to the dashboard only when both are set; with one of them missing it warns and reviews as before. The token only works for its own repository (another one gets 403 `This token belongs to <owner>/<name>`), and GitHub Actions masks it in the log. The repository's page in the dashboard shows the token's prefix, when it was created and last used, and has **Regenerate token** (shows a new token once; the old one stops working at once) and **Revoke** (CI then neither pulls settings nor sends results until an admin creates a new token). A rejected token (401 or 403) is reported in the job log, with what to fix.
181
+
182
+ **Settings.** Before the review, `argus ci` reads the repository's settings from the dashboard (global settings plus the repository's overrides). Layers, lowest first:
183
+
184
+ ```
185
+ built-in defaults ─► global config file ─► CI variables and flags (ARGUS_PROVIDER, ARGUS_MODEL, …) ─► dashboard ─► .argus.yml (target branch, admin-only keys removed)
186
+ ```
187
+
188
+ The dashboard layer is filtered in CI, so a dashboard can never make a CI job run commands or send secrets elsewhere: it may choose each model's `provider` and `model` and every review setting that is not admin-only, but never the execution and sandbox settings (sandbox, isolation, runtime, image, install and test commands, resources, timeouts), the analyzer configuration (`semgrepConfig`, analyzer timeouts), ticket allow-lists (`tickets.allowedRepos`, `tickets.projectKeys`), approvals, the cost cap, or any model's `baseUrl` or `apiKey`. It may switch `execution.enabled`, `execution.runTests`, `execution.proveFindings` and `analyzers.enabled` off, but not on: a `true` from the dashboard is ignored. Those stay in the CI flags, the CI environment or the global config file, and the job log lists any dashboard setting it ignored. API keys always come from the CI secrets.
189
+
190
+ **Reviews off.** When reviews are turned off for the repository in the dashboard, `argus ci` prints `argus: skipped — Reviews are turned off for this repository in the Argus dashboard`, posts nothing to the pull request, sends nothing to the dashboard and exits 0. The server also refuses results for such a repository (409 `Reviews are turned off for this repository`).
191
+
192
+ **Results.** After the review, skip or failure (also for `@argus` commands), `argus ci` sends the result, gzip-compressed, to `POST /api/ci/reviews`. The dashboard shows it as a CI review with a **View CI run** link; it cannot be retried or cancelled from the dashboard. The findings' outcomes (open, fixed, accepted, resolved, dismissed) are recorded like those of server reviews. **Send summary only** on the repository's page (admins) keeps only the outline (counts, titles and locations of findings, timings and usage) and leaves explanations, suggested fixes, code and the summary text on the pull request; the server enforces it on everything it stores, whatever the client sends. Results stored before the switch was turned on stay as they were stored.
193
+
194
+ **Waits.** Reading the settings waits at most 30 s and sending the result at most 30 s, retrying network errors, 5xx and 429 with 1 s, 2 s, 4 s, … backoff (401, 403, 409, 413 and an answer over 1 MB are final). If the settings cannot be read, the review runs with the CI settings only; if the dashboard rejected the token while reading them (401 or 403), the result is not sent either. Nothing the dashboard does changes the job's exit code. The generated files start a background `curl` to `$ARGUS_URL/api/health` at the start of the job, so a dashboard that sleeps when idle is awake by the time the review ends. The server accepts bodies up to 32 MiB, compressed or not (413 above that).
195
+
158
196
  The Docker sandbox needs Docker in the job. GitHub and Azure hosted Ubuntu agents have it. The GitLab file adds a `docker:27-dind` service (the runner must be privileged and x86_64; gitlab.com `saas-linux` runners are, because the job downloads the x86_64 Docker CLI). The GitLab file also sets `ARGUS_EXEC_DIR` inside the project because dind cannot see `/tmp`. Do not mark any Argus variable on GitLab Protected, or it will not reach merge request pipelines on unprotected branches. The Bitbucket file uses `services: [docker]` and Runtime v3; without Runtime v3 the sandbox is skipped and the AI review still runs. Plan availability of Runtime v3 and `concurrency-group` is not verified.
159
197
 
198
+ ## Blocking merges
199
+
200
+ Every review sets an `argus` commit status on the pull request's head commit (on Azure DevOps a pull request status `argus/review`). To block merging until Argus passes, make it required:
201
+
202
+ | Platform | Where |
203
+ |---|---|
204
+ | GitHub | Branch protection or ruleset → Require status checks → `argus` |
205
+ | GitLab | Settings → Merge requests → "Pipelines must succeed" (external statuses count) |
206
+ | Bitbucket Cloud | Branch restrictions → Require passing builds |
207
+ | Bitbucket Server / Data Center | Repository settings → Required builds → `argus` |
208
+ | Azure DevOps | Branch policies → Status checks → Add `argus/review` |
209
+
210
+ The token Argus uses needs permission to set statuses: GitHub `statuses: write` (the GitHub App manifest and the generated Actions workflow include it), GitLab the `api` scope, Azure DevOps "Contribute to pull requests". If a token may not set statuses, the review still runs and the summary says so. In CI, `--fail-on <severity>` also fails the job itself.
211
+
212
+ Change the threshold with `review.status.failOn` (`critical`, `major` or `minor`), or turn statuses off with `review.status.enabled: false`. Only the operator can change these; `.argus.yml` cannot.
213
+
160
214
  ## Using a Claude, ChatGPT or Copilot subscription
161
215
 
162
216
  Choose the provider **Claude subscription (Claude Code)**, **ChatGPT subscription (Codex)** or **GitHub Copilot**. Argus runs the official CLI in headless mode (`claude -p --json-schema …`, `codex exec --output-schema …`, `copilot`) in a read-only checkout, so reviews count against your plan instead of API billing. Usage limits of your plan apply.
@@ -164,6 +218,8 @@ Choose the provider **Claude subscription (Claude Code)**, **ChatGPT subscriptio
164
218
  - **Claude Code and Codex:** log in once with `claude` or `codex login` on the machine that runs Argus.
165
219
  - **GitHub Copilot:** the Copilot CLI gets only read-only tools (view, glob, grep). Log in with `copilot login`, or set `COPILOT_GITHUB_TOKEN` (or `GH_TOKEN`) to a fine-grained personal access token with the "Copilot Requests" permission. `GITHUB_TOKEN` is only used inside GitHub Actions; on a server it is Argus's own GitHub credential and is never handed to Copilot. The dashboard can't check a `copilot login` and shows the login as unknown until you set a token. The model is free text (for example `auto`, `claude-sonnet-5.5`, `gpt-6-luna` or `gemini-3.8-flash`); Copilot offers Claude, GPT and Gemini families.
166
220
 
221
+ **In a company.** Subscription plans belong to a person and have personal usage limits. They suit `argus local`, the pre-commit hook and small teams. Before running one plan as the reviewer for a whole team on a server, check the provider's terms. For a shared server, an API key or a company gateway that speaks the OpenAI API (provider `openai-compatible` with a base URL) is the safer choice, and `review.maxCostUsd` keeps each review bounded.
222
+
167
223
  ## Configuration
168
224
 
169
225
  Settings come in layers: built-in defaults, then global settings (UI), then repository overrides (UI), then `.argus.yml` in the repository, then command-line flags. `argus init` writes a starter file, and every repository page in the UI can export its effective settings as YAML.
@@ -173,7 +229,7 @@ Settings come in layers: built-in defaults, then global settings (UI), then repo
173
229
  A pull request author must not be able to change how Argus reviews their pull request, so `.argus.yml` and the guideline files are read from the **target (base) branch**, never from the pull request's head. What changes there takes effect after it is merged.
174
230
 
175
231
  A repository file may only tune a review (allow-list; anything else is dropped and listed in the summary comment):
176
- - `review`: language, profile, severity and confidence floors, categories, suggestions, agent prompts, incremental; numeric limits (`maxComments`, `maxFiles`, `maxCostUsd`, passes, steps, …) only lower than the operator's; extra stages (verification, cross-file, voting, agent, examples, function review, auto-resolve, adaptive feedback) can only be turned off
232
+ - `review`: language, profile, severity and confidence floors, categories, suggestions, agent prompts, incremental; numeric limits (`maxComments`, `maxFiles`, `maxCostUsd`, passes, steps, …) only lower than the operator's; extra stages (verification, cross-file, voting, agent, auto-resolve, adaptive feedback) can only be turned off
177
233
  - `summary`: presentation keys; `applyLabels` only off, `updateDescription` only towards `never` (`append` > `when-empty` > `never`)
178
234
  - `files`: include/exclude, guideline files; code graph and bug history only off; `contextDepth` only lower (`related` > `files` > `diff`); `maxContextChars` lower only
179
235
  - `autoReview`: turn off, add ignored title keywords and authors; `labels`/`baseBranches` only when the operator set none
@@ -215,16 +271,13 @@ rules:
215
271
  ```
216
272
 
217
273
  Argus can also:
218
- - **Hunt for bugs with property-based tests.** For the riskiest changed functions it writes property tests from their contract, runs them in Docker on the PR and on the base branch, and reports properties the change broke.
219
- - **Get a second opinion.** `models.second` (or `--second codex/gpt-6-luna`) adds an independent reviewer from another model family; findings both models report gain confidence.
220
274
  - **Use past bug fixes as context.** Commits that fixed bugs in the changed files are shown to the reviewer.
221
275
  - **Learn from past human reviews.** `argus learn <repo-url>`, or **Learn from past reviews** on a repository page, turns the conventions your reviewers keep asking for into suggested learnings.
222
- - **Run CodeQL** for cross-file data flow when the `codeql` CLI is installed.
223
276
  - **Cache** identical model answers, code-graph symbols and Docker dependency installs, and report time per stage.
224
277
 
225
278
  A syntax-tree code graph (tree-sitter: TypeScript, JavaScript, Python, Go, Java, Rust, Ruby, PHP, C#, C++) gives the reviewer real callers with the function they sit in, definitions, implementations and the transitive impact of a change.
226
279
 
227
- Files are routed by risk: formatting-only and trivial changes go to an optional light model without exploration, and high-risk files to an optional deep model with voting. `review.maxCostUsd` caps the spend of one review on paid APIs. When a provider reports no cost, it is estimated from the token counts, and calls in flight are counted against the cap before they finish. Local and private-network endpoints, `openai-compatible` endpoints with a custom base URL, and the `claude`/`codex` CLIs on a subscription count as free; set `inputPricePerMTok` and `outputPricePerMTok` on a model to price it yourself. A platform rate limit that resets more than a minute away fails the review with a rate-limit error instead of waiting.
280
+ Files are routed by risk: formatting-only and trivial changes go to an optional light model without exploration, and high-risk files get extra voting passes. `review.maxCostUsd` (default $5) caps the spend of one review on paid APIs, and `review.timeoutMinutes` (default 30) stops a review that runs too long. When a provider reports no cost, it is estimated from the token counts, and calls in flight are counted against the cap before they finish. Local and private-network endpoints, `openai-compatible` endpoints with a custom base URL, and the `claude`/`codex` CLIs on a subscription count as free; set `inputPricePerMTok` and `outputPricePerMTok` on a model to price it yourself. A platform rate limit that resets more than a minute away fails the review with a rate-limit error instead of waiting.
228
281
 
229
282
  ### Linked tickets
230
283
 
@@ -254,7 +307,7 @@ Anyone can ask questions and read `help`. `review`, `full review`, `review focus
254
307
  | Bitbucket Server | A token with repository or project admin; permissions granted only through groups are not visible |
255
308
  | Azure DevOps | The commenter's effective Git permissions on the repository (Contribute = write, Manage permissions = admin, group grants included); the token needs the **Identity (Read)** and **Security (Manage)** scopes, otherwise only the pull request's author can use the author commands |
256
309
 
257
- When someone with write access corrects a finding or uses `remember`, Argus stores the lesson as a **learning** scoped to the relevant paths. On the server it arrives **pending approval** (disabled): a maintainer or admin approves it under **Learnings** before later reviews apply it. In CI, Argus replies with the `.argus.yml` snippet instead. The server handles at most `ARGUS_CHAT_RATE_LIMIT` (default 10) chat comments per pull request per 10 minutes.
310
+ When someone with write access corrects a finding or uses `remember`, Argus stores the lesson as a **learning** scoped to the relevant paths. On the server it arrives **pending approval** (disabled): a maintainer or admin approves it under **Learnings** before later reviews apply it. In CI, Argus replies with the `.argus.yml` snippet instead. The server handles at most 10 chat comments per pull request per 10 minutes.
258
311
 
259
312
  ## Development
260
313