Transparent development environments using containers https://boxc.li
  • Rust 96.5%
  • Shell 3.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-26 14:01:54 +02:00
.forgejo/workflows Add vulnerability check CI 2026-07-26 14:01:54 +02:00
contrib/direnv Allow specifying custom context in build_image 2026-01-20 17:23:40 +01:00
src Automount & configure CWD by default 2026-03-15 13:35:03 +01:00
.gitignore Cargo bootstrap 2025-09-14 11:09:13 +02:00
Cargo.lock Support per-command overrides 2025-09-14 18:11:51 +02:00
Cargo.toml Support per-command overrides 2025-09-14 18:11:51 +02:00
LICENSE Add LICENSE 2025-10-14 21:08:09 +02:00
README.md Automount & configure CWD by default 2026-03-15 13:35:03 +01:00

BOX

Box provides transparent development environments by replacing your dev tools with symlinks that run the tool inside an isolated container.

Think inside the box.

See the blog post for some additional background.

Installation

cargo install --git https://codeberg.org/galen/box-cli

Quickstart

As a quickstart, we can follow an example configuration for a Golang development environment. All configuration options must be prefixed with BOX_. See full list of configurations here.

export BOX_IMAGE="golang:1.25-alpine3.23"
export BOX_VOLUMES="GOCACHE=$HOME/.cache/go-build"
export BOX_ENVS="GOCACHE=$HOME/.cache/go-build"

Once the environment variables are exported, an alias can be added to invoke the commands set for the workspace. For example:

box alias add go

With the alias in place, every invocation of go from the workspace would run inside the container built via the image specified in the configuration with BOX_IMAGE.

Box will automatically mount and configure the current working directory at the same path within the container, so that commands in the container have a consistent view with the host system.

Configuration

Box exposes a number of configuration options to bootstrap the OCI containers. All env vars are parsed according to shell rules.

BOX_AUTOCONFIGURE_CWD

Automatically mount & configure the current working directory in the container. Defaults to true.

Example: BOX_AUTOCONFIGURE_CWD=false

BOX_CMD

Specifies the default command to execute when the container is started.
Example: BOX_CMD="python run.py".

This option should rarely be set; by default, the command given to the development tool gets executed as the container command. For example, for a development environment boxed for Golang, go build . will spawn the go container with build . command.

BOX_ENTRYPOINT

Specifies the default executable for the container.
Example: BOX_ENTRYPOINT="/bin/bash"

BOX_ENVS

Space-separated list of environment variables to be exported in the container.
Example: BOX_ENVS="DEBUG_LEVEL=info DB_HOST=localhost"

BOX_EXTRA_OPTS

Extra arguments that get passed through transparently to the container runtime.
Example: BOX_EXTRA_OPTS=--read-only

BOX_IMAGE

Container image for the development environment.
Example: BOX_IMAGE="alpine:3.23"

BOX_INIT

Boolean configuration to replace the BOX_ENTRYPOINT or BOX_CMD with a container init process with PID 1 to manage signal handeling and child process reaping. Defaults to true.
Example: BOX_INIT=false

BOX_INTERACTIVE

Boolean configuration to start the container in interactive mode. Defaults to true.
Example: BOX_INTERACTIVE=false

BOX_NETWORKS

Space-separated list of container networks.
Example: BOX_NETWORKS="app_network db_network"

BOX_NO_COMMAND

Remove the command name from the list of arguments passed as the container CMD. Defaults to false.
Example: BOX_NO_COMMAND=true

This option is useful if the image sets the entrypoint to a specific tool rather than a shell, as is common for CLI applications packaged in containers.

BOX_NO_MOUNT_DIRS

Space-separated list of directories that should not be mounted as volumes in the container. Volumes set via BOX_VOLUMES which reference a host path in this list will be automatically filtered out. Defaults to user's home directory.

Example: BOX_NO_MOUNT_DIRS="$HOME /some/private/dir"

This option is useful to prevent certain directories from being mounted in the container if they are the current working directory.

BOX_PORTS

Space-separated list of port mappings between host and container.
Example: BOX_PORTS="8000:8000 80:80"

BOX_PRIVILEGED

Boolean configuration to grant extended privileges to the container. Defaults to false.
Example: BOX_PRIVILEGED=true

BOX_RUNTIME

Required configuratin to select OCI runtime for the workspace container. Supports podman and docker.
Example: BOX_RUNTIME=podman

BOX_TTY

Boolean configuration to attach pseudo-tty to the container. Defaults to true if stdin, stdout, and stderr are all TTYs, otherwise false.
Example: BOX_TTY=true

BOX_USER

Specifies the container user.
Example: BOX_USER=1000

BOX_VOLUMES

Space-separated list of bind mounts for the container.
Example: BOX_VOLUMES="$PWD:$PWD $HOME/cloud_config:$HOME/cloud_config"

BOX_WORKDIR

Specifies the working directory inside the container. Defaults to the current working directory unless BOX_AUTOCONFIGURE_CWD is disabled.
Example: BOX_WORKDIR=/app

Command-specific configurations

Box also allows to override the defined configuration options for specific commands. For example, in case of an already configured development environment, we might want to change some env vars when we want to execute a helper script bin/my-script. This can be achieved by the match rule overrides for the box configurations.

BOX_<key>_MATCH

Specifies the key and value for a command, whose invocation should use different configuration options than otherwise specified.

e.g. BOX_my_script_MATCH="bin/my-script"

bin/my-script command may now invoke the same main container with different configuration options. e.g. BOX_my_script_ENVS="DEBUG_LEVEL=trace"

All box supported configurations are applicable for BOX_my_script_ matcher.

Box alias

Box provides a utility subcommand alias to add symlinks to the development tools as: box alias add <alias_name>

The path where box stores aliases can be found by box path (defaults to $XDG_DATA_HOME/box). This directory must be added to your $PATH.

A list of aliases can be seen with: box alias list

Aliases can be removed via: box alias remove <alias_name>

Context-specific aliases

The location where box stores aliases can be changed by setting $BOX_PATH. This can be used to create aliases only available within a specific context.

For example, all aliases for a workspace called my_todos could be created by setting the box path:

export BOX_PATH=$(box path)/my_todos

All alias subcommands will work only in the context of specified workspace.

Box and direnv

Box pairs well with direnv for seamless export of configuration variables and provides some helper directives that work with direnv.

Here is an example .envrc configuration for go environment with box helper directives:

image="$(build_image ./Dockerfile)"
export BOX_IMAGE=$image

go_path="${GOPATH:-$HOME/.go}"
go_cache_path="${GOCACHE:-$HOME/.cache/go-build}"

my_envs="$(envs_from_dotenv)"
export BOX_ENVS="$my_envs GOPATH=$go_path GOCACHE=$go_cache_path"

export BOX_VOLUMES="$go_path:$go_path $go_cache_path:$go_cache_path $PWD:$PWD"

export BOX_PORTS="8080:8080 5432:5432"

export BOX_WORKDIR="$PWD"

Check out dev-envs for more examples.