# syntax=docker/dockerfile:1.7 ARG CODE_SERVER_VERSION=4.128.0 ARG UV_VERSION=0.11.29 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv FROM ghcr.io/coder/code-server:${CODE_SERVER_VERSION} ARG CLAUDE_CODE_CHANNEL=latest USER root # Install a small native build toolchain, the official Claude Code CLI, # and the official ngrok Agent CLI. RUN set -eux; \ case "${CLAUDE_CODE_CHANNEL}" in latest|stable) ;; *) exit 2 ;; esac; \ apt-get update; \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ curl \ git \ jq \ pkg-config \ ripgrep \ unzip; \ install -d -m 0755 /etc/apt/keyrings; \ curl -fsSL https://downloads.claude.ai/keys/claude-code.asc \ -o /etc/apt/keyrings/claude-code.asc; \ printf '%s\n' \ "deb [signed-by=/etc/apt/keyrings/claude-code.asc] https://downloads.claude.ai/claude-code/apt/${CLAUDE_CODE_CHANNEL} ${CLAUDE_CODE_CHANNEL} main" \ > /etc/apt/sources.list.d/claude-code.list; \ curl -fsSL https://ngrok-agent.s3.amazonaws.com/ngrok.asc \ -o /etc/apt/keyrings/ngrok.asc; \ printf '%s\n' \ 'deb [signed-by=/etc/apt/keyrings/ngrok.asc] https://ngrok-agent.s3.amazonaws.com buster main' \ > /etc/apt/sources.list.d/ngrok.list; \ apt-get update; \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ claude-code \ ngrok; \ CLAUDE_BIN="$(command -v claude)"; \ test -x "${CLAUDE_BIN}"; \ ln -sf "${CLAUDE_BIN}" /usr/local/bin/claude-system; \ /usr/local/bin/claude-system --version; \ ngrok version; \ git --version; \ rm -rf /var/lib/apt/lists/* COPY --from=uv /uv /uvx /usr/local/bin/ ENV HOME=/home/coder \ PORT=7860 \ WORKSPACE=/home/coder/workspace \ VIRTUAL_ENV=/home/coder/workspace/.venv \ UV_PYTHON_INSTALL_DIR=/opt/uv/python \ UV_LINK_MODE=copy \ UV_COMPILE_BYTECODE=1 \ PATH="/home/coder/workspace/.venv/bin:/home/coder/.local/bin:${PATH}" \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ CS_DISABLE_GETTING_STARTED_OVERRIDE=true \ CLAUDE_SYSTEM_BIN=/usr/local/bin/claude-system \ CLAUDE_VSCODE_WRAPPER=/usr/local/bin/claude-vscode-wrapper # /data is mounted at runtime. Build all reusable artifacts in the image and # restore them into the persistent disk from the startup initializer. RUN install -d -m 0755 /etc/claude-code \ && install -d -o coder -g coder \ /opt/bootstrap \ /opt/bootstrap/code-server-user-data \ /opt/bootstrap/extensions \ /opt/bootstrap/workspace-src \ /opt/uv/python \ /home/coder/workspace COPY --chown=coder:coder pyproject.toml /home/coder/workspace/pyproject.toml COPY --chown=coder:coder workspace/README.md /opt/bootstrap/workspace-src/README.md COPY --chown=coder:coder workspace.gitignore /opt/bootstrap/workspace.gitignore USER coder # Resolve the dependency manifest and build the Python 3.12 environment at the # same path it will use at runtime. Archive the environment and preserve the # project manifest and lockfile for the candidate workspace. RUN set -eux; \ cd /home/coder/workspace; \ uv python install 3.12; \ uv sync --python 3.12 --no-install-project; \ cp pyproject.toml uv.lock /opt/bootstrap/workspace-src/; \ cat pyproject.toml uv.lock | sha256sum | awk '{print $1}' \ | tee /opt/bootstrap/venv.id > .venv/.hf-bootstrap-id; \ tar -C /home/coder/workspace -czf /opt/bootstrap/venv.tar.gz .venv; \ cd /; \ uv cache clean; \ rm -rf /home/coder/workspace # Install and verify the requested extensions into image-side bootstrap paths. RUN set -eux; \ code-server \ --user-data-dir /opt/bootstrap/code-server-user-data \ --extensions-dir /opt/bootstrap/extensions \ --install-extension Anthropic.claude-code \ --install-extension ms-python.python; \ code-server \ --user-data-dir /opt/bootstrap/code-server-user-data \ --extensions-dir /opt/bootstrap/extensions \ --list-extensions | tee /tmp/preinstalled-extensions.txt; \ grep -Fxi 'Anthropic.claude-code' /tmp/preinstalled-extensions.txt; \ grep -Fxi 'ms-python.python' /tmp/preinstalled-extensions.txt; \ rm -f /tmp/preinstalled-extensions.txt USER root COPY --chown=root:root --chmod=0755 scripts/10-init-persistent-data.sh \ /usr/local/bin/init-persistent-data COPY --chown=root:root --chmod=0755 scripts/start-code-server.sh \ /usr/local/bin/start-code-server COPY --chown=root:root --chmod=0755 scripts/claude-vscode-wrapper.sh \ /usr/local/bin/claude-vscode-wrapper COPY --chown=root:root --chmod=0644 config/claude-managed-settings.json \ /etc/claude-code/managed-settings.json ENV UV_CACHE_DIR=/data/cache/uv \ HF_HOME=/data/cache/huggingface \ CLAUDE_CONFIG_DIR=/data/claude USER coder # The workspace symlink is created after the HF persistent disk is mounted. WORKDIR /home/coder EXPOSE 7860 ENTRYPOINT ["/usr/local/bin/start-code-server"]