packaging.md

Packaging and releases

Packaging is part of the baseline when the project is meant to be installed, not an afterthought. Choose the artifact based on how people will actually use the project.

Choose the artifact

  • Library: no binary packaging unless examples/tools are part of the repo.
  • Plain CLI or MCP server: release archives or cross-compiled binaries are usually enough.
  • System service: add service files and consider native packages.
  • Desktop app: include desktop files, icons, runtime dependencies, and OS installer/package constraints from the start.

Version gating

Package tasks should fail on ambiguous versions. Prefer exact tags for release packages. For development builds, VERSION=dev is fine; for packages, be stricter.

For Git-tagged releases, a package task can gate on an exact tag:

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 language build metadata unless the project explicitly chose that policy.

Native Linux packages

Use nFPM when shipping .deb, .rpm, .apk, or Arch-style package artifacts from a non-distro package pipeline. Keep package metadata boring, explicit, and consistent with the project's chosen license.

Visible mise tasks should be simple: pkg, pkg:deb, pkg:rpm, pkg:apk, pkg:arch. Put version resolution, icon conversion, binary staging, package builds, and optional compression in hidden/helper tasks when needed.

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

Document cross-compilation constraints in task descriptions and preconditions rather than letting users discover linker or runtime failures.

Go path

For Go binaries, MCP servers, TUIs, web apps, or Wails releases, read golang/index.md first and follow its packaging chain. The Go path covers static builds, CGO exceptions, Wails/Linux constraints, and Go version-injection policy.