What the agent does
The agent reads how the service is built and configured before writing a line of Dockerfile. In an Axum API shaped like launchbadge/realworld-axum-sqlx, Cargo.toml is a single crate on edition 2021 that depends on axum 0.3.4, tokio 1.14 with the multi-thread runtime, sqlx 0.5 with runtime-tokio-native-tls and postgres, clap 3.0.0-beta.5 for configuration, argon2 0.3.1 for passwords, and dotenv, env_logger and anyhow. There is no Dockerfile, no Compose file and no rust-toolchain file. src/config.rs is a clap::Parser struct with database_url and hmac_key, each read from a flag or the environment, and .env.sample documents DATABASE_URL, HMAC_KEY and RUST_LOG with {password} and {random-string} placeholders; .gitignore keeps .env out of the repository.
Two facts in src/main.rs and src/http/mod.rs decide the design. The service runs sqlx::migrate!().run(&db) at startup, with the four files in migrations/ compiled into the binary, so the container needs no separate migration step. And http::serve binds 0.0.0.0:8080 with no port variable, so the Compose file maps 8080 and the Dockerfile exposes it. The harder fact is in the handlers: src/http/ uses sqlx::query! and query_as! in 26 places, and those macros check every statement against a live database at compile time. A plain cargo build inside docker build has no database, so the agent prepares SQLx's offline data: it starts Postgres in its sandbox, runs sqlx db setup as the CI workflow in .github/workflows/rust.yml does, runs cargo sqlx prepare to write the query metadata file for sqlx 0.5, commits it, and builds with SQLX_OFFLINE=true.
The Dockerfile is two stages. The builder uses the official Rust image, copies Cargo.toml and Cargo.lock first and the sources after so dependency compilation is cached across source changes, and runs cargo build --release with SQLX_OFFLINE=true. The runtime stage is a slim Debian image with ca-certificates and the OpenSSL runtime library that native-tls links against, copies the single binary, runs as a non-root user and starts it directly. A .dockerignore excludes target/, .git/ and .env, which also keeps a developer's HMAC_KEY out of the build context. compose.yaml defines db from the postgres:14 image the README recommends, with a pg_isready healthcheck copied from the CI service definition, and api built from the Dockerfile, with DATABASE_URL pointing at the db service, HMAC_KEY and RUST_LOG from the environment, depends_on waiting for the healthcheck, and port 8080 published.
Then it proves the stack boots. It runs docker compose up --build, watches the migrations apply in the API's log, and sends the registration and login requests from the RealWorld API spec to http://localhost:8080/api/users, keeping the responses. It runs cargo test against the same database the way CI does, and cargo fmt --check. The pull request includes the Compose log lines showing the migration run and the HTTP responses, and explains the offline-query decision so a reviewer knows why a metadata file joined the repository and when it has to be regenerated: whenever a query! statement changes, run cargo sqlx prepare again.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "claude",
"input": "Dockerize this Axum API. Read Cargo.toml, src/main.rs, src/http/mod.rs, src/config.rs, .env.sample, .gitignore, the migrations directory and .github/workflows/rust.yml first. The handlers use sqlx query! macros that need a database at compile time, so start Postgres, run sqlx db setup and cargo sqlx prepare, commit the offline query data, and build with SQLX_OFFLINE=true. Write a two-stage Dockerfile: a Rust builder that caches dependencies, and a slim runtime image with ca-certificates and the OpenSSL runtime, running the binary as a non-root user on port 8080. Add a .dockerignore that excludes target, .git and .env. Write compose.yaml with a postgres:14 service with a pg_isready healthcheck and the api service depending on it, with DATABASE_URL, HMAC_KEY and RUST_LOG from the environment. Run docker compose up --build, confirm the migrations run, register and log in a user through the API, run cargo test and cargo fmt --check, and open a pull request with the Compose log and the responses.",
"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 its own branch that adds Dockerfile, .dockerignore, compose.yaml and the SQLx offline query metadata file, and changes nothing under src/. The description quotes the Compose output from the run: the Postgres healthcheck turning healthy, the API's log lines as sqlx::migrate! applies the four migrations, and the JSON responses from the registration and login requests. It also states the Rust image tag the builder stage uses and why the runtime stage needs the OpenSSL library, which follows from the runtime-tokio-native-tls feature in Cargo.toml.
A reviewer checks three things. That the offline metadata was generated from the current migrations, by reading the cargo sqlx prepare command in the transcript next to the sqlx db setup that preceded it. That no secret made it into the image: HMAC_KEY comes from the environment at run time, .env is excluded from the build context, and the Compose file carries no value for it. And that the cargo test run in the transcript passed against the Compose database, since the tests are what CI runs with its own Postgres service.
Run it on every service without a Dockerfile
A script on your server lists the organization's repositories with GET /o/{org}/github, checks each for a Cargo.toml and no Dockerfile, and sends one POST /o/{org}/sessions per match with this prompt and that repository as the resources URL. Each run works in its own sandbox and opens its own pull request; a request_id per repository makes the script safe to re-run.
Set a webhook_url on the API key and Rush POSTs run.completed when each turn finishes, with the session_url to read the pull request from; a run.failed names the service whose build the agent could not get green.
The use case this job follows, with its automation and trigger: Hand off from your terminal.
Why run it on Rush?
Containerizing an SQLx service is where a straightforward task turns into an afternoon: the first docker build fails on query! because there is no database inside the build, and the fix needs a database, the sqlx-cli tool and a decision about committing generated metadata. The agent has a computer of its own to run Postgres, the CLI and Docker, and it records the decision in the pull request instead of in a Slack thread.
The result is a pull request a reviewer can read with the proof attached: the Compose log, the migration lines and the API responses, all in the transcript. The same prompt can containerize several Rust services at once, each in its own sandbox and branch.
Frequently asked questions
Why does the pull request add a generated SQLx file?
Because sqlx::query! and query_as! verify each SQL statement against a database when the crate compiles, and docker build has none. cargo sqlx prepare saves the checked metadata so SQLX_OFFLINE=true builds can skip the live check. The description says when to regenerate it: after any change to a query! statement or a migration.
Does the container run the migrations?
Yes, the application does it itself. src/main.rs calls sqlx::migrate!().run(&db) before serving, with the files from migrations/ embedded in the binary, so starting the container against an empty database creates the schema. The Compose file only has to wait for Postgres to be healthy, which the pg_isready healthcheck does.
Where does HMAC_KEY come from?
From the environment at run time, as src/config.rs already expects through clap's env attribute. The Dockerfile bakes no key, .dockerignore excludes .env, and the Compose file passes the variable through from your shell or an env file you keep out of git. The agent generates a throwaway value for its own run and does not commit it.
Will it upgrade axum or sqlx while it is at it?
No. Cargo.toml pins axum 0.3.4 and sqlx 0.5, and the prompt asks for a container, not an upgrade. The agent builds what is there and says in the pull request if any build warning points at a version worth a separate run.