Getting started
Every tool here is a command under cmd/ that a repository runs with go tool, at the version
its go.mod pins. There is nothing to install globally, and nothing to keep in sync between
machines.
Add the tools you want
Section titled “Add the tools you want”go get -tool github.com/spin-stack/go-tools/cmd/mutatego get -tool github.com/spin-stack/go-tools/cmd/testqualitygo get -tool github.com/spin-stack/go-tools/cmd/versionsEach adds a tool line to go.mod, and go tool <name> runs it. Moving to a newer go-tools is
one command, reviewed like any other dependency bump:
go get github.com/spin-stack/go-tools@<commit>Run them where developers already run checks
Section titled “Run them where developers already run checks”The spin-stack repositories put the quick gates in task lint and the test-driven ones after
task test, so CI runs exactly what a developer runs locally:
tasks: lint: cmds: - golangci-lint run ./... - go tool ctxlife - go tool testquality ./... - go tool refs - go tool mutate -stale-exempts - go tool sfw check - go tool taskgate - go tool vulngate ./...
mutate: vars: BASE: '{{.BASE | default "origin/main"}}' cmds: - go tool mutate -base {{.BASE}} -max 200steps: - uses: actions/checkout@... with: fetch-depth: 0 # mutate diffs against the branch point - run: task lint - run: task test - run: task mutate BASE="origin/${{ github.base_ref }}"The mutate page has the full CI step, which also handles pushes
to main.
Which tool for which problem
Section titled “Which tool for which problem”| you want to know | tool |
|---|---|
| whether the tests would catch a bug in what this change touched | mutate |
| whether some tests can’t fail at all | testquality |
| whether a goroutine is cancelled when its caller returns | ctxlife |
| whether the agent instructions still describe this tree | refs |
| whether the code calls a vulnerable function that has a fix | vulngate |
| where every pinned image, tarball and commit is, and which are out of date | versions |
| whether every package install is pnpm, through Socket Firewall | sfw |
| whether every workflow step is a task a developer can run too | taskgate |
| what a repository would show if it were made public | exposure |
| what a release was built from, signed | provenance, attestgate, sbom |
Libraries
Section titled “Libraries”Some of these are also packages another repository imports: versions (reading
versions.yaml), versions/upstream, versions/gate, provenance, attestgate, sbom and
trustroot. The rest is internal/. Only two are linked into anything spin-stack ships:
versions, which spin’s binaries use to read the pins they carry, and trustroot, which they
verify release signatures against.

