Generate curl | sh and irm | iex installers for your project's binary releases.
ingen takes a small JSON manifest describing your release artifacts and generates portable shell and PowerShell installers.
npm install --global ingen-cliOne-line installers (curl | sh and irm | iex) provide a great installation experience for users, but writing and maintaining portable shell and PowerShell installers is surprisingly involved.
While exploring how to add this kind of installer to a project, I discovered cargo-dist, a distribution automation tool that generates high-quality shell and PowerShell installers while also building, packaging, and publishing software.
cargo-dist solves a broader problem than the one I was trying to solve. It provides an opinionated, end-to-end release pipeline that automates building, packaging, publishing, and installer generation. For many projects, that's exactly the right solution.
ingen is for the cases where you only want installer generation. You describe the release artifacts you already produce, and ingen generates the same style of shell and PowerShell installers without taking over the rest of your release process.
Initialize a new manifest:
ingen initThis creates an installer.manifest.json with valid placeholders and a $schema reference. Most editors will automatically pick up the schema and provide validation, field suggestions, and documentation as you edit.
Edit the manifest to describe your project's release artifacts.
If you publish releases on GitHub, you can leave checksum fields out of the manifest and let ingen sync fill them in from the release assets:
ingen sync installer.manifest.jsoningen sync fetches the checksums published by GitHub for each release asset and updates the manifest accordingly.
Once your manifest is ready, generate the installers:
ingen generate installer.manifest.json ./distThis produces:
dist/installer.shdist/installer.ps1
Upload both files to any location accessible over HTTPS (for example, as assets on a GitHub release), then link to them from your documentation:
curl --proto '=https' --tlsv1.2 -LsSf https://example.com/installer.sh | shpowershell -ExecutionPolicy Bypass -c "irm https://example.com/installer.ps1 | iex"See the manifest reference for all available manifest fields, including their types, required/optional status, and descriptions.
The examples/ directory contains complete manifests for real-world projects.
In particular, examples/caddy demonstrates how a Go project maps its release artifacts to Rust target triples, which ingen uses to identify supported platforms.
When you release a new version of your project, you can update your ingen manifest and regenerate the installers as part of your release process.
The fields that usually change are app_version and the archives[].checksum fields.
If your release artifacts are hosted on GitHub, ingen sync can update both app_version and checksum fields from the new release's assets:
ingen sync installer.manifest.json --app-version <new-version>Whether you manually updated the manifest or used ingen sync, the next step is to regenerate the installers using the updated manifest:
ingen generate installer.manifest.json ./distEvery installer generated by ingen supports flags and environment variables that let users change its behavior.
These options come from the cargo-dist installer templates that ingen uses.
Environment variable names use your app_name in the manifest. For an app named
myapp, the installers expect environment variables prefixed with MYAPP_.
Hyphens in app_name are replaced with underscores. For example, my-app
uses the MY_APP_ prefix.
curl ... | sh -s -- --verbose # -v, more output
curl ... | sh -s -- --quiet # -q, less output
curl ... | sh -s -- --help # -h, print usage and exit| Variable | Description |
|---|---|
{APP}_DOWNLOAD_URL |
Download archives from this URL instead of the default URLs. |
{APP}_INSTALLER_GITHUB_BASE_URL |
Use a different github.com-compatible domain. |
{APP}_INSTALLER_GHE_BASE_URL |
Use a GitHub Enterprise instance instead of github.com. |
{APP}_INSTALL_DIR |
Install to this directory. |
{APP}_UNMANAGED_INSTALL |
Install only to this directory without modifying PATH. Useful for CI and scripts. |
{APP}_NO_MODIFY_PATH |
Set to 1 to skip modifying shell rc files or the Windows PATH registry key. |
{APP}_PRINT_VERBOSE |
Same as --verbose. |
{APP}_PRINT_QUIET |
Same as --quiet. |
{APP}_GITHUB_TOKEN |
Authentication token for downloading releases from a private repository. |
Example:
{APP}_NO_MODIFY_PATH=1 curl ... | shThis installs the application without modifying the user's PATH.
The generated installers come from templates that are included directly in this repository. ingen does not download installer code at runtime or silently replace the templates during generation.
The templates are based on a pinned cargo-dist release, and local changes are tracked and documented. See templates/README.md to compare the vendored templates with upstream and review every change made by ingen.
On macOS, browser downloads are marked with the com.apple.quarantine extended attribute, which triggers Gatekeeper's quarantine checks when the downloaded software is run. Files downloaded with curl do not receive this extended attribute, so binaries installed through the generated curl | sh installer do not trigger Gatekeeper's quarantine checks. This is a side effect of using curl to download release artifacts, not behavior specific to ingen.
ingen builds on ideas and engineering from the dist project.
In particular, it vendors dist's installer templates and ports its platform compatibility logic.