SkillAgentSearch skills...

Boq

Create isolated dev env on Linux. For confident `alias claude="claude --dangerously-skip-permissions"`

Install / Use

/learn @zhengbuqian/Boq
About this skill

Quality Score

0/100

Supported Platforms

Claude Code
Claude Desktop

README

boq

Isolated development environment using Linux kernel overlayfs.

Why boq?

boq allows:

  • You to use yolo or --dangerously-skip-permissions mode without worrying about AI screwing up your Linux system.
  • You to instantly create an isolated environment that runs exactly like your familiar system.
    • All your familiar commands and AI tools ready to use - no need to re-install, login, authenticate, or configure.
    • Zero learning curve - same shell, same muscle memory, same dotfiles. It just feels like home.
    • Full access to your entire $HOME - all your projects, references, and personal scripts. Not trapped in a single project directory.
    • Your existing compilers, interpreters, and build cache ready to use - no re-downloading, no re-building.
  • You to run multiple isolated environments simultaneously (dev, experiment, feature-x) - each with independent file changes, but sharing the same build toolchain.
  • You to let multiple AI agents work in parallel on the same project, each in its own isolated environment.
  • You to experiment fearlessly - don't like the result? boq destroy and start fresh. No leftover config files, broken dependencies, or system pollution.
  • No Dockerfile to write, no image to build, instant start.

Note: Files unchanged by boq are read from the host in real-time. If you git pull on the host, unmodified files will update inside the boq. Best practice: keep host files untouched while AI is working, and sync periodically.

Features

  • Configurable overlay directories (default: $HOME, /usr, /opt, /home/linuxbrew)
  • Passthrough paths that bypass overlay and share with host
  • Full file locking support (unlike fuse-overlayfs)
  • TOML-based configuration with 3-tier override system

Networking

  • In default bridge mode, each boq gets a static IP and a host alias boq-<name>.
  • From host, you can access services inside boq directly, for example: curl http://boq-dev:8080.
  • Legacy rootless running boqs do not provide this host-access alias; restart them with boq stop <name> then boq enter <name> to upgrade.
  • For docker-backed boqs (create --runtime docker), boq auto-manages a user-defined network boq-docker-net. Its subnet is auto-detected once and persisted in ~/.boq/.docker-subnet.
  • With docker runtime, container.network only supports host / none (or unset). Any other configured network name is rejected.

Installation

Requires Python 3.11+ and one container runtime: podman or docker.

# Install one runtime (choose one)
sudo apt install podman
# or
sudo apt install docker.io

# Install boq (choose one)
pipx install boq          # Recommended: isolated global install
uv tool install boq       # Alternative: using uv
pip install boq           # Or: install to current environment

# For development
git clone https://github.com/zhengbuqian/boq.git
cd boq
uv pip install -e .               # Editable install

Optionally, add the following to your ~/.bashrc or ~/.zshrc to get auto completion and auto yolo mode:

if [ -z "$BOQ_NAME" ]; then
    # add auto completion only in host.
    eval "$(boq completion -s zsh 2>/dev/null)"
else
    echo "In boq env, using yolo mode by default for AI cli tools."
    alias claude="claude --dangerously-skip-permissions"
    alias codex="codex --dangerously-bypass-approvals-and-sandbox"
    alias gemini="gemini --yolo"
    # if you use zsh and see error like `zsh: can't rename ~/.zsh_history.new to $HISTFILE`,
    # you can suppress this error by unsetting `HIST_SAVE_BY_COPY` option.
    unsetopt HIST_SAVE_BY_COPY
fi

# I personally also use this to know where am I, in host or in some boq.
PROMPT="[%m] ${PROMPT}"

Note: Requires sudo for mounting kernel overlayfs.

Quick Start

# Create a boq and enter it (exit shell to detach, container keeps running)
boq create dev

# Re-enter existing boq
boq enter dev

# Open VS Code attached to boq
boq code dev

# Create and open in VS Code directly
boq create dev --code

# See what changed
boq diff dev

# Run a command in boq
boq run dev "make test"

# Stop boq
boq stop dev

# Remove boq
boq destroy dev

Commands

| Command | Description | |---------|-------------| | create <name> | Create a new boq and enter it (use --no-enter to skip, --code to open VS Code, --runtime to pick backend, and --docker-sudo/--no-docker-sudo for docker mode) | | enter [name] | Attach shell to boq (starts if not running; use --migrate-to-docker to migrate a stopped boq to docker) | | code [name] | Open VS Code attached to boq (starts if not running; use --workdir to set working directory) | | run <name> <cmd> | Run a command in boq (must be running; may be interrupted by stop/destroy) | | stop [name] | Stop a boq immediately (may interrupt active sessions) | | destroy <name> | Destroy a boq immediately (stops if running; may interrupt active sessions) | | diff [name] [path] | Show changes made in boq | | status [name] | Show boq status | | list [--size] | List all boq instances (--size also shows disk usage) | | version | Show current boq version | | completion -s <shell> | Output shell completion script |

