encapsule

Run isolated toolbox containers with podman

https://github.com/juhp/encapsule

Stackage Nightly 2026-07-22:0.3
Latest on Hackage:0.3

See all snapshots encapsule appears in

Apache-2.0 licensed and maintained by Jens Petersen
This version can be pinned in stack with:encapsule-0.3@sha256:309661866087a0d99e9243b5c9112dfae329ff03838e3e4be9606ccefea9e837,2599

Module documentation for 0.3

There are no documented modules for this package.

encapsule

CLI tool to run developer containers, isolating your home directory and host from container side effects: “encapsules” a project and/or temp home dir together with select “capabilities”.

Originally derived from toolbox-constrained tool.

Run a (toolbox) container or image as an isolated podman container. Unlike with toolbox enter, this does not bind-mount your home directory or integrate with the host by default. You can explicitly choose what dir(s) to mount or features to enable, selecting user-configured “capabilities” that the encapsule container can access.

encapsule TOOLBOX [options] [CMD...]

if TOOLBOX is a container it will be committed (saved) to an “encapsule” container image from the named toolbox container using buildah.

Examples

# Isolated shell without host fs access
$ encapsule my-toolbox

# Mount current (project) directory in / and set it as the working directory
# (also names the container after the project, e.g. encapsule-my-toolbox-myproject)
$ encapsule my-toolbox -p .

# Bind mount a volume
$ encapsule my-toolbox -v ~/data:/data

# Mount a temp "home" directory (created if it doesn't exist)
$ encapsule my-toolbox --home /tmp/somedir

# Use capabilities from config
$ encapsule my-toolbox --cap ssh --cap git

# Read-only container filesystem
$ encapsule my-toolbox --readonly

# Remove the saved image
$ encapsule my-toolbox --delete-image

# Set environment variables and prepend to PATH
$ encapsule my-toolbox -e MY_VAR=hello -P ~/.local/bin

# Run a specific command
$ encapsule my-toolbox -- ls /

# Dry run: print the full podman command without running it
$ encapsule my-toolbox --dryrun

# run directly from an image
$ encapsule fedora:44 --home tmphome

Encapsule containers are ephemeral by default: use --keep to leave the encapsule container around for reuse. Note the saved image will be reused next time unless using --refresh.

Usage

$ encapsule --version

0.3

$ encapsule --help

encapsule

Usage: encapsule [--version] [TOOLBOX] [-v|--volume HOST:CONTAINER[:opts]]
                 [-e|--env KEY[=VALUE]] [-P|--path DIR] [-i|--init CMD]
                 [--cap NAME] [--home DIR] [-p|--project DIR] [-n|--name NAME]
                 [--caps | --list | --remove | --delete-image | --stop] [--keep]
                 [--readonly] [--no-network] [--no-sudo] [--unique]
                 [--podman-opt OPTION] [--debug] [--dryrun] [--refresh] [CMD]

  Run a toolbox image in an isolated podman container

Available options:
  -h,--help                Show this help text
  --version                Show version
  -v,--volume HOST:CONTAINER[:opts]
                           Bind mounts (default to selinux :z)
  -e,--env KEY[=VALUE]     Set or pass through an environment variable
  -P,--path DIR            Prepend a directory to PATH inside the container
  -i,--init CMD            A bash snippet run when creating the encapsule
                           container
  --cap NAME               Enable a capability from the config file
  --home DIR               Mount a directory as a writable home (created if
                           missing)
  -p,--project DIR         Mount a project directory and set as workdir
  -n,--name NAME           Container name (for creating or actions)
  --caps                   List available capabilities from the config file
  --list                   List encapsule images and containers
  --remove                 Remove encapsule container
  --delete-image           Remove encapsule image
  --stop                   Stop encapsule container
  --keep                   Keep the encapsule container after exiting
  --readonly               Make the encapsule container filesystem read-only
  --no-network             Disable network access
  --no-sudo                Skip passwordless sudo setup
  --unique                 Run a new encapsule container even if one is already
                           running
  --podman-opt OPTION      Pass an option directly to podman
  --debug                  Show debug output
  --dryrun                 Print the podman command instead of running it
  --refresh                Force re-commit of the toolbox image

