What the agent does
The agent starts with Cargo.toml and the router, because how an Axum app is assembled decides how a test can reach it. In an API like launchbadge/realworld-axum-sqlx it finds axum 0.3.4, sqlx 0.5 with the postgres, uuid and time features, and tower 0.4. src/http/mod.rs builds the app in a private api_router() that merges users::router(), profiles::router() and articles::router(), and the only public entry is serve(config, db), which binds 0.0.0.0:8080. A test in tests/ compiles as a separate crate and cannot call a private function, so the one source change the agent makes is a small public constructor in src/http/mod.rs that returns the Router with its ApiContext extension layer, which serve then calls. Behaviour does not change; the pull request says so.
Next it sets up the database the way the code expects. The SQLx query! and query_as! macros check every query against a live database at compile time, and the repository has no offline query data, so cargo test will not even build without a migrated Postgres behind DATABASE_URL. The agent starts Postgres in its sandbox, runs sqlx db setup the way .github/workflows/rust.yml does, and sets HMAC_KEY, the second field src/config.rs reads. The #[sqlx::test] attribute arrived in SQLx 0.6, so on 0.5 it writes a helper in tests/common/mod.rs that creates a uniquely named database per test, applies sqlx::migrate!() to it, and builds the app on that pool, so tests run in parallel without sharing rows.
Then it covers the routes the routers declare, one file per area: tests/users.rs for POST /api/users, POST /api/users/login and GET and PUT /api/user; tests/profiles.rs for /api/profiles/:username and its follow; tests/articles.rs for create, list, the feed, read, update, delete, favorite and GET /api/tags; and tests/comments.rs for /api/articles/:slug/comments and deleting one by id. Each test builds a Request, sends it with tower::ServiceExt::oneshot, and asserts on the status and the JSON body. It checks the failure paths src/http/error.rs defines: 401 with a WWW-Authenticate: Token header when the Authorization: Token ... header is missing or forged, 403 when one user edits another's article, 404 for an unknown slug, and 422 with an errors map when a username or email hits the user_username_key or user_email_key constraint.
It runs cargo test and reads the output, including the existing test_slugify unit test in src/http/articles/mod.rs, which must still pass. A test that fails because of the code rather than the test stays in the pull request marked #[ignore] with a note explaining what the route returned and what the RealWorld spec asks for, so the suite is green and the finding is not lost.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Write integration tests under tests/ that start this Axum app against a real Postgres with SQLx migrations and call every route through tower::ServiceExt::oneshot. Start Postgres in the sandbox and set DATABASE_URL so the sqlx query macros compile. If the router is not reachable from an integration test, add the smallest public constructor that returns it and have the existing serve function use it; change nothing else in src/. Give each test its own database with migrations applied, so tests can run in parallel. For every route assert the success status and JSON body, and cover missing or invalid auth tokens, editing another user's resource, unknown ids and duplicate usernames or emails. Run cargo test, and if a test fails because of the application rather than the test, mark it #[ignore] with a comment saying what the route returned. Open a pull request listing each route and the cases tested.",
"resources": [
{
"url": "https://github.com/your-org/your-api"
}
]
}- 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
The pull request adds a tests/ directory with a shared common module and one file per router, plus the small change in src/http/mod.rs that makes the router constructible from a test. For a codebase shaped like realworld-axum-sqlx, Cargo.toml gains dev dependencies only, typically serde_json for reading bodies and tower features the tests need, and Cargo.lock changes to match. The description lists every route from the routers with the cases each test covers, and names any route left out with the reason.
Its proof is the run in two places. The repository's existing Rust workflow, which already starts a postgres service and runs cargo test --verbose, picks the new tests up on the pull request with no workflow change. And the session record keeps the agent's own cargo test output from its sandbox, so a reviewer can see each test name pass, and read any #[ignore] case with the response that caused it.
Before merging, a reviewer checks that the new public constructor exposes nothing beyond the router, that the per-test database helper drops or reuses databases so a long-running CI host does not fill up, and that assertions check the RealWorld response shapes the frontend relies on, such as the user.token field after login, rather than only status codes.
Run it on every route added without a test
Run it from a GitHub webhook on pull_request: when a pull request changes a file under src/http/ and no file under tests/, your server sends this request with the pull request URL in resources (https://github.com/<owner>/<repo>/pull/<n>), so the agent works on that branch and adds tests for the routes it touched. Each pull request gets its own session in its own sandbox with its own Postgres.
A webhook URL set on the API key receives run.completed or run.failed when the turn ends, with the session URL, so your server can comment on the original pull request with what was added.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
An SQLx project with checked queries does not compile without a migrated database, so writing its first integration tests on a laptop means installing Postgres, running sqlx-cli, setting DATABASE_URL and keeping a database you then have to reset. On Rush the agent starts Postgres in its own sandbox, applies the migrations, compiles and runs the suite there, and nothing is installed on your machine or left running afterwards.
Every cargo build and cargo test the agent ran stays in the session with its full output, so a claim in the pull request such as "PUT /api/articles/:slug returns 403 for another user" can be checked against the test that proves it. The same request can run on several Rust services at once, each in its own sandbox, each with a pull request someone reviews.
Frequently asked questions
Why tower's oneshot instead of starting the server on a port?
oneshot sends one request straight into the Router as a tower Service, with no socket, no port to pick and no wait for the server to start. Tests stay fast and run in parallel. The request and response are the same types a real server handles, so routing, extractors and error conversion are all exercised.
Does it work with #[sqlx::test]?
Yes, on SQLx 0.6 and later. That attribute creates a fresh test database per test, applies the migrations and hands the test a pool, so the agent uses it instead of a hand-written helper. On SQLx 0.5, as in realworld-axum-sqlx, the attribute does not exist, and the agent writes the equivalent helper in tests/common/mod.rs.
Will it change my application code?
Only if the router cannot be built from outside the crate, and then by the smallest public constructor that returns it, used by the existing server function. The prompt forbids any other change under src/, and the diff shows exactly what moved. A bug a test finds is reported as an ignored test, not fixed.
What about the sqlx offline query data?
The agent compiles against a live database in the sandbox, so it does not need it. If your CI builds with SQLX_OFFLINE=true, ask in the prompt and it runs cargo sqlx prepare and commits the generated query data, so the build no longer needs a database to compile.