binzo-cli
v0.0.3
Published
Your tools, straight from the source.
Readme
binzo
Your tools, straight from the source. Install command-line tools from release downloads and keep them up to date.
Install with npm (Node.js 20 or newer; Bun is not required):
npm install --global binzo-clinpm selects the binary package for your OS, architecture, and Linux libc. A one-time install script places that executable at npm’s command path. Running binzo then starts the native executable directly, without a Node launcher or wrapper process.
The binzo-cli package contains the install script, README, license, and package metadata; each platform package contains its executable, README, license, and package metadata. Application source code, tests, and development tools are excluded from the published payload.
binzo add aaif-goose/goose
goose
binzo install aaif-goose/[email protected]
binzo update aaif-goose/goose
binzo update --all
binzo listadd and install are aliases. A reference without a tag uses GitHub’s latest published stable release. @TAG selects an exact release tag, including prereleases. Tags select the initial version; they do not pin updates. Both update commands move tagged installs to latest. binzo update owner/repo@TAG explicitly switches an installed tool to a particular release.
What happens during installation?
- Binzo gets the release and its uploaded assets directly from GitHub. No registry configuration or
jqis needed for GitHub. - It matches asset filenames against the current OS and CPU architecture, including common aliases such as
aarch64/arm64andx86_64/amd64. Known incompatible platforms are excluded. On musl Linux, known glibc-only downloads are excluded. - It downloads the selected asset, checks its size and GitHub SHA-256 digest when supplied, and unpacks it into a temporary directory.
- It inspects files for executable headers or a Unix shebang, rather than treating every extensionless file as a binary. Support files remain with the executable; desktop
.appbundles are not treated as CLI tools. - It stores the installation under
~/.binzo/packages, links the executable into~/.binzo/bin, and records the registry, repository, release tag, asset, executable, and command in~/.binzo/installed.json.
Updates prepare the replacement before switching the command. Tracking writes and link replacements use atomic renames, with a recovery journal for interrupted changes. The previous installation is retained until the replacement is committed. A lock prevents concurrent installs from overwriting each other’s tracking records.
If an earlier installation stopped unexpectedly, Binzo offers Recover and continue. If another installation is still running, choose Wait and continue automatically. Binzo checks the recorded process and handles lock cleanup and transaction recovery for you. For scripts, add --recover to recover an abandoned lock or --wait to wait for the active installation. Neither option terminates a running process.
update --all continues past individual download/selection failures, reports totals, and exits unsuccessfully if any tool failed. If transaction recovery is blocked, it stops before changing more tools.
Ambiguous downloads
Release naming is not standardized. Binzo recognizes common target triples and aliases, but asks you to choose when several variants match, when the target is unclear, or when an archive has multiple executables. Equivalent compression formats with the same filename stem are collapsed, preferring .tar.gz.
Your selected asset variant and executable are remembered for updates. If they cannot be identified unambiguously in a new release, Binzo asks again. It does not run downloaded code during discovery.
Downloads show a live progress bar with percentage and downloaded/total size in the terminal. When the total size is unavailable, Binzo shows the downloaded byte count instead. CI, redirected output, and JSON mode omit the animated display.
For scripts or CI, make ambiguous choices explicit:
binzo add owner/repo \
--asset tool-aarch64-apple-darwin.tar.gz \
--binary release/bin/tool \
--name tool--asset: exact uploaded filename, not a URL or glob.--binary: relative path inside the extracted archive, using/separators.--name: command name (defaults to the executable filename). Existing command names are preserved during updates. One executable is tracked per repository per registry.--no-interactive: disables menus. CI, redirected input/output, and JSON mode also disable menus. Errors include available choices and the flags to use.--json: newline-delimited JSON events on stdout; errors on stderr. No terminal styling or prompts.--verbose: adds executable and tracking paths.--debug: includes technical error details.
Binzo never replaces an unrelated file in its command directory. If another tool already owns a command name, select a different name. It also reports when a command elsewhere on PATH takes precedence.
Shell setup
Binzo configures the detected shell: zsh, bash, fish, or the Windows user PATH. Unix uses symlinks; Windows uses .cmd launchers without requiring administrator symlink permissions.
An installer cannot change its parent terminal’s environment. If ~/.binzo/bin is not already on PATH, Binzo shows the exact command to enable it in the current terminal. New terminals use the saved shell configuration. Windows terminals may need to be fully restarted to inherit the changed user PATH.
Use --no-modify-path to receive instructions without editing shell configuration. Set BINZO_HOME to use a different storage location.
Supported downloads
- Standalone executable files
.tar,.tar.gz,.tgz,.zip.gzcontaining a single executable.tar.xz,.txz,.xzwhenxzis available.tar.bz2,.tbz2,.bz2whenbzip2is available
OS installer packages (.dmg, .pkg, .deb, .rpm, .msi, etc.), source archives, and metadata are excluded. ZIP symlinks are rejected with guidance to use another format. Native system libraries and runtime dependencies remain the project’s responsibility; consult its release instructions if an installed tool cannot start.
Private repositories and API limits
Set GH_TOKEN or GITHUB_TOKEN to a GitHub token with read access to the repository. Tokens are not saved in installed-tool tracking and are not forwarded to GitHub’s asset-storage redirects. Public repositories work without authentication, subject to GitHub’s anonymous API limit. Errors explain how to resolve authentication, missing releases, and rate limits.
Additional registries
Release resolution is separate from the shared installation pipeline. src/providers/types.ts defines the common release/asset contract. GitHub is a built-in provider; declarative registries use the existing map_vars/lookup/jq definition format through a separate adapter.
Add a definition URL or absolute local path in ~/.binzo/config.json (or $BINZO_HOME/config.json):
{
"version": "1.0.0",
"registries": [{ "url": "/absolute/path/to/registry.yaml" }]
}JSON and YAML configs are supported, also under ~/.config/binzo. Remote definitions must use HTTPS. An optional auth field authenticates the definition fetch. The shorthand github:owner/repo:ref reads .binzo/registry.yaml from that repository/ref.
Example definition:
sources:
- name: Example registry
map_vars:
name: "{word:org}/{word:repo}"
lookup:
versions:
url: https://registry.example.com/{org}/{repo}/versions
jq: "[.versions[].tag]"
assets:
url: https://registry.example.com/{org}/{repo}/versions/{version}/assets
jq: "[.assets[] | {name: .filename, url: .download_url, size: .size}]"
download:
headers:
Accept: application/octet-streambinzo add organization/tool --registry 'Example registry'
binzo update organization/tool --registry 'Example registry'
binzo update --all # remembers each tool’s registryDefinitions may contain a single registry object or a sources array. Registry names must be unique; github is reserved for the built-in provider. Lookup headers belong in each lookup’s headers object. Download headers are explicit and separate.
The versions expression must return one array of installable tags, newest first. Binzo does not assume tags follow semantic versioning. The assets expression returns one array of HTTPS URL strings, or objects with url, optional name, and optional size. {name} and {version} are built in; {word:variable} patterns capture name components for URL placeholders. Substituted values are URL-encoded.
Custom definitions require jq on PATH; it is launched directly with the expression as an argument, not through shell evaluation. They are an extension point for JSON APIs. Providers needing other authentication, response formats, or latest-version semantics can implement the same typed provider contract without changing matching, installation, or tracking.
Development
Requires Bun 1.3.14 or newer.
bun install
bun run src/index.ts --help
bun run src/index.ts add aaif-goose/goose --no-modify-path
bun test
bun run typecheck
bun run lint
bun run fmt:check
bun run build
./dist/binzo --helpUnit tests cover platform matching, ambiguity, reference parsing, archive bytes/path handling, registry mappings, and installation transaction recovery. They do not download or execute third-party tools.
Publishing a release
Push a new tag to run .github/workflows/release.yml:
git tag -a v0.0.1 -m "Release v0.0.1"
git push origin v0.0.1The tagged commit must include the workflow. Every newly pushed tag triggers it; ordinary branch pushes and updates to existing tags do not publish releases.
The workflow runs the project checks, builds and verifies eight platform binaries, then publishes a GitHub Release with generated release notes:
- macOS: x64 and ARM64 (
.tar.gz) - Linux: x64 and ARM64, each for glibc and musl (
.tar.gz) - Windows: x64 and ARM64 (
.zip) SHA256SUMSfor the release archives
The tag supplies the binary’s version, with a leading v removed from numeric versions. For example, v0.0.1 produces binzo --version → 0.0.1; no separate package-version edit is required. Tags such as v0.1.0-beta.1 create prereleases.
Publishing uses the built-in GITHUB_TOKEN; no additional secret is needed. Failed runs can be rerun from GitHub Actions: an unfinished draft is resumed, and an already published release is left intact.
Rebuilding a release from main
To use the current main branch for an existing release tag, open Actions → Release → Run workflow, choose main, and enter the tag (for example, v0.0.2). Or run:
gh workflow run release.yml --ref main -f tag=v0.0.2The manual trigger must first be committed and pushed to main. It checks and builds one fixed commit from main, uses the supplied tag as the binary version, and creates or updates that tag’s GitHub Release. Existing mutable release assets are replaced. The release notes record the actual build commit; the Git tag itself is not moved.
Publishing to npm manually
npm publishing is separate from GitHub Actions. The eight binary packages live in npm/ as npm workspaces. Keep their versions and the root package’s exact optionalDependencies versions aligned with the root version.
Publish the binary packages first, then the main package:
bun install
npm login
npm publish --workspaces
npm publishEach binary package’s prepack command builds its executable directly with Bun before packing or publishing. Publishing uses your local npm authentication and requires access to binzo-cli and the eight unscoped binzo-* names. For prereleases, add --tag next to both publish commands.
To change a published binary, increment the version and rebuild; npm versions are immutable. If a publish is interrupted, publish the remaining workspaces individually with npm publish --workspace <package-name>.
For local packaging work, build just one platform:
npm run build --workspace binzo-darwin-arm64Preview exactly what will be published:
npm pack --dry-run
npm pack --workspace binzo-darwin-arm64 --dry-runbun run build:npm builds all platforms without publishing. npm installation requires optional dependencies and install scripts to be enabled. The install script only places the downloaded binary; it does not compile code or download additional files. If scripts were disabled, enable them and run npm rebuild binzo-cli (npm rebuild --global binzo-cli for a global installation).
License
MIT.
