Skip to main content

omnidist

Go Report Card lint test codecov version npm PyPI license

Package and publish a Go CLI as npm, uv, and RubyGems installable tools with prebuilt cross-platform binaries.

omnidist gives Go CLI maintainers one repeatable release flow:

build -> stage -> verify -> publish

The generated npm packages use platform-specific optional dependencies, so users can run your CLI with npx without install-time downloader scripts. The uv distribution stages wheel artifacts so users can run the same CLI from Python tooling with uvx. The RubyGems distribution stages platform-specific gems so users can install the same CLI with gem install.

Requirements

  • Go 1.25+
  • Node.js and npm for npm staging, verification, and publishing
  • uv for uv staging, verification, and publishing
  • Ruby and RubyGems for gem staging, verification, and publishing
  • git when version.source: git-tag
  • NPM_PUBLISH_TOKEN for npm token publishing, unless using --dry-run or trusted publishing
  • UV_PUBLISH_TOKEN or omnidist uv publish --token for uv publishing, unless using --dry-run
  • GEM_HOST_API_KEY / RUBYGEMS_API_KEY for gem token publishing, unless using --dry-run or trusted publishing

Install

Run without installing:

npx -y @omnidist/omnidist@latest --help
uvx omnidist --help

Install with npm:

npm i -g @omnidist/omnidist
omnidist --help

Install with Go:

go install github.com/metalagman/omnidist/cmd/omnidist@latest
omnidist --help

Install with RubyGems after publication:

gem install omnidist
omnidist --help

Run from a checkout:

go run ./cmd/omnidist --help

Quick Start

Initialize an existing Go CLI repository:

omnidist init

This creates .omnidist/omnidist.yaml and initial workspace directories under .omnidist/default/. The generated config uses profiles.default.

Edit the generated config before building:

$EDITOR .omnidist/omnidist.yaml

At minimum, check these fields:

  • tool.name: the binary name users will run.
  • tool.main: the Go main package, for example ./cmd/mytool.
  • distributions.npm.package: the npm package, for example @my-org/mytool.
  • distributions.uv.package: the uv/PyPI package, for example mytool.
  • distributions.gem.package: the RubyGems package, for example mytool.
  • version.source: usually git-tag, file, env, or fixed.

Then run the local release pipeline:

omnidist build
omnidist stage
omnidist verify

Publish only after verification passes:

omnidist publish

Generate a GitHub Actions release workflow:

omnidist ci

The generated workflow is written to .github/workflows/omnidist-release.yml. It runs on v* tag pushes, builds once, stages and verifies artifacts, publishes npm, uv, and gem distributions, then uploads the built binaries and checksums.txt to the GitHub release.

Configuration

omnidist init writes profiles-mode config by default:

profiles:
  default:
    tool:
      name: mytool
      main: ./cmd/mytool

    version:
      source: git-tag # git-tag | file | env | fixed
      file: VERSION # used only when source is file
      fixed: 1.2.3 # required only when source is fixed

    targets:
      - os: darwin
        arch: amd64
      - os: darwin
        arch: arm64
      - os: linux
        arch: amd64
      - os: linux
        arch: arm64
      - os: windows
        arch: amd64

    build:
      ldflags: -s -w
      tags: []
      cgo: false

    distributions:
      npm:
        package: "@my-org/mytool"
        registry: https://registry.npmjs.org
        access: public # public | restricted
        publish-auth: token # token | trusted
        include-readme: true

      uv:
        package: mytool
        index-url: https://upload.pypi.org/legacy/
        linux-tag: manylinux2014 # manylinux2014 | musllinux_1_2
        include-readme: true

      gem:
        package: mytool
        registry: https://rubygems.org
        publish-auth: token # token | trusted
        repository-url: https://github.com/my-org/mytool
        include-readme: true

Select a profile with --profile <name> or OMNIDIST_PROFILE. If profiles is present and no profile is selected, default is used. Profiles write artifacts to .omnidist/<profile>/.

