A containerized, sandboxed environment for running AI coding agents.
Pibox wraps a coding agent inside an Arch Linux-based Docker image so the agent executes against your working directory without having unrestricted access to your host system. The container mirrors your host user (UID/GID/name) so files created inside the container keep consistent ownership on the host.
Three harnesses are supported:
| Harness | Agent | Image |
|---|---|---|
pi (default) |
pi | ghcr.io/badjware/pibox:pi |
claude |
Claude Code | ghcr.io/badjware/pibox:claude |
pi-web |
PI WEB, a web UI for pi | ghcr.io/badjware/pibox:pi-web |
- Sandboxed execution: the agent runs inside a container with an ephemeral filesystem.
- Host-user mirroring: files written from inside the container are owned by your host user.
- Persistent config:
~/.piis always bind-mounted, and~/.claudeis bind-mounted for the claude harness, so settings and sessions survive between runs. - Optional rootless Docker-in-Docker: opt in with
--unsafe-enable-dockerwhen the agent needs to run containers itself. - Pre-built images: distributed via GitHub Container Registry.
- Docker
YMMV on WSL.
git clone https://github.com/badjware/pibox.git
cd pibox
./launch.shYou can invoke launch.sh from any directory. The directory you run it from
becomes the working directory bind-mounted into the container.
Set aliases in your shell for convenience:
alias pibox='/path/to/pibox/launch.sh'
alias claudebox='/path/to/pibox/launch.sh --harness claude'./launch.sh [options] [-- <agent args>]
| Flag | Short | Description |
|---|---|---|
--help |
-h |
Show usage help and exit. |
--harness pi|claude|pi-web |
-H |
Choose the agent to run. Defaults to pi. |
--build |
Build the image locally from the Dockerfiles instead of using the published image. | |
--pull |
Update the image prior to launching. | |
--unsafe-enable-docker |
Start a rootless Docker daemon in DinD mode inside the container so the agent can run containers. | |
--unsafe-enable-aws |
Mount ~/.aws into the container. |
|
--unsafe-enable-kube |
Mount ~/.kube into the container. |
|
--unsafe-host-wayland |
Mount the Wayland socket into the container and forward Wayland environment variables. | |
--unsafe-host-tmux |
Mount the tmux socket into the container and forward the tmux environment variable. | |
--unsafe-host-net |
Share the host network namespace. | |
--ephemeral, --tmp |
-e |
Start in a temporary working directory instead of the current one. |
--workdir <dir> |
-w |
Use <dir> as the working directory instead of the current one. Incompatible with --ephemeral. |
--read-only, --ro |
-r |
Mount all volumes as read-only inside the container. |
--volume <spec> |
-v |
Bind-mount an extra volume (repeatable, same syntax as docker run -v). |
--extra-package <name> |
-P |
Install an extra pacman or AUR package at container startup. Repeatable and non-persistent. |
--port <spec> |
-p |
Publish a container port. Repeatable, using Docker -p syntax such as 9119:9119. Replaces the default pi-web port mapping. |
Any arguments after -- are passed through to the agent inside the container.
Launch pi (default):
./launch.shLaunch Claude Code:
./launch.sh --harness claudeLaunch PI WEB and open http://127.0.0.1:8504:
./launch.sh --harness pi-webBy default, pi-web is published on 127.0.0.1:8504 only. Any --port replaces
that mapping. pi-web listens on port 8504 inside the container, so target it
explicitly, for example --port 0.0.0.0:9000:8504. Set PIBOX_PI_WEB_PORT to
change the default host port. With --unsafe-host-net, pi-web binds
127.0.0.1:${PIBOX_PI_WEB_PORT:-8504} directly on the host. PI WEB assumes
trusted users; only expose it on a trusted network.
Pass arguments through to the agent (everything after -- is forwarded):
./launch.sh -- -p "summarize the README"Install extra packages at startup (repo or AUR):
./launch.sh -P tree -P openscad-gitPackages known to pacman are installed from the official repositories. Anything else is treated as an AUR package: it is cloned, its dependencies are installed, and it is built from source at container startup. AUR builds are not recursive, so an AUR package whose own dependencies are AUR-only will fail to build. This covers packages whose dependencies all live in the official repositories.
Force-refresh the image from GHCR:
./launch.sh --pullForward Wayland for GUI apps:
./launch.sh --unsafe-host-waylandA zsh completion is provided at completions/_pibox. To enable it, add the
completions/ directory to your $fpath before compinit in ~/.zshrc:
fpath=(/path/to/pibox/completions $fpath)
autoload -U compinit && compinitThe container ships with a set of tools suited to a coding agent:
git,vim(as$EDITOR),tmuxnode,python(Python 3),go,gcc,makefd,rg,jq,yq,bc,zip,unzip,diffutils,curldocker+docker composekubectl,aws(aws-cli)chromium,wl-clipboard,patchright(Playwright),trafilatura
Tools deliberately not installed: sudo, ssh, scp, wget.
These paths are always bind-mounted.
| Host | Container | Mode |
|---|---|---|
| current working directory | same absolute path | rw |
~/.pi |
~/.pi |
rw |
~/.pi/agent/extensions |
~/.pi/agent/extensions |
ro |
~/.claude (claude only) |
~/.claude |
ro |
~/.claude/project (claude only) |
~/.claude/project |
rw |
~/.claude.json (claude only) |
~/.claude.json |
rw |
~/.pi-web (pi-web only) |
~/.pi-web |
rw |
~/.config/pi-web (pi-web only) |
~/.config/pi-web |
rw |
~/.gitconfig |
~/.gitconfig |
ro |
pibox-cache volume |
~/.cache |
rw |
/etc/fonts |
/etc/fonts |
ro |
/usr/share/fonts |
/usr/share/fonts |
ro |
/var/cache/fontconfig |
/var/cache/fontconfig |
ro |
| host CA bundle | /etc/ssl/host-ca-bundle.pem |
ro |