Created
January 19, 2026 17:29
-
-
Save jamesob/930c9620b60ae414b910aa0e8565c933 to your computer and use it in GitHub Desktop.
claude sandbox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| IMAGE_NAME="claude-code-runner" | |
| CONTAINER_NAME="claude-code-$(basename $(pwd))" | |
| RED='\033[0;31m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[1;33m' | |
| NC='\033[0m' # No Color | |
| # Parse arguments | |
| REBUILD=false | |
| for arg in "$@"; do | |
| case $arg in | |
| --rebuild) | |
| REBUILD=true | |
| shift | |
| ;; | |
| esac | |
| done | |
| echo -e "${GREEN}Starting Claude Code in isolated container...${NC}" | |
| echo -e "${YELLOW}Only files in $(pwd) are accessible${NC}" | |
| echo "" | |
| # Build image if it doesn't exist or --rebuild flag is passed | |
| if ! docker image inspect $IMAGE_NAME > /dev/null 2>&1 || [ "$REBUILD" = true ]; then | |
| if [ "$REBUILD" = true ]; then | |
| echo -e "${YELLOW}Rebuilding Docker image (--rebuild flag set)...${NC}" | |
| docker rmi -f $IMAGE_NAME 2>/dev/null | |
| else | |
| echo -e "${YELLOW}Building Docker image (first run only)...${NC}" | |
| fi | |
| TMPDIR=$HOME/tmp | |
| mkdir -p $TMPDIR | |
| # Create temporary Dockerfile | |
| cat > $TMPDIR/Dockerfile.claude << 'EOF' | |
| FROM debian:bookworm-slim | |
| ARG TZ | |
| ENV TZ="$TZ" | |
| ARG CLAUDE_CODE_VERSION=latest | |
| ARG GO_VERSION=1.25.6 | |
| ARG GIT_DELTA_VERSION=0.18.2 | |
| # Install base packages | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| # Essential tools | |
| curl \ | |
| wget \ | |
| ca-certificates \ | |
| less \ | |
| procps \ | |
| sudo \ | |
| unzip \ | |
| xz-utils \ | |
| # Version control & dev tools | |
| git \ | |
| gh \ | |
| gnupg2 \ | |
| # Shell & editor | |
| zsh \ | |
| fzf \ | |
| nano \ | |
| vim \ | |
| man-db \ | |
| # Network tools | |
| iptables \ | |
| ipset \ | |
| iproute2 \ | |
| dnsutils \ | |
| aggregate \ | |
| openssh-client \ | |
| # Data processing | |
| jq \ | |
| yq \ | |
| # Build essentials (needed for native extensions) | |
| build-essential \ | |
| # Python | |
| python3 \ | |
| python3-pip \ | |
| python3-venv \ | |
| python3-dev \ | |
| # Additional useful tools for development | |
| ripgrep \ | |
| fd-find \ | |
| tree \ | |
| htop \ | |
| tmux \ | |
| sqlite3 \ | |
| rsync \ | |
| zip \ | |
| && apt-get clean && rm -rf /var/lib/apt/lists/* | |
| # Create symlinks for common command names | |
| RUN ln -sf /usr/bin/python3 /usr/bin/python && \ | |
| ln -sf /usr/bin/fdfind /usr/bin/fd | |
| # Install Node.js (LTS) | |
| RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ | |
| apt-get install -y nodejs && \ | |
| apt-get clean && rm -rf /var/lib/apt/lists/* | |
| # Install Go | |
| RUN ARCH=$(dpkg --print-architecture) && \ | |
| if [ "$ARCH" = "amd64" ]; then GOARCH="amd64"; \ | |
| elif [ "$ARCH" = "arm64" ]; then GOARCH="arm64"; \ | |
| else echo "Unsupported architecture: $ARCH" && exit 1; fi && \ | |
| wget -q "https://go.dev/dl/go${GO_VERSION}.linux-${GOARCH}.tar.gz" && \ | |
| tar -C /usr/local -xzf "go${GO_VERSION}.linux-${GOARCH}.tar.gz" && \ | |
| rm "go${GO_VERSION}.linux-${GOARCH}.tar.gz" | |
| ENV PATH=$PATH:/usr/local/go/bin | |
| # Install Bun | |
| RUN curl -fsSL https://bun.sh/install | bash && \ | |
| mv /root/.bun/bin/bun /usr/local/bin/ && \ | |
| rm -rf /root/.bun | |
| # Install git-delta | |
| RUN ARCH=$(dpkg --print-architecture) && \ | |
| wget -q "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ | |
| dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ | |
| rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" | |
| # Create node user (mimicking node image) | |
| RUN groupadd --gid 1000 node && \ | |
| useradd --uid 1000 --gid node --shell /bin/zsh --create-home node | |
| # Setup npm global directory | |
| RUN mkdir -p /usr/local/share/npm-global && \ | |
| chown -R node:node /usr/local/share/npm-global | |
| # Setup command history | |
| RUN mkdir /commandhistory && \ | |
| touch /commandhistory/.bash_history && \ | |
| chown -R node /commandhistory | |
| # Allow node user to run apt-get without password | |
| RUN echo "node ALL=(ALL) NOPASSWD: /usr/bin/apt-get, /usr/bin/apt" >> /etc/sudoers.d/node-apt && \ | |
| chmod 0440 /etc/sudoers.d/node-apt | |
| # Install Playwright globally with Chromium for headless browser testing (as root for deps) | |
| RUN npm install -g playwright && \ | |
| npx playwright install chromium --with-deps | |
| # Setup Go path for node user | |
| RUN mkdir -p /home/node/go && \ | |
| chown -R node:node /home/node/go | |
| ENV DEVCONTAINER=true | |
| ENV GOPATH=/home/node/go | |
| ENV PATH=$PATH:/home/node/go/bin | |
| WORKDIR /workspace | |
| USER node | |
| ENV NPM_CONFIG_PREFIX=/usr/local/share/npm-global | |
| ENV PATH=$PATH:/usr/local/share/npm-global/bin | |
| ENV SHELL=/bin/zsh | |
| ENV EDITOR=vim | |
| ENV VISUAL=vim | |
| # Install Claude Code | |
| RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} | |
| # Install uv for Python package management (as node user) | |
| RUN curl -LsSf https://astral.sh/uv/install.sh | sh | |
| ENV PATH=$PATH:/home/node/.local/bin | |
| EOF | |
| if docker build -t $IMAGE_NAME -f $TMPDIR/Dockerfile.claude $TMPDIR; then | |
| echo -e "${GREEN}Image built successfully${NC}" | |
| else | |
| echo -e "${RED}Image build failed${NC}" | |
| rm $TMPDIR/Dockerfile.claude | |
| exit 1 | |
| fi | |
| rm $TMPDIR/Dockerfile.claude | |
| fi | |
| # Remove existing container if it exists | |
| docker rm -f $CONTAINER_NAME 2>/dev/null | |
| # Run Claude Code | |
| echo -e "${GREEN}Launching Claude Code...${NC}" | |
| echo "" | |
| mkdir -p $(pwd)/.claude | |
| docker run -it --rm \ | |
| --name $CONTAINER_NAME \ | |
| -v "$(pwd):/workspace" \ | |
| -v "$(pwd)/.claude:/workspace/.claude" \ | |
| -v "$HOME/.claude:/home/node/.claude" \ | |
| -v "/commandhistory" \ | |
| -w /workspace \ | |
| $IMAGE_NAME \ | |
| claude --model=opus --dangerously-skip-permissions |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment