All jobs

Dockerize a Spring Boot App

Yes. An agent writes a multi-stage Dockerfile for your Spring Boot app, adds it to the compose file beside its database, boots it in a sandbox and opens a PR.

Run this on RushIn a Project that has your repository.

What the agent does

The agent clones the repository into its own cloud sandbox and reads the build before it writes a Dockerfile. In a Spring Boot app like spring-projects/spring-petclinic the README.md says it outright: there is no Dockerfile, and the suggested route is ./mvnw spring-boot:build-image. pom.xml inherits from spring-boot-starter-parent 4.1.0 with java.version set to 17, the Maven wrapper pins Apache Maven 3.9.16, and build.gradle mirrors it with a Java 17 toolchain and Gradle 9.5.1. application.properties defaults database to h2, exposes every actuator endpoint, and the spring-boot-starter-actuator dependency means /actuator/health already exists. The docker-compose.yml already defines two services, mysql:9.7 and postgres:18.4, each named after the Spring profile that uses it, and application-postgres.properties reads POSTGRES_URL, POSTGRES_USER and POSTGRES_PASS with localhost defaults.

It also reads what must stay out of the image. .gitignore lists target/ and build/, so the .dockerignore starts there and adds .git, the k8s/ manifests and the .devcontainer. spring-boot-docker-compose and spring-boot-testcontainers are both test scope in pom.xml, so neither ships in the jar and the packaged app will not try to start Docker Compose from inside a container. k8s/petclinic.yml points at an image named dsyer/petclinic; the agent leaves that file alone and notes the name in the pull request, because an image tag is a deployment decision.

Then it writes the Dockerfile in two stages. The build stage starts from a JDK 17 image, copies mvnw, .mvn/ and pom.xml first and runs ./mvnw -B dependency:go-offline so the dependency layer caches apart from the source, then copies src/ and runs ./mvnw -B package -DskipTests. Tests are skipped in the image build only because they run in the next step, not because they are optional. The run stage starts from a JRE 17 image, creates a non-root user, uses Spring Boot's jar mode to extract the jar into layers so a code change does not invalidate the dependency layer, exposes 8080 and sets the entrypoint to java with the extracted launcher. A HEALTHCHECK calls /actuator/health, which the actuator starter already serves.

It wires the image into docker-compose.yml as an app service with build: ., SPRING_PROFILES_ACTIVE=postgres, POSTGRES_URL=jdbc:postgresql://postgres/petclinic with the user and password the existing postgres service declares, and depends_on the database. In the sandbox it runs ./mvnw -B verify once so the tests pass before anything is containerised, then docker compose up --build app, waits for /actuator/health to report UP, requests /owners/find and /vets.html to see rendered pages rather than a stack trace, and keeps that output. Only then does it open the pull request.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Dockerize this Spring Boot app. Read README.md, pom.xml, build.gradle, docker-compose.yml, application.properties and the profile properties files first. Write a multi-stage Dockerfile that builds with the Maven wrapper, caches dependencies in their own layer, runs as a non-root user on a JRE image matching java.version, extracts the jar into layers, exposes 8080 and adds a HEALTHCHECK on /actuator/health. Add a .dockerignore based on .gitignore. Add an app service to docker-compose.yml that runs with the postgres profile against the existing postgres service. Run ./mvnw -B verify, then docker compose up --build app, wait for /actuator/health to report UP, request /owners/find and /vets.html, and keep the output. Do not change k8s/ or any Java source. Open a pull request with the commands you ran and their output.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  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 pull request on its own branch that adds Dockerfile and .dockerignore and changes docker-compose.yml to add the app service. No Java source, properties file or Kubernetes manifest changes. The description explains each stage of the Dockerfile, names the base images and why they match java.version, and quotes the docker compose up output: the Postgres container starting, the app logging that it started on port 8080, the health endpoint answering UP and the two page requests returning 200.

A reviewer checks three things before merging. That the build stage copies pom.xml before src/ so the dependency layer caches. That the run stage has no JDK, no Maven and no source, only the extracted layers and a non-root user. And that docker compose up app on their own machine reproduces what the session shows, which it can, because the compose file now carries every environment variable the postgres profile reads.

The session's transcript keeps every command: ./mvnw -B verify with the test summary, the image build with its layer output, and the curl calls against the running container. GET /o/{org}/sessions/{id}/messages returns it, so the evidence outlives the sandbox.

Run it on every new service without a Dockerfile

When a new Spring Boot repository is created, a handler on your server receives GitHub's repository event and sends POST /o/{org}/sessions with this prompt and the new repository as the resources URL. The Rush GitHub App must already be installed on it, which GET /o/{org}/github confirms. Each run gets its own sandbox and opens its own pull request.

Set a webhook_url on the API key and Rush POSTs run.completed when the turn finishes, with the session_url to read the pull request from. A run.failed event is the one that needs a person; the rest need a reviewer.

The use case this job follows, with its automation and trigger: Hand off from your terminal.

Why run it on Rush?

Dockerizing an app you did not write is a loop of build, wait, read a stack trace, fix, and build again, and each loop on a laptop downloads the same dependencies and competes with everything else you are doing. The agent runs that loop in its own sandbox with a real Docker daemon, a real Postgres from your own compose file and the app's own tests, and your machine does nothing.

The pull request arrives with the container already booted once and the health endpoint already answering, and the session keeps the output that proves it. Reviewing a Dockerfile against a transcript of it working is a different job from reviewing one against a hunch, and several services can get the same treatment at once, each in its own sandbox.

Frequently asked questions

Why not just use ./mvnw spring-boot:build-image, as the README suggests?

Buildpacks work and the agent says so in the pull request. A Dockerfile is what most CI systems, registries and reviewers expect to read, it builds without a Docker daemon on the build host when using BuildKit remotely, and it lets you choose the base image and the non-root user yourself. If you prefer the buildpack route, say so in the prompt and the agent adds the docker-compose.yml service around the image that goal produces instead.

Maven or Gradle?

The repository has both wrappers. The agent builds with Maven because the README.md leads with ./mvnw and the CI workflow maven-build.yml runs ./mvnw -B verify, and it says so. Ask for Gradle and the build stage runs ./gradlew bootJar instead; the run stage is the same.

Which database does the compose service use?

Postgres, through the postgres profile, because docker-compose.yml already defines a postgres service and application-postgres.properties already reads POSTGRES_URL, POSTGRES_USER and POSTGRES_PASS from the environment. The image itself is database-neutral: run it with no profile and it uses the embedded H2 database, exactly as ./mvnw spring-boot:run does.

Which JDK does the image use?

One matching java.version in pom.xml, which is 17, for both stages: a JDK for the build and a JRE for the run stage. The .devcontainer asks for Java 21, and the pull request notes the difference so you can raise java.version deliberately rather than by accident of a base image.

Does it change the Kubernetes manifests?

No. k8s/petclinic.yml names an image, dsyer/petclinic, that your registry decides. The agent leaves k8s/ untouched and notes in the pull request that the manifest will need the new image name once you publish one.