Skip to content

Instantly share code, notes, and snippets.

@jamesob
Created January 19, 2026 17:29
Show Gist options
  • Select an option

  • Save jamesob/930c9620b60ae414b910aa0e8565c933 to your computer and use it in GitHub Desktop.

Select an option

Save jamesob/930c9620b60ae414b910aa0e8565c933 to your computer and use it in GitHub Desktop.
claude sandbox
#!/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