What the agent does
The agent checks out the pull request and reads which functions it changes in each package. In a Go service like gothinkster/golang-gin-realworld-example-app the HTTP handlers live in users/routers.go (UsersRegistration, UsersLogin, UserUpdate, ProfileFollow, ProfileUnfollow) and articles/routers.go (ArticleCreate, ArticleList, ArticleFeed, ArticleUpdate, ArticleDelete, the favorite and comment handlers), with validation in each package's validators.go, response shapes in serializers.go and GORM queries in models.go. It lists every new branch the diff adds, such as a new query filter in ArticleList or a new rule in a validator, and searches the package's tests for one that reaches it.
Then it reads the package's own test file, because this repository keeps all of a package's tests in one unit_test.go inside the package, not in a separate _test package. users/unit_test.go has a TestMain that calls common.TestDBInit(), runs AutoMigrate() and frees the database with common.TestDBFree at the end. articles/unit_test.go builds a Gin engine with setupRouter(), wires users.AuthMiddleware, creates fixtures with createTestUser and createArticleWithUser, and resets data with resetDBWithMock. Requests go through httptest with common.HeaderTokenMock adding a JWT, and assertions use testify's assert. The repository's AGENTS.md says the same: tests live beside the source, use TestDBInit and TestDBFree, and go test ./... runs before every commit.
The agent adds new TestXxx functions to those files in the same style, one per behavior, named for what they check (TestArticleListFilterByFavorited rather than TestArticleList2). Where the existing file already drives a test from a table of cases, as TestArticleRouters does with articleRequestTests and TestWithoutAuth with unauthRequestTests, it adds rows to that table instead of a new function. It reuses the fixture helpers rather than inserting rows by hand, so a later change to a model only needs one helper updated.
It then runs go test ./... with the module's go 1.21 directive and reads the output, and runs gofmt -l the way scripts/gofmt.sh does in CI, because a test file that fails formatting turns the check red too. The SQLite driver, gorm.io/driver/sqlite over mattn/go-sqlite3, compiles C code, so the sandbox needs cgo and a C compiler, which the agent checks before the first run. A test that fails because a handler is wrong stays out of the commit; the prompt forbids changing application code, and the agent reports it instead.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "codex",
"input": "This pull request changes the users and articles packages. Read the diff against the base branch and list the new or changed behavior in users/ and articles/ (routers, validators, serializers, models) that no existing test covers. Write Go tests for each item in that package's unit_test.go, following the existing style: TestMain with common.TestDBInit and TestDBFree, setupRouter, the createTestUser and createArticleWithUser helpers, httptest requests with common.HeaderTokenMock, testify assert, and table cases where the file already uses them. Run go test ./... and gofmt -l until the new tests pass and are formatted. Do not change application code: if a test fails because the code is wrong, leave it out and describe the failure. Push the tests to this pull request's branch and post a comment listing each test and the behavior it covers.",
"resources": [
{
"url": "https://github.com/your-org/your-app/pull/123"
}
]
}- 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 commit on the pull request's branch that changes only users/unit_test.go, articles/unit_test.go or common/unit_test.go. Each new test is a func TestXxx(t *testing.T) that sets up its rows with the existing helpers, sends a request through the Gin router with httptest.NewRecorder, and asserts the status code and the decoded JSON, or calls a model or validator function directly when that is what the pull request changed. No dependency is added to go.mod.
The agent's comment on the pull request lists every test by name, the behavior it pins and the commands it ran, go test ./... and gofmt -l. If a test caught a bug, for example a handler returning 200 for an article the user does not own, the comment shows the failing assertion and the line in routers.go. The repository's CI then runs scripts/coverage.sh across Go 1.21, 1.22 and 1.23 on the pushed commit, which is the check a reviewer trusts.
Before merging, a reviewer checks that each test leaves the shared SQLite test database in a state the next test expects, since the package's tests share one database for the whole TestMain, and that tests do not rely on the order rows come back in when the handler does not sort them.
Run it on every pull request opened
On the Project connected to the repository, add an automation with this prompt and a GitHub trigger on pull_request.opened. Each pull request from someone who can write to the repository starts its own run; the run's prompt names the pull request number, URL, title, author and base branch. Pull requests from forks never fire it. To also cover commits pushed after the pull request opens, add pull_request.synchronize to the same trigger.
A service that already receives GitHub webhooks can start the same runs itself: on a pull_request event with action opened, send this request with the pull request's URL in resources, which clones its branch. Read the result from the session, or set a webhook URL on the API key and get run.completed when the turn ends.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
Go tests for a router are fast to run but slow to get right: the first versions fail on a missing auth header, a wrong JSON key or a row left over from the previous test, and each fix is another go test cycle on someone else's branch. On Rush that loop happens in the agent's own sandbox at the pull request's branch, with its own module cache and its own SQLite file, while your checkout and your Go build cache stay as they were.
The run ends with evidence, not a summary. The trajectory has every go test invocation and its output, and the repository's CI repeats the suite on three Go versions for the pushed commit. Because each pull request gets its own run, five open pull requests get their tests in parallel rather than in a queue on one machine.
Frequently asked questions
Will it put the tests in a separate _test package?
Not in this repository. Each package keeps its tests in unit_test.go in the same package, so they can call unexported helpers like resetDBWithMock. The agent follows whatever the package already does; in a codebase that uses external _test packages, it uses those.
Does it use testify or the standard library only?
It uses what the module already imports. This one requires github.com/stretchr/testify and its tests use assert, so the new tests do too. In a module that uses only testing, the agent writes t.Errorf checks and adds no dependency.
Does it need a database server?
No. common.TestDBInit() opens a SQLite file for the tests, so go test ./... runs without Postgres or MySQL. The SQLite driver needs cgo, which the agent checks for before it starts.
How does it avoid flaky tests?
It runs the package's tests more than once before pushing, does not depend on map iteration order or wall-clock time, and creates the rows each test reads rather than relying on rows another test left behind.