Docs
Guidesince 1.0.0-alpha.3

Install the CLI

Three ways to install penv, and what each installer verifies before it puts the binary in place.

penv is one static binary with nothing under it. No Node, no plugins, no runtime.

macOS and Linux

curl -fsSL https://penv.cloud/install | sh

Windows

irm https://penv.cloud/install.ps1 | iex

When npm should own it

npm i -g @penvhq/cli@next

@penvhq/cli is an npm package that runs the platform binary. npm installs the one platform package that matches your machine and skips the other five. There is no install script. When npm skips a platform package silently, penv says which one is missing and that the two installers above need no npm.

While 1.0 is a prerelease, next is the tag that carries it. Install without that tag and npm gives you 0.16.2, the retired 0.x package whose only executable is penv-engine, so you end up with no penv on your PATH. See upgrade from 0.16.

Where the binary lands

$HOME/.penv/bin/penv, or %USERPROFILE%\.penv\bin\penv.exe on Windows. PENV_INSTALL_DIR moves it.

Neither installer edits a shell startup file. When the install directory is already on your PATH, the shell installer says nothing about it and prints the next command to run. Otherwise it prints one line, chosen from the shell $SHELL names:

fish_add_path "$HOME/.penv/bin"                            # fish
echo 'export PATH="$HOME/.penv/bin:$PATH"' >> ~/.zshrc     # zsh
echo 'export PATH="$HOME/.penv/bin:$PATH"' >> ~/.profile   # bash, and every other shell

The PowerShell installer writes your user PATH only when you ask for it. Run the file with -AddToPath, or set $env:PENV_ADD_TO_PATH = '1' when you pipe it through iex, which has no flags to take.

Installer variables

VariableWhat it doesInstaller
PENV_VERSIONPin a tag such as v1.2.3 instead of taking the latest release.both
PENV_INSTALL_DIRWhere the binary lands.both
PENV_RELEASE_BASEThe address the release is read from. Only the installers read it. The binary carries the one address.both
PENV_TARGETInstall for another machine's target triple instead of this one's.install.sh
PENV_ALLOW_ROOT1 installs as root. The default refuses.install.sh
PENV_ALLOW_ELEVATED1 installs from an elevated shell. The default refuses.install.ps1
PENV_ADD_TO_PATH1 writes your user PATH when the script is piped through iex.install.ps1

Both installers refuse to run with administrator rights because they write into a home directory, and a binary owned by root is one the person who runs penv cannot replace.

What each installer checks

Every download is compared against the sha256 digest the release publishes, and a file that does not match is never installed. The download happens before that comparison, so a refusal is a temporary file removed rather than a byte never fetched. install.sh downloads into the install directory, which it creates first, and renames the file into place so the move lands over a running penv atomically. install.ps1 downloads into a temporary directory and creates the install directory only once the digest holds.

The signature over that digest is a second check, and the two installers can prove different amounts of it:

InstallerSignature over the checksum file
install.shVerified where OpenSSL 1.1.1 or newer is on PATH, which is where Ed25519 arrived. Where there is none it prints one dim line saying so and installs on the digest.
install.ps1Prints that line always. .NET carries no Ed25519 and this installer takes no dependency to get one.

penv upgrade is stricter than either installer. It verifies the signature against every release key compiled into your binary, and refuses before it reads a digest.

Check what you have

penv --version
penv

penv with no arguments prints the state you are in and the one next command.

Staying current

penv upgrade replaces the binary an installer placed, after the signature and the digest hold. penv upgrade --check reports what the latest release carries and changes nothing.

Where a package manager owns the binary, upgrade refuses and names the command that manager uses. That covers npm, Homebrew, Nix, winget and Scoop.

Run the quickstart