# Setup and Superset Integration

> Prerequisites, building the image, copying the .superset/ launcher into a repo, configuring a Superset agent, and the first workspace launch flow.

- 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

- `SETUP.md`
- `.superset/setup.sh`
- `README.md`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:
- [SETUP.md](SETUP.md)
- [README.md](README.md)
- [.superset/setup.sh](.superset/setup.sh)
- [.superset/launch.sh](.superset/launch.sh)
- [Dockerfile](Dockerfile)
- [entrypoint.sh](entrypoint.sh)
- [.dockerignore](.dockerignore)
</details>

# Setup and Superset Integration

This page explains how to prepare the claude-sandbox Docker image and wire it into Superset so Claude Code runs inside an isolated container while the workspace remains a normal host-side git worktree. The integration lets each Superset workspace launch its own sandbox, with the worktree bind-mounted at `/workdir` so all edits, git history, and diffs stay visible to Superset exactly as before.

The flow centers on two scripts in the `.superset/` directory: `launch.sh` (invoked by Superset for every agent start) and `setup.sh` (run once per worktree by Superset). The container itself is intentionally generic; project-specific dependencies are added either ad-hoc via `docker exec` or persistently via a thin derived Dockerfile.

## Prerequisites

Before the first launch, the host must satisfy four checks. These are performed both manually and automatically inside `launch.sh`.

```bash
docker version            # Docker Desktop or engine must be running
claude --version          # Claude Code must be installed on the host
ls ~/.claude.json         # host login state must exist (run `claude /login` if not)
security find-generic-password -s "Claude Code-credentials" -w >/dev/null \
    && echo OK            # macOS only: keychain entry must exist
```

If any check fails, correct it before proceeding. `launch.sh` repeats the Docker, image, and `~/.claude*` checks on every invocation and exits with a clear message when something is missing.

**Sources:** [SETUP.md:7-17](), [README.md:16-20](), [.superset/launch.sh:34-59]()

## Building the Image

From the repository root, build the image once:

```bash
docker build -t claude-sandbox:latest .
```

The build pulls Ubuntu 24.04, installs git, build tools, ripgrep, fd, Python + uv, Node 22, and the `@anthropic-ai/claude-code` npm package, then creates a `claude` user and installs `entrypoint.sh`. Subsequent builds are fast due to layer caching. Rebuild only when `Dockerfile` changes.

Verify the image:

```bash
docker run --rm claude-sandbox:latest claude --version
```

The `.dockerignore` keeps the build context small and prevents accidental inclusion of secrets or the `.superset/` launcher itself.

**Sources:** [Dockerfile:1-65](), [SETUP.md:19-36](), [.dockerignore:1-21]()

## Copying the Launcher into a Repository

`launch.sh` is deliberately a relative-path script so each repository carries its own copy and can be customized per project. The recommended approach is to copy the entire `.superset/` directory:

```bash
cp -r .superset /path/to/your/repo/
cd /path/to/your/repo/
git add .superset/
git commit -m "Add Superset sandbox launcher"
```

`setup.sh` runs on the host when Superset first creates a worktree. It is idempotent and currently does two things: copies `../.env` into the worktree if one does not yet exist, and prints a reminder that Python or Node dependencies must be installed *inside* the running container (the image is intentionally generic).

An alternative global install (drop `launch.sh` on `$PATH`) is supported for users who prefer not to add files to every repository.

**Sources:** [SETUP.md:38-52](), [.superset/setup.sh:1-27]()

## Configuring a Superset Agent

In Superset, go to **Settings → Agents**. Either duplicate the built-in `claude` preset or create a new agent. The minimal configuration is:

| Field                  | Value                                      |
|------------------------|--------------------------------------------|
| Label                  | `Claude (sandbox)`                         |
| Enabled                | ON                                         |
| Command (No Prompt)    | `.superset/launch.sh`                      |
| Command (With Prompt)  | `.superset/launch.sh`                      |
| Prompt Command Suffix  | *(empty)*                                  |
| Environment            | `CLAUDE_SANDBOX_NETWORK=bridge` (optional) |

If you installed the launcher globally, replace the command with the absolute path. The **Environment** field is the place to set `CLAUDE_SANDBOX_*` variables (one per line); Superset injects them into the shell that runs `launch.sh`.

**Sources:** [SETUP.md:54-70](), [README.md:34-55]()

## First Workspace Launch Flow

When you select the sandbox agent and send a prompt, Superset invokes `.superset/launch.sh` with the worktree as `$PWD`. The script performs the following steps:

1. **Preflight** – verifies Docker is on PATH, the daemon is reachable, the chosen image exists, and the host `~/.claude` directory and `.claude.json` are present. On macOS it also extracts the keychain credential blob into `~/.claude/.credentials.json` so the Linux container can authenticate.
2. **Container naming** – computes a stable name `claude-sandbox-<basename>-<path-hash>` so every worktree gets its own container.
3. **Reattach check** – if a container with that name is already running, the script does `docker exec` (explicitly calling `entrypoint.sh` so `.env` is re-sourced) and exits. This is how closing and reopening a Superset terminal pane reattaches to the same sandbox.
4. **Docker run** – otherwise it assembles a long `docker run` command with:
   - `--rm -it --name ...`
   - bind mount of the worktree at `/workdir`
   - read-write mount of `~/.claude` and `~/.claude.json`
   - read-only mount of `~/.gitconfig`
   - UID/GID matching (`-u $(id -u):$(id -g)`) so bind-mount writes succeed
   - special handling for git worktree `.git` files (mounts the parent `.git` directory at its absolute host path)
   - automatic mounting of external symlink targets (read-only by default, configurable via `CLAUDE_SANDBOX_SYMLINK_*` variables)
   - forwarding of all `ANTHROPIC_*` and selected Superset workspace variables
5. **Entrypoint** – inside the container, `entrypoint.sh` sources `/workdir/.env` (if present) and then `exec`s the `claude` command (plus any initial prompt).

The first launch therefore performs a full `docker run`; subsequent launches in the same workspace usually take the fast `docker exec` path.

```mermaid
flowchart TD
  Start[Superset invokes launch.sh] --> Preflight{Preflight OK?}
  Preflight -->|No| Exit[Exit with message]
  Preflight -->|Yes| Exists{Container running?}
  Exists -->|Yes| Exec[docker exec entrypoint.sh claude ...]
  Exists -->|No| Run[docker run ... entrypoint.sh claude ...]
  Run --> Claude[Claude Code starts]
  Exec --> Claude
```

**Sources:** [.superset/launch.sh:34-130](), [entrypoint.sh:1-14](), [Dockerfile:55-64]()

## Reattachment and Container Lifecycle

Because the container is started with `--rm`, it disappears as soon as the `claude` process exits (user `/quit`, crash, or explicit exit). Worktree state is never inside the container, so nothing is lost. While the container lives, any later launch of the same agent in the same workspace reattaches via `docker exec`, preserving the Claude session, REPL history, and any ad-hoc packages installed during that lifetime.

**Sources:** [SETUP.md:72-80](), [.superset/launch.sh:110-115]()

## Environment Variables and Per-Project Customization

Host-side variables (read by `launch.sh`) are set in the agent's **Environment** field or exported before starting Superset. Container-side secrets belong in a `.env` file at the worktree root; `entrypoint.sh` sources it on every launch and reattach. `setup.sh` will propagate `../.env` into a new worktree automatically.

For persistent extra tools, create a thin derived image:

```dockerfile
FROM claude-sandbox:latest
RUN pip install --break-system-packages mne nibabel
```

Build it, then point `launch.sh` at it with `CLAUDE_SANDBOX_IMAGE=claude-sandbox-myproj` in the agent's environment.

**Sources:** [README.md:95-140](), [.superset/setup.sh:8-20]()

## Troubleshooting First-Launch Issues

| Symptom | Cause | Fix |
|---------|-------|-----|
| `docker: command not found` | Docker not on PATH | Start Docker Desktop or install Docker Engine. |
| `image 'claude-sandbox:latest' not found` | Image never built | `docker build -t claude-sandbox:latest .` |
| `Claude configuration file not found at: /home/claude/.claude.json` | Host `~/.claude.json` missing or stale container | `claude /login` on host, then `docker rm -f` any old container. |
| `couldn't read 'Claude Code-credentials' from keychain` | macOS keychain entry absent | Run `claude /login` on the host. |
| `fatal: not a git repository` inside container | Worktree `.git` pointer cannot resolve | Ensure current `launch.sh` is deployed (it auto-mounts the parent `.git`). |
| `permission denied` writing files | UID mismatch on bind mount | Do not override the `-u $(id -u):$(id -g)` logic in `launch.sh`. |

**Sources:** [SETUP.md:82-100]()

The design keeps the sandbox generic, the worktree authoritative, and the integration portable across projects simply by copying `.superset/`. All behavior is driven by the verified scripts and Dockerfile described above.

**Sources:** [README.md:1-15]()
