Roboviewer
Automated code review for merge requests, running entirely on your machine.
Point it at two branches and it comes back with a ranked list of problems worth fixing — not a wall of style nitpicks.
roboviewer develop
▸ muse-glimmer-30b @ api.fireworks.ai
▸ nmc/albums_customisation → master: 32 files, 3 checklist items
▸ Started: Runtime behaviour
▸ Started: Contracts and structure
▸ Started: Risks and coverage
• Contracts and structure: 0 findings (ok) · 404015 tokens · 21s
• Risks and coverage: 0 findings (ok) · 56984 tokens · 26s
• Runtime behaviour: 5 findings (ok) · 57932 tokens · 39s
▸ After merge and deduplication: 5 findings
▸ Stage 1 of 2: checking 5 findings, one pass each
▸ Stage 2 of 2: ruling on 5 verified findings
▸ Confirmed 5 of 5
F001 [Blocker] iOSClient/Albums/AlbumsViewController.swift:14 — @Environment used in a UIKit UIViewController
F002 [Major] .../Details/AlbumDetailsViewModel.swift:128 — UI state mutated from a background callback in loadAlbumPhotos
F004 [Major] .../Details/AlbumDetailsViewModel.swift:292 — isLoadingPopupVisible toggled per iteration in onPhotosSelected
F003 [Minor] .../Details/PhotosGridView.swift:69 — Database write performed inside view code when building viewer metadata
F005 [Minor] iOSClient/Albums/Domain/Models/Album.swift:55 — Fallback dates set to now when dateRange decoding fails
Confirmed 5 of 5 · 1927677 tokens · 99% from cache
Report: .roboviewer/runs/20260820-202715/report.md
A real run, not an illustration: muse-glimmer-30b over nextcloud/ios#4091. Four of those five findings are verified against the code, the fifth is unadjudicated — see Measurements.
Findings come back in English. --language ru asks the model for another one
without touching the prompts — see Output language.
The problem
Review arrives late, and tired. A merge request waits hours or days, and by the time someone opens it they are on their fourth review of the afternoon. The blocker ships under three comments about whitespace.
Hosted reviewers want your code. CodeRabbit, Copilot and the rest do good work, but every one of them means uploading the repository to somebody else's infrastructure. Inside a corporate network that is where the conversation ends.
They also want your forge. They plug into GitHub or GitLab and review what is already a merge request. Looking over your own branch before you open it, or reviewing a mirror that lives nowhere but your laptop, is not something they do.
Pasting a diff into a chat window invents problems. Given a few lines of context, a model will confidently report a missing nil check that sits twenty lines above the hunk. Nothing is ranked, nothing is verified, and a real blocker arrives in the same flat list as a naming preference.
What you get
Your code stays where it is. Roboviewer talks to any OpenAI-compatible endpoint — including a corporate gateway — so reviews never leave the network you already trust. Nothing is uploaded anywhere else, and there is no service to sign up for.
Any git repository, no integration. It reads two branches through plain git. No app to install on your organisation, no webhooks, no permissions to request.
Review before you open the MR. Run it on your own branch, fix what it finds, and let the humans spend their attention on design instead of on the bug you would have caught yourself.
The change is the scope, not the file. It reports what the diff introduces and what the diff breaks, and it draws that line by consequence rather than by authorship. If the changed code now calls into something that was already broken, that call is a finding: the branch is what ships, and the code having been wrong before this MR does not make it work now. Long-standing problems the change does not touch stay out.
A ranked list you can act on. Findings carry a severity, a file and a line, and a final judge pass throws out the ones that do not survive a second look — between 6% and 54% of them, depending on how noisy the model is. What survives is not guaranteed right: see Measurements for the rate that has been verified against code.
Where it stands
Measured on nextcloud/ios#4091 — an Albums feature, 32 files and 3903 lines once the resource files are excluded — against 31 defects established by hand. This is a starting line, published so it can be argued with and moved; the full table, every setting and the caveats are in Measurements.
Recall. How many of the 31 known defects a configuration surfaced across its runs. One block is one defect.
┌───────────────────────────────┐ 31
nemotron-lightning-30b · 8 items │██ │ 2 6%
muse-glimmer-30b · 3 items │████████████ │ 12 39%
muse-glimmer-30b · 8 items │███████████████ │ 15 48%
claude-opus-5 · 1 item │██████████████████████ │ 22 71%
└───────────────────────────────┘
False positives. Of everything a configuration shipped, how much was verified wrong against the code. Solid is proven false; light is not yet adjudicated, so the real rate sits inside the bar.
0% 10% 20% 30%
├─────────┼─────────┼─────────┤
nemotron-lightning-30b · 8 items │██░░░░░░ │ 4%…15%
muse-glimmer-30b · 3 items │██████░░░░ │ 12%…20%
muse-glimmer-30b · 8 items │████░░░░░░░░░░░ │ 8%…30%
claude-opus-5 · 1 item │█░░░░░░░░░░ │ 2%…21%
A low rate can still be a bad report. Of the 48 findings the nemotron configuration shipped, 36 are one "this file has no tests" entry per file — formally correct, and one thought repeated thirty-six times. Counting findings rewards that; counting distinct defects does not, which is why the recall chart above is drawn per defect rather than per finding.
Three things this does not say. It is one merge request, so n = 1 at the
repository level. Fifteen of the 31 defects entered the truth set by verifying
one model's output, so that model is being graded partly on ground it defined —
origin in benchmarks/references/ios-4091.toml marks which entries are
independent. And Opus ran without the judge, as a ceiling to aim at rather
than a configuration of this tool.
Requirements
- Python 3.11+
- git
- An OpenAI-compatible endpoint with tool calling — the agents drive the
review through tools, so a completions-only gateway will not work.
roboviewer --check-providertells you which side of that line yours is on.
Install
git clone git@github.com:axazeano/Roboviewer.git && cd Roboviewer
python3 -m venv .venv && .venv/bin/pip install -e .
ln -sf "$PWD/.venv/bin/roboviewer" ~/.local/bin/roboviewer
Docker
The image carries the tool and git. The repository under review, the config and the reports stay on your side, as mounts.
docker run --rm \
-v "$PWD:/repo" \
-v ~/.config/roboviewer/provider.toml:/provider.toml:ro \
-v ~/.config/roboviewer/config.toml:/config.toml:ro \
-v "$PWD/.roboviewer:/out" \
-e ROBOVIEWER_API_KEY -e ROBOVIEWER_PROVIDER_CONFIG=/provider.toml \
axazeano/roboviewer:latest develop --config /config.toml --output /out
Mount the repository with its history — a shallow clone has no merge base to
diff against. The image runs as an unprivileged user; on Linux add
--user "$(id -u):$(id -g)" so the reports it writes belong to you.
latest is what you want at a keyboard. A pipeline should name a release —
axazeano/roboviewer:0.1.2 — so that a rerun of an old commit reviews it with
the version it was reviewed with.
Configure
mkdir -p ~/.config/roboviewer
cp provider.example.toml ~/.config/roboviewer/provider.toml
cp config.example.toml ~/.config/roboviewer/config.toml
export ROBOVIEWER_API_KEY=...
roboviewer --check-provider
Set provider.base_url and reviewer.model. Everything else has working
defaults and is documented inline in
provider.example.toml and
config.example.toml.
The provider lives in its own file so the settings file stays safe to copy: a
--config file carrying a [provider] section is refused.
--check-provider makes a handful of targeted requests and names what is wrong
— wrong auth scheme, a base_url missing /v1, a gateway that cannot do tool
calling — instead of leaving you to infer it from eight agents failing at once.
The sections, the rule that --config replaces rather than layers, and what to
do about rate limits: Configuration.
Use
roboviewer <target> [source]
The target branch is required. The source defaults to your current branch, and naming it explicitly lets you review someone else's branch without checking it out.
roboviewer develop # current branch into develop
roboviewer develop feature/login # someone else's branch
roboviewer -C ~/projects/app develop # a repository living elsewhere
Reports land in .roboviewer/runs/<timestamp>/, and --diff-only shows what
would be reviewed without spending tokens. Every flag:
Command line.
Documentation
| Page | What is in it |
|---|---|
| Configuration | The config file, checking the gateway, rate limits |
| Command line | Every flag and the environment variables behind them |
| How it works | Whole files, the reference pre-pass, one agent per concern, the judge |
| Reports and output | What a run writes, the four formats, overriding a template |
| Continuous integration | Exit codes, and a job for GitLab and for GitHub |
| Customise the checklist | Adding a concern without touching code |
| Output language | Findings in a language other than English |
| Tuning | Prompts, how many agents, thinking, the turn limit |
| Measurements | What it finds and gets wrong, per model and checklist size |
| Watching a run | What the agents did with the context: the log, the page, the command |
| The benchmark | `benchmark list |
docs/ also carries the map of the code, the tooling baseline and how the benchmark is built and run.
What it doesn't do
- It does not post comments on your merge request, and does not talk to GitHub or GitLab at all. Output is files on disk; in CI it is the pipeline that publishes them, from formats the forge already understands.
- It does not modify your code. The agents get read-only tools —
read_file,grep,list_files,git_show— and nothing else. - It does not replace a human reviewer. On the merge request it was measured against it surfaced between 6% and 48% of the known defects depending on the model and the checklist, and it has no idea whether the feature was worth building.
- It does not try to reproduce a human review, and nothing here measures how closely it agrees with one. Overlap with reviewer comments would measure similarity, not correctness — the two miss different things, and a run that matched a reviewer perfectly would have added nothing. It is measured against defects established in the code, not against what somebody happened to write in a comment thread.
- It keeps no state between runs. Every run starts from the diff and nothing else, so in CI it reports the same findings again on every push — including the ones you have already read and decided to leave. Nothing in the tool suppresses a repeat, and that is the usual reason review bots get switched off. Until that changes, the honest place for it is a branch you run by hand.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file roboviewer-0.3.0.tar.gz.
File metadata
- Download URL: roboviewer-0.3.0.tar.gz
- Upload date:
- Size: 222.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4df5d74fd90153d71a4db0c097621eec153ccc7459032b7ea012dcc8ba5441c5
|
|
| MD5 |
ea7f889df89868833699e770ab588942
|
|
| BLAKE2b-256 |
7a0d19bc8a78bccebf98f42508d06a8470eaf4400b995a512fa85dabeb23630e
|
Provenance
The following attestation bundles were made for roboviewer-0.3.0.tar.gz:
Publisher:
release.yml on axazeano/Roboviewer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
roboviewer-0.3.0.tar.gz -
Subject digest:
4df5d74fd90153d71a4db0c097621eec153ccc7459032b7ea012dcc8ba5441c5 - Sigstore transparency entry: 2613913002
- Sigstore integration time:
-
Permalink:
axazeano/Roboviewer@6bc149e527f0704356e721d8b003c6c071b6c08b -
Branch / Tag:
refs/tags/Release/0.3.0 - Owner: https://github.com/axazeano
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6bc149e527f0704356e721d8b003c6c071b6c08b -
Trigger Event:
push
-
Statement type:
File details
Details for the file roboviewer-0.3.0-py3-none-any.whl.
File metadata
- Download URL: roboviewer-0.3.0-py3-none-any.whl
- Upload date:
- Size: 200.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5acc66fe7bb51fa8a09f1bd665d7cafebf131999ad4d9448441a54b7f9389f1b
|
|
| MD5 |
e2cbd9716f8a37910d5b192a4b0f813c
|
|
| BLAKE2b-256 |
56560f10fe2b1adea54372a121c7fd78477d8bb737a61d6e10faded5b23d108c
|
Provenance
The following attestation bundles were made for roboviewer-0.3.0-py3-none-any.whl:
Publisher:
release.yml on axazeano/Roboviewer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
roboviewer-0.3.0-py3-none-any.whl -
Subject digest:
5acc66fe7bb51fa8a09f1bd665d7cafebf131999ad4d9448441a54b7f9389f1b - Sigstore transparency entry: 2613913118
- Sigstore integration time:
-
Permalink:
axazeano/Roboviewer@6bc149e527f0704356e721d8b003c6c071b6c08b -
Branch / Tag:
refs/tags/Release/0.3.0 - Owner: https://github.com/axazeano
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6bc149e527f0704356e721d8b003c6c071b6c08b -
Trigger Event:
push
-
Statement type: