What the agent does
The agent reads how the server is built before it writes a test. In dani-garcia/vaultwarden the package is vaultwarden 1.0.0, edition 2024, rust-version 1.97.1, with rust-toolchain.toml pinning channel 1.99.0 with rustfmt and clippy. The [features] block has an empty default, so a build must pick sqlite, mysql or postgresql; sqlite also bundles libsqlite3-sys. There is no [dev-dependencies] section and no tests/ directory, and because the crate is a binary with everything under src/main.rs, tests live in #[cfg(test)] mod tests blocks inside the modules they cover. Nine files have one today: src/auth.rs tests client_ip_from_header_values with several X-Forwarded-For shapes, src/api/core/two_factor/email.rs tests obscure_email, and src/util.rs has two IP range tests that are #[ignore] and behind the unstable feature.
That leaves two pure modules with no tests at all. src/crypto.rs wraps ring: hash_password and verify_password_hash do PBKDF2-HMAC-SHA256 with a caller-supplied iteration count, hmac_sign signs with HMAC-SHA1 and returns lowercase hex, get_random_string_numeric and get_random_string_alphanum draw from fixed alphabets, generate_send_file_id encodes 32 random bytes as hex, generate_api_key returns 30 alphanumeric characters, ct_eq is a constant-time compare and sha256_hex hashes to hex. In src/util.rs, get_display_size divides by 1024 up to PB and formats two decimals, upcase_first and lcase_first change one character, format_date prints RFC 3339 with microseconds and a Z, validate_and_format_date falls back to 1970-01-01T00:00:00.000000Z on bad input, format_datetime_http prints RFC 2822 with GMT, parse_date reads RFC 3339, is_valid_email rejects addresses whose domain does not parse as a host, convert_json_key_lcase_first walks nested objects and arrays, and parse_experimental_client_feature_flags filters a comma list against SUPPORTED_FEATURE_FLAGS. The agent writes a test module in each file with a round trip or a known vector per function: a hash verified with the same salt and rejected with another, get_display_size(1536) and the PB boundary, the 1970 fallback, an email with a path in its domain.
For the routes it reads src/main.rs. launch_rocket builds rocket::custom(config) and mounts api::web_routes() at /, api::core_routes() at /api, then /admin, /events, /identity, /icons and /notifications, registers the catchers, manages the DbPool and attaches the AppHeaders, Cors and BetterLogging fairings. In src/api/core/mod.rs the meta_routes list holds alive, now, version, config and get_api_webauthn: GET /api/now returns the current time through format_date, GET /api/version returns crate::VERSION, and GET /api/alive takes a DbConn guard, which src/db/mod.rs resolves from the managed pool and answers 503 when it cannot. The two unauthenticated routes the prompt asks for are /api/now and /api/version: the agent builds a Rocket with core_routes() mounted at /api, uses rocket::local::blocking::Client::tracked, and asserts the status, the Content-Type and that the body parses as the date or the version string. CONFIG is a LazyLock that reads .env and data/config.json, so the test sets DATA_FOLDER to a temporary directory before touching it.
Then it runs what .github/workflows/build.yml runs, with RUSTFLAGS=-Dwarnings: cargo test --profile ci --features sqlite, cargo clippy --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3 and cargo fmt --all -- --check with the repository's rustfmt.toml (max_width = 120). The [workspace.lints] sections forbid unsafe_code, deny warnings and the rust_2024_compatibility group, and warn on the clippy pedantic and style groups, so a test with an unused import or a needless clone fails the build the same way production code would.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Write tests for this Rocket server. Read Cargo.toml and rust-toolchain.toml first and build with the toolchain and the database feature they imply (in a server shaped like dani-garcia/vaultwarden, --features sqlite). The crate is a binary, so put unit tests in #[cfg(test)] mod tests blocks inside the modules they cover, in the style of the existing tests in src/auth.rs. Cover every public function in src/crypto.rs and the untested helpers in src/util.rs (display sizes, date formatting and parsing, email validation, JSON key conversion, feature flag parsing) with round trips and known vectors. Add Rocket local-client tests for two unauthenticated routes in src/api/core/mod.rs, GET /api/now and GET /api/version, by mounting core_routes() at /api on a test Rocket and asserting status, content type and body; set DATA_FOLDER to a temporary directory before anything reads CONFIG. Change no production code unless a test reveals a bug; if it does, fix it in its own commit and say so. Run cargo test --profile ci --features sqlite, cargo clippy --profile ci --features sqlite,mysql,postgresql,enable_mimalloc,s3 with RUSTFLAGS=-Dwarnings, and cargo fmt --all -- --check, and open a pull request listing each function now covered.",
"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 a pull request on a new branch that adds a mod tests block at the end of src/crypto.rs, extends the one in src/util.rs with tests that run without the unstable feature, and adds a mod tests to src/api/core/mod.rs for the two meta routes. No tests/ directory appears, Cargo.toml is unchanged because rocket::local needs no extra dependency, and Cargo.lock does not move.
The description lists each function with the cases it now has, quotes the cargo test --profile ci --features sqlite summary with the number of tests that ran, and the clippy and fmt results. If a test found a bug, a separate commit carries the fix and the description names it. The transcript keeps the full output of every command, including the first compile with the sqlite feature.
Before merging, a reviewer checks that the PBKDF2 vectors use a small iteration count so the suite stays fast, that the date tests pin the microsecond and Z format the clients depend on, and that the route tests mount only core_routes() rather than reaching for the full launch_rocket, which needs a database pool.
Run it on every nightly
Create an automation in the Project with this prompt and a schedule trigger (cron 0 2 * * * in your timezone). Each night's run looks at what changed and adds tests for the untested functions the diff touched; a night with nothing new to cover ends with no pull request and a one-line result saying so. Set max_runs_per_hour to 1 so a retried fire cannot start two runs on the same tree.
To start it from your own scheduler instead, send this body to POST /o/{org}/sessions with an Idempotency-Key built from the repository name and the date, and set a webhook URL on the API key: Rush then POSTs run.completed with session_url when the turn ends, and your handler can assign the pull request to whoever owns the module that gained tests.
The use case this job follows, with its automation and trigger: Write the missing tests.
Why run it on Rush?
A Rocket server with no default feature and a hard -Dwarnings policy is slow to test by hand: the first build with sqlite and argon2 at opt-level 3 takes a while, and a stray warning in a test module fails the whole run. On Rush the agent takes that build in its own sandbox, iterates until clippy and fmt are clean under the repository's [workspace.lints], and hands back a pull request that is already green on the same commands CI runs.
The pull request carries its own proof: the test list, the exact cargo test summary, and the clippy output in the transcript. A reviewer reads the vectors rather than trusting a coverage number, and the same request runs against every Rocket service you maintain in parallel.
Frequently asked questions
The crate has no lib.rs. Where do the tests go?
Inside the modules, as #[cfg(test)] mod tests blocks, the way src/auth.rs and src/api/core/two_factor/email.rs already do. A tests/ directory cannot see a binary crate's private functions, so the agent does not create one unless you ask it to add a library target first.
Which database feature does it build with?
The one the prompt names, sqlite, which bundles SQLite and needs no server. CI also tests mysql and postgresql, but the helper and meta-route tests do not touch the database, so one feature is enough to prove them; the description says which feature set ran.
Does a local-client test need a running database?
Not for /api/now and /api/version, which take no DbConn. /api/alive does, and src/db/mod.rs answers 503 when the pool is missing, so the agent leaves it out of the first pass or tests the 503 explicitly if you ask.
Will it run the Playwright suite under playwright/?
No. That suite starts MariaDB, MySQL and Postgres through Docker Compose and drives the web vault in Firefox, which is a different job. The pull request says the Rust suite ran and the Playwright suite did not.