Files
recipe-maintainer/sandbox
autonomic-bot f283a371bb recipe-maintainer: public snapshot (secrets + deployment plans removed, single commit)
Sanitized single-commit public mirror of recipe-maintainer.
- Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders.
- Removed plans/ and planned-updates/ (deployment-planning docs) so no client/
  deployment domains appear in the public repo.
- All other secret stores were already gitignored.
- docs.coopcloud.tech retained as a submodule (public upstream).
2026-06-16 20:18:24 +00:00
..

sandbox

Run Claude Code inside a Docker container so it only has access to the directory you explicitly mount in — not your whole filesystem.

Why?

Claude Code runs shell commands, edits files, and installs packages. Running it in a container means:

  • It can only see the project directory you mount in (not ~/.ssh, ~/.gnupg, etc.)
  • Sensitive files (.env, secret.json, etc.) are automatically hidden via /dev/null mounts
  • Sensitive directories (~/.ssh, ~/.gnupg) under the workspace are hidden via tmpfs overlays
  • Your host system stays untouched — packages Claude installs stay in the container

Quick start

# 1. Build the image
./build.sh

# 2. (Optional) Set up environment variables
cp .env.sample .env
# Edit .env if you want to pre-configure API keys

# 3. Run Claude Code on a project directory
python3 claude.py

This drops you into Claude Code with your current working directory mounted at /workspace inside the container.

How it works

claude.py — the launcher

The Python wrapper does three things:

  1. Scans your project for sensitive files (.env, .envrc, secret.json, secrets.json) and generates a Docker Compose override that mounts /dev/null over each one
  2. Hides sensitive directories (~/.ssh, ~/.gnupg) that fall under the mounted workspace using tmpfs overlays
  3. Runs docker compose run with your current directory mounted at /workspace

entrypoint.sh — user mapping

The entrypoint creates a non-root claude user inside the container whose UID/GID matches your host user. This means files Claude creates or edits have the right ownership on your host filesystem.

docker-compose.yml — persistence

A named Docker volume (claude_userhome) persists Claude's settings, auth tokens, and conversation history across runs.

Usage

Set up a shell alias

Add this to your ~/.bashrc or ~/.zshrc for convenience:

alias claude='python3 /path/to/sandbox/claude.py'

Then from any project directory:

cd ~/projects/my-app
claude          # launches Claude Code with my-app mounted
claude .        # same thing
claude --help   # pass any flags through to Claude Code

Authentication

You have two options:

  1. Interactive login — run claude login inside the container. Credentials persist in the claude_userhome volume.
  2. API key — copy .env.sample to .env and set ANTHROPIC_API_KEY.

Passing extra arguments

Any arguments to claude.py are forwarded to the Claude Code CLI:

python3 claude.py --help
python3 claude.py --model sonnet
python3 claude.py -p "explain this codebase"

What's in the image

The Dockerfile installs:

  • Core: git, Node.js, Python 3, ripgrep, fd, gh (GitHub CLI), vim
  • Build tools: cmake, build-essential, pkg-config
  • Rust: rustup + cargo (with musl target)
  • Playwright: Chromium + browser automation deps
  • Hugo: static site generator
  • Terraform: infrastructure as code
  • abra: Co-op Cloud CLI
  • Caddy: web server / reverse proxy
  • Tailscale: mesh VPN

The tools beyond core are included because this project (a Co-op Cloud recipe maintainer) uses them. If you're adapting this for your own use, remove or comment out what you don't need in the Dockerfile to speed up the build, and add your own tools:

# Example: add Go
RUN curl -fsSL https://go.dev/dl/go1.22.0.linux-amd64.tar.gz | tar -xz -C /usr/local

Then rebuild with ./build.sh.

Sensitive file protection

The launcher automatically hides files matching these names anywhere in your project tree:

  • .env
  • .envrc
  • secret.json
  • secrets.json

And hides these directories if they exist under the mounted workspace:

  • ~/.ssh
  • ~/.gnupg

To add more, edit the SENSITIVE_NAMES set or SENSITIVE_DIRS list in claude.py.

Running the tests

The test suite verifies that sensitive files are properly hidden inside the container:

python3 tests/test_env_hiding.py

Requires the sandbox image to be built first.

Troubleshooting

"Permission denied" on mounted files — make sure HOST_UID / HOST_GID are passed correctly. The claude.py launcher handles this automatically; if using docker compose directly, set them:

HOST_UID=$(id -u) HOST_GID=$(id -g) docker compose run --rm claude

Claude Code not found — rebuild the image (./build.sh). The install script fetches the latest version at build time.

Persisted state issues — to reset Claude's saved state, remove the Docker volume:

docker volume rm sandbox_claude_userhome