Help us shape the future of Go! Take the 2026 Go Developer Survey

letsgo

module
v1.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: MIT

README

letsgo

A release tool for Go. Only Go.

Status: v1. letsgo releases itself, reproducibility is proven across Linux, macOS and Windows on every push, and what v1 will not break is written down.

It builds your Go project, refuses to ship it if it's wrong, publishes it reproducibly, and lets anyone prove afterwards that the binaries match the source.

GoReleaser is a distribution tool. letsgo is an integrity tool. GoReleaser's job is getting your software to many places — Homebrew, Docker, deb, rpm, snap, AUR, Discord. It's very good at that. letsgo's job is proving a release is what it claims to be and never leaving it half-finished. If you need deb packages, snap or a dozen package managers, use GoReleaser for that repo.

Install

go install github.com/danielriddell21/letsgo/cmd/letsgo@latest

Or with the installer letsgo generated for its own release, which carries each archive's SHA-256 and fails rather than installing a substituted one:

curl --proto "=https" --tlsv1.2 -fsSL https://github.com/danielriddell21/letsgo/releases/latest/download/install.sh | sh

Or from the tap. letsgo writes the formula from the manifest it just published, so what brew installs is the archive the release attests to:

brew install danielriddell21/tap/letsgo

Usage

letsgo plan [--explain] [--json] [--publish] [--diff [--exit-code]] [--format md] [-out file]  resolve and check a release without performing one
letsgo build [--snapshot] [-o dir]     build every artifact into dist/ without publishing
letsgo release [--draft] [-o dir]      build and publish, resumably
letsgo apply [file] [-auto-approve]   publish a release as a saved plan agreed it; with no file, plan it, show it and ask
letsgo plan -yank <tag> [-out file]    show what retracting a release would change
letsgo release --snapshot              rehearse a release without publishing
letsgo verify [tag] [--json] [--words]  rebuild a published release and compare it
letsgo doctor [--json]                 diagnose tools and repository state, read-only
letsgo audit [<tag>]                   re-check published releases against today's vulnerability database
letsgo diff <from> [to] [--format text|md|json]  compare two releases: size, dependencies, API
letsgo promote <rc-tag>                rebuild a prerelease as a stable release
letsgo yank <tag> [--reason "..."]     retract a release, including the go.mod directive
letsgo tag [--major|--minor|--patch|--pre|--json]  work out the next version and tag it
letsgo update [--check]                update letsgo itself, verified against its manifest
letsgo plugin install [<name>]         install a plugin, verified against its manifest (or every pin, with none)
letsgo plugin list [--json]            the plugins this repository pins, and what is installed
letsgo plugin prune                    remove store entries no pin in this repository references
letsgo features [--json]               the feature catalogue: what can be disabled or required
letsgo fmt [file|-]                    format letsgo.mod; - reads stdin, writes to stdout
letsgo lsp [--restricted]              serve letsgo.mod over stdio JSON-RPC, for an editor
letsgo version                         print the version (also --version)

There is usually no config file — project name, module path, main packages, repo owner and version are all derived from go.mod, git, and your directory layout. letsgo plan resolves and checks all of it in about two seconds without building anything, so a misconfigured release fails before the cross-compile rather than after it.

cd ~/code/foo
git tag v1.3.0
letsgo plan            # no side effects; --explain shows where each value came from
letsgo release         # idempotent, so a failed run resumes rather than restarts
letsgo verify v1.3.0   # rebuild it and check it against what was published

Configuration

letsgo.mod is only needed to depart from what letsgo derives — optional behaviours switched off with disable, made mandatory with require, plugins pinned by digest, a Homebrew tap or container image turned on. Machine settings that must not change what a release is — the Go and git to use, the build cache, an opt-in update-check notice — go in a separate global config.mod instead. See Configuration, Features and Global config in the wiki.

In GitHub Actions

letsgo-action installs letsgo and runs it on a runner:

      - uses: actions/setup-go@v7
        with:
          go-version-file: go.mod

      - uses: danielriddell21/letsgo-action@v1

Go is a prerequisite rather than something the action installs: the Go version changes the bytes you ship, so choosing it belongs to the workflow that knows which one the project releases with. See GitHub Action for inputs, outputs, permissions and approval-gated releases.

Agreeing a release before making it

letsgo plan -out release.plan    # build, read the forge, show and save what would change
letsgo apply release.plan        # rebuild, refuse unless it matches the plan, then publish

The plan holds digests, not bytes. apply rebuilds and compares the manifest before any write, so a changed toolchain or dependency between the two steps is caught before anything is published. See Plan and apply for the plan format, yank plans and an approval-gated release in CI.

After a release

The release body ends with a collapsed "what shipped" section comparing the manifest against the previous release, letsgo audit re-checks a shipped release against today's vulnerability database, and letsgo promote turns a prerelease into the stable release it was rehearsing. See What shipped, Audit and Prereleases.

Self-update

Any binary released with letsgo gets verified self-update for the cost of an import:

update, err := selfupdate.Check(ctx, selfupdate.Options{
	Repo:    "you/tool",
	Current: version,
})
if err != nil || update == nil {
	return err // a nil update means the running binary is current
}
return update.Apply(ctx)

Nothing is written until Apply, so a program can offer the update rather than take it. letsgo update is the same package, pointed at letsgo — see Self-update.

Stability

From v1.0.0 the command line, letsgo.mod, the JSON output, the manifest and plan files, the plugin wire contract and the public Go packages follow semantic versioning. Internals and human-readable output do not.

Documentation

Full documentation lives in the letsgo wiki: every command, monorepo releases, global config, editor support, publishing to Homebrew and container registries, plugins, the GitHub Action, migrating from GoReleaser, and the design rationale behind all of it.

Directories

Path Synopsis
cmd
letsgo command
Command letsgo builds and publishes Go releases.
Command letsgo builds and publishes Go releases.
internal
apply
Package apply holds a plan's enforcement: what an apply may write, and when a plan has gone stale.
Package apply holds a plan's enforcement: what an apply may write, and when a plan has gone stale.
archive
Package archive writes byte-for-byte reproducible release archives.
Package archive writes byte-for-byte reproducible release archives.
audit
Package audit re-checks a shipped release's source against today's vulnerability database and records what it finds.
Package audit re-checks a shipped release's source against today's vulnerability database and records what it finds.
brew
Package brew generates and publishes Homebrew formulas.
Package brew generates and publishes Homebrew formulas.
build
Package build compiles and packages release artifacts.
Package build compiles and packages release artifacts.
bump
Package bump works out which version a release should carry.
Package bump works out which version a release should carry.
bytesize
Package bytesize parses and renders sizes in bytes.
Package bytesize parses and renders sizes in bytes.
changelog
Package changelog turns a range of commits into release notes.
Package changelog turns a range of commits into release notes.
credential
Package credential resolves the tokens a release is written with.
Package credential resolves the tokens a release is written with.
diff
Package diff compares two releases.
Package diff compares two releases.
discover
Package discover derives everything letsgo needs from what is already in the repository: go.mod, the git remote, the directory layout, and the source itself.
Package discover derives everything letsgo needs from what is already in the repository: go.mod, the git remote, the directory layout, and the source itself.
doctor
Package doctor diagnoses the tools and repository state a release needs, read-only and offline: see docs/hld/doctor.md.
Package doctor diagnoses the tools and repository state a release needs, read-only and offline: see docs/hld/doctor.md.
feature
Package feature holds the catalogue of letsgo's optional behaviours: what each one is called, whether a repository may turn it off or make it strict, and what it defaults to.
Package feature holds the catalogue of letsgo's optional behaviours: what each one is called, whether a repository may turn it off or make it strict, and what it defaults to.
forgerelease
Package forgerelease uploads a built release, idempotently.
Package forgerelease uploads a built release, idempotently.
forgetest
Package forgetest serves a letsgo-published release the way a forge does.
Package forgetest serves a letsgo-published release the way a forge does.
gate
Package gate runs the correctness checks that decide whether a release is fit to publish.
Package gate runs the correctness checks that decide whether a release is fit to publish.
git
Package git runs git: every read of a repository letsgo needs, and every write it makes (tags, pushes, worktrees), through one Runner that carries the binary and the directory so a call states only what it asks.
Package git runs git: every read of a repository letsgo needs, and every write it makes (tags, pushes, worktrees), through one Runner that carries the binary and the directory so a call states only what it asks.
github
Package github publishes releases to GitHub.
Package github publishes releases to GitHub.
gobuild
Package gobuild invokes the Go toolchain with the flags and environment a reproducible release requires.
Package gobuild invokes the Go toolchain with the flags and environment a reproducible release requires.
goproxy
Package goproxy is the Go module proxy: which one to use, warming it with a new version, and escaping module paths for its URLs.
Package goproxy is the Go module proxy: which one to use, warming it with a new version, and escaping module paths for its URLs.
install
Package install generates a self-verifying installer for a release.
Package install generates a self-verifying installer for a release.
lsp
Package lsp implements letsgo lsp: a language server over stdio for letsgo.mod, the global config.mod and .letsgo/*.mod.
Package lsp implements letsgo lsp: a language server over stdio for letsgo.mod, the global config.mod and .letsgo/*.mod.
notes
Package notes writes a release's notes: the changelog since the previous tag, the "what shipped" comparison of manifests, and the manifest's fingerprint.
Package notes writes a release's notes: the changelog since the previous tag, the "what shipped" comparison of manifests, and the manifest's fingerprint.
notes/notestest
Package notestest holds the fixtures the release-notes tests share: a repository with a history, and a forge that serves a manifest.
Package notestest holds the fixtures the release-notes tests share: a repository with a history, and a forge that serves a manifest.
oci
Package oci builds container images without a daemon or a build system.
Package oci builds container images without a daemon or a build system.
oci/ocitest
Package ocitest is an in-process container registry for tests: enough of the distribution API to exercise a real push and the reads that decide whether to make one.
Package ocitest is an in-process container registry for tests: enough of the distribution API to exercise a real push and the reads that decide whether to make one.
pgpwords
Package pgpwords encodes bytes as the PGP word list (Juola & Zimmermann, 1995), for reading a digest aloud.
Package pgpwords encodes bytes as the PGP word list (Juola & Zimmermann, 1995), for reading a digest aloud.
plan
Package plan resolves a release without performing one.
Package plan resolves a release without performing one.
plugin
Package plugin runs the external programs a repository may put in the middle of a release.
Package plugin runs the external programs a repository may put in the middle of a release.
pluginstore
Package pluginstore is the content-addressed store plugin binaries are installed into.
Package pluginstore is the content-addressed store plugin binaries are installed into.
promote
Package promote rebuilds a prerelease as a stable release.
Package promote rebuilds a prerelease as a stable release.
publication
Package publication makes a built release available: the forge release and its assets, the checksum and proxy gate that stands in front of them, the Homebrew tap and the container images.
Package publication makes a built release available: the forge release and its assets, the checksum and proxy gate that stands in front of them, the Homebrew tap and the container images.
randomart
Package randomart draws a digest as a drunken-bishop picture, the same fingerprint art OpenSSH prints for `ssh-keygen -lv`.
Package randomart draws a digest as a drunken-bishop picture, the same fingerprint art OpenSSH prints for `ssh-keygen -lv`.
receipt
Package receipt renders a verification as a till receipt.
Package receipt renders a verification as a till receipt.
receipt/code128
Package code128 encodes text as a Code 128 barcode in character set B.
Package code128 encodes text as a Code 128 barcode in character set B.
release
Package release turns a plan into a complete set of publishable files.
Package release turns a plan into a complete set of publishable files.
releaser
Package releaser owns the release flow: resolve a plan, build it, hold the build to a saved plan, guard the forge, then publish or rehearse.
Package releaser owns the release flow: resolve a plan, build it, hold the build to a saved plan, guard the forge, then publish or rehearse.
releases
Package releases reads Published Releases back from the forge: it selects which one a command means, and fetches its Manifest.
Package releases reads Published Releases back from the forge: it selects which one a command means, and fetches its Manifest.
releases/githubsource
Package githubsource adapts the forge client to the releases package's sources, for one repository.
Package githubsource adapts the forge client to the releases package's sources, for one repository.
releasetest
Package releasetest builds a minimal, real release for tests that need release.Build's actual output — a source tree, a git tag, and the resulting manifest and archives — rather than a hand-rolled stand-in.
Package releasetest builds a minimal, real release for tests that need release.Build's actual output — a source tree, a git tag, and the resulting manifest and archives — rather than a hand-rolled stand-in.
repro
Package repro drives the release pipeline for reproducibility testing.
Package repro drives the release pipeline for reproducibility testing.
repro/cmd/reprodigest command
Command reprodigest builds the reproducibility fixture and prints the resulting digests as JSON.
Command reprodigest builds the reproducibility fixture and prints the resulting digests as JSON.
safeexec
Package safeexec constrains where helper programs are found and what they can find in turn.
Package safeexec constrains where helper programs are found and what they can find in turn.
sbom
Package sbom describes a release's dependencies in a form other tools read.
Package sbom describes a release's dependencies in a form other tools read.
semver
Package semver compares version tags.
Package semver compares version tags.
suggest
Package suggest finds the name a mistyped one probably meant, for a did-you-mean in an error message.
Package suggest finds the name a mistyped one probably meant, for a did-you-mean in an error message.
sumdb
Package sumdb cross-checks a release's published source archive against sum.golang.org and the module proxy: see docs/hld/sumdb.md.
Package sumdb cross-checks a release's published source archive against sum.golang.org and the module proxy: see docs/hld/sumdb.md.
updatecheck
Package updatecheck tells an interactive user, at most once per interval, that a newer letsgo release exists.
Package updatecheck tells an interactive user, at most once per interval, that a newer letsgo release exists.
verify
Package verify rebuilds a published release and compares it against what was actually shipped.
Package verify rebuilds a published release and compares it against what was actually shipped.
yank
Package yank retracts a published release.
Package yank retracts a published release.
Package manifest describes a release in a form a machine can act on.
Package manifest describes a release in a form a machine can act on.
Package modsyntax reads and formats the line-and-block directive syntax shared by letsgo.mod, the global config and every Plugin's own config.
Package modsyntax reads and formats the line-and-block directive syntax shared by letsgo.mod, the global config and every Plugin's own config.
Package plan is what a release plan says it will do.
Package plan is what a release plan says it will do.
Package plugin is the SDK a letsgo plugin is written against.
Package plugin is the SDK a letsgo plugin is written against.
Package selfupdate updates a binary released by letsgo, from inside that binary.
Package selfupdate updates a binary released by letsgo, from inside that binary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL