Runs AI coding agents (Claude, Gemini, Goose) inside a bubblewrap sandbox. The host filesystem is read-only, only the current project directory and the dotfiles you whitelist are accessible. The sandbox also starts with a clean environment, only variables explicitly allowed are visible to the agent.
- Linux
bwrapinstalled (e.g.sudo dnf install bubblewraporsudo apt install bubblewrap)
curl -Lo ~/.local/bin/bwai https://github.com/umago/bubblewrap-ai/releases/latest/download/bwai
chmod +x ~/.local/bin/bwaimake build
cp bin/bwai ~/.local/bin/Run bwai from inside the project directory you want to give the agent access to:
cd ~/my-project
bwaiBy default, bwai opens a sandboxed bash shell. From there you can launch any agent:
[🫧] > claude
[🫧] > goose
[🫧] > geminiTo skip the shell and launch an agent (or any command) directly, you can either:
- Set the
commandfield in~/.bwai.json:
{ "command": ["claude"] }- Use the
--command(or-c) CLI flag, which overrides the config file:
bwai --command claude
To append arguments to the command configured in ~/.bwai.json, use --:
# With "command": ["goose"] in config
bwai -- session -r # runs "goose session -r" to resume a session
# With "command": ["claude"] in config
bwai -- --model gemini-2.0-flash-exp # runs "claude --model gemini-2.0-flash-exp"Everything after -- is passed as extra arguments to the resolved command.
bwai works out of the box with no config file. To customise behaviour, create ~/.bwai.json as a global config. This can be overridden per-run with the --config flag:
bwai --config /path/to/my-config.jsonTo see the full default configuration as a starting point, run:
bwai --dump-config > ~/.bwai.jsonExample ~/.bwai.json:
{
"bwrap_path": "bwrap",
"bwrap_extra_args": ["--unshare-pid", "--unshare-ipc"],
"command": ["bash"],
"home_allow": [
".claude",
".gemini",
".claude.json",
".config/goose",
".config/gcloud",
".local/state",
".local/share/goose",
".cache",
".cargo"
],
"home_block": [
".gnupg",
".ssh",
".pki",
".aws",
".kube",
".azure",
".bashrc",
".bashrc.d",
".password-store",
".bash_history*",
".config/Bitwarden"
],
"env_allow": [
"TERM",
"COLORTERM",
"LANG",
"LC_ALL",
"LC_MESSAGES",
"LC_CTYPE",
"HOME",
"USER",
"LOGNAME",
"PATH",
"EDITOR",
"ANTHROPIC_API_KEY",
"ANTHROPIC_MODEL",
"ANTHROPIC_DEFAULT_OPUS_MODEL",
"ANTHROPIC_DEFAULT_SONNET_MODEL",
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
"CLAUDE_CODE_USE_VERTEX",
"CLOUD_ML_REGION",
"ANTHROPIC_VERTEX_PROJECT_ID",
"GEMINI_API_KEY",
"GOOGLE_API_KEY",
"GCLOUD_PROJECT",
"GOOGLE_CLOUD_PROJECT",
"GOOSE_PROVIDER",
"GOOSE_MODEL",
"GOOSE_PLANNER_PROVIDER",
"GOOSE_PLANNER_MODEL",
"OPENAI_API_KEY",
"OPENAI_API_BASE",
"OPENROUTER_API_KEY",
]
}| Field | Description | Default |
|---|---|---|
bwrap_path |
Path to the bwrap binary |
"bwrap" |
bwrap_extra_args |
Extra arguments forwarded to bwrap (e.g. --unshare-net) |
["--unshare-pid", "--unshare-ipc"] |
command |
Command (and args) to run inside the sandbox | ["bash"] |
home_allow |
Dotfiles/dirs in $HOME the agent may read and write |
see above |
home_block |
Dotfiles/dirs in $HOME that are never exposed |
see above |
env_allow |
Environment variables from the host passed into the sandbox | see above |
home_allow takes precedence over home_block.