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.35

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.35
File
omnidist-0.1.35-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
omnidist-0.1.35-py3-none-manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
omnidist-0.1.35-py3-none-manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
omnidist-0.1.35-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
omnidist-0.1.35-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.35-py3-none-win_amd64.whl

Download URL omnidist-0.1.35-py3-none-win_amd64.whl
Size 6.1 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
fbcb49e62b149fa7eb3381da6d038f8305c35976a73330f62712eb46d13c233b
BLAKE2b-256 checksum
How to use checksums
49862f8c9b357f779afaf0bb437d833bd04ad30ae0ee825918aacaa602b3ed95
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.35-py3-none-manylinux2014_x86_64.whl

Download URL omnidist-0.1.35-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
f2840e86ff96e5491b1ba96f47b74bb1fe3007bb04de6054dad92294d1b0496a
BLAKE2b-256 checksum
How to use checksums
cbd40173b32d517cfea57fc4bf724c0da7621aef0add685bdb46176f59ab4672
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.35-py3-none-manylinux2014_aarch64.whl

Download URL omnidist-0.1.35-py3-none-manylinux2014_aarch64.whl
Size 5.5 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
798ba0fb676083844f28dbb9c36eeb0bf217ff8973118e2bdca4283d47534b53
BLAKE2b-256 checksum
How to use checksums
7eb395a6008aba58906007756eee0d346435b34f584e849f286c54fca6365a0f
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.35-py3-none-macosx_11_0_arm64.whl

Download URL omnidist-0.1.35-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
58a8f1b3407de55dbc5469d3882d2468d05da1abd755d4a30ba8d092c8f4cb59
BLAKE2b-256 checksum
How to use checksums
4ac3b30254f8ef70ea93896b44e471103db0e47af4c472ce89d20d0035d389f6
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.35-py3-none-macosx_10_13_x86_64.whl

Download URL omnidist-0.1.35-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
2e5e2be6e7dbaea619a6f0d072d8e873efdaac4a48fd4b572b01329a5a518b89
BLAKE2b-256 checksum
How to use checksums
b352bba6460dc77dfae566efb09b6c31c3c652a5fa76253fcd0e52cfee441699
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