# Go packaging and releases

Read [../packaging.md](../packaging.md), [baseline.md](baseline.md),
[mise.md](mise.md), and [cli.md](cli.md) before applying these Go release
specifics.

Packaging is part of the baseline when the project is meant to be installed, not
an afterthought.

## Choose the artifact

- **Plain CLI/MCP server**: cross-compiled binaries are usually enough.
- **System service**: add systemd/OpenRC files and consider nFPM packages.
- **Desktop/Wails app**: use nFPM for Linux packages, desktop files, icons, and
  WebKit runtime dependencies; use Wails/NSIS for Windows installers when needed.
- **Library**: no binary packaging unless examples/tools are part of the repo.

## Version gating

Package tasks should fail on ambiguous versions. Prefer exact tags for release
packages. For Git-tagged releases, a package task can gate on an exact tag:

```sh
version=$(git describe --tags --exact-match 2>/dev/null) || {
  echo "Error: package builds require an exact vMAJOR.MINOR.PATCH tag" >&2
  exit 1
}
version=${version#v}
```

For jj-backed projects, use the project's agreed jj/git-derived release command
instead. Do not infer package versions from Go `BuildInfo` unless the project
explicitly chose that policy. For development builds, `VERSION=dev` is fine; for
packages, be stricter.

## nFPM baseline

```yaml
# yaml-language-server: $schema=https://nfpm.goreleaser.com/static/schema.json
name: example
arch: ${GOARCH}
version: ${VERSION}
release: ${RELEASE:-1}
section: utils
priority: optional
maintainer: Amolith <amolith@secluded.site>
description: Short human description
homepage: https://example.invalid
license: LicenseRef-MutuaL-1.2

contents:
  - src: build/pkg/example
    dst: /usr/bin/example
```

For Wails/Linux desktop apps, add package assets and WebKit dependencies:

```yaml
contents:
  - src: build/pkg/example
    dst: /usr/bin/example
  - src: packaging/example.desktop
    dst: /usr/share/applications/example.desktop
  - src: dist/example.png
    dst: /usr/share/icons/hicolor/512x512/apps/example.png

overrides:
  deb:
    depends:
      - libwebkit2gtk-4.1-0
    recommends:
      - xdg-utils
  rpm:
    depends:
      - (webkit2gtk4.1 or libwebkit2gtk-4_1-0)
  apk:
    depends:
      - webkit2gtk-4.1
  archlinux:
    depends:
      - webkit2gtk-4.1
```

## mise package tasks

Use hidden preparation tasks for version, icon conversion, package build, and
optional compression. Visible tasks should be simple: `pkg`, `pkg:deb`,
`pkg:rpm`, `pkg:apk`, `pkg:arch`.

Minimal visible tasks look like this:

```toml
[tasks."pkg:deb"]
description = "Build a deb package"
env = { RELEASE = "1" }
run = "nfpm package -f packaging/nfpm.yaml -p deb -t build/pkg"

[tasks."pkg:rpm"]
description = "Build an rpm package"
env = { RELEASE = "1" }
run = "nfpm package -f packaging/nfpm.yaml -p rpm -t build/pkg"
```

UPX is optional. Use it for Linux binaries when size matters; do not assume it
works well for every OS or binary format.

## Cross-compilation

- `CGO_ENABLED=0` makes plain Go binaries easy to cross-compile.
- For CLI, TUI, and MCP release binaries, prefer `netgo`, `osusergo`, optional
  project-specific `static_build`, `-d -s -w -buildid=`, and
  `-extldflags=-static` when dependencies are pure Go.
- Treat Go VCS build metadata as a policy choice, not the package version source.
  If a package needs exact version or commit strings, derive them in the package
  task and inject them. If a release intentionally relies on Go `BuildInfo`, make
  that explicit and consider `-buildvcs=true`.
- Wails/Linux builds require native CGO and WebKitGTK.
- Windows Wails cross-builds from Linux need mingw-w64; NSIS packages need
  `makensis`.
- macOS desktop builds require macOS unless a project has proven otherwise.

Document these constraints in task descriptions and preconditions rather than
letting users discover linker failures.
