All jobs

Review Pull Requests on an Actix Web API

Yes. An agent checks out the pull request, runs cargo clippy with -D warnings and cargo test in its sandbox, and posts one review on extractors and shared state.

Run this on RushIn a Project that has your repository.

What the agent does

The agent reads the workspace before the diff, because in actix/examples a change to one crate is built under rules set at the root. Cargo.toml is a workspace with resolver = "3", seventy-four members from auth/casbin to websockets/echo, edition = "2024" and rust-version = "1.98" in [workspace.package], and a [workspace.dependencies] table that pins actix-web at 4.11, actix at 0.13, actix-session at 0.11, actix-ws at 0.4, awc at 3.7, tokio at 1.24.2 and the rest, so a member Cargo.toml says actix-web.workspace = true rather than a version. databases/sqlite is excluded from the workspace. examples-common is a member that the TLS and tracing examples share. A pull request that adds a version to a member crate, or a crate without adding it to members, is a finding before any code is read.

Then it runs what CI runs. .github/workflows/clippy-fmt.yml runs zizmor over the workflows, a rustfmt check, and cargo clippy --workspace --all-features --tests -- -D warnings, so a single warning fails the pull request. ci.yml installs sqlite3, libpq-dev and redis-server, installs sqlx-cli and diesel_cli, creates todo.db with sqlx database create and sqlx migrate run --source=./basics/todo/migrations, starts Redis, then runs cargo check --workspace --bins --examples --tests and cargo test --workspace --all-features --no-fail-fast --exclude=db-diesel -- --nocapture, with the Diesel example tested separately after diesel migration run. rustfmt.toml sets group_imports = "StdExternalCrate", imports_granularity = "Crate" and use_field_init_shorthand, which justfile applies with cargo +nightly fmt. The agent runs clippy with the same flags across the workspace, cargo fmt --check with the nightly toolchain, and cargo test in the touched example, with the SQLite and Redis setup from ci.yml when the example needs it.

The tests are concentrated in a few examples, which tells the agent where proof is available. Ten files carry #[actix_web::test], among them json/json, basics/hello-world, basics/nested-routing, forms/form, databases/diesel, databases/diesel-async, databases/mongodb, templating/yarte, guards and auth/redis-session. json/json/src/main.rs is the model: test::init_service(App::new().service(...)), a TestRequest::post().uri("/").set_json(MyObj { ... }), app.call(req), then to_bytes(resp.into_body()) compared with the exact JSON string. An example that gets new behaviour without a test in that shape gets a finding that names the file, and the agent writes the case in the sandbox to confirm the behaviour before posting it.

The diff is read with the three questions the prompt names. Extractors: json/json shows web::Json<MyObj> with JsonConfig::default().limit(4096) set on the app and a tighter limit(1024) on one resource, and index_manual taking web::Bytes and calling serde_json::from_slice; a new handler that takes web::Json without a limit where the app sets none, or that unwraps a Result extractor, is a finding. Shared state: basics/state/src/main.rs explains the three kinds, Data<Mutex<usize>> and Data<AtomicUsize> created outside the HttpServer::new closure and cloned in, and a Cell<u32> created inside the closure so each worker thread gets its own; a diff that builds a Data inside the closure and expects it to be shared, or holds a Mutex guard across an .await, gets a finding with the line. Blocking inside async handlers: basics/todo uses sqlx with runtime-tokio, while a std::fs::read, a synchronous reqwest::blocking call or a std::thread::sleep inside a handler stalls the worker; the fix the review names is web::block or the async client. One GitHub review is posted per run, quoting clippy, fmt and the example's tests, separating blocking issues from suggestions, with file and line on every finding. 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 an Actix Web examples workspace. Check it out, run cargo clippy --workspace --all-features --tests -- -D warnings and cargo +nightly fmt --check, then cargo test -p <crate> for each example the diff touches, setting up todo.db with sqlx-cli or starting redis-server first as .github/workflows/ci.yml does when the example needs them. Read the diff with the example's main.rs, its Cargo.toml, the root Cargo.toml workspace table and any #[cfg(test)] module. Look for member crates that pin a version instead of using workspace = true or are missing from members, web::Json or web::Form extractors without a payload limit where the app sets none, Result extractors unwrapped in handlers, Data built inside the HttpServer closure that the code treats as shared, Mutex guards held across .await, blocking file, network or sleep calls in async handlers, and new behaviour with no #[actix_web::test] case. 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 clippy, fmt and test 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"
    }
  ]
}
  1. 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.
  2. 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.
  3. 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. Its summary quotes cargo clippy with -D warnings, the rustfmt check, and cargo test for each touched example with its pass and fail counts, plus the SQLite or Redis setup it needed. Findings follow with file and line in the example's src/, marked blocking or suggestion, and a state finding says which of the three patterns in basics/state the code should have used.

