Skip to content

punix shell

Try software without installing it.

punix shell ripgrep jq          # a subshell with both on $PATH; exit to leave
punix shell just -c 'just --version'

What it answers

"Can I use this tool for ten minutes without changing my machine?" is the question nix-shell and guix shell answer, and it is how most people first meet a functional package manager, and the one Punix had no answer to.

Punix builds whatever isn't already in the store, symlinks the binaries into a temporary directory, prepends it to $PATH, and starts your shell. When you exit, the directory is gone and your machine is exactly as it was.

What it does not do, on purpose

It writes no generation. punix install changes your machine and records that change so you can undo it; punix shell doesn't change it, so there is nothing to undo. No profile is created, current is not touched, and punix profile list looks the same afterwards.

But the build is not thrown away. The store is shared, so a package you build inside a shell stays built: the second punix shell ripgrep is instant, and a later punix install ripgrep is a cache hit. Ephemeral describes the environment, not the work.

Knowing you're in one

$PUNIX_SHELL is set to 1 inside, so a prompt can show it:

# in your shell rc
[ -n "$PUNIX_SHELL" ] && PS1="(punix) $PS1"

Running one command

-c runs a single command in the environment and exits with that command's status, which makes the whole thing scriptable:

$ punix shell shellcheck -c 'shellcheck ./deploy.sh'
$ echo $?
0

Options

  • --file PATH: PCL file or directory (default: $PUNIX_PACKAGES, then ./packages/).
  • --store-root PATH: store location (default ~/.punix/store).
  • --bootstrap MODE: fast / seeded / source / bootstrappable, as for punix install.
  • --scenario NAME, --quiet / -q.

Exit codes: the shell's (or -c's) own; 2 for an unknown module or bad usage; 3 if a build failed.

Not here yet

Three things are absent until something asks for them. They are the questions ADR-032 D6 left open, and the project's rule is to wait for a real driver rather than guess:

  • a per-project punix.pcl that a bare punix shell would read;
  • --pure, a scrubbed environment. It sounds like one flag and is really a contract about HOME, locale, TMPDIR and your shell's own rc files;
  • shell integration: entering an environment automatically on cd, which only pays off once the first two exist.