The image contract
Your project decides everything about the base image its workspaces come from.
What the image must have
para's own mechanism needs very little:
- a workspace user,
$PARA_USERwith uid/gid$PARA_UID/$PARA_GID(appand1000/1000by default). para runs hooks andpara shas that user and chowns every pushed file to those ids; - bash, because para invokes hooks and shells via
su -s /bin/bash; - util-linux
su, if you runpara sh <ws> -c '<cmd>'from a terminal; - a shutdown path. Provide either a
poweroffcommand that the guest's init acts on, or an init that responds to LXC's halt signal (SIGPWRby default). Without either,para downwaits 60 seconds and fails with an error namingincus stop -f <container>.
Everything else is your project's choice.
For a workspace that is pleasant to work in, also include a login shell like zsh, your dotfiles, and whatever agent harness you use.
Building with para image build
The command is base-agnostic plumbing:
- launches a builder from
$PARA_IMAGE_BASEwithsecurity.nesting=true; - runs
$PARA_IMAGE_BOOTSTRAPin it viash -c, if there is one; - pushes the composed layer stack to
/opt/.paraspacein the builder, with each layer at/opt/.paraspace/stack/<layer name>, the same layout a workspace gets at~/.paraspace; - runs
hooks/image-buildfrom every layer that defines it, in stack order, as root, with no tty and no stdin; - removes
/opt/.paraspaceand publishes the result as$PARA_IMAGE_NAME.
Two caveats:
- Images are per-arch, so build on the machine that runs them (arm64 on Apple Silicon).
-i/--from-currentlayers onto the existing$PARA_IMAGE_NAMEinstead of a pristine base, and skips the bootstrap. A fast iterative rebuild while you're tuning the hook; it assumes your hook is idempotent, and you should do one clean build before relying on the result.
The bundled base layer's hooks/image-build is the reference: Void packages, a workspace user, and the zsh extension paths bundled layers use. Docker lives in its own layer.
Checking it with para image status
$ para image status
image myapp
built 2026/07/21 14:02 UTC
base images:voidlinuxbase is what this image was built from, stamped at build time.
Rebuild when you've edited your hooks/image-build.
para image rm deletes $PARA_IMAGE_NAME, to reclaim space or force a fully clean next build. Workspaces already up are clones and keep running.