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 | shWindows
irm https://penv.cloud/install.ps1 | iexWhen 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 shellThe 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
| Variable | What it does | Installer |
|---|---|---|
PENV_VERSION | Pin a tag such as v1.2.3 instead of taking the latest release. | both |
PENV_INSTALL_DIR | Where the binary lands. | both |
PENV_RELEASE_BASE | The address the release is read from. Only the installers read it. The binary carries the one address. | both |
PENV_TARGET | Install for another machine's target triple instead of this one's. | install.sh |
PENV_ALLOW_ROOT | 1 installs as root. The default refuses. | install.sh |
PENV_ALLOW_ELEVATED | 1 installs from an elevated shell. The default refuses. | install.ps1 |
PENV_ADD_TO_PATH | 1 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:
| Installer | Signature over the checksum file |
|---|---|
install.sh | Verified 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.ps1 | Prints 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
penvpenv 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.