# Vroot – Instant, daemonless root sandboxes from a single flag

> Source: <https://github.com/gairxx/vroot/tree/main>
> Published: 2026-11-01 03:51:53+00:00

**Instant, isolated, single-file Linux development environments that boot in milliseconds — built from a flag.**

`vroot` gives you a **throwaway or persistent root filesystem** that starts in
milliseconds, is fully isolated from your host, and contains exactly the tools
you asked for:

```
vroot                      # banner + quick-start help
vroot -base                # a root shell (blank Alpine Linux)
vroot -python              # a root shell that has Python
vroot -node -python        # compose flags freely
vroot -sqlite -python db   # a persistent sandbox named "db"
vroot -rust -- cargo build # run one command instead of opening a shell
```

Nothing from your host is visible inside unless you expose it with `-v`, and
the sandbox disappears when you exit (unless you give it a name).

It is also the shortest path from an AI agent to a working toolchain: no
daemon, no image registry, no sudo, no build queue. See
[docs/AGENTS.md](https://github.com/gairxx/vroot/blob/main/docs/AGENTS.md) for the machine-facing contract.

Agents do not need a nicer terminal, they need **resources on demand and no
coordination overhead**. `vroot` is built for that shape of work:

- **No daemon, no registry, no sudo.** A toolchain is one flag away and starts
in tens of milliseconds, so an agent can afford to spawn a fresh environment
per step instead of reusing a fragile one.
- **JSON when you ask for it.**`vroot build -python --json` ,`vroot ls --json` ,`vroot envs --json` ,`vroot info NAME --json` — stdout is
pure JSON, logs stay on stderr, exit codes are meaningful.
- **Parallel-safe.** N agents asking for the same environment produce one
image: the first builds, the rest wait and report`"cached": true` . Cache
extraction is atomic, so concurrent launches cannot corrupt each other.
- **Checkpoint, then fork.**`vroot save NAME golden.vroot` turns a good state
into one file; boot it as many named sandboxes as you like and throw the
failed ones away. The image is never modified.
- **Host stays hidden.** Real uid 0 inside, but no host filesystem, no host
processes, no host network surprises unless explicitly mounted.
- **Deterministic surface.** Anonymous sandboxes are ephemeral, named ones
persist,`-offline` cuts the network, and`vroot doctor` is an explicit
preflight.

``` bash
$ vroot build -python --json
{"env":"/home/u/.local/share/vroot/envs/python-84d0423ed3.sqfs","cached":false}
$ vroot -python task1 -- pytest -q            # exit code is pytest's
$ vroot save task1 task1.vroot && vroot task1.vroot retry -- pytest -q
```

The full contract (output shapes, locking, fork semantics, rules for agents)
lives in [docs/AGENTS.md](https://github.com/gairxx/vroot/blob/main/docs/AGENTS.md).

`vroot` is a lightweight sandbox and container alternative for the common case
where you just want a **clean, disposable Linux shell with some language or
tool installed** — without images to build, a daemon to run, or a slow boot.

- **Instant.** Environments are stored as single compressed images and mounted
copy-on-write. Starting a shell is a`mount` +`exec` , not a container boot.
Typical cold start is tens of milliseconds.
- **Isolated.** Your real`$HOME` , files and processes are not visible by
default. The sandbox has its own root, PID namespace, hostname and network
(disable networking with`-offline` ).
- **Real root, no sudo.** Inside you are`uid 0` with full capabilities, using
unprivileged user namespaces and bubblewrap. No daemon, no setuid helper, no
root on the host.
- **Composable.**`-php -sqlite -git` builds one environment containing all
three. Every distinct combination is cached separately and reused.
- **Single file.** Build once, then`save` a sandbox — including your changes —
into one portable`.vroot` image you can boot anywhere, and register as a
real file type on your desktop with`vroot filetype install` .
- **Extensible.** Every flag is a small text recipe. Add your own language or
tool in a few lines — see[docs/BUILDING.md](https://github.com/gairxx/vroot/blob/main/docs/BUILDING.md) .

|  | **vroot** | Docker / Podman | chroot | proot | full VM | 
|---|---|---|---|---|---|
| Boot time | ~10–50 ms | ~0.3–2 s | instant | ~0.1–1 s | seconds | 
| Requires root / daemon | **no / no** | no / yes (or rootless setup) | **yes** | no | no | 
| Host filesystem hidden | **yes** | yes | no | partial | yes | 
| Real `uid 0` inside | **yes** | yes | yes | no (faked) | yes | 
| Storage per environment | **one file** | layered image + container | directory | directory | disk image | 
| Compose tools by flag | **yes** | Dockerfile / run args | manual | manual | manual | 
| Best for | root shells, language sandboxes, reproducible dev shells | services, images, orchestration | legacy sysadmin | emulation, odd arches | full isolation | 

- **Linux** with unprivileged user namespaces enabled (default on modern
distros; check with`vroot doctor` ).
- `bubblewrap` ,`util-linux` (`unshare` ),`squashfs-tools` (`mksquashfs` ,`unsquashfs` ).
- `curl` or`wget` — only for the first build (to fetch the base rootfs).
- `docker` — only if you use a flag whose recipe targets the Debian base
(`bun` ,`clojure` ,`groovy` ,`julia` ,`kotlin` ,`scala` ,`swift` ).

```
sudo apt install bubblewrap util-linux squashfs-tools curl
sudo dnf install bubblewrap util-linux squashfs-tools curl
sudo pacman -S bubblewrap util-linux squashfs-tools curl
```

Then verify your host:

```
vroot doctor
```

One line, no sudo, no daemon:

```
curl -fsSL https://raw.githubusercontent.com/gairxx/vroot/main/install.sh | sh
```

That installs the launcher to `~/.local/bin/vroot` and the recipe catalogue to
`~/.local/lib/vroot`. Then check the host and start a shell:

```
vroot doctor      # verify bubblewrap, namespaces, squashfs
vroot -python     # a root shell with Python
```

Prefer clicking? **[gairxx.github.io/vroot](https://gairxx.github.io/vroot/)**
has copy buttons for every method.

| Method | Command | 
|---|---|
| One-line install | `curl -fsSL https://raw.githubusercontent.com/gairxx/vroot/main/install.sh \| sh` | 
| Clone and install | `git clone https://github.com/gairxx/vroot && cd vroot && sh install.sh` | 
| Source archive | [main.tar.gz](https://github.com/gairxx/vroot/archive/refs/heads/main.tar.gz) → unpack →`sh install.sh` | 
| Custom prefix | `curl -fsSL ... \| sh -s -- --prefix /opt/vroot` | 
| Pin a ref | `curl -fsSL ... \| sh -s -- --version <branch-or-tag>` | 
| Uninstall | `curl -fsSL ... \| sh -s -- --uninstall` | 

`install.sh` installs from the working tree when run inside a checkout, and
otherwise downloads a tarball — no build step either way. Uninstalling keeps your
sandboxes and images in `~/.local/share/vroot`.

```
# Banner + quick-start help (no sandbox)
vroot

# A disposable root shell (blank Alpine)
vroot -base

# A root shell with a language
vroot -python
vroot -node
vroot -rust

# Compose as many tools as you like
vroot -php -sqlite -git

# Run a single command and exit
vroot -node -- node -e 'console.log(process.version)'

# A persistent sandbox you can come back to
vroot -python work
vroot work -- python3 -c 'print("still here")'

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

# Fully offline
vroot -python -offline
```

Everything is root inside, but your host is untouched:

``` bash
$ vroot -python -- sh -c 'id; hostname; ls /home'
uid=0(root) gid=0(root)
vroot
ls: /home: No such file or directory
```

One flag per tool or language. Combine them to build exactly the environment you need.

| `-python` | `-node` | `-deno` | `-bun` | 
| `-php` | `-ruby` | `-perl` | `-lua` | 
| `-r` | `-julia` | `-go` | `-rust` | 
| `-zig` | `-nim` | `-crystal` | `-d` | 
| `-swift` | `-haskell` | `-elixir` | `-erlang` | 
| `-ocaml` | `-clojure` | `-groovy` | `-java` | 
| `-kotlin` | `-scala` | `-dotnet` | `-fsharp` | 
| `-gcc` | `-clang` | `-cmake` | `-gfortran` | 
| `-nasm` | `-sqlite` | `-postgres` | `-mysql` | 
| `-git` | `-openssh` | `-curl` | `-vim` | 
| `-base` | `-debian` |  |  | 

Flags answer to aliases too (`-python3`, `-nodejs`, `-cargo`, `-golang`, ...).
See the full catalog with details in [docs/LANGUAGES.md](https://github.com/gairxx/vroot/blob/main/docs/LANGUAGES.md) or:

```
vroot recipe list
vroot [FLAGS] [NAME] [OPTIONS] [-- COMMAND]
```

| Option | Meaning | 
|---|---|
| `-v SRC[:DST][:ro]` | expose a host path (read-write, or read-only with `:ro` ) | 
| `-offline` | no network (loopback only) | 
| `-cwd DIR` | working directory (default `/root` ) | 
| `-env K=V` | set an environment variable | 
| `-name NAME` | persistent sandbox name | 
| `-hostname H` | hostname inside (default: the sandbox name) | 
| `-clean` | start with an empty environment | 
| `-rm` | delete the sandbox after this session | 
| `--json` | machine-readable output for `build` ,`ls` ,`envs` ,`info` | 

| Command | Meaning | 
|---|---|
| `vroot ls` | list sandboxes | 
| `vroot rm NAME... \| --all` | delete sandboxes | 
| `vroot info NAME` | sandbox details | 
| `vroot save NAME [OUT.vroot]` | pack a sandbox into one `.vroot` image file | 
| `vroot OUT.vroot` | boot from a saved image file | 
| `vroot filetype install` | register the `.vroot` image file type with the OS | 
| `vroot envs` | list built environment images | 
| `vroot prune` | clear caches and temporary files | 
| `vroot recipe list\|show\|new\|edit\|path` | work with recipes | 
| `vroot doctor` | check the host setup | 

1. **Resolve.** Flags are looked up in recipes; matching recipes are merged
(packages, setup steps, environment,`PATH` , verification).
2. **Build once.** A single environment image (`envs/<flags>-<hash>.sqfs` ) is
built the first time a combination is used: a minimal base rootfs — Alpine,
or Debian when a recipe needs glibc — is populated inside a sandbox and
packed with`mksquashfs` .
3. **Launch.** Each session caches/unpacks the image and starts it through an**overlayfs** mount plus**bubblewrap** , giving you a root shell with full
capabilities, isolated namespaces and copy-on-write writes.

Persistent sandboxes keep their changed files in
`~/.local/share/vroot/instances/<name>/upper`, so `save` can pack the exact
state back into a portable single-file image.

```
                 ┌──────────── envs/python+sqlite-<hash>.sqfs ────────────┐
                 │  read-only squashfs image (built once, cached)         │
                 └───────────────────────┬───────────────────────────────┘
                                         │ unsquashfs
                     lowerdir ───────────┤
                                         ▼
  host $HOME ── overlayfs (COW) ──► merged root ── bubblewrap ──► uid 0 shell
  (hidden)         upperdir (your writes)        namespaces: user, pid,
                                                   uts, ipc, net, mount
```

Every flag is a small recipe. Adding a language or tool usually takes a few lines:

```
name = mytool
provides = mytool
base = alpine
packages = mytool
verify = mytool --version
description = My tool
vroot recipe new mytool     # create + edit, then:
vroot -mytool
```

See [docs/BUILDING.md](https://github.com/gairxx/vroot/blob/main/docs/BUILDING.md) for worked examples, and
[docs/RECIPES.md](https://github.com/gairxx/vroot/blob/main/docs/RECIPES.md) for the field reference.

- [docs/AGENTS.md](https://github.com/gairxx/vroot/blob/main/docs/AGENTS.md) — the contract for AI agents and automation
- [docs/BUILDING.md](https://github.com/gairxx/vroot/blob/main/docs/BUILDING.md) — add your own language/tool
- [docs/LANGUAGES.md](https://github.com/gairxx/vroot/blob/main/docs/LANGUAGES.md) — full flag catalog
- [docs/RECIPES.md](https://github.com/gairxx/vroot/blob/main/docs/RECIPES.md) — recipe field reference
- [examples/](https://github.com/gairxx/vroot/blob/main/examples) — example recipes

**Is this Docker?**
No. Docker builds and runs OCI images via a daemon and is great for services and
orchestration. `vroot` is a single script that gives you an isolated root shell
from a single-file, copy-on-write image — no daemon, no image build, near-instant
startup. It is closer to `proot` or a beefed-up `chroot`.

**Do I need root or sudo?**
No. Everything runs through unprivileged user namespaces and bubblewrap.

**Is it safe? Do I really get root?**
Inside the sandbox you are `uid 0` with full capabilities, but you are confined
by user, PID, mount, UTS and IPC namespaces, and by default the host filesystem
is not visible. It is real root in an isolated namespace, not root on your host.

**Can I access my project files?**
Yes, explicitly, with `-v ~/src:/src`. Nothing is shared until you ask.

**Where are environments stored?**
Under `~/.local/share/vroot/` (`envs/`, `cache/`, `instances/`). Override
with `$VROOT_HOME`. Recipes are read from
`~/.config/vroot/recipes/` (override with `$VROOT_CONFIG`).

**How do I make a portable environment?**
`vroot save NAME out.vroot` writes a single image file; boot it with
`vroot out.vroot`. Images are squashfs under the hood and also work with a
`.sqfs` extension.

**Can my file manager recognise vroot images?**
Yes. Run `vroot filetype install` once. It registers a custom
`application/x-vroot-image` MIME type (globs `*.vroot` / `*.sqfs`, plus
detection by squashfs magic) and a desktop handler, so images show a distinct
type and open with `vroot`. Undo with `vroot filetype uninstall`;
`vroot filetype status` shows what is installed.

**Why Alpine by default?**
Alpine images are tiny and build in seconds. Recipes that need glibc or
`apt`-only packages opt into a Debian base automatically.

**Does it work without systemd / in a container / under WSL?**
It needs unprivileged user namespaces. Run `vroot doctor` to check.

**Can an AI agent use it?**
Yes, that is a first-class use case. Management commands take `--json`, stdout
is pure JSON, exit codes are forwarded from the command you run, builds of the
same environment are serialised across parallel processes, and a sandbox can be
checkpointed with `save` and forked by booting the image file under new names.
See [docs/AGENTS.md](https://github.com/gairxx/vroot/blob/main/docs/AGENTS.md).

root shell sandbox · unprivileged Linux sandbox · container alternative · lighter than Docker · Docker alternative for shells · proot alternative · chroot alternative · bubblewrap sandbox · user namespace sandbox · rootless sandbox · run as root without sudo · isolated development shell · ephemeral root shell · persistent dev environment · single-file environment · squashfs environment image · overlayfs copy-on-write · instant Linux sandbox · fast sandbox boot · language sandbox · Python sandbox · Node.js sandbox · Rust sandbox · PHP sandbox · Go sandbox · polyglot dev environment · reproducible development environment · disposable shell · dev container alternative · sandbox for AI agents · agent sandbox · LLM tool sandbox · autonomous agent environment · machine-readable sandbox · parallel agent sandboxes · checkpoint and fork sandbox · JSON CLI sandbox · coding agent runtime.

[MIT](https://github.com/gairxx/vroot/blob/main/LICENSE) © 2026 gairxx
