# Overview

> What claude-sandbox is, its core design goals (isolation without Container Use, host worktree as source of truth), and how it integrates with Superset workspaces and Claude Code.

- Repository: hans/claude-container
- GitHub: https://github.com/hans/claude-container
- Human wiki: https://grok-wiki.com/public/wiki/hans-claude-container-cf30219c8958
- Complete Markdown: https://grok-wiki.com/public/wiki/hans-claude-container-cf30219c8958/llms-full.txt

## Source Files

- `README.md`
- `SETUP.md`

---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [README.md](README.md)
- [SETUP.md](SETUP.md)
- [.superset/launch.sh](.superset/launch.sh)
- [.superset/setup.sh](.superset/setup.sh)
- [Dockerfile](Dockerfile)
- [entrypoint.sh](entrypoint.sh)
- [.dockerignore](.dockerignore)

</details>

# Overview

claude-sandbox runs Claude Code sessions inside per-workspace Docker containers launched by Superset. Each Superset workspace (a git worktree) receives an isolated execution sandbox while the host worktree remains the single source of truth: code, git history, and diffs live on the host and stay visible to Superset's diff viewer and other tools.

The container is deliberately *not* a Container Use (`cu`) setup. It provides a clean execution environment for the agent's bash tool and Claude Code process; all persistent state and git operations occur on the host bind mount at `/workdir`.

This design lets teams keep their normal Superset + git workflows while giving Claude Code a hermetic sandbox that cannot accidentally pollute the host or other workspaces.

## Core Design Goals

- **Isolation without Container Use.** The container supplies a separate filesystem view, process space, and network namespace. Git history, commits, and file changes never leave the host worktree. Superset continues to see the worktree exactly as before.
- **Host worktree as source of truth.** The worktree directory is bind-mounted at `/workdir` inside the container. Writes from Claude Code or its bash tool appear immediately on the host. Git worktree pointers and external symlinks are explicitly handled so the agent's view matches the host's view.
- **Per-workspace sandboxes.** Superset workspaces run in parallel; each receives its own named container. No shared state exists between sandboxes except what the user explicitly mounts.
- **Generic image, project-local extension.** The published image contains only a baseline Ubuntu toolchain plus Claude Code. Per-project Python packages, binaries, or tools are added either by ad-hoc `docker exec` (ephemeral) or by deriving a project `Dockerfile` from `claude-sandbox:latest` (persistent).

Sources: [README.md:3-11](README.md), [.dockerignore:1-4](.dockerignore)

## Integration with Superset Workspaces and Claude Code

Superset workspaces are ordinary git worktrees. To run Claude Code inside the sandbox, the user (or organization) configures a Superset agent whose **Command (No Prompt)** and **Command (With Prompt)** both point at `.superset/launch.sh` relative to the worktree root.

When Superset launches the agent it `cd`s into the worktree and executes the launcher, appending any prompt text as arguments. The launcher script therefore becomes the single integration point between Superset and the Docker runtime.

Deployment is intentionally per-repository:

- Copy the `.superset/` directory (containing `launch.sh` and `setup.sh`) into each repo that should use sandboxed agents.
- Commit it so every worktree carries its own launcher.
- In Superset's agent settings, set the command fields to `.superset/launch.sh`.

`setup.sh` runs on the host when Superset creates a new worktree; it copies a parent `.env` (if present) and prints reminders that project dependencies must be installed *inside* the container on first use.

Sources: [SETUP.md:1-5](SETUP.md), [SETUP.md:40-55](SETUP.md), [.superset/setup.sh:1-27](.superset/setup.sh)

## Launch Flow and Container Lifecycle

`.superset/launch.sh` performs these steps on every invocation:

1. Preflight checks: Docker present and running, target image exists, host `~/.claude` and `~/.claude.json` present.
2. On macOS, extracts the `Claude Code-credentials` keychain item into `~/.claude/.credentials.json` so the Linux container can authenticate.
3. Computes a stable container name from the worktree basename plus a short hash of its absolute path.
4. If a container with that name is already running, executes `docker exec` into it (invoking the container entrypoint so `.env` is re-sourced) — this provides instant reattach when the user closes and reopens a Superset terminal pane.
5. Otherwise builds a `docker run --rm -it` command with the mounts and environment described below and starts a fresh container.

The container is always started with `--rm`. When the `claude` process exits (user `/quit`, crash, or Superset pane closed while Claude is idle), the container is destroyed. The next launch creates a clean one. All worktree changes survive because they live on the host bind mount.