Capabilities

Define reusable groups of volumes, environment variables, PATH entries, and init commands in ~/.config/encapsule/config.toml:

[capabilities.ssh]
volumes = ["~/.ssh:~/.ssh:ro"]

[capabilities.git]
volumes = ["~/.gitconfig:ro"]

[capabilities.wayland]
env = ["WAYLAND_DISPLAY", "XDG_RUNTIME_DIR"]
volumes = ["$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"]
security_opts = ["label=disable"]

[capabilities.rust]
path = ["~/.cargo/bin"]

Each capability can define:

  • volumes — list of bind mount specs
  • env — list of environment variables to set or pass through
  • path — list of directories to prepend to $PATH
  • init — a bash snippet to run on encapsule container creation
  • security_opts — list of --security-opt values passed to podman

~ and envvars are expanded in volume and path specs. If the host and container paths are the same, you can use the shorthand PATH[:opts] instead of PATH:PATH[:opts].

How it works

  1. Commits the named toolbox container to an encapsule image using buildah commit (reuses the existing image unless --refresh is passed)
  2. Runs podman run with --userns=keep-id so you are your own user, not root
  3. Tries to install runuser (util-linux) and sudo if they are missing with dnf or apt-get.
  4. Sets up passwordless sudo inside the encapsule container (unless --no-sudo)
  5. Bind mounts get SELinux :z (shared) labels automatically, so multiple containers can safely access the same directories
  6. When -p/--project DIR is used (and --name isn’t), the container name includes the project directory’s name (e.g. encapsule-mytoolbox-myproject), so you can run the same toolbox against different projects at the same time in separate encapsule containers

Installation

A copr repo is available for Fedora and Epel 10:

https://copr.fedorainfracloud.org/coprs/petersen/encapsule/

Building from source

cabal install

or stack install.

Requirements

  • podman and buildah
  • An existing (toolbox) container (created with toolbox create) or image.
  • Alternatively some non-toolbox other container/images may also work.

Related projects

I already mentioned toolbox-constrained from which the initial code was derived.

There is also similarly schupfn which uses QEMU to run a toolbox container image in a VM with a direct private ssh connection.

For stronger sandboxing and isolation, specially network, consider using OpenShell.

Contribute

encapsule is at https://github.com/juhp/encapsule and distributed under the Apache-2.0 license.

Changes

encapsule releases

0.3 (2026-07-20)

  • project renamed from constrained-toolbox
  • rename --persistent to --keep
  • add --list command to show encapsule containers and images
  • add --no-sudo to remove sudo from the container
  • check toolbox container exists before buildah commit
  • support running container images directly (name:tag)
  • add --name option
  • add --debug flag for verbose startup output
  • use --name ^... to reference a full container name explicitly
  • export TERM and COLORTERM
  • --delete and commit image now respect –dryrun
  • use shell-monad for installSetup Script
  • installScript now respects --no-sudo and outputs “installing”
  • use xdg-basedir for config file
  • error for --project/--home on HOME
  • --project now names the container after the project directory too, so different projects can run concurrently in separate containers
  • add --podman-opt to pass options directly to podman

0.2.1 (2026-07-17)

  • add –delete container command
  • handle missing container gracefully in –stop and –remove
  • default to ephemeral containers again, use –persistent to keep

0.2 (2026-07-16)

  • add --home option to mount a directory as a writable home
  • name the container and exec into it if already running
  • add --unique option to run a separate container instance
  • make home directory writable and workdir by default
  • change --delete to --delete-image standalone command
  • add --ephemeral, restart stopped containers
  • error for unused options when joining running container
  • add –stop command

0.1 (2026-07-03)

  • initial release with --delete and --project options
  • defaults to :z shared bind mounts
  • --caps to list user’s defined capabilities
  • wayland: fix socket handling in SELinux labeling
  • add security_opts capability field
  • support PATH[:opts] shorthand for same host/container mount path (makes config incompatible with toolbox-constrained)
  • add --no-network option to disable network access
  • exit cleanly on shell error instead of throwing an exception