CLI tool
kyoh86/richgo avatar
kyoh86/richgo

richgo: colour for go test output, and a maintainer asking you not to use it

Enrich `go test` outputs with text decorations.

857 stars28 forksGoNOASSERTION

At a glance

What is it?
richgo wraps go test and reprints its output with ANSI styling, with per-category styles for build, start, pass, fail, skip and coverage lines configured from a YAML preference file. The unusual thing about it is the NOTICE section at the top of the README, where the author says he no longer uses it, calls the approach of parsing and adjusting standard output a poor method, and recommends sticking with plain go test instead.
Who is it for?
Adopt richgo only if you want coloured test output and are willing to accept that it parses the standard output of go test rather than replacing the test runner. The author's own advice in the README is not to use it and to improve the upstream tool instead, which is worth reading before you adopt it.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 99 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The NOTICE, and why it comes before the installation instructions

richgo will enrich go test outputs with text decorations. That is the one-line description, and it is followed by badges, an asciinema recording, and then a section titled NOTICE, which is what I think about richgo.

The contents of that section are unusual enough to quote closely. For some years, the author has not been using richgo. Now he does not feel much effect from a little tweaking to the appearance of the test output. And it is a poor method that richgo parses and adjusts the standard output of go test. So he recommends you do not use richgo, get used to pure go test, train an ability to find the error from the output and contribute to improve the official go test if you need it. He acknowledges that some may think he has too much faith in pure Go, but says this is his honest feeling.

Then the practical pointer: if you want a good suggestion for an alternative tool, issue 57 collects them.

This changes how to read the rest of the README. Everything below the notice is still accurate documentation of a working tool, but the author is telling you the tool is the wrong answer and that the right answer is a better go test. That is a more useful position than a project quietly drifting, because it tells you the maintainer's view of the design problem.

The technical objection is well founded and worth stating in your own words. richgo works by taking what go test wrote to standard output, recognising the shapes of the lines, and reprinting them with escape sequences added. It is a text transformation on a stream that was never designed to be parsed. The go test output format is not a stable interface, and when it changes, a tool that parses it breaks in ways that are annoying to diagnose because the symptom is mangled output rather than an error.

That is also why the tool has a mode for the opposite problem, which comes later in this article.

Installing and running it

There are three documented installation routes, one per package manager.

With go get:

code
go get -u github.com/kyoh86/richgo

With Homebrew, from the author's own tap:

code
brew install kyoh86/tap/richgo

And with asdf, which needs the plugin added first and then a version installed:

code
asdf plugin add richgo
asdf install richgo 0.3.6

The basic usage is one command that shadows the test runner:

sh
richgo test ./...

That is the whole model. richgo invokes go test, captures its output, categorises each line, and prints its own styled version.

There is also a way to make it entirely transparent, through a shell alias, so that typing go test gives you the decorated output. The README gives the alias for both shells, pointing at ~/.bashrc for bash and ~/.zshrc for zsh:

code
alias go=richgo

This is the form most people will use, because it means nothing in your build scripts has to change.

The repository layout gives a sense of the implementation. There is main.go at the root, a config/ directory, an editor/ directory that appears to hold the terminal preview used by the editor integration, a richgo.json at the root, and a sample/ directory with a set of test fixtures covering the categories: buildfail, cover05, coverall, emptytest, nocover and notest directories alongside sample_ok_test.go, sample_ng_test.go, sample_skip_test.go and sample_timeout_test.go, plus a run.sh that drives them and two expected-output files, out_colored.txt and out_raw.txt.

Those fixtures are the interesting part of the layout, because they are how a tool that reformats someone else's output proves it still produces the right thing. The Makefile has a gen target that regenerates the embedded sample data with statik, and the sample target runs the sample script.

The testfilter subcommand, and the case where it matters

There is one feature in richgo that survives the author's own criticism, and it is the reason the tool is still useful in a pipeline.

If your build scripts expect to interact with the standard output format of go test, for instance if you are using go-junit-report, you need the testfilter subcommand rather than the plain mode. The example given is:

sh
go test ./... | tee >(richgo testfilter) | go-junit-report

