# Go baseline

Start from Amolith's strict Go baseline, then adapt it deliberately with the
user and the project in front of you. This file is for Go tooling,
architecture, libraries, tests, packaging, and build workflow, not for copying a
boilerplate blindly.

## Go operating mode

1. Inspect `go.mod`, existing task runner, build files, packaging files, UI
   surface, and tests.
2. Classify the project: library, CLI, TUI, MCP server, light web app, Wails
   desktop app, frontend-heavy app, service, or some mix.
3. Start from the strict baseline, then relax, remove, or add further pieces only
   when the project needs them.
4. Verify each slice with the narrowest useful `mise run ...` task.

Do not introduce Taskfiles or justfiles by default. If an older project uses
Task or just, translate the useful commands into `mise.toml` unless the user
explicitly asks to keep the old runner.

## Defaults

Default to:

- `mise.toml` for tools and tasks
- `golangci-lint fmt` for formatting
- `golangci-lint run --enable-only modernize --fix ./...` for modernization
- `golangci-lint run --fix` for lint fixes
- `govulncheck ./...` for vulnerability scanning
- slower, race-enabled tests in development: `go test -v -race -count=5 -p=3
  -timeout=5m ./...`, with `CGO_ENABLED=1` for the test task
- pure-Go static release builds for CLIs, TUIs, and MCP servers when the project
  does not require CGO
- explicit build/install tasks for binaries
- nFPM when shipping native Linux packages
- small packages with domain names, not generic `utils`
- standard library first unless a preferred library clearly fits
- Amolith's licensing convention when the project does not already say
  otherwise: CC0 for docs/examples/config/prompt text, MutuaL for meaningful code

Use this `.golangci.toml` shape unless the project already has a stronger local
configuration. Replace the module path placeholders with the module from
`go.mod`:

```toml
version = "2"

[linters]
enable = ["bodyclose", "errcheck", "errorlint", "exhaustive", "gocognit", "govet", "ineffassign", "modernize", "nilerr", "nilnil", "noctx", "revive", "staticcheck", "unused"]

[linters.settings.gocognit]
min-complexity = 15

[[linters.settings.revive.rules]]
name = "file-length-limit"
arguments = [{ max = 1000, skip-comments = true, skip-blank-lines = true }]

[[linters.settings.revive.rules]]
name = "max-control-nesting"
arguments = [5]

[formatters]
enable = ["goimports", "gofumpt", "gci", "golines"]

[formatters.settings.goimports]
local-prefixes = ["<module-path>"]

[formatters.settings.gofumpt]
module-path = "<module-path>"

[formatters.settings.gci]
sections = ["standard", "default", "localmodule"]

[formatters.settings.golines]
max-len = 120
```

Default away from:

- Taskfiles and justfiles in new setup
- clix/kong, even when another Go skill recommends it; use stdlib flags for tiny
  tools and Cobra + Fang for user-facing CLIs
- generated wrappers around one command
- large frontend stacks for light server-rendered pages
- configuration frameworks when direct parsing is enough
- hidden global state unless a test seam restores it with `t.Cleanup`

Use generic Go skills for implementation details, but this skill wins for
Amolith-specific setup choices: mise, golangci-lint formatting/fixing,
modernize, static build shape, CLI framework, packaging, Wails frontend stack,
web styling posture, and explicit gocuke adoption.

Gocuke is an explicit project choice. Ask whether the project wants gocuke/BDD
automation; if yes, load the gocuke skill after behaviour is formulated. If no,
use ordinary Go tests.