Legacy top-level config is still accepted when loading existing config files, but do not mix top-level runtime fields with a profiles map in the same file.

Targets use Go values: os is GOOS, and arch is GOARCH. Distribution workflows map them as needed, for example windows/amd64 becomes npm win32/x64. For RubyGems, windows/amd64 defaults to x64-mingw-ucrt; set targets[].variant: mingw32 if you need x64-mingw32, or targets[].variant: musl for Linux musl gem platforms.

Versioning

omnidist build resolves the release version and writes it to .omnidist/<profile>/dist/VERSION. Stage and publish commands use that build version so npm, uv, and gem artifacts stay in sync.

Supported version sources:

  • git-tag: HEAD must be on an exact SemVer tag, either vX.Y.Z or X.Y.Z.
  • file: read the version from version.file, defaulting to VERSION.
  • env: read OMNIDIST_VERSION.
  • fixed: read version.fixed.

For local prerelease staging, use:

omnidist stage --dev

--dev generates prerelease artifact versions from git metadata. For npm publishing, -dev prerelease versions are automatically published with --tag dev when no tag is supplied.

Environment and Build Variables

omnidist loads .env at startup when the file exists.

Environment variables:

  • OMNIDIST_VERSION: used only when version.source: env. VERSION is not used.
  • OMNIDIST_CONFIG: config file path, equivalent to --config.
  • OMNIDIST_PROFILE: config profile name, equivalent to --profile.
  • OMNIDIST_OMNIDIST_ROOT: project root directory, equivalent to --omnidist-root.
  • NPM_PUBLISH_TOKEN: npm token for distributions.npm.publish-auth: token.
  • UV_PUBLISH_TOKEN: uv publish token when --token is not provided.
  • GEM_HOST_API_KEY: RubyGems token for distributions.gem.publish-auth: token.
  • RUBYGEMS_API_KEY: alternate RubyGems token env name.
  • GEM_HOST_OTP_CODE: RubyGems MFA OTP for token-based publish.

Build ldflags template variables:

  • OMNIDIST_VERSION: expanded in build.ldflags during omnidist build.
  • OMNIDIST_GIT_COMMIT: populated by omnidist build when git metadata is available.
  • OMNIDIST_BUILD_DATE: populated by omnidist build as UTC RFC3339.

Example:

build:
  ldflags: >-
    -s -w
    -X github.com/your-org/mytool/internal/version.version=${OMNIDIST_VERSION}
    -X github.com/your-org/mytool/internal/version.gitCommit=${OMNIDIST_GIT_COMMIT}
    -X github.com/your-org/mytool/internal/version.buildDate=${OMNIDIST_BUILD_DATE}

build.ldflags uses os.ExpandEnv, so both $VAR and ${VAR} are supported. Unset variables expand to empty strings.

npm Distribution

The npm distribution has two package types:

  • Meta package: distributions.npm.package, with a small Node shim.
  • Platform packages: one package per target, selected by npm os and cpu constraints.

The meta package lists platform packages as optionalDependencies at the same version. Published packages do not use postinstall scripts or network downloaders.

Common npm commands:

omnidist npm stage
omnidist npm verify
omnidist npm publish --tag latest

Token publishing uses NPM_PUBLISH_TOKEN. omnidist writes a workspace .omnidist/.npmrc from distributions.npm.registry with npm's token substitution syntax.

Trusted publishing uses npm OIDC instead of NPM_PUBLISH_TOKEN:

distributions:
  npm:
    publish-auth: trusted
    repository-url: git+https://github.com/your-org/your-repo.git

In trusted mode:

  • repository-url is required and is written to staged package metadata.
  • omnidist npm publish skips token-only auth preflight.
  • GitHub Actions must grant id-token: write.
  • Each npm package, including platform packages, needs a trusted publisher configured on npm.

Print trusted publisher setup commands:

omnidist npm trust

Apply them directly:

omnidist npm trust --apply