Default name is default for commands that accept [name].

diff options

boq diff dev                      # Show all content changes
boq diff dev ~/project            # Filter by path (respects .gitignore)
boq diff dev --no-gitignore       # Include gitignored files
boq diff dev --include-metadata   # Include metadata-only changes

Shell Completion

# Bash: add to ~/.bashrc
eval "$(boq completion -s bash)"

# Zsh: add to ~/.zshrc
eval "$(boq completion -s zsh 2>/dev/null)"

Configuration

TOML-based configuration with 3-tier override system:

  1. defaults.toml (shipped with package) - base defaults
  2. ~/.boq/config.toml (user global) - override defaults
  3. ~/.boq/<name>/config.toml (per-boq) - override for specific boq

Higher priority overrides lower. Lists append by default (use <key>_replace to fully replace).

Example ~/.boq/config.toml

[container]
# Change default shell
shell = "/bin/zsh"

# Change base image
image = "ubuntu:24.04"

[runtime]
# auto: prefer docker when available, else podman
default = "auto"

[docker]
# default for create when runtime is docker
use_sudo = false

[container.env]
# Add custom environment variables
MY_VAR = "value"

[overlays]
# Add additional overlay directory
"/data" = "data"

[passthrough]
# Add paths that bypass overlay (appends to default list)
paths = [
    "$HOME/.my-tool",
]

# Or replace the entire list
paths_replace = [
    "$HOME/.zsh_history",
    "$HOME/.claude",
]

[mounts]
# Custom mounts: mount a file/directory to a different location in the container
# Each entry specifies: src (host path), dest (container path), mode ("ro" or "rw")
custom = [
    { src = "/path/on/host", dest = "/path/in/container", mode = "ro" },
]

Default Configuration

[container]
image = "ubuntu:22.04"
shell = "/bin/bash"
capabilities = ["SYS_PTRACE"]

[runtime]
default = "auto"

[docker]
use_sudo = false

[overlays]
"$HOME" = "home"
"/usr" = "usr"
"/opt" = "opt"
"/home/linuxbrew" = "linuxbrew"

[passthrough]
# sharing shell history and AI cli tools config/history bewteen boq and host by default
paths = [
    "$HOME/.zsh_history",
    "$HOME/.bash_history",
    "$HOME/.claude",
    "$HOME/.gemini",
    "$HOME/.codex",
    "$HOME/.factory",
]

[mounts]
readonly = ["/bin", "/lib", "/lib64", "/lib32", "/sbin"]
direct = []
custom = []

Environment variable expansion ($HOME, $USER, etc.) is supported in all string values.

How It Works

  • create sets up overlays, starts container, and enters shell (use --no-enter to skip, --code to open VS Code instead)
  • enter attaches a shell; exiting detaches but container stays running
  • code opens VS Code attached to the container via Dev Containers extension (starts container if needed)
  • create picks runtime automatically by default (prefer docker when available, else podman)
  • create --runtime docker|podman explicitly selects runtime
  • create --docker-sudo/--no-docker-sudo controls docker command prefix for that boq
  • enter --migrate-to-docker can migrate a stopped podman boq to docker backend
  • run executes a single command (container must be running)
  • stop immediately stops container and unmounts overlays (active sessions may be interrupted)
  • destroy immediately stops/removes container and deletes boq files (active sessions may be interrupted)
  • Container manages its own /proc, /sys, /dev, /tmp

Overlay Directories

Multiple directories are overlayed (copy-on-write) using kernel overlayfs. Changes are stored in ~/.boq/<name>/<overlay>/upper/.

Read-only Mounts

  • /bin, /lib, /lib64, /lib32, /sbin - essential system directories, read-only from host

Known Limitations

Host file changes visible in running boq

Symptom: If you run git pull on the host while boq is running, new files appear inside the boq.

Cause: Overlayfs lowerdir is live, not a snapshot.

Workaround: Do NOT modify files on the host while boq is running.

  • To update code: run git pull inside the boq, OR
  • Stop the boq first, update on host, then re-enter

Troubleshooting

Symlinks to external/mounted drives don't work

Symptom: You have a symlink like ~/.ccache -> /mnt/nvme1n1p1/.ccache, but inside boq the symlink is broken:

$ ls -la ~/.ccache
lrwxrwxrwx 1 user user 22 Feb 21 2024 .ccache -> /mnt/nvme1n1p1/.ccache
$ ls ~/.ccache/
ls: cannot access '/home/user/.ccache/': No such file or directory

Cause: By default, /mnt (or other mount points for external drives) is not mounted inside boq. The symlink exists in the $HOME overlay, but its target doesn't exist.

Solutions: There are three approaches, each with different trade-offs:

Solution 1: Dir

Related Skills

View on GitHub
GitHub Stars14
CategoryDevelopment
Updated7d ago
Forks1

Languages

Python

Security Score

75/100

Audited on Apr 2, 2026

No findings