Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code Container

An isolated container environment for running Claude Code on Apple's container runtime, with persistent state and support for multiple concurrent sessions.

Overview

This project builds a Debian-based container image and a launcher script for running Claude Code — including in YOLO mode (--dangerously-skip-permissions) — inside a VM-isolated container instead of directly on your host.

Built for Apple's container runtime; adaptable to Docker/Podman with modifications.

Isolation note: There is no network egress filtering — the container has unrestricted network access. Isolation comes from the VM boundary that Apple's container runtime provides. (An earlier host-side pf firewall experiment was abandoned and is not part of this project.)

Features

  • Concurrent sessions — each launch gets its own numbered container (claude-dev-1, claude-dev-2, …), so multiple Claude Code sessions can run side by side.
  • Persistent state — home directory, shell history, and per-repo node_modules survive container restarts.
  • Pre-configured environment — git, gh, lazygit, micro, vim, zsh + powerlevel10k, fzf, tmux, Node 20, and Claude Code installed and ready.
  • Single-script management — build, launch, and clean up with claude-dev.sh.

Components

Dockerfile

Builds the claude:latest image:

  • debian:trixie-slim base, timezone America/Chicago.
  • Dev tools: git, gh, lazygit, micro, vim, zsh, bash, fzf, tmux, jq, plus curl/wget/gnupg2/unzip/sudo/less/procps/man-db.
  • Node.js 20 unpacked from a tarball the build script downloads and copies in.
  • Non-root claude user with passwordless sudo.

On first run, the entrypoint provisions the rest into the (persistent) home volume so it survives across containers without rebuilding the image:

  • Installs Claude Code (claude.ai/install.sh), Python 3, uv, and powerlevel10k if absent.
  • Seeds ~/.zshrc, ~/.tmux.conf, and ~/.claude/settings.json if not already present.

claude-dev.sh

The launcher. Running it with no arguments:

  1. Builds claude:latest if the image doesn't exist (downloading the Node tarball first).
  2. Picks the next free container slot (claude-dev-N).
  3. Starts a --rm container with the current directory mounted at /workspace.

Flags:

Flag Effect
--build Force-rebuild the image even if claude:latest exists.
--prune-volumes Remove this repo's node_modules volumes that aren't held by a running container, then exit.
-h, --help Show usage.

Mounts:

Host Container Purpose
shared-home/ /home/claude Persistent home (configs, Claude/gh/wrangler creds).
shared-history/ /commandhistory Persistent shell history.
$(pwd) /workspace The repo you launch from.
claude-<repo>-node_modules[-N] (named volume) /workspace/node_modules Per-repo node_modules, isolated from the host checkout.

Containers get 8 GB memory, 4 CPUs, and join the claude network.

Why node_modules is a separate volume

node_modules lives on its own ext4 block volume rather than the /workspace bind mount — this keeps Linux-native binaries out of your macOS checkout and speeds up installs. Because a block volume can't be attached to two live VMs at once, each container slot gets its own volume: slot 1 reuses the unnumbered claude-<repo>-node_modules, and concurrent slots get -2, -3, … (each needs a one-time npm install). --prune-volumes reclaims the numbered ones once their containers exit.

Quick Start

1. Build the image

container builder start -m 8G   # 4G also works; stop the builder afterward
./claude-dev.sh --build         # downloads Node, builds claude:latest

(Or just run ./claude-dev.sh — it builds automatically if the image is missing.)

2. Launch

./claude-dev.sh

Run it again from another terminal to start a second concurrent session.

3. Use Claude Code

Inside the container:

IS_SANDBOX=1 claude --dangerously-skip-permissions

4. Clean up stale node_modules volumes

./claude-dev.sh --prune-volumes   # run from the repo whose volumes you want to clean

State & Security Notes

  • shared-home/ and shared-history/ are host directories that persist live credentials (Claude, gh, wrangler, supabase, and anything in your shell history). They are gitignored — do not commit or share them, and don't zip the project directory for distribution. Share via git only.
  • sudo is passwordless inside the container for convenience; the VM boundary is the real isolation.
  • Network egress is unrestricted (see the isolation note above).

Customization

  • Container resources: edit the --memory / --cpus flags in claude-dev.sh.
  • Image tools: add packages to the apt-get install list in the Dockerfile.
  • First-run setup: edit the entrypoint heredoc in the Dockerfile.

Requirements

  • Apple container runtime (or Docker/Podman with modifications)
  • Internet access for the image build and first-run tool installs

Differences from Anthropic's Reference Dockerfile

Adapted from Anthropic's reference .devcontainer:

  • debian:trixie-slim base instead of a Node.js image (Node added from a tarball).
  • Claude Code installed at first run via the standalone installer, not baked in via npm.
  • Adds lazygit, micro, powerlevel10k, tmux, uv, and other personal preferences.
  • Numbered containers + per-repo node_modules volumes for concurrent sessions.
  • No in-container firewall; relies on the runtime's VM isolation.

License

Provided as-is for personal use. Claude Code and related trademarks are property of Anthropic.

Acknowledgments

Based on Anthropic's reference .devcontainer, adapted for the Apple container runtime.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages