Skip to content

Features

Dan Riddell edited this page Sep 30, 2026 · 1 revision

Features

letsgo features [--json]

letsgo's optional behaviours are named, and the names are a closed set. disable turns one off; require turns its "skipped" into a failure. Both live in letsgo.mod, both are repeatable, and both are recorded in the release manifest.

// letsgo.mod
disable sbom proxy-warm
require vulncheck api-gate

A required feature that cannot run fails the plan instead of skipping. That is the whole point of it: govulncheck missing from a runner is a warning by default, because most repositories would rather release than stop, and a Fail for the repositories that would rather stop.

The catalogue

letsgo features prints every feature with its current state, where that state came from, and the directive that would change it. --json gives the same thing with schema: 1.

Integrity — never optional. disable naming one of these is a config error.

feature what it means
reproducible the build is reproducible from source
source a source archive is published with the release
manifest letsgo.json records what was built and how
checksums SHA256SUMS lists every artifact's digest
tag-check the tag matches the version letsgo resolved
module-path the module path matches its major version

Gates

feature default disable require
vulncheck on yes yes
api-gate on yes yes
sumdb on yes yes
budget off — —

Outputs

feature default disable require
sbom on yes yes
install-script on yes yes
changelog on yes yes
diff-notes on yes yes
randomart on yes yes

Publishing

feature default disable require
proxy-warm on yes —
brew off — —
image off — —

budget, brew and image are off until their own directive turns them on, so there is nothing for disable to do — removing the directive is how you switch them off, and disable brew is an error that says so.

What each one does

  • vulncheck — govulncheck must find no reachable vulnerabilities. --allow-vulnerable publishes anyway and records which findings were accepted.
  • api-gate — an incompatible API change needs a major version bump. --allow-breaking overrides it for one run.
  • sumdb — sum.golang.org must agree with the source archive before any asset is published. See Publishing.
  • sbom — a reproducible CycloneDX bill of materials is published.
  • install-script — install.sh is generated, carrying each archive's digest.
  • changelog — commits since the previous tag become the release body.
  • diff-notes — the collapsed what shipped section.
  • randomart — a collapsed visual fingerprint of the manifest digest in the notes, for comparing a release by eye.
  • proxy-warm — proxy.golang.org is primed before the release is published. --no-proxy-warm does the same thing for one run, and is recorded the same way.

Errors worth knowing about

  • An unknown name is an error with a did-you-mean suggestion: disable sbmo says sbom.
  • The same feature in both disable and require is a config error.
  • A duplicate name inside one directive is tidied by letsgo fmt, not an error.
  • disable changelog together with --append-notes leaves the existing release body untouched and appends nothing.

In the manifest

Departures from the defaults are recorded, and nothing is recorded when there are none:

"features": {
  "disabled": ["sbom"],
  "required": ["vulncheck"]
}

letsgo verify prints a features line whenever that field is present, so a release that skipped something says so to anyone checking it later. A plugin cannot change any feature's state — the catalogue is core's, and a release that quietly turned off its own SBOM because a plugin asked would be a release whose manifest lies.

Each module in a monorepo sets features independently, in its own letsgo.mod.

Clone this wiki locally