This tees the output of the standard go test run into a richgo testfilter process as well as passing the original output to go-junit-report.

Read that carefully, because it is the opposite of what the rest of the tool does. Everywhere else, richgo replaces the output. Here, the output is passed through untouched to the tool that needs it, and richgo is inserted in a side branch that only decorates what a human reads on a terminal.

That is a much better design for the same underlying problem, and it is the design implied by the author's own note that at some point this recommendation may change, as the go test tool may learn how to produce a standard output format that both this tool and others could rely on. The linked upstream issue, golang/go#2981, is the tracking issue for a stable machine-readable test output format.

So the honest summary of the tool's remaining value is this. The plain richgo test mode is decoration applied to a stream it should not be parsing. The testfilter mode is decoration applied alongside a stream that is left alone, which is safe, and which solves the actual problem of wanting readable output and machine-readable output at the same time.

If you adopt richgo for CI, adopt it for the second reason, not the first.

The line categories and what each one means

richgo separates the output lines into categories, and the README shows the raw go test output for each so you can see what is being matched.

Build covers the case where Go fails to build, printing errors like t.Foo undefined. Start covers the === RUN lines that Go prints at the top of a test. Pass covers the per-subtest PASS lines. Fail covers the --- FAIL line together with the source line underneath it. Skip covers both an explicitly skipped test and the no test files line for a package with nothing to run.

PassPackage and FailPackage are the bare PASS and FAIL words that Go prints once per package, and Cover is the coverage line, both in the per-test form and in the per-package form that appears next to the ok line.

Each category can be styled separately, and the labels are also configurable. The long form gives BUILD, START, PASS, FAIL, SKIP and COVER. The short form gives the two-character markers !!, >, o, x, - and %. And there is a none setting, where richgo will never output labels at all.

That last option is worth noting, because it is the one that makes the tool least intrusive. With labels off, the only difference from plain go test is colour, and colour is something you can turn off again when the output is redirected to a file.

The coverage styling has a related knob. The coverThreshold setting is a number from 0 to 100, and there are two separate styles, coveredStyle for lines with coverage above the threshold and uncoveredStyle for those below, so the coverage you care about can be the one that stands out.

The YAML preference file and where it is looked for

Styles are changed through a preference file, and richgo loads preferences from a list of paths in order.

The search walks four directories and three filenames in each. The current working directory is checked first, with .richstyle, .richstyle.yaml and .richstyle.yml. Then the GOPATH directory with the same three names, then the GOROOT directory with the same three names, and finally the home directory with the same three names.

Setting the environment variable RICHGO_LOCAL to 1 changes the behaviour to load only ${CWD}/.richstyle*, which is the sensible thing to do in a project that wants to pin its own styling and not inherit anything from a developer's machine.

The format is YAML only, and the README is emphatic about that in bold: now Rich-Go supports only YAML formatted. The configuration is long because each line category has its own style block, and each style block has the same set of properties.

Those properties are the ANSI attributes you would expect: hide, bold, faint, italic, underline, blinkSlow, blinkRapid, inverse, conceal, crossOut, frame, encircle and overline, plus foreground and background colours. Colours accept a hex value, an rgb value in either decimal or hex form, or a colour name. The buildStyle, startStyle, passStyle, failStyle, skipStyle, fileStyle, lineStyle, passPackageStyle and failPackageStyle blocks all take the same format.

There are three settings that are not styling. coverThreshold is the number described above. removals is a list of regular expressions, and the comment says that if you want to delete lines, write the regular expressions. leaveTestPrefix is a boolean, and the comment explains that if you want to leave Test prefixes, set it to true, so by default the prefix is stripped from the displayed test names.

The default configuration shows the intended look: long labels, bold yellow for build lines, light black for start and skip, green for pass, bold red for fail, and the bare package-level PASS and FAIL hidden so they do not double up with the per-test lines.

Limits: parsing a format that was never meant to be parsed

The limits are structural rather than incidental.

The first is that richgo parses standard output. The go test output is a human-facing format with alignment, timings and blank lines, and nothing in the toolchain promises it will stay that way. When it changes, richgo either miscategorises a line or fails to match one, and the symptom is output that looks wrong rather than an error message telling you the tool is out of date. The author's own judgement, that it is a poor method, is the summary of this problem.

The second is that it only handles what it has seen. The categories are fixed at build, start, pass, fail, skip, the two package-level lines and cover. A new go test output shape, a different failure format, a panic trace or a line from a subprocess that happens to be interleaved, falls into no category and comes through unstyled at best.

The third is that the styling is a matter of taste, and the maintainer no longer shares the taste. The NOTICE section exists to make sure nobody installs this on the strength of the badges and the demo video without reading that the author would rather you did not.

The fourth is maintenance state. The tagged releases are v0.3.12 from 2023-02-26, v0.3.11 from 2022-11-16 and v0.3.10 from 2021-10-30, while the last push to the repository was on 2026-07-18. So there is a gap of three and a half years between the newest release and the newest commit, which is the pattern of a maintainer who keeps the code working but does not release it often. The asdf instructions in the README install version 0.3.6, which is older still.

The fifth is that the licences are awkward for a tool that only decorates output. The repository records a custom licence that GitHub cannot classify, with the text in the LICENSE file at the root. That is a legal question about a wrapper, and the simplest answer is that the upstream go test needs no permission at all, which is the author's point.

richgo against plain go test and against the alternatives in issue 57

Two comparisons make the choice clearer.

The first is against plain go test, which is the author's recommendation and the default position. The difference in approach is that go test produces the output directly, and whatever you learn to read in it is a skill that transfers to every Go project and every CI log you will ever read. richgo makes the output prettier in the moment and does not make you better at reading it. The author's phrasing is that you should train an ability to find the error from the output and contribute to improve the official go test if you need it, which is a request for upstream contribution rather than a wrapper.

There is a real argument for colour, though, and it is not aesthetic. Go test output is dense, and the failures in a large suite are scattered among hundreds of passing lines. Colour is a way of making the failures findable without reading. If that is the only thing you want, the cheapest version of the idea is to configure your CI's own tooling to colour the output rather than to route the stream through a parser.

The second comparison is against the alternatives collected in issue 57, which the README points to for a good suggestion for an alternative tool. The existence of that issue is the point: the author considers the problem real and thinks his own tool is the wrong solution, and the alternatives are the recommended path.

The pattern across both comparisons is the same. The problem richgo addresses, making a dense text stream easier to scan, is real and worth solving. richgo's particular solution, parsing and reprinting another program's output, is the fragile way to solve it, and the author says so. If you want colour in your test output, use the approach in issue 57 or wait for the stable output format tracked in golang/go#2981, which would let a tool like this work on a documented interface rather than a guess.

Editorial conclusion

Adopt richgo only if you want coloured test output and are willing to accept that it parses the standard output of go test rather than replacing the test runner. The author's own advice in the README is not to use it and to improve the upstream tool instead, which is worth reading before you adopt it. Verify first that your CI parses go test output, because that is exactly the case the testfilter subcommand exists for, and that the version you install is current, since the last tagged release is from 2023 while the repository has moved on.

Frequently asked questions

What does richgo do to go test output?

It wraps go test, captures its standard output, sorts the lines into categories such as build, start, pass, fail, skip and cover, and reprints them with ANSI styling. Each category has its own style block in a YAML preference file, and the label text can be long, short or omitted entirely.

How do I use richgo in a build pipeline that parses test output?

Use the testfilter subcommand rather than replacing the output: go test ./... | tee >(richgo testfilter) | go-junit-report tees the original output to go-junit-report while a separate richgo process decorates what a human reads. The README notes that this recommendation may change once go test can produce a standard output format.

Where does richgo look for its configuration file?

It loads preferences from .richstyle, .richstyle.yaml or .richstyle.yml in the current working directory, then in the GOPATH directory, then in the GOROOT directory, then in the home directory. Setting RICHGO_LOCAL to 1 restricts it to ${CWD}/.richstyle* only, and the format is YAML.

Official sources

  1. Issues
  2. kyoh86/richgo on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kyoh86-richgo.svg)](https://hysenlabs.com/projects/kyoh86-richgo)

Was this useful?