# Runtime image for Pi Web on HF Sandboxes. Every workspace machine is an HF Sandbox (a Job # in its user's own account) started from this image, so the Space is public: Jobs in any # namespace can pull it. It holds no secret. The Space itself only serves a short page. FROM node:22-bookworm # Tools for the coding agent, and zstd for the workspace archives. RUN apt-get update \ && apt-get install -y --no-install-recommends \ python3-venv python3-pip python-is-python3 zstd ripgrep fd-find jq less vim-tiny procps htop git-lfs unzip zip rsync \ && ln -sf /usr/bin/fdfind /usr/local/bin/fd \ && rm -rf /var/lib/apt/lists/* ARG UV_VERSION=0.12.21 RUN curl -LsSf "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-x86_64-unknown-linux-gnu.tar.gz" \ | tar -xz --strip-components=1 -C /usr/local/bin uv-x86_64-unknown-linux-gnu/uv uv-x86_64-unknown-linux-gnu/uvx # The Hugging Face CLI and its agent skills, for every project: pi reads ~/.agents/skills. # AWS SageMaker skills are left out (no AWS credentials in a sandbox). ARG HF_CLI_VERSION=2.1.1 ARG HF_SKILLS_EXCLUDE="^hf-cloud-" RUN UV_TOOL_DIR=/opt/uv-tools UV_TOOL_BIN_DIR=/usr/local/bin uv tool install --python /usr/bin/python3 "huggingface_hub==${HF_CLI_VERSION}" \ && hf skills add --global --force \ && for skill in $(hf skills list -q 2>/dev/null | grep -vx 'hf-cli' | grep -Ev "${HF_SKILLS_EXCLUDE}"); do hf skills add "$skill" --global --force; done \ && rm -rf /root/.claude /root/.cache/huggingface \ && ls /root/.agents/skills # Only hf-cli is on by default; the other skills stay installed but off (sandbox/skill-defaults.py). ARG HF_SKILLS_ENABLED="hf-cli" COPY sandbox/skill-defaults.py /tmp/skill-defaults.py RUN python3 /tmp/skill-defaults.py /root/.agents/skills ${HF_SKILLS_ENABLED} && rm /tmp/skill-defaults.py # A real Chromium for Pi Web's Browser pane and the agent's browser_* tools (lib/browser): the # revision playwright-core 1.63.0 drives (Pi Web's own dependency), with the system libraries # and fonts it needs. Pi Web finds it through PLAYWRIGHT_BROWSERS_PATH. ARG PLAYWRIGHT_VERSION=1.63.0 ENV PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers RUN npx -y "playwright-core@${PLAYWRIGHT_VERSION}" install --with-deps --no-shell chromium \ && apt-get update && apt-get install -y --no-install-recommends fonts-noto-color-emoji \ && rm -rf /var/lib/apt/lists/* /root/.npm \ && chmod -R a+rX /opt/pw-browsers \ && ls /opt/pw-browsers # git authenticates to huggingface.co with the token lent by the sign-in, if any. COPY sandbox/git-credential-huggingface /usr/local/bin/git-credential-huggingface RUN chmod 755 /usr/local/bin/git-credential-huggingface \ && git config --system credential.https://huggingface.co.helper /usr/local/bin/git-credential-huggingface \ && git config --system credential.https://hf.co.helper /usr/local/bin/git-credential-huggingface # Pi Web (upstream main at PI_WEB_COMMIT, past its 0.12.2 tag) with the "Pi Web on Hugging Face" # design (piweb/hf-design.patch: Claude Code Desktop's layout on Base UI: the composer with its # "/" and "@" lists, modes and context meter; the header's panes: Changes with review comments, # the machine's Browser (the agent also acts in the user's direct preview), Files, Terminal; the # Hugging Face connector; Geist type, the pi mark, Lucide icons, a sidebar slot for the gateway's # workspace menu), built from that commit and installed as its npm package would be. The patch is # the diff of the hf-design branch in the project's pi-web-hf/ worktree against that commit # (git diff --binary hf-design); nothing else is changed. # Next runs one build worker per CPU but one (CIRCLE_NODE_TOTAL stands in for the CPU count): on # the Space builder's 16 CPUs, 15 workers ran out of memory collecting page data (OOMKilled), so # it builds with 4. ARG PI_WEB_VERSION=0.12.2 ARG PI_WEB_COMMIT=e533d9b3975f8a74b378d5007c92fdf4d15d3fba COPY piweb /tmp/piweb RUN git init --quiet /tmp/pi-web \ && cd /tmp/pi-web \ && git fetch --quiet --depth 1 https://github.com/agegr/pi-web "${PI_WEB_COMMIT}" \ && git checkout --quiet FETCH_HEAD \ && git apply --binary /tmp/piweb/hf-design.patch \ && PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 NEXT_TELEMETRY_DISABLED=1 npm ci --no-audit --no-fund \ && NEXT_TELEMETRY_DISABLED=1 CIRCLE_NODE_TOTAL=5 npm run build \ && npm pack --silent \ && npm install -g --no-audit --no-fund "./agegr-pi-web-${PI_WEB_VERSION}.tgz" \ && cd / && rm -rf /tmp/pi-web /tmp/piweb && npm cache clean --force COPY sandbox /opt/hfpi COPY www /opt/hfpi/www RUN chmod -R a+rX /opt/hfpi EXPOSE 7860 CMD ["python3", "-m", "http.server", "7860", "--directory", "/opt/hfpi/www"]