|
| 1 | +# Sandbox Environment Context (Docker Container Backend) |
| 2 | + |
| 3 | +You are running inside an **sbox sandbox** using the **Docker Container** backend - a standard Docker container environment for Claude Code. |
| 4 | + |
| 5 | +## Environment Overview |
| 6 | + |
| 7 | +The Container backend runs your session inside a regular Docker container. This mode offers compatibility with all Docker environments and uses named volumes for persistence. |
| 8 | + |
| 9 | +### User & Paths |
| 10 | + |
| 11 | +- **User**: `agent` (non-root with sudo access) |
| 12 | +- **Home directory**: `/home/agent` |
| 13 | +- **Claude config**: `/home/agent/.claude` (persisted via named volume) |
| 14 | +- **Workspace**: Mounted at the same path as on the host (check `$PWD` or `$WORKSPACE_DIR`) |
| 15 | + |
| 16 | +### Pre-installed Tools |
| 17 | + |
| 18 | +- **Git**: Version control |
| 19 | +- **Node.js & npm**: JavaScript runtime |
| 20 | +- **rsync**: File synchronization |
| 21 | +- **curl, wget**: HTTP clients |
| 22 | +- **jq**: JSON processor |
| 23 | +- **sudo**: Elevated privileges when needed |
| 24 | + |
| 25 | +Additional tools may be available depending on configured profiles. |
| 26 | + |
| 27 | +## Freedom & Limitations |
| 28 | + |
| 29 | +### What You Can Do |
| 30 | + |
| 31 | +- Full read/write access to the workspace directory |
| 32 | +- Install packages with `sudo apt-get install` |
| 33 | +- Run any command as root with `sudo` |
| 34 | +- Access the internet (subject to firewall rules) |
| 35 | +- Run Docker commands (if `--docker-socket` was enabled) |
| 36 | + |
| 37 | +### Limitations |
| 38 | + |
| 39 | +- **Installed packages are ephemeral**: Lost when container is recreated |
| 40 | +- **Docker access requires explicit flag**: Must use `sbox run --docker-socket` |
| 41 | +- **Network restrictions**: Some external services may be blocked by firewall |
| 42 | +- **Docker socket permissions**: Requires `sudo` for Docker commands |
| 43 | + |
| 44 | +## Persistence |
| 45 | + |
| 46 | +| What | Persists Across Restarts | Persists Across Recreate | |
| 47 | +|------|-------------------------|-------------------------| |
| 48 | +| Workspace files | Yes | Yes | |
| 49 | +| Claude state (`~/.claude`) | Yes (named volume) | Yes (named volume) | |
| 50 | +| Installed apt packages | Yes | No | |
| 51 | +| Files outside workspace | Yes | No | |
| 52 | + |
| 53 | +To persist environment variables: |
| 54 | +```bash |
| 55 | +echo 'export MY_VAR=value' >> /etc/profile.d/sbox-env.sh |
| 56 | +# Use login shell to load: bash -l -c "command" |
| 57 | +``` |
| 58 | + |
| 59 | +## Docker Usage |
| 60 | + |
| 61 | +Docker access requires the `--docker-socket` flag when starting the sandbox. The Docker socket from the host is mounted into the container. |
| 62 | + |
| 63 | +**Important**: Docker commands require `sudo` because the mounted socket has root permissions. |
| 64 | + |
| 65 | +### Checking Docker Access |
| 66 | + |
| 67 | +```bash |
| 68 | +# Verify Docker is available |
| 69 | +sudo docker info |
| 70 | + |
| 71 | +# If you see "permission denied", Docker socket was not mounted |
| 72 | +# Ask the user to restart with: sbox run --docker-socket |
| 73 | +``` |
| 74 | + |
| 75 | +### Running Docker Containers |
| 76 | + |
| 77 | +```bash |
| 78 | +# Always use sudo for Docker commands |
| 79 | +sudo docker run hello-world |
| 80 | + |
| 81 | +# Run a container with port mapping |
| 82 | +sudo docker run -d -p 8080:80 nginx |
| 83 | + |
| 84 | +# Access the container (localhost works because of host network) |
| 85 | +curl http://localhost:8080 |
| 86 | +``` |
| 87 | + |
| 88 | +### Docker Compose |
| 89 | + |
| 90 | +```bash |
| 91 | +# Docker Compose is available as a plugin |
| 92 | +sudo docker compose up -d |
| 93 | +sudo docker compose logs -f |
| 94 | +sudo docker compose down |
| 95 | +``` |
| 96 | + |
| 97 | +### Testcontainers |
| 98 | + |
| 99 | +Testcontainers require the Docker socket to be mounted. Configure testcontainers to use sudo or set up Docker group permissions: |
| 100 | + |
| 101 | +**Option 1: Configure DOCKER_HOST (if socket is accessible)** |
| 102 | +```bash |
| 103 | +export DOCKER_HOST=unix:///var/run/docker.sock |
| 104 | +``` |
| 105 | + |
| 106 | +**Option 2: Use testcontainers with root privileges** |
| 107 | + |
| 108 | +For languages that spawn Docker commands, you may need to run tests as root: |
| 109 | +```bash |
| 110 | +sudo -E go test ./... # -E preserves environment |
| 111 | +sudo -E npm test |
| 112 | +``` |
| 113 | + |
| 114 | +**Java example:** |
| 115 | +```java |
| 116 | +// May need to run with sudo or configure Docker socket permissions |
| 117 | +@Container |
| 118 | +PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15"); |
| 119 | +``` |
| 120 | + |
| 121 | +**Go example:** |
| 122 | +```go |
| 123 | +// Run test with: sudo -E go test ./... |
| 124 | +container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ |
| 125 | + ContainerRequest: testcontainers.ContainerRequest{ |
| 126 | + Image: "postgres:15", |
| 127 | + ExposedPorts: []string{"5432/tcp"}, |
| 128 | + }, |
| 129 | + Started: true, |
| 130 | +}) |
| 131 | +``` |
| 132 | + |
| 133 | +**Node.js example:** |
| 134 | +```javascript |
| 135 | +// Run test with: sudo -E npm test |
| 136 | +const container = await new GenericContainer("postgres:15") |
| 137 | + .withExposedPorts(5432) |
| 138 | + .start(); |
| 139 | +``` |
| 140 | + |
| 141 | +### Volume Mounts - Important! |
| 142 | + |
| 143 | +When mounting volumes from Docker containers, you must use **host paths**, not container paths. The Docker daemon runs on the host, not inside this container. |
| 144 | + |
| 145 | +```bash |
| 146 | +# WRONG - uses container path (won't work) |
| 147 | +sudo docker run -v $(pwd):/app alpine ls /app |
| 148 | + |
| 149 | +# CORRECT - the workspace is mounted at the same path, so this works |
| 150 | +# because $(pwd) returns the same path as on the host |
| 151 | +sudo docker run -v ${WORKSPACE_DIR}:/app alpine ls /app |
| 152 | +``` |
| 153 | + |
| 154 | +If you need to mount paths outside the workspace, you'll need to know the host path. |
| 155 | + |
| 156 | +## Common Patterns |
| 157 | + |
| 158 | +### Installing packages (ephemeral) |
| 159 | +```bash |
| 160 | +sudo apt-get update && sudo apt-get install -y <package> |
| 161 | +``` |
| 162 | + |
| 163 | +### Running as root |
| 164 | +```bash |
| 165 | +sudo <command> |
| 166 | +# Or for a root shell: |
| 167 | +sudo -i |
| 168 | +``` |
| 169 | + |
| 170 | +### Checking if Docker socket is available |
| 171 | +```bash |
| 172 | +if [ -S /var/run/docker.sock ]; then |
| 173 | + echo "Docker socket is mounted" |
| 174 | + sudo docker ps |
| 175 | +else |
| 176 | + echo "Docker socket not available - restart with: sbox run --docker-socket" |
| 177 | +fi |
| 178 | +``` |
| 179 | + |
| 180 | +### Setting up Docker group (alternative to sudo) |
| 181 | +```bash |
| 182 | +# Add agent to docker group (if it exists) |
| 183 | +sudo usermod -aG docker agent |
| 184 | +# Then start a new shell to pick up the group |
| 185 | +newgrp docker |
| 186 | +# Now docker commands work without sudo |
| 187 | +docker ps |
| 188 | +``` |
0 commit comments