Useful trust options:

  • --workflow-file <name> for a workflow filename other than omnidist-release.yml.
  • --repo <owner/repo> to override distributions.npm.repository-url.
  • --environment <name> for npm trusted publishers restricted to a GitHub Actions environment.
  • --allow-stage-publish to allow npm stage publish.

uv Distribution

The uv distribution stages wheel artifacts under .omnidist/<profile>/uv/dist. During staging, versions are converted to PEP 440 where needed.

Common uv commands:

omnidist uv stage
omnidist uv verify
omnidist uv publish

Publish to a different PyPI-compatible index:

omnidist uv publish --publish-url https://test.pypi.org/legacy/ --token <token>

omnidist uv verify rejects versions with local metadata (+...) for PyPI/TestPyPI publishing, because those indexes reject local versions.

RubyGems Distribution

The RubyGems distribution stages one platform-specific .gem per configured target under .omnidist/<profile>/gem/pkg. Each gem contains:

  • a wrapper executable under exe/
  • the prebuilt CLI binary under libexec/
  • platform metadata so RubyGems installs the matching package

Common gem commands:

omnidist gem stage
omnidist gem verify
omnidist gem publish

Token publishing uses GEM_HOST_API_KEY or RUBYGEMS_API_KEY. If your RubyGems account requires MFA for pushes, also pass --otp or set GEM_HOST_OTP_CODE.

Trusted publishing uses RubyGems OIDC instead of static secrets:

distributions:
  gem:
    publish-auth: trusted
    registry: https://rubygems.org
    repository-url: https://github.com/your-org/your-repo

In trusted mode:

  • GitHub Actions must grant id-token: write.
  • The repository/workflow must be registered as a trusted publisher on RubyGems.org.
  • omnidist can publish a brand-new gem name once the pending trusted publisher is configured on RubyGems.org.

README and License Staging

README source precedence during staging:

distributions.<name>.readme-path -> readme-path -> README.md

If a configured readme-path is set and cannot be read, staging fails. Set include-readme: false for a distribution to skip README inclusion.

For npm packages, license can be set explicitly under distributions.npm. When it is omitted, omnidist includes the project license file when present and writes package metadata that points to that file.

CI Releases

Generate a release workflow:

omnidist ci

Overwrite an existing generated workflow:

omnidist ci --force

The workflow installs omnidist with npm. When generating this repository's own release workflow, it uses go run ./cmd/omnidist instead. The workflow also sets FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true for JavaScript-based GitHub Actions.

Before the first tag release, configure the required registry credentials:

  • npm token mode: NPM_PUBLISH_TOKEN GitHub secret.
  • npm trusted mode: npm trusted publishers for every staged npm package.
  • uv publishing: UV_PUBLISH_TOKEN GitHub secret.
  • gem token mode: RUBYGEMS_API_KEY GitHub secret, and optionally RUBYGEMS_OTP_CODE.
  • gem trusted mode: RubyGems trusted publisher for the release workflow.

Release by pushing a SemVer tag:

git tag v1.2.3
git push origin v1.2.3

Command Reference

Top-level commands:

omnidist init
omnidist quickstart
omnidist build
omnidist stage [--dev] [--only npm|uv|gem|npm,uv,gem]
omnidist verify [--only npm|uv|gem|npm,uv,gem]
omnidist publish [--dry-run] [--only npm|uv|gem|npm,uv,gem]
omnidist ci [--force] [--dry-run]
omnidist version

Global flags:

--config <path>
--profile <name>
--omnidist-root <path>

npm commands:

omnidist npm stage [--dev]
omnidist npm verify
omnidist npm publish [--dry-run] [--tag <tag>] [--registry <url>] [--otp <code>]
omnidist npm trust [--apply] [--workflow-file <name>] [--repo <owner/repo>] [--environment <name>] [--allow-stage-publish]

uv commands:

omnidist uv stage [--dev]
omnidist uv verify
omnidist uv publish [--dry-run] [--publish-url <url>] [--token <token>]

gem commands:

omnidist gem stage [--dev]
omnidist gem verify
omnidist gem publish [--dry-run] [--host <url>] [--api-key <token>] [--otp <code>]

Top-level stage, verify, and publish run distributions in deterministic order: npm first, then uv, then gem. Use --only to limit the command to one or more distributions.

Troubleshooting

omnidist build says no version could be resolved:

Check version.source. For git-tag, HEAD must be exactly on a SemVer tag. For env, set OMNIDIST_VERSION. For file, create the configured version file.

omnidist stage says the build version file is missing:

Run omnidist build first. Stage commands use the build version persisted under .omnidist/<profile>/dist/VERSION.

npm install cannot find a platform package:

Run omnidist npm verify before publishing. It checks package versions, platform os and cpu fields, required binaries, forbidden postinstall scripts, repository metadata, and optional dependency parity.

Trusted npm publish fails:

Verify that distributions.npm.repository-url matches the GitHub repository, the workflow grants id-token: write, and every npm package has a trusted publisher configured.

uv publish rejects the version:

Restage with a publishable version. PyPI and TestPyPI reject local version metadata containing +.

Contributing

For repository layout, development workflow, package model details, and migration notes, see CONTRIBUTING.md.

Metadata

Release files for omnidist 0.1.34

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for omnidist 0.1.34
File
omnidist-0.1.34-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
omnidist-0.1.34-py3-none-manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
omnidist-0.1.34-py3-none-manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
omnidist-0.1.34-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
omnidist-0.1.34-py3-none-macosx_10_13_x86_64.whl Python 3 none macOS 10.13+ x86-64 Details

Total release size: 28.9 MB

Release files / omnidist-0.1.34-py3-none-win_amd64.whl

Download URL omnidist-0.1.34-py3-none-win_amd64.whl
Size 6.1 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
eb6a0ab2915b1088c846ef7fe9ee91aba7ad698a0e2d83bb54b13ee8a435f876
BLAKE2b-256 checksum
How to use checksums
67db933d52202316027faaa45244d35c6489599cd79f7b6d4ab492bf1428fa98
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / omnidist-0.1.34-py3-none-manylinux2014_x86_64.whl

Download URL omnidist-0.1.34-py3-none-manylinux2014_x86_64.whl
Size 5.8 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
c13de8554199dffd209e7a75d731db780b962eb8f3e1f2073f4118976ee7b64d
BLAKE2b-256 checksum
How to use checksums
61f19a093e88038f2192b5ac99b30af322dc6bd5a98a2192d02442fcee4d88df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / omnidist-0.1.34-py3-none-manylinux2014_aarch64.whl

Download URL omnidist-0.1.34-py3-none-manylinux2014_aarch64.whl
Size 5.5 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
146a9076b61196e3aa61679e1f0a4cc16223f465b5ad3a588bdb5c9a4b1d92c4
BLAKE2b-256 checksum
How to use checksums
e5b763f8040d645ea250d9113555cfc81c242fb4145ac7341720b98d816ae9b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / omnidist-0.1.34-py3-none-macosx_11_0_arm64.whl

Download URL omnidist-0.1.34-py3-none-macosx_11_0_arm64.whl
Size 5.6 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
393cfb1cff8408038bfc75ed4b00fba598b15a9b56b8de4f72d438fc20d2629f
BLAKE2b-256 checksum
How to use checksums
cefcbfd5b52241148614a1cb8571c113d5c224545d6421bc88b1b9bc6fdcbfc9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / omnidist-0.1.34-py3-none-macosx_10_13_x86_64.whl

Download URL omnidist-0.1.34-py3-none-macosx_10_13_x86_64.whl
Size 5.9 MB
Tags Python 3 macOS 10.13+ x86-64
SHA-256 checksum
How to use checksums
22fe3e39815e2dd0f3673df5f76c3f26ac43747b3564898a6f6e3bfbe09cdebc
BLAKE2b-256 checksum
How to use checksums
a625de8ed2a6cb78b1d213e7ed107b88b8afbce3a29b38b009caab154781377c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page