# Go mise

Read [../mise.md](../mise.md) and [baseline.md](baseline.md) before applying
this file. Use `mise.toml` as the project task runner and tool installer.
Translate older Taskfile/justfile commands into mise instead of preserving the
old runner by default.

## Baseline Go `mise.toml`

Adapt names and paths, but keep the shape recognisable:

```toml
min_version = "2026.2.4"

[env]
GOAMD64 = "v3"

[vars]
test_args = "-v -race -count=5 -p=3 -timeout=5m ./..."

[tools]
go = "latest"
"go:golang.org/x/vuln/cmd/govulncheck" = "latest"
golangci-lint = "latest"

[tasks.fmt]
description = "Format Go code"
run = "golangci-lint fmt"

[tasks.tidy]
description = "Tidy go.mod and go.sum"
run = "go mod tidy"

[tasks.modernize]
description = "Apply Go modernization fixes"
run = "golangci-lint run --enable-only modernize --fix ./..."

[tasks.lint]
description = "Lint Go code and apply safe fixes"
run = "golangci-lint run --fix"

[tasks.fix]
description = "Format, modernize, and apply lint fixes"
run = [
  "mise run fmt",
  "mise run modernize",
  "mise run lint",
]

[tasks.vet]
description = "Run go vet"
run = "go vet ./..."

[tasks.vuln]
description = "Run govulncheck"
run = "govulncheck ./..."

[tasks.build]
description = "Build all Go packages"
run = "go build ./..."

[tasks.test]
description = "Run Go tests repeatedly with the race detector"
env = { CGO_ENABLED = "1" }
run = "go test {{vars.test_args}}"

[tasks."test:quiet"]
description = "Run Go tests with quiet success output"
env = { CGO_ENABLED = "1" }
run = '''
if output=$(go test {{vars.test_args}} 2>&1); then
  echo "✓"
else
  echo "$output"
  exit 1
fi
'''

[tasks.check]
description = "Format, tidy, lint, scan, build, and test"
run = [
  "mise run fix",
  "mise run tidy",
  "mise run vet",
  "mise run vuln",
  "mise run build",
  "mise run test:quiet",
]
```

`GOAMD64=v3` is Amolith's personal/performance baseline. Lower or remove it for
public binaries that need broad x86-64 compatibility.

Do not add a non-mutating tidy check unless the user asks for it. `tidy` is the
task.

## Binary projects

For a user-facing binary, make build/install tasks target the actual command:

```toml
[vars]
binary = "example"
main = "./cmd/example"
static_tags = "netgo,osusergo,static_build"
static_ldflags = "-d -s -w -buildid= -extldflags=-static"

[tasks.build]
description = "Build a static pure-Go binary"
env = { CGO_ENABLED = "0" }
run = '''
go build \
  -trimpath \
  -tags '{{vars.static_tags}}' \
  -ldflags '{{vars.static_ldflags}}' \
  -o {{vars.binary}} \
  {{vars.main}}
'''

[tasks.install]
description = "Install a static pure-Go binary"
env = { CGO_ENABLED = "0" }
run = '''
go install \
  -trimpath \
  -tags '{{vars.static_tags}}' \
  -ldflags '{{vars.static_ldflags}}' \
  {{vars.main}}
'''
```

Do not settle version policy by copying the static template. The template leaves
`-buildvcs` unspecified, so Go uses its `auto` behavior. For version reporting,
those fields matter only if project code or Fang reads them; they can still
matter for reproducibility or privacy, so choose `-buildvcs` explicitly when that
matters. Choose the policy with the user:

- **Best-effort local/dev metadata**: leave `-buildvcs` unset and read
  `runtime/debug.BuildInfo` or Fang's fallback when `unknown` is acceptable.
- **Release/package/user-visible version**: derive an exact semver or commit in
  the task and inject it with `-ldflags -X ...`.
- **jj-derived versions or multiple version surfaces**: keep a project-owned
  resolver and pass the values to Fang, server metadata, package metadata, and
  tests.
- **Reproducible or privacy-sensitive builds**: consider `-buildvcs=false`, but
  document the tradeoff. If a release task relies on Go VCS metadata, consider
  `-buildvcs=true` so missing metadata fails loudly.

The static template is for pure-Go binaries. It will not work for Wails, race
tests, or projects that require CGO, native keychains, WebKitGTK, or C-backed
database drivers.

`netgo` forces the pure-Go DNS resolver. `osusergo` forces pure-Go user/group
lookup. `static_build` is only a project convention unless files or dependencies
use that build tag. `-extldflags=-static` asks the external linker for static C
libraries when external linking is involved; it is not a magic fix for CGO.

## Optional pprof tasks

Add these only when the project intentionally exposes `net/http/pprof`, usually
on localhost and behind an explicit debug flag:

```toml
[tasks."profile:cpu"]
run = "go tool pprof -http :6061 'http://127.0.0.1:6060/debug/pprof/profile?seconds=15'"

[tasks."profile:heap"]
run = "go tool pprof -http :6061 'http://127.0.0.1:6060/debug/pprof/heap'"

[tasks."profile:allocs"]
run = "go tool pprof -http :6061 'http://127.0.0.1:6060/debug/pprof/allocs'"
```

## Frontend or Wails projects

Add only the tools the project needs. For Wails, see [wails.md](wails.md); for
light web apps, see [web.md](web.md). Keep frontend package manager choice
project-specific: use the existing lockfile, or ask before introducing npm, Bun,
pnpm, or yarn.
