Recommended .golangci.yml: pin the lint floor byob idioms assume
byob-release.7
release
Problem: byob-release.3 names golangci-lint run as the body of make lint,
but golangci-lint v2 ships with most useful linters disabled by default.
Without a pinned .golangci.yml, the rules byob's idioms quietly assume
(consistent initialism casing, exported-doc shape, errcheck on every
return) aren't enforced — agents drift, fresh code accumulates lint
debt, and the memory layer that names these rules is paper protection.
Idea: ship a recommended .golangci.yml that enables the linters byob
relies on, with a small allowlist of overrides for cases the template's
idioms generate (e.g. noctx off in _test.go because test helpers
legitimately use background context).
Enable, at minimum:
errcheck— every returned error is handled or annotated.staticcheck— SA bug-checks plus the ST naming rules, especially ST1003 (initialism casing).revivewithexported,var-naming,receiver-naming,unused-receiver— covers the doc-comment-shape and the Get-prefix / initialism naming memories.gocritic— opinionated correctness/style.govetwithnilnessandshadow— backstop for the typed-nil return-signature decision (byob-errors.5).ineffassign,unused— dead-code hygiene.
Plus goimports (formatter) for import group order matching byob's
stdlib / third-party / project convention.
Tradeoffs: more friction on legacy code being ported into a byob-shaped layout. byob targets greenfield Go CLI tools, so the cost is small at template-instantiation time and only grows if you defer adoption. The config is opt-in (the file ships in the template; targets edit it).
When not to use: never. If you remove the lint floor you also remove
the golangci-lint invocation from make lint; otherwise the makefile
target lies about what it's checking.
Design
# .golangci.yml — pinned defaults for byob-shaped Go CLIs.
# Schema is golangci-lint v2.
version: "2"
linters:
default: none
enable:
- errcheck
- staticcheck
- revive
- gocritic
- govet
- ineffassign
- unused
settings:
staticcheck:
checks:
- all
- "-ST1000" # package comment — not mandated on internal pkgs
revive:
rules:
- name: exported
- name: var-naming
- name: receiver-naming
- name: unused-receiver
govet:
enable:
- nilness
- shadow
exclusions:
rules:
# Test helpers legitimately use context.Background() and unkeyed
# struct literals for fakes — silence those classes in _test.go.
- path: _test\.go
linters:
- noctx
- govet
formatters:
enable:
- goimports
settings:
goimports:
local-prefixes:
- github.com/<your-org>/<bin>
Replace <your-org>/<bin> at template-instantiation time so the
project-local import group lands in the third position
(stdlib / third-party / project).