Platforms

Rune ships one native binary per platform. The meta package @gio-labs/rune lists all six as exact-pinned optional dependencies, and the package manager installs the one that matches.

PlatformPackageTarget triple
Windows x64@gio-labs/rune-win32-x64x86_64-pc-windows-msvc
Windows arm64@gio-labs/rune-win32-arm64x86_64-pc-windows-msvc, run under emulation
macOS x64@gio-labs/rune-darwin-x64x86_64-apple-darwin
macOS arm64@gio-labs/rune-darwin-arm64aarch64-apple-darwin
Linux x64@gio-labs/rune-linux-x64x86_64-unknown-linux-musl
Linux arm64@gio-labs/rune-linux-arm64aarch64-unknown-linux-musl

Tested floors: Windows 10, macOS 10.15 on x64 and macOS 11 on arm64, any Linux distribution.

Linux

Both Linux binaries are statically linked against musl, so one binary per architecture runs everywhere. There is no glibc and musl split, no minimum glibc version, and no runtime detection in the wrapper. Alpine and Debian install the same package.

Windows arm64

The arm64 package carries the x64 binary and runs under Windows on ARM emulation. Where the arm64 package is missing but the x64 one is installed, the wrapper spawns the x64 binary and says so once:

warning: no arm64 binary found, running the x64 build under emulation

Installation shape

The meta package declares no engines, no os and no cpu, so it installs everywhere and its diagnostics can run on a machine it does not support. There is no postinstall script, no download at install time, and no network access after the packages are fetched.

Platform packages set preferUnplugged: true so Yarn Plug'n'Play materialises the executable on disk, which it must be to run.

Wrapper resolution

  1. RUNE_BINARY_PATH, when set. A missing file there is a hard error.
  2. A rune installed in the repository you are standing in, found by walking up from the working directory to the first node_modules/@gio-labs/rune and stopping at the repository boundary. When that install is not the copy already running, it takes over from there.
  3. require.resolve on the platform package for the current process.platform and process.arch.
  4. On arm64, the x64 sibling, with the warning above.
  5. Diagnostics.

Step 2 is why a rune installed globally does not override the version a repository pins. Inside that repository, the pinned copy runs, which is the copy CI runs — CI goes through package.json, so it always resolves the local one. It happens silently, because running the pinned version is what you meant. rune --version prints the binary that answered under the version line, so you can confirm it.

Handover runs that install's own entry point, so its override handling, its emulation fallback and its diagnostics are the ones that apply. An install inside the repository that cannot produce a binary reports its own diagnostics; nothing falls back to a copy outside the repository, because the install that needs repairing is the local one.

The binary is spawned with inherited standard input, output and error. The wrapper mirrors the child's exit code, and re-raises the child's fatal signal on itself so the parent shell sees 128 + n rather than a plain exit.

Diagnostics

When no binary resolves, the wrapper reports the reason it can prove rather than a generic message:

CauseWhat it prints
Platform outside the tableThe supported matrix, and the platform and architecture it found
Lockfile omits optional dependenciesThe exact command that repairs it, for the detected package manager
Binaries for another platform presentAn explanation naming the likely cause, usually a container or WSL boundary
Anything elseThe resolution paths it tried

The package manager is detected from npm_config_user_agent, so the repair command matches the one in use.

Building from source

git clone https://github.com/giancarlosisasi/rune
cd rune
cargo build --release
RUNE_BINARY_PATH=$PWD/target/release/rune pnpm test

The release profile uses fat link-time optimisation, one codegen unit and stripped symbols.