Go + Standard Toolchain
Category: Tech Stack · Areas: all
Description
Category
tech-stack
Areas
all
Components
- Language: Go (version pinned in
go.mod) - Build system:
go build/go test(standard toolchain) - Formatter:
gofmt(non-negotiable) - Linter:
golangci-lintwith.golangci.ymlconfig - Security scanner:
gosec+govulncheck - CLI framework: Cobra (for CLI projects)
- Testing:
go testwith build tags for test levels
Constraints
- All code must pass
gofmt -l .(zero diff) - All code must pass
go vet ./... - All code must pass
golangci-lint runwith project.golangci.yml - Errors must be wrapped with context:
fmt.Errorf("context: %w", err)— no nakedreturn err - No
panicoutside ofmain()or initialization — return errors - Pass
context.Contextas first parameter to functions that do I/O or may be cancelled - Define interfaces in the consuming package, not the providing package
- Version metadata embedded at build time via
-ldflags "-X main.Version=..." govulncheck ./...must pass (no known vulnerabilities)
Lint Policy (golangci-lint baseline)
Enabled linters:
govet(withenable-all, disablefieldalignment)staticcheckineffassignmisspellunconvertgosec(severity: high, confidence: high)gocritic(diagnostic, performance, style tags)
Disabled linters (too opinionated):
wsl,wrapcheck,varnamelen,nlreturn,exhaustructparalleltest,testpackage,mnd,funlen
Generated files (.pb.go, .gen.go, mock_*.go) excluded from linting.
When to use
All Go projects — CLIs, services, libraries. The standard toolchain and
go fmt are universal; golangci-lint + gosec are the quality layer on top.
ADR References
Practices by activity
Agents working in any of these activities inherit the practices below via the bead’s context digest.
Requirements (Frame activity)
- Specify minimum Go version in
go.mod - Identify test levels needed: unit, integration (VCR/stubbed), functional (binary), E2E (live)
- If the project hits external HTTP APIs, plan for VCR recording in integration tests
Design
- Package layout:
cmd/for CLI entry points,internal/for application logic - Define interfaces in the consumer package; return concrete types where practical
- Use minimal, consumer-driven interfaces
- Guard shared state explicitly; prefer immutable data; use
errgroupfor concurrent work - Embed version metadata:
Version,BuildTime,GitCommitvia-ldflags
Implementation
- Formatting:
go fmt ./...(run before every commit — enforced bygofmt -l .check) - Error wrapping:
fmt.Errorf("context: %w", err)— always add context - Sentinel errors: define with
errors.Newfor expected conditions; compare witherrors.Is - Concurrency: pass
context.Contextfirst; useerrgroup.WithContextfor fan-out; avoid goroutine leaks - Logging: structured with
log/slog(stdlib) or project-chosen structured logger; nofmt.Print*in library code - No
panicoutside startup; inmain(), convert panics to fatal log + exit
Testing
- Run with:
go test ./... - Race detection:
go test -race ./...for concurrent code - Build tags for test levels:
- (no tag): fast unit tests, no external deps
-tags=integration: VCR playback, no live APIs-tags=functional: built binary CLI tests-tags=e2e: live API tests (requires credentials)
- Table-driven tests for pure functions
- HTTP stubs: VCR cassette recording (
VCR_MODE=recordto capture,VCR_MODE=playbackfor CI) - Use
testify/assertortestify/requirefor assertions; not baret.Fatalcomparisons - Coverage:
go test -coverprofile=coverage.out ./...+go tool cover -func; 80% threshold
Quality Gates (pre-commit / CI)
go fmt ./...(orgofmt -l .check)go vet ./...golangci-lint rungosec ./...(high severity/confidence)govulncheck ./...go test -race ./...(unit + integration tags)
Dependency Management
go mod tidyafter any dependency changego mod downloadfor reproducible builds- No vendoring unless required by deployment constraints
govulncheck ./...before releases