idx-cli/docs/NPM_DISTRIBUTION.md
0xrsydn 809966925e docs: keep a CHANGELOG.md, with one entry file per PR
Release notes were written by hand on GitHub at tag time, so the contents
of a stacked release had to be pieced together from every PR, and output
changes that scripts and agents rely on were easy to miss.

- CHANGELOG.md backfills every published release (0.2.0 to 0.4.0) from its
  GitHub notes, verbatim.
- A PR adds changes/unreleased/<branch-name>.md instead of editing
  CHANGELOG.md, so stacked PRs never conflict. changes/README.md gives the
  sections, including Output Changes for JSON, MCP and error-code changes.
- scripts/changelog.sh: `check` validates entries and CHANGELOG.md,
  `release X.Y.Z` folds the entries into a new section (ordered by PR), and
  `notes X.Y.Z` prints a section as GitHub release notes.
- The release workflow sets the GitHub notes from the tag's section.
- New flake check `changelog` runs scripts/changelog-test.sh; both scripts
  are shellchecked.
- Entries for 0.5.0: #73, #74, #75, #78, #79, #80, #81 and this PR.

Claude-Session: https://claude.ai/code/session_01RqPPVeVDrnLoP7NUZmLRxY
2026-11-04 19:48:58 +07:00

5.8 KiB

npm distribution

The npm packages idx-cli (repo root) and idx-mcp (npm/idx-mcp/) are small wrappers around the native idx and idx-mcp binaries. Both use the same launcher and installer from scripts/; the package's nativeBinary field picks the binary, and npm/idx-mcp copies the scripts in at prepack. The idx-cli package The package keeps the JavaScript launcher and postinstall downloader. The downloader selects a prebuilt GitHub Release asset for the current platform and places it at the path used by the idx bin entry.

Supported release assets:

npm platform Rust target Release asset
Linux x64 x86_64-unknown-linux-musl idx-linux-x64
Linux arm64 aarch64-unknown-linux-musl idx-linux-arm64
macOS arm64 aarch64-apple-darwin idx-darwin-arm64
macOS x64 x86_64-apple-darwin idx-darwin-x64

idx-mcp assets use the same platforms with an idx-mcp- prefix, for example idx-mcp-linux-x64.

The Linux binaries are statically linked against musl, so they do not depend on the host glibc version.

Windows and other platform combinations are out of scope. The postinstall script reports the supported targets when it rejects a platform.

Use the package

npm install --global idx-cli
idx --help

# Or run the package without a global install.
npx idx-cli --help

The package version and the release tag must match. For example, package version 0.5.0 downloads assets from the v0.5.0 GitHub Release.

The postinstall script downloads SHA256SUMS from the same release and refuses to install a binary whose checksum does not match.

When postinstall does not run

npm 12 blocks install scripts of unapproved packages under npx and npm install -g (its allow-scripts policy), and pnpm 10+ and bun skip dependency lifecycle scripts by default. The launcher then runs the installer itself on first start, logging to stderr so the idx-mcp stdout channel stays clean; it fails only when that download fails too. Hermes Agent runs npx with its own npm 12, which is how 0.3.1 broke there (issue #41).

The binary goes in the package's bin/, or, when that is not writable (a root-owned sudo npm install -g whose postinstall npm 12 skipped), in a per-user cache: $XDG_CACHE_HOME (if absolute), else ~/.cache (~/Library/Caches on macOS), under <package>/<version>/<platform>-<arch>/. The launcher looks in both. With no absolute cache root (an empty or relative HOME) there is no fallback, so nothing under the current directory is run. A termination signal during that first-run download stops the installer too, and it removes its partial file.

To install the binary up front instead, allow the script explicitly:

# pnpm
pnpm add --global --allow-build=idx-cli idx-cli

# bun
bun add --global --trust idx-cli

# npm 12
npm install --global --allow-scripts=idx-cli idx-cli

Local smoke test

The smoke script builds or reuses target/release/idx, packs the npm wrapper, installs the tarball into a new temporary directory, and runs the installed idx command, then installs idx-mcp again with --ignore-scripts to check the launcher's first-run install, also with a read-only package directory (the per-user cache fallback). It uses IDX_BINARY_URL with a local file: URL, so the test does not need a registry publish or a network download.

nix develop -c bash -c 'scripts/npm-smoke.sh'
nix develop -c bash -c 'npm pack --dry-run'

The postinstall script performs the release download for normal package installation. It skips the download when it runs inside this source checkout (where Cargo.toml exists) unless IDX_BINARY_URL is set. IDX_BINARY_URL accepts an HTTP(S) URL, a file: URL, or an existing local path for local testing. Set IDX_BINARY_SHA256 to verify an override binary as well.

GitHub Release workflow

Pushing a tag that matches v* starts .github/workflows/release.yml. The workflow builds all supported Rust targets, names the binaries with the asset names above, writes SHA256SUMS, and attaches everything to the matching GitHub Release. The asset names and URLs must stay aligned with scripts/install.js.

To attach binaries to a tag that already exists, run the workflow manually:

gh workflow run release.yml -f tag=v0.5.0

Pull requests that touch the workflow or the installer run the build jobs without publishing, so target breakage shows up before a release.

Release order:

  1. Bump the version together in Cargo.toml (workspace version and the idx-core dependency pin), package.json, and npm/idx-mcp/package.json. A version number can never be republished.
  2. In the same release PR, run scripts/changelog.sh release X.Y.Z (the date defaults to today, UTC). It folds changes/unreleased/ into a new CHANGELOG.md section in the fixed section order, ends it with the **Full Changelog** compare link, and deletes the entries. Add a changes/unreleased/summary.md first for a one-line opener, such as an upgrade note when a fix is urgent. Edit the section by hand if needed; scripts/changelog.sh notes X.Y.Z prints it as GitHub will show it.
  3. Push the tag, or run the workflow for an existing tag. The workflow attaches the binaries and sets the release notes to the tag's CHANGELOG.md section; a tag whose CHANGELOG.md lacks its version keeps the notes it has.
  4. Publish the crates from the tagged commit, dependency first: cargo publish -p idx-core, then -p idx-cli and -p idx-mcp.
  5. Confirm the release has all eight binaries plus SHA256SUMS and the notes. To fix the notes later, edit CHANGELOG.md and run gh release edit vX.Y.Z --notes-file <(scripts/changelog.sh notes X.Y.Z).
  6. Run npm publish in the repo root and in npm/idx-mcp/ from the tagged commit. The account has two-factor auth, so npm asks for a browser approval or --otp=<code>.