Files
sandcage/docs/docker-image.md
2026-05-24 19:52:42 +02:00

111 lines
3.8 KiB
Markdown

# Docker Image
## Base image contents
The sandcage image is built on `debian:bookworm-slim` and includes:
- **Shell:** zsh (default), bash
- **VCS:** git, openssh-client
- **Search:** ripgrep, fd-find
- **Utilities:** jq, curl, sudo, ca-certificates, npm
- **Task runner:** just (installed from upstream binary)
- **Python tooling:** uv (installed per-user at `/home/agent/.local/bin`)
The image creates an `agent` user (UID 1000) with a home at `/home/agent`, zsh as the default shell, and passwordless sudo.
Pre-created directories: `/workspace`, `/home/agent/.claude`, `/home/agent/.codex`, `/home/agent/.gemini`.
## How agents are installed
AI coding agents (Claude Code, Codex, Gemini CLI) are **not** baked into the image. They are installed on first run via their respective entrypoint scripts. The agent home directories (`~/.claude`, `~/.codex`, `~/.gemini`) are persisted across runs through volume mounts to `~/.sandcage/` on the host, so installation only happens once.
Each service has its own entrypoint script installed at `/usr/local/bin/sandcage-<service>-entrypoint`.
## Building images
Build the sandcage image with:
```
sandcage build
```
### Force rebuild
To bypass the cache and rebuild unconditionally:
```
sandcage build --force
```
When `--force` is used, Docker's `--no-cache` flag is also passed to ensure layers are rebuilt from scratch.
### Service filter
Build only images required for specific services:
```
sandcage build claude shell
```
Unknown service names produce an error listing available services.
## Cache awareness
Sandcage uses hash-based rebuild detection to avoid unnecessary image builds.
On each build, the SHA-256 hash of the Dockerfile content (bundled or custom) is computed and compared against the stored hash in `~/.sandcage/.build-hashes`. If they match, the build is skipped with an "up to date" message.
After a successful build, the new hash is persisted. The hash file uses a simple `image:hash` line format.
This means:
- Editing the Dockerfile (or switching to/from a custom one) triggers a rebuild automatically.
- The `--force` flag bypasses hash comparison entirely.
## Custom Dockerfiles
You can override the bundled Dockerfile by specifying a path in configuration.
### Global config (`~/.sandcage/config.toml`)
```toml
[dockerfiles]
sandcage = "/path/to/my/Dockerfile"
```
### Project config (`.sandcage.yml`)
```yaml
dockerfiles:
sandcage: ./docker/Dockerfile.custom
```
The path can point to either:
- A **file** -- used as the Dockerfile with a temporary build context.
- A **directory** -- used as the full build context (must contain a `Dockerfile`).
### trusted_projects requirement
Project-level Dockerfile overrides are only applied if the project directory is listed in the global `trusted_projects` setting. This prevents untrusted repositories from injecting arbitrary build instructions.
```toml
# ~/.sandcage/config.toml
trusted_projects = [
"/home/user/projects/my-trusted-repo",
"/home/user/work",
]
```
A project is considered trusted if its canonical path starts with any entry in `trusted_projects` (prefix matching). If a project specifies `dockerfiles` but is not trusted, the override is silently ignored with a warning.
Global config overrides (`~/.sandcage/config.toml`) are always trusted.
## Cross-platform notes
### UID/GID handling
On **Linux**, sandcage queries the host user's UID and GID via `id -u` / `id -g` and passes them into the container as `SANDCAGE_UID` and `SANDCAGE_GID`. This ensures files created inside the container have correct ownership on bind-mounted host directories.
On **Windows**, UID/GID passthrough is not meaningful. Sandcage hardcodes both to `1000`, matching the `agent` user built into the image. File ownership on Windows bind mounts is handled by Docker Desktop's filesystem sharing layer.