All jobs

Write Tests for a Go CLI

Yes. An agent writes Go tests for your CLI's flags, config loading and input sources, adds golden-file output tests, runs go test ./... and opens a pull request.

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 command before the tests. In a Cobra and Bubble Tea CLI like charmbracelet/glow (module charm.land/glow/v3, Go 1.26.7, Cobra 1.10.2, Bubble Tea v2, Glamour v2), main.go holds the root command and its flags as package-level variables: --pager, --tui, --style (default auto), --width, --all, --line-numbers, --preserve-new-lines, a hidden --mouse, and a persistent --config. validateOptions runs as PersistentPreRunE and decides the style and width when they were not set, and tryLoadConfigFromDefaultPlaces reads glow.yml through Viper from GLOW_CONFIG_HOME, then XDG_CONFIG_HOME/glow, then the user config directory, and writes a default file when none is found.

Then it reads what is already tested, so it adds rather than repeats. glow_test.go has one table test that parses -p, -s light and -w 40. url_test.go checks GitHub and GitLab README URL resolution, but every case calls t.Skip("test uses network, sometimes fails for no reason"), so none of them runs. ui/ and utils/ have their own tests for the pager, raw painting and text sizing. Nothing tests sourceFromArg, the function that turns an argument into something to read: - for stdin, a GitHub or GitLab shorthand, an http or https URL (any other scheme is refused as not supported, and a non-200 answer is an error), a directory searched for a README by the names in readmeNames, or a plain file.

It writes tests for each of those without the network. URL sources run against an httptest.Server that answers 200, 404 and a redirect, so the skipped tests' intent finally runs. Directory sources use t.TempDir() with a Readme.md nested a level down and with none at all, which must return missing markdown source. Config loading sets GLOW_CONFIG_HOME with t.Setenv to a temporary directory, so the default glow.yml it writes never lands in a real home directory. Because the flags are package globals that rootCmd.ParseFlags mutates, each test resets them, and none of these tests calls t.Parallel().

For output it adds golden files. executeCLI renders to any io.Writer, so a test feeds a fixed Markdown file through it with a fixed style such as notty and a fixed --width, and compares the bytes with a file under testdata/, using charmbracelet/x/exp/golden, which is already in go.sum, and an -update flag to rewrite them. Where the TUI is involved it uses teatest to drive the Bubble Tea model, send key presses and compare the final screen with a golden file. It runs go test ./... and then go test -race ./..., the same -race flag the repository's coverage.yml workflow uses.

Start it with one API call

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

{
  "agent": "claude",
  "input": "Write Go tests for this CLI. Read main.go and the config code first, and list what is untested: flag parsing and option validation, config file loading from each directory it searches, and every input source the CLI accepts (stdin, repository shorthands, http and https URLs, directories searched for a README, plain files, and the errors for each). Test URL sources against an httptest server, never the real network, and keep every file the code writes inside t.TempDir() by setting the config environment variables with t.Setenv. Reset any package-level flag variables between tests. Add golden-file tests for rendered output with a fixed style and width, with an -update flag to regenerate them, and use teatest with golden files where the TUI is involved. Run go test ./... and go test -race ./... until both pass, and open a pull request that lists what each new test covers.",
  "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. For a CLI like glow, the diff adds test files beside the code they test (main_test.go or a source_test.go for sourceFromArg, a config test, a ui/ test for the TUI), a testdata/ folder with the Markdown input and the golden output, and test-only dependencies in go.mod and go.sum such as teatest. The description lists each test against the path it covers and calls out the network-dependent URL tests that were skipped and are now covered by a local server.

The session transcript keeps every command with its output: go test ./... and go test -race ./..., including runs that failed while the tests were being written, and the run that generated the golden files. The pull request's checks then run the repository's own workflows, which for glow include the coverage job's go test -race -covermode atomic ./....

Before merging, a reviewer reads the golden files, since they are the expected output and a wrong one would lock in a rendering bug, and checks that nothing in the tests reads the real home directory or the network.

Run it on every pull request that adds a flag

When a pull request adds a flag or an input source without a test, send POST /o/{org}/sessions with the pull request's URL, https://github.com/<owner>/<repo>/pull/<n>, in resources; the agent clones that branch and adds the tests for what changed. A small step in your own CI or a GitHub webhook handler on your server can send it.

Set a webhook_url on the API key and Rush posts run.completed or run.failed when the turn ends, with a session_url for the result. A follow-up message to POST /o/{org}/sessions/{id}/messages asks for more cases in the same sandbox.

The use case this job follows, with its automation and trigger: Write the missing tests.

Why run it on Rush?

CLI tests that touch config files, environment variables and a home directory are exactly the ones that are unsafe to iterate on a laptop: one test that forgets t.TempDir() writes a glow.yml into a real config directory. In a Rush sandbox the agent writes and reruns them on a machine that exists for this run, and the -race runs that slow a laptop do not slow anyone.

The transcript keeps every go test run with its output, so the reviewer sees the failures that shaped the tests and the passing -race run, and the golden files are generated from a run that is on the record rather than from someone's terminal.

Frequently asked questions

Will the tests hit the network?

No. The prompt says to test URL sources against httptest.Server. glow's own URL tests are skipped because they used the network and failed at random; the new ones cover the same code paths against a local server that answers 200, 404 and other statuses on demand.

How do golden files get updated when the output changes on purpose?

Each golden test takes an -update flag, so go test ./... -update rewrites the files and the diff shows exactly what changed in the output. The pull request explains the flag so the team knows how to use it.

Can teatest test a Bubble Tea v2 program?

The agent checks which teatest release matches the Bubble Tea version in go.mod before adding it. If no compatible release exists, it tests the model's Update and View functions directly with golden files and says so in the pull request.

Will it refactor main.go to make it testable?

Only as far as tests need and no further. glow's executeCLI already writes to an io.Writer, so output can be tested as is. If a function reads os.Stdin directly, the agent may pass the reader in, and the pull request lists every non-test change.