All jobs

Dockerize a Gin API

Yes. An agent writes a multi-stage Dockerfile and compose file for your Gin API, builds it with the SQLite driver's cgo, 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 starts by reading what the binary needs, because a Go image that ignores cgo is the usual way this job goes wrong. In a Gin API like gothinkster/golang-gin-realworld-example-app, go.mod says go 1.21 with gin-gonic/gin v1.10.0, gorm.io/gorm v1.25.12 and gorm.io/driver/sqlite v1.5.7, and the indirect list carries mattn/go-sqlite3, which compiles C. So the build stage cannot set CGO_ENABLED=0, and the runtime image cannot be scratch: it needs the C library the driver links against. hello.go is the entrypoint; it opens the database through common.Init(), runs GORM AutoMigrate for the user, article, tag, favorite and comment models on every start, and listens on PORT, defaulting to 8080. common/database.go reads DB_PATH, defaulting to ./data/gorm.db, and creates that directory if it is missing. There is no Dockerfile, no compose file and no .dockerignore in the repository; .env.example lists PORT, GIN_MODE and DB_PATH.

From that it writes a two-stage Dockerfile. The build stage uses the Go toolchain image for the version the CI matrix in .github/workflows/ci.yml tests last, installs gcc and the musl headers so go-sqlite3 compiles, copies go.mod and go.sum first so go mod download caches as its own layer, then builds hello.go with CGO_ENABLED=1. The runtime stage is a small Alpine image with sqlite-libs and CA certificates, a non-root user, a /data directory that user owns, DB_PATH=/data/gorm.db, GIN_MODE=release, EXPOSE 8080 and a HEALTHCHECK that requests /api/ping, the route hello.go registers for exactly this purpose. A .dockerignore keeps tmp/, *.db, .env and the coverage.out file CI writes out of the build context, matching what .gitignore already excludes.

The compose file is short because the app has no separate database: one api service built from the Dockerfile, a named volume mounted at /data so the SQLite file survives a restart, PORT and GIN_MODE passed from the environment, and the health check wired to depends_on for anything you add later. Since migrations run inside main(), there is no separate migrate step to script, and the agent says so in the pull request rather than inventing one.

Then it proves the image works. In its sandbox it runs docker compose build, starts the service, and waits on /api/ping the way scripts/run-api-tests.sh does. That script also shows how the repository tests its own API: it downloads the Conduit Postman collection and runs it with Newman against port 8080. The agent runs the same collection against the container, so a build that compiled but cannot open its database or write to /data fails here, not on your machine. It records docker image ls for the image size and fixes and rebuilds until the collection passes.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Containerize this Gin API. Read go.mod, go.sum, hello.go, common/database.go, .env.example, .gitignore, scripts/run-api-tests.sh and .github/workflows/ci.yml first, and list the Go version, the cgo dependencies, the port, the database path and the directories the process writes. Write a multi-stage Dockerfile: a build stage that caches go mod download in its own layer and builds hello.go with cgo enabled for the SQLite driver, and a small runtime stage with the C library the driver needs, a non-root user, a writable data directory for DB_PATH, GIN_MODE=release, EXPOSE for the port and a HEALTHCHECK on /api/ping. Add a .dockerignore and a compose.yaml with the api service, a named volume for the database file and configuration from environment variables. Build it in the sandbox, start it, wait for /api/ping, then run the Conduit Postman collection with Newman against the container the way scripts/run-api-tests.sh does. Fix anything until it passes, and open a pull request with the image size and the commands to run it locally.",
  "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 with Dockerfile, compose.yaml, .dockerignore and a README section with the build and run commands. The description lists each choice and the file it came from: the Go version from the CI matrix, cgo kept on because of go-sqlite3, the C library in the runtime image, the /data volume because DB_PATH defaults to a relative path the container would lose, and the health check on /api/ping because the route already exists.

The transcript on the session keeps every command with its output: each docker compose build, the container logs showing GORM's migrations, the wait loop on /api/ping, the Newman run against the container, and any build that failed before the fix. The repository's own CI workflow runs on the pull request too, so the gofmt check, the coverage run, golangci-lint and the API test job all report on a change that touches no Go file.

Before merging, a reviewer checks that the runtime image carries no Go toolchain or gcc, that the process runs as the non-root user and can still write the database file, that .env is not copied into the image, and that the health check path matches the route. If production uses Postgres rather than SQLite, one follow-up message to the same session swaps the driver and adds a database service, and the sandbox boots the stack again.

Run it on every new Go service without a Dockerfile

A team containerizing several Go services starts one run per repository: a POST /o/{org}/sessions with that repository in resources and this prompt. Send an Idempotency-Key per repository so a retried request returns the run it already started.

Each run has its own sandbox with its own Docker daemon, so several builds run at once without sharing a layer cache or a port. Up to the key's max_concurrent runs proceed in parallel, and a webhook on the key receives run.completed or run.failed for each turn with the session_url that holds the pull request.

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

Why run it on Rush?

The slow part of this job is the loop: build, start, watch it fail on a missing shared library or a read-only directory, change one line, build again. On a laptop that loop fills the local Docker cache and competes with whatever is already on port 8080. In a Rush sandbox the agent has its own daemon and its own ports, and the sandbox parks when the turn ends, so nothing is left running on your machine.

The pull request carries its own proof. The Newman run against the container, the health check output and the image size are in the transcript beside the commands that produced them, so a reviewer can see the API answered the shared Conduit collection from a clean image rather than from a machine that already had Go, gcc and SQLite installed.

Frequently asked questions

Why does the image need gcc and a C library for a Go program?

Because gorm.io/driver/sqlite depends on mattn/go-sqlite3, which compiles the SQLite engine from C through cgo. The build stage needs a C compiler and the runtime stage needs the C library the binary links to. A CGO_ENABLED=0 build or a scratch image fails at runtime with a driver error, which is why the agent reads go.mod before writing the Dockerfile.

Could it switch to a pure-Go SQLite driver instead?

It could, and the pull request mentions the option, but it does not change the driver unless the input asks. Swapping go-sqlite3 for a pure-Go driver changes the database layer of the app, which is a different review from adding a Dockerfile.

Where does the database file live when the container restarts?

On a named volume mounted at /data, with DB_PATH pointing there. Without the volume, the file would sit in the container's writable layer and disappear with it. The non-root user owns the directory, so GORM can create the file on first start.

Does it run the Postman collection against my API?

Yes, in the sandbox only, against the container it just built. The script scripts/run-api-tests.sh already downloads the Conduit collection and runs it with Newman; the agent reuses that collection as the proof the containerized API behaves like the one CI tests.