File size: 5,084 Bytes
63e753b
 
ece8fa9
 
 
 
 
 
a7277a1
 
ece8fa9
 
a7277a1
63e753b
a7277a1
 
 
 
ece8fa9
 
 
a7277a1
ece8fa9
 
 
a7277a1
 
 
 
 
 
 
 
 
 
ece8fa9
a7277a1
 
 
ece8fa9
a7277a1
 
 
 
 
 
 
 
ece8fa9
 
 
 
 
 
 
 
 
 
 
 
 
a7277a1
 
 
ece8fa9
a7277a1
 
dd861a9
 
ece8fa9
63e753b
ece8fa9
 
 
 
 
a7277a1
 
 
ece8fa9
 
 
a7277a1
 
 
ece8fa9
 
 
 
a7277a1
 
 
ece8fa9
81fb3f5
 
a7277a1
ece8fa9
63e753b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ece8fa9
 
63e753b
 
ece8fa9
 
a7277a1
 
dd861a9
 
ece8fa9
63e753b
 
 
 
ece8fa9
63e753b
a7277a1
ece8fa9
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# 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"]