Sources: [.superset/launch.sh:1-15](.superset/launch.sh), [.superset/launch.sh:110-115](.superset/launch.sh)

## Filesystem, Git, and Symlink Fidelity

The launcher constructs the following bind mounts for every container:

- `$PWD:/workdir` — the worktree itself (read-write).
- `$HOME/.claude:/home/claude/.claude` and `$HOME/.claude.json:...` — Claude Code configuration and session state (read-write).
- Host user's `~/.gitconfig` (read-only).
- When `$PWD/.git` is a file (the git-worktree case), the parent `.git` directory is mounted at the same absolute host path so the `gitdir:` pointer resolves inside the container. This also supports submodules.
- Optional `~/.ssh` (read-only, opt-in via `CLAUDE_SANDBOX_MOUNT_SSH=1`).
- Every symlink inside the worktree whose target lies outside `$PWD` is resolved; its target directory is bind-mounted at the identical absolute host path. Targets are mounted read-only by default; `CLAUDE_SANDBOX_SYMLINK_MOUNTS_RW=1` or `CLAUDE_SANDBOX_SYMLINK_RW_PATHS` can selectively enable writes.

The container runs as `-u $(id -u):$(id -g)` so file ownership and permissions on the host bind mounts match the developer's host user. Git is configured at the system level inside the image to treat `/workdir` as a safe directory regardless of UID mismatch.

These mechanisms together guarantee that `git status`, `git commit`, edits to symlinked datasets, and Superset's own diff viewer all see exactly the same content whether the change originated from the host editor or from Claude Code's bash tool inside the container.

Sources: [.superset/launch.sh:118-129](.superset/launch.sh), [.superset/launch.sh:132-147](.superset/launch.sh), [.superset/launch.sh:154-166](.superset/launch.sh)

## Container Image and Environment

The image ([Dockerfile](Dockerfile)) starts from `ubuntu:24.04` and installs:

- Core tools: git, openssh-client, build-essential, ripgrep, fd, jq, vim, etc.
- `uv` (Python package manager) pinned to `/usr/local/bin`.
- Node 22 + `@anthropic-ai/claude-code` installed globally.
- A `claude` user (UID 1000) whose home is mode 0777 so the runtime UID/GID can write into it.

`entrypoint.sh` is the image ENTRYPOINT. On every start (both `docker run` and `docker exec` paths) it sources `/workdir/.env` (if present) with `set -a`, then `exec`s the command (normally `claude --dangerously-skip-permissions ...`).

Host-side `CLAUDE_SANDBOX_*` variables control the launcher itself (image name, network mode, symlink behavior, etc.). Any `ANTHROPIC_*` variable present on the host is forwarded into the container. Project secrets live in the worktree's `.env` file and become visible to the agent via the entrypoint.

Sources: [Dockerfile:1-5](Dockerfile), [entrypoint.sh:1-14](entrypoint.sh), [README.md:112-130](README.md)

## Network and Security Trade-offs

- Default network mode `bridge` gives the container outbound Internet but prevents it from reaching `localhost` services on the host.
- `host` mode shares the host network stack (useful for local APIs) at the cost of reduced isolation.
- `none` disables networking entirely.

Because the container runs as the developer's own UID and receives full read/write access to the worktree (plus any symlinked targets), it has the same filesystem powers the developer has on the host. The sandbox protects the *host system* from the agent, not the worktree contents from the agent. Users should only symlink directories they are comfortable exposing.

Sources: [README.md:140-160](README.md) (network section), [.superset/launch.sh:166-230](.superset/launch.sh) (symlink mount logic)

## What the Project Deliberately Does Not Provide

- Container Use / nested branch / auto-commit semantics — git lives on the host.
- Built-in multi-agent orchestration — Superset launches one container per workspace; parallelism is managed by the workspace system.
- GPU passthrough or Windows support.
- A long-lived daemon — containers are `--rm` and ephemeral.

These boundaries keep the tool small, auditable, and focused on the single job of giving Claude Code a clean, host-faithful execution environment inside Superset.

Sources: [README.md:200-230](README.md)

## Summary

claude-sandbox is a thin, Superset-native launcher plus a minimal Docker image that gives every workspace an isolated Claude Code runtime while preserving the host git worktree as the authoritative source of code, history, and collaboration state. All complex fidelity logic (gitdir pointers, escaping symlinks, credential staging, UID matching, reattach) lives in `.superset/launch.sh`; the container itself stays generic and rebuilds only when the base toolchain changes.

Sources: [README.md:3-11](README.md)