The transcript keeps the crate downloads, every command with its output, the todo.db migration when it ran, and the #[actix_web::test] cases the agent wrote to confirm a finding, so when the review says a handler blocks the worker, the test that timed out is in the record.

Before merging, a reviewer runs clippy and the touched example's tests on the branch, opens each cited line, and decides which suggestions to keep. A clippy warning, a guard held across .await or a blocking call in a handler is blocking by default; a request to add a test to an example that never had one is a suggestion.

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, branch_patterns set to main, and this prompt. Each fire adds the pull request after the prompt, so every pull request and every push to it gets its own sandbox, its own target/ directory and its own review. Set read_only so the runs comment and never push.

The review is the result on the pull request; the run is listed in the Project. max_runs_per_hour, 1 to 30, bounds a dependency-update morning, since .github/dependabot.yml runs weekly Cargo updates behind a three-day cooldown and groups them; a fire past the cap is skipped as rate_limited and the pull request is reviewed on its next push.

The use case this job follows, with its automation and trigger: Review every pull request.

Why run it on Rush?

An Actix review that stops at the diff misses what clippy with -D warnings catches across seventy-four crates, what a Mutex guard across an .await does under load, and whether the example's test still passes once todo.db has been migrated and Redis is up. Doing that locally means a full workspace build and the service setup from ci.yml. On Rush the agent does it in its own sandbox and keeps every command and its output, so the review of an extractor or a state change rests on a compiled, tested branch rather than a reading.

One sandbox per pull request keeps reviews parallel when several examples change at once, each with its own target/ and its own SQLite file, and nothing is pushed to the author's branch. The reviewer gets findings with the clippy and test output attached and the author gets the same verdict CI would give, with the fix named in the terms basics/state and json/json already use.

Frequently asked questions

Does it build every crate in the workspace?

Clippy and cargo check run across the workspace as clippy-fmt.yml and ci.yml do, since a workspace dependency change affects every member. cargo test runs for the touched examples only, with --all-features to match CI.

Which examples need a service to test?

basics/todo needs todo.db created and migrated with sqlx-cli, databases/diesel needs diesel migration run and is excluded from the workspace test run, auth/redis-session and cache/redis need redis-server, and databases/mongodb has a test marked #[ignore] that needs a MongoDB instance. The agent sets up what ci.yml sets up and says in the review which tests it could not run.

Why does the fmt check need nightly?

rustfmt.toml uses group_imports, imports_granularity and use_field_init_shorthand, and the first two are nightly-only options, which is why justfile runs cargo +nightly fmt. The sandbox installs the nightly toolchain for the check only; the build and tests use stable, as the README asks.

What does it do with a new example?

It checks the crate is in the root members list, uses workspace = true for shared dependencies, has a README.md with run instructions, and compiles under clippy's -D warnings. CI's cargo check --workspace --bins --examples --tests will fail on an unlisted crate's dependency drift, so the review treats that as blocking.