What the agent does
The agent reads how the API is wired before it reads the diff, because in a Gin service most review findings are about which group a route sits in and what the middleware guarantees. In gothinkster/golang-gin-realworld-example-app, hello.go registers users.UsersRegister on /api/users with no auth, then applies users.AuthMiddleware(false) for the anonymous article, tag and profile routes, then users.AuthMiddleware(true) for /api/user, profile follow and the authenticated article routes, and sets RedirectTrailingSlash = false. Handlers in articles/routers.go and users/routers.go read the user with c.MustGet("my_user_model").(users.UserModel), which panics if a route is added to a group the middleware does not cover. extractToken in users/middlewares.go accepts a Token header or an access_token query parameter, and the signing key is the JWTSecret constant in common/utils.go, which AGENTS.md flags as not for production.
Then it reads the checks the repository already runs so the review quotes real output. .github/workflows/ci.yml tests on Go 1.21, 1.22 and 1.23, runs scripts/gofmt.sh, collects per-package coverage through scripts/coverage.sh with -covermode=atomic, runs golangci-lint with the repository's .golangci.yml, runs gosec with -no-fail, and then an API job that builds hello.go, starts it on port 8080, waits on /api/ping and runs the RealWorld Postman collection with Newman through scripts/run-api-tests.sh. go.mod pins gin v1.10.0, gorm v1.25.12 with the SQLite driver, golang-jwt/jwt/v5 and validator/v10; the readme notes that gorm v1.30 and later has breaking changes and validator v10.30 needs Go 1.24. Tests are three unit_test.go files that use common.TestDBInit and common.TestDBFree around a SQLite file.
With the branch checked out the agent runs go vet ./... and go test -race ./..., which needs cgo for the SQLite driver and so is run in the sandbox rather than skipped. Then it reads the diff with the three questions the prompt names. Error handling: ArticleUpdate returns 404 for an unknown slug and 403 when articleModel.AuthorID differs from the caller, while ArticleDelete deletes whether or not the article exists; a new handler should match one of those contracts and AGENTS.md forbids discarding errors with _. GORM: the conventions in AGENTS.md are Preload for eager loads, Association().Find() for many-to-many, Updates for struct updates, pointers in Delete, and int64 from Count; FindManyArticle in articles/models.go shows the house pattern of paging with Offset and Limit and then reloading with Where("id IN ?", ids). Goroutine safety: common.DB is a package global, UpdateContextUserModel writes to the request context, and any new goroutine that touches either is a candidate for the race detector.
For each candidate finding the agent checks whether a test already pins the behavior and, where it can, writes a short test in the sandbox to confirm the problem before it posts, keeping that test out of the pull request. One GitHub review is posted per run: the summary quotes the go vet and go test -race results and the gofmt check, separates blocking issues from suggestions, and every finding cites file and line in articles, users or common. The prompt forbids pushing commits, so the agent pushes nothing.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Review this pull request on a Gin API. Check it out, run go vet ./..., go test -race ./... and bash scripts/gofmt.sh, and read the diff with the surrounding handlers, models and middleware. Look for handlers that read my_user_model from a route group without AuthMiddleware(true), errors discarded or returned with the wrong status compared with the existing handlers, GORM calls that break the conventions in AGENTS.md, and goroutines that touch common.DB or the request context. Confirm a finding with a short test in the sandbox where you can, but do not add it to the branch. Post one GitHub review that quotes the vet, race and gofmt results, separates blocking issues from suggestions, and cites file and line for every finding. Do not push commits.",
"resources": [
{
"url": "https://github.com/your-org/your-app/pull/42"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
What comes back is a review on the pull request. The summary quotes the go vet ./... result, the go test -race ./... result with any race report the detector printed, and the gofmt check, then lists the findings with file and line in the package they belong to, marked as blocking or suggestion. Inline comments sit on the cited lines, and a finding about a GORM call names the convention from AGENTS.md it departs from.
The session's trajectory keeps the module download, every command and its output, the short tests the agent wrote to confirm a finding, and the files it opened while tracing a handler into its model. When the review says a route can panic on MustGet, the trajectory shows the request it sent to prove it.
Before merging, a reviewer reproduces the blocking findings with go test -race ./... on the branch, opens each cited line, and dismisses suggestions that do not hold. A race report is blocking by default; a style finding is not.
Run it on every pull request opened
Create an automation in the Project with a github trigger on pull_request.opened and pull_request.synchronize, limited to the branch the API merges to, and this prompt. The trigger adds the pull request after the prompt, so every pull request gets its own sandbox, its own race run and its own review.
The review is the result: it appears on the pull request, and the run shows in the Project like one started from the console. The automation's max runs per hour, 1 to 30, caps a burst of small pull requests; a fire past it is skipped as rate_limited and that pull request waits for its next push, so set the cap to the busiest hour you expect.
The use case this job follows, with its automation and trigger: Review every pull request.
Why run it on Rush?
The findings that matter in a Gin API are the ones a diff does not show: a route in the wrong group, a status code that disagrees with its neighbors, a write to a shared *gorm.DB from a new goroutine. Catching them means checking out the branch, building with cgo for SQLite and running the race detector, which is why most reviews skip it. On Rush the agent does that in its own sandbox and keeps every command and its output, so the review rests on an executed suite rather than a reading.
One sandbox per pull request keeps reviews parallel when the API takes changes from several contributors at once, each with its own go test -race run and its own SQLite file. The author keeps their checkout, the reviewer gets findings with the evidence attached, and nothing is pushed to the branch.
Frequently asked questions
Which Go version does it use?
The CI matrix runs 1.21, 1.22 and 1.23 and go.mod says 1.21, so the agent uses the newest of those for the race run and notes if the pull request moves the go directive. A dependency that needs a newer Go than the matrix, like validator v10.30, is a finding.
Does the race detector need anything special here?
cgo, because gorm.io/driver/sqlite builds on mattn/go-sqlite3. The sandbox has a C toolchain, so go test -race ./... runs as written. The tests share a SQLite file through TEST_DB_PATH, so the agent runs packages serially if a race report points at the test database rather than the code.
Will it run the Newman API tests too?
Ask for it in the prompt and the agent runs scripts/run-api-tests.sh, which builds the server, starts it on port 8080 and runs the RealWorld Postman collection. The review then quotes the collection result alongside the unit tests. It is left out by default because it downloads the collection from the upstream repository at run time.
What does it do with the hard-coded JWT secret?
If the pull request touches common/utils.go, users/middlewares.go or common/test_helpers.go, the review checks that the secret still comes from one place and that the tests still sign tokens with it. A change that reads the secret from an environment variable gets a finding if the test helper or CI was not updated to set it.