All jobs

Run a Large Refactor on a Go Codebase

Hand Rush a Go refactor that touches many files, and get a pull request in small commits, each with the build and tests run after it.

Run this on RushIn a Project that has your repository.

What the agent does

In a Go codebase like umputun/remark42, the target refactor is stated as one mechanical change with a wide blast radius: replace the package-level logger with a logger passed through constructors. The agent first maps the territory. Logging today is a mix: backend/app/main.go calls the standard library's log.Printf directly at lines 53 and 105, while most packages under backend/app, including cmd, rest and storage, build loggers from go-pkgz/lgr. A constructor-passed logger means every package's constructors gain a logger parameter and internal helpers receive it, so the agent lists the constructors in each affected package before editing and fixes the import graph as the package-level sinks disappear.

The repository is large enough that the work is staged in small commits, and the agent proves each one. The backend is its own module at backend/go.mod on go 1.27.0 with vendored dependencies, and the backend test command is make race_test: go test -race -timeout=300s -count 1 ./... from backend/app, which CI runs with coverage. make lint runs go vet, a gofmt check and golangci-lint, and .golangci.yml requires the SPDX header on every file, so edits to headers or new files must preserve it. After each commit the agent runs the build and the race test suite, and a commit that cannot keep the tests green is where the run stops and reports.

The frontend is a separate pnpm workspace at frontend/apps/remark42 and the e2e tests live in their own Go module at e2e/go.mod; the logger refactor targets the backend, but the agent confirms the boundary by building the whole tree the Makefile supports, since some backend packages embed webassets. Where a package's tests construct fixtures through unexported helpers, threading the logger changes test setup too, and those hunks stay in the same commit as the code they set up. Nothing in the change touches version stamping, which the Makefile derives from an exact-match git tag.

When a step cannot keep the tests green, the run stops at needs_review with a summary instead of pushing a broken branch: which commit failed, which test, and the last green commit. Otherwise the pull request opens listing each commit in order, and the description explains the migration rule the agent followed, such as the longest-lived constructor at each package boundary receiving the logger and everything below it taking it as a parameter.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Refactor this codebase: replace the package-level logger with a logger passed through constructors. Work in small commits, run the build and tests after each, and stop at needs_review with a summary if a step cannot keep the tests green. Open a pull request listing each commit.",
  "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

The pull request arrives as a sequence of small commits, each with the build and the race-enabled test suite run after it. The diff removes the shared logger sinks and threads a logger through constructors across the affected packages, with test setup updated in the same commits as the code it exercises. If the run stopped early, the branch ends at the last green commit and the description names the failing step, the failing test and why, so the remaining work is scoped rather than discovered by you.

A reviewer reads the commit list in order, since each one should stand alone with tests green. The hunks to watch are places where a logger's level or format was silently changed to make a test pass, and the diff should show no such adjustments. The session read returns the repository and pull request information, and the transcript holds every build and test run, which is how you verify the per-commit claim without rerunning anything yourself.

Run it on every refactor issue labelled

When an issue describes a mechanical refactor at repository scale, your automation sends POST /o/{org}/sessions with the issue text and this prompt the moment the label lands, so the work starts while the motivation is fresh. Install the Rush GitHub App on the repository first and authenticate with an API key; an Idempotency-Key header keeps a retried submission from starting two runs.

Keep the returned execution_id and read the session when the run settles, or receive the key's completion webhook. A refactor this size is worth a morning review either way; if a commit's message is unclear, send a follow-up on the finished turn asking the agent to explain that step, and the messages endpoint wakes the parked sandbox where it left off.

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

Why run it on Rush?

A refactor that touches most files in backend/app takes hours and wants a machine that is free to run go test -race ./... after every commit for the whole session. That is the point of handing it to Rush: the work runs in its own sandbox on Rush's compute, not on your laptop, and it keeps going after you close the terminal. The per-commit proof lives in the transcript, so reviewing the pull request does not require you to trust a summary of what passed.

For several refactors, submit one repository per run within your key's concurrency allowance and they proceed in parallel, each in its own sandbox with its own commit history. You review the resulting pull requests independently. The useful proof is a commit list where each entry stands alone with the race detector green, and an honest needs_review stop if any step could not keep it that way.

Frequently asked questions

How big is too big for one run?

The prompt scopes one mechanical change: one kind of edit, many files. remark42's backend has dozens of packages under backend/app, which is why the run works in small commits and stops at the first step that cannot keep go test -race ./... green. A second, unrelated refactor belongs in a second run.

What stops the run from leaving the tests red?

The instruction itself: after each commit the agent runs the build and the race test suite, and if a step fails it stops, reports needs_review with the failing commit, test and reason, and opens a pull request up to the last green commit. The transcript shows every run, so you can see exactly where green became red.

The repo mixes log packages. What happens to that?

The agent maps both sinks first: log.Printf in main.go and the go-pkgz/lgr loggers in the packages. The migration rule is set in the pull request description, such as constructors receiving the logger and helpers taking it as a parameter, and the reviewer checks the rule was applied uniformly rather than mixed at boundaries.

Does the frontend get refactored too?

No. The logger change targets the Go backend; the frontend workspace at frontend/apps/remark42 and the e2e module at e2e/go.mod are untouched except where the whole tree is built to confirm the boundary held.

Can I really close the laptop and review in the morning?

Yes. Save the execution_id the API returns; the sandbox keeps working after your terminal closes. Read the session in the morning or receive the key's completion webhook, and you get either the finished pull request or a needs_review summary naming the blocker.