Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# AGENTS.md

## What This Project Is

`bwai` is a CLI tool that runs AI coding agents (Claude, Gemini, Goose) inside a [bubblewrap](https://github.com/containers/bubblewrap) sandbox. The sandbox enforces a read-only host filesystem, whitelisted dotfiles and environment variables, and restricts writes to the current working directory only — preventing agents from accessing sensitive data like SSH keys, AWS credentials, or GPG keys.

## Project Layout

```
cmd/bwai/
main.go # Entry point, flag parsing, bwrap command construction
config.go # Config struct, defaults, JSON loading (~/.bwai.json)
mounts.go # Filesystem mount logic (home, DNS, GPU, shm)
bwrap.go # Low-level bwrap argument helpers (roBind, rwBind, devBind, tmpfs)
update.go # Self-update from GitHub releases with SHA-256 verification
version.go # Version constant (set at build time via ldflags)
*_test.go # Unit tests for each module
scripts/
check.sh # Runs fmt, lint, and tests (used in CI and pre-commit)
Makefile # build, install, test, fmt, lint, clean targets
```

## Language and Dependencies

- Pure Go 1.21, zero external dependencies (stdlib only)
- Requires `bwrap` installed on the host system (Linux only)

## Build and Test

```sh
make build # Compiles to bin/bwai
make test # Runs all unit tests
make lint # Runs golangci-lint
make fmt # Formats code
```

CI runs `scripts/check.sh` which chains fmt-check, lint, and test.

## Configuration

The config file lives at `~/.bwai.json`. Key fields:

| Field | Purpose |
|---|---|
| `bwrap_path` | Path to the `bwrap` binary |
| `bwrap_extra_args` | Extra flags passed directly to bwrap |
| `command` | Default command to run inside the sandbox |
| `home_allow` | Dotfiles/paths from `$HOME` to expose (read-only) |
| `home_block` | Dotfiles/paths to explicitly block |
| `env_allow` | Environment variables to pass through |

`home_allow` takes precedence over `home_block`. Patterns support glob suffixes (e.g., `.bash_history*`) and nested paths (e.g., `.config/goose`).

## Key Design Decisions

- **Read-only by default**: The entire host OS tree is bind-mounted read-only. Only the current working directory is writable.
- **No parent-process exit issue**: Non-bash commands are wrapped in `bash -i -c` to avoid agent processes becoming orphaned when the shell exits.
- **GPU support**: `gpuMounts()` in `mounts.go` auto-detects and mounts NVIDIA and DRI devices.
- **Safe self-update**: Downloads binary, verifies SHA-256 digest, replaces atomically with rollback on failure.
- **Zero dependencies**: Keeps the supply chain minimal; everything uses Go stdlib.

## CLI Flags

```
bwai # Open sandboxed bash shell
bwai -c claude # Launch claude directly inside sandbox
bwai --ro-dir /some/path # Expose extra read-only directory
bwai -- --some-agent-flag # Pass args to the configured command
bwai update # Self-update to latest GitHub release
bwai --dump-config # Print default config as JSON
```

## Adding New Features

- **New mount type**: Add a helper function in `mounts.go` following the existing pattern (`[]string` return, appended in `main.go`).
- **New CLI flag**: Add to `main.go` using the `flag` package; wire into the bwrap args slice.
- **New config field**: Add to the `Config` struct in `config.go` and update `defaultConfig()`.
- **New agent support**: Add its dotfiles to `home_allow` defaults and its API key to `env_allow` defaults in `config.go`.

## Testing

Tests live alongside source files (`*_test.go`). They use only `testing` from stdlib. Run with `make test`. There is no integration test harness — unit tests cover mount logic, bwrap arg construction, and the update mechanism.
Loading