Documentation

Everything you need to use vroot, from the first command to portable single-file environments.

# Usage

vroot [FLAGS] [NAME] [OPTIONS] [-- COMMAND]

Options

OptionMeaning
-v SRC[:DST][:ro]expose a host path (read-write, or read-only with :ro)
-offlineno network (loopback only)
-cwd DIRworking directory (default /root)
-env K=Vset an environment variable (repeatable)
-name NAMEpersistent sandbox name
-hostname Hhostname inside (default: sandbox name)
-cleanstart with an empty environment
-rmdelete the sandbox after this session
--jsonmachine-readable output (build, ls, envs, info)

# Examples

# banner + quick-start help (no sandbox)
vroot

# disposable root shell (blank Alpine)
vroot -base

# a shell with a language
vroot -python
vroot -go

# compose tools
vroot -php -sqlite -git

# one command, then exit
vroot -node -- node -e 'console.log(process.version)'

# persistent sandbox
vroot -python work
vroot work -- python3 -c 'print("still here")'

# expose a host directory (rw), everything else hidden
vroot -go -v ~/src:/src -- sh -c 'cd /src && go test ./...'

# fully offline
vroot -python -offline

# Managing sandboxes

CommandMeaning
vroot lslist sandboxes
vroot rm NAME... | --alldelete sandboxes
vroot info NAMEsandbox details
vroot save NAME [OUT.vroot]pack a sandbox (including your changes) into one .vroot image
vroot OUT.vrootboot from a saved image file
vroot filetype installregister .vroot as a custom file type with MIME/desktop handler
vroot envslist built environment images
vroot pruneclear caches and temporary files
vroot recipe list|show|new|edit|pathwork with recipes
vroot doctorcheck the host setup

# Persistence

Ephemeral instances run on a temporary upper layer and are discarded on exit. Name a sandbox to keep it:

$ vroot -python work
==> building env 'python' ...
  ok built env -> envs/python-84d0423ed3.sqfs (25M)
root@vroot:~# echo notes > /root/notes.txt
root@vroot:~# exit

$ vroot work -- cat /root/notes.txt
notes

Changed files live in ~/.local/share/vroot/instances/work/upper. vroot save work out.vroot packs the whole thing into a single portable image you can hand to anyone with vroot and boot with vroot out.vroot.

# How environments are built

  1. Resolve. Flags map to recipes (built-in in recipes/, yours in ~/.config/vroot/recipes/). Recipes are merged: packages, setup steps, environment, PATH and verification.
  2. Build once. A minimal base rootfs — Alpine by default, Debian when a recipe needs glibc — is populated in a build sandbox with apk/apt, then packed with mksquashfs into envs/<flags>-<hash>.sqfs.
  3. Launch. Each session unpacks the image to a cache, mounts it with overlayfs (upper = tmpfs for throwaway, or the sandbox's upper/ dir if persistent) and execs bubblewrap with full capabilities and isolated namespaces.
Storage root: ~/.local/share/vroot (override with $VROOT_HOME). Recipes dir: ~/.config/vroot/recipes (override with $VROOT_CONFIG).

# Machine interface

Scripts and agents get the same tool with a stable contract: JSON on stdout, logs on stderr, and exit codes that mean something.

vroot build -python --json   {"env":"/…/python-84d0423ed3.sqfs","cached":false}
vroot ls --json              [{"name","env","image","bytes","age_minutes"}]
vroot envs --json            {"images":[…],"bases":[…]}
vroot info NAME --json       {"name","env","image","created","bytes","changed_files","path"}
Full contract: agents.html · llms.txt · llms-full.txt · flags.json.

# Requirements

Run vroot doctor to check everything at once.

# FAQ

Is this Docker?

No. Docker builds and runs OCI images via a daemon; great for services and orchestration. vroot is a single script that gives an isolated root shell from a single-file, copy-on-write image — no daemon, no image build, near-instant start. Closer to proot or a beefed-up chroot.

Do I need root or sudo?

No. Everything runs through unprivileged user namespaces and bubblewrap. Inside the sandbox you are uid 0 with full capabilities, but confined by user, PID, mount, UTS and IPC namespaces, and the host filesystem is not visible by default.

Can I access my files?

Yes, explicitly, with -v ~/src:/src. Nothing is shared until you ask.

Why Alpine by default?

Tiny and builds in seconds. Recipes that need glibc or apt-only packages automatically opt into a Debian base.

Does it work without systemd / in a container / under WSL?

It needs unprivileged user namespaces. Run vroot doctor to check.