What the agent does
The agent clones the service into its own cloud sandbox and runs coverage the way the repository already does, so its numbers match what the team sees. In a Gin API like gothinkster/golang-gin-realworld-example-app, scripts/coverage.sh loops over every directory under ./* that holds Go files, runs go test -coverprofile=profile.out -covermode=atomic in each, and appends the lines to one coverage.out; the test job in .github/workflows/ci.yml runs that script on Go 1.21, 1.22 and 1.23 and uploads the 1.23 result to Coveralls. readme.md quotes the result as roughly 90 percent in total, with users at 99.5 percent, articles in the low nineties and common at 85.7 percent. The agent runs the script, then go tool cover -func=coverage.out, which lists every function with its own percentage, and that list, not the package totals, is the raw material of the report.
The first finding comes from the script itself. find ./* -maxdepth 10 -type d lists directories, so the repository root is never visited and hello.go, package main, is never measured: Migrate, which calls AutoMigrate for every model, and main, which builds the router, order the middleware and read PORT, do not appear in coverage.out at all. The report says so and distinguishes the two kinds of gap: code that is measured and uncovered, and code that is not measured. The agent also notes that api/Conduit.postman_collection.json, run by scripts/run-api-tests.sh with newman in the api-test job, exercises the real binary end to end but produces no coverage data, so an endpoint can be exercised by Postman and still show as uncovered.
Then it reads the uncovered functions against the tests that exist. articles/unit_test.go has 41 test functions, common/unit_test.go has 16 and users/unit_test.go has 6; they build a router with setupRouter, which mirrors the groups and the two AuthMiddleware calls from hello.go, open a SQLite database through common.TestDBInit at TEST_DB_PATH, create users with createTestUser and a bcrypt hash, and send requests through httptest with common.HeaderTokenMock for the token header. For each function under its package's figure the agent reads the branches the tests skip: the database error paths in articles/routers.go that return 422 from common.NewError, the access_token query parameter branch in users/middlewares.go that extractToken supports but the header-only tests never take, and whichever of ProfileFollow, ProfileUnfollow, ArticleFavorite, ArticleUnfavorite and ArticleCommentDelete the function list shows below full coverage.
The ranking weighs how reachable the gap is from the outside against how much the function does. An unauthenticated branch of a handler ranks above an unreachable error path in a serializer, and a handler that writes to the database ranks above one that reads. Every entry names the function, its file and the percentage from go tool cover -func, the branch or condition the tests miss, and the test that would cover it written in the file's own style: a setupRouter request through httptest, a createTestUser fixture, a token from HeaderTokenMock and the assert calls from testify. The agent changes no file, pushes nothing and opens no pull request; the report is the result.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Find the test coverage gaps in this Gin service and write coverage-gaps.md. Run bash scripts/coverage.sh exactly as .github/workflows/ci.yml does, then go tool cover -func=coverage.out, and keep the full function list. Compare the package totals with the figures readme.md quotes. Check which directories scripts/coverage.sh visits and report any Go code it never measures, such as package main in hello.go. Read articles/unit_test.go, users/unit_test.go and common/unit_test.go to learn the test style, including setupRouter, TestDBInit, createTestUser and HeaderTokenMock, and read the handlers in articles/routers.go and users/routers.go and the middleware in users/middlewares.go to see which branches the tests skip. Rank the ten riskiest uncovered functions, putting handler branches reachable over HTTP first, and for each give the function, file, percentage, the missed branch and the test that would cover it in the existing style. Add a section on what api/Conduit.postman_collection.json exercises that coverage does not count. Do not change any file, commit, push or open a pull request.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- 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 one file, coverage-gaps.md, as an artifact on the session, with a download link that works for an hour and is refreshed on each read of the session. It opens with the package totals from the run beside the figures readme.md quotes, and the full output of go tool cover -func as an appendix so every number in the report can be traced to a line. Then it lists the code the coverage script never measures, with the find expression from scripts/coverage.sh that explains why.
The body is the ranked list: for each of the ten riskiest gaps, the function, its file and percentage, the branch the suite skips in a sentence, and a test sketch in the repository's own style, so the next step is a copy into the right unit_test.go rather than a redesign. A closing section maps the Postman collection's requests to endpoints and marks the ones that reach code the unit tests do not, which is where an end-to-end check is standing in for a unit test.
A reviewer reads the ranking first and the appendix second, checks that the ranking is about reachability rather than only the percentage, and decides which sketches to turn into tests. A follow-up on the same session that asks for the top three as a pull request picks up the same clone with coverage.out already written.
Run it on every release tag
Coverage gaps matter most just before a release, when the team decides what to test by hand. No automation trigger fires on a tag push, so the release script on your server starts the run: it sends this request with resources set to https://github.com/your-org/your-app/tree/<tag> and a request_id made from the tag, so a retried call returns the run already started, and the report describes exactly what ships.
Give the key a webhook URL and Rush POSTs run.completed with data.session_url when the turn ends; a handler reads the session, takes the coverage-gaps.md link from its artifacts and attaches it to the release.
The use case this job follows, with its automation and trigger: Produce a report or file, no repo.
Why run it on Rush?
The function-level list behind a coverage badge takes a Go toolchain, a writable path for the SQLite test database and a run of the whole suite, and reading it well takes the handlers and the tests side by side. The agent does that in its own sandbox from a fresh clone, so the report reflects the branch as pushed rather than a laptop with a stale coverage.out, and nothing it runs touches a shared database.
Every number is traceable. The transcript at GET /o/{org}/sessions/{id}/messages holds the coverage script's output and the go tool cover -func list, and the report cites them. Several services, or several tags of one, can be measured at once in separate sandboxes.
Frequently asked questions
Does it change any code or add tests?
No. This run writes the report only. Each gap comes with a test sketch in the style of the existing unit_test.go files, and a follow-up on the same session can turn the top entries into a pull request with the tests written and run.
Why does the report mention hello.go when the badge says 90 percent?
Because scripts/coverage.sh only visits directories under ./*, so package main at the repository root is never run under coverage and its Migrate and main functions are absent from coverage.out. The badge is honest about what it measures; the report says what it does not.
Does the Postman collection count as coverage?
Not in the numbers. scripts/run-api-tests.sh builds the binary and runs the collection against it with newman, which exercises the real routes but writes no coverage profile. The report maps those requests to endpoints so the team can see which handlers are tested only end to end.
What makes one gap riskier than another?
Reachability and effect. A handler branch a client can hit over HTTP ranks above an internal error path, and a branch that writes, such as a follow or a comment delete, ranks above one that reads. The percentage from go tool cover -func is shown but is not the sort key on its own.