Spaces:
Running
Bake the QoL toolchain into the image
Browse filesEveryday tools agents and humans kept missing: jq, htop, lsof, tree,
ncdu, sqlite3, vim/nano, zip/unzip, file, watch, less, ffmpeg,
imagemagick, gh (GitHub CLI), git-lfs, plus fonts so headless
screenshots don't render tofu. Git gets system-level defaults
(safe.directory for the FUSE bucket, default branch, fallback
identity) that the operator's own config still overrides.
Playwright's headless Chromium is preinstalled with system deps at a
shared world-writable PLAYWRIGHT_BROWSERS_PATH, so node and python
playwright work with zero downloads. The default python3 becomes a
dedicated /opt/py venv (system python stays PEP-668 clean) shipping
numpy, pandas, matplotlib (MPLBACKEND=Agg), seaborn, requests, pillow,
huggingface_hub and ipython; login shells keep it on PATH.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Dockerfile +45 -5
|
@@ -11,10 +11,32 @@ RUN npm run build
|
|
| 11 |
FROM node:22-bookworm AS runtime
|
| 12 |
|
| 13 |
# System deps: tmux (session durability), git, build tools (node-pty native build),
|
| 14 |
-
# ripgrep (used by the coding CLIs), curl/ca-certs
|
|
|
|
|
|
|
| 15 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 16 |
-
tmux git ca-certificates curl python3 make g++ ripgrep bubblewrap rsync \
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
ENV LANG=C.UTF-8
|
| 20 |
|
|
@@ -45,18 +67,36 @@ RUN env UV_TOOL_BIN_DIR=/usr/local/bin UV_TOOL_DIR=/opt/uv-tools \
|
|
| 45 |
uv tool install --python /usr/bin/python3 "huggingface_hub[cli]" \
|
| 46 |
|| echo "hf cli install failed"
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
# Login shells source /etc/profile, which RESETS PATH — dropping the build-time
|
| 49 |
# ~/.local/bin and the user-install dirs under $AM_LOCAL (pip --user, npm
|
| 50 |
# prefix). profile.d runs after that reset, so restore them here.
|
| 51 |
RUN printf '%s\n' \
|
| 52 |
-
'PATH="/home/node/.local/bin:$PATH"' \
|
| 53 |
'[ -n "$AM_LOCAL" ] && PATH="$AM_LOCAL/py/bin:$AM_LOCAL/npm/bin:$AM_LOCAL/bin:$PATH"' \
|
| 54 |
'export PATH' \
|
| 55 |
> /etc/profile.d/agent-manager.sh
|
| 56 |
|
| 57 |
# Non-root user: the node base image already ships uid 1000 as "node" (HF runs as uid 1000).
|
| 58 |
ENV HOME=/home/node
|
| 59 |
-
ENV PATH=/home/node/.local/bin:$PATH
|
| 60 |
WORKDIR /app
|
| 61 |
RUN chown node:node /app
|
| 62 |
|
|
|
|
| 11 |
FROM node:22-bookworm AS runtime
|
| 12 |
|
| 13 |
# System deps: tmux (session durability), git, build tools (node-pty native build),
|
| 14 |
+
# ripgrep (used by the coding CLIs), curl/ca-certs — plus everyday QoL tools
|
| 15 |
+
# agents and humans reach for (jq/htop/sqlite3/editors/media, fonts so headless
|
| 16 |
+
# Chromium screenshots don't render tofu).
|
| 17 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 18 |
+
tmux git git-lfs ca-certificates curl python3 make g++ ripgrep bubblewrap rsync \
|
| 19 |
+
jq htop lsof tree ncdu sqlite3 vim nano zip unzip file procps less \
|
| 20 |
+
ffmpeg imagemagick fonts-liberation fonts-noto-color-emoji \
|
| 21 |
+
&& rm -rf /var/lib/apt/lists/* \
|
| 22 |
+
&& git lfs install --system
|
| 23 |
+
|
| 24 |
+
# Git defaults every agent benefits from: the FUSE bucket trips "dubious
|
| 25 |
+
# ownership" without safe.directory, and commits die without an identity —
|
| 26 |
+
# these are SYSTEM level, so anything the operator sets globally still wins.
|
| 27 |
+
RUN git config --system safe.directory '*' \
|
| 28 |
+
&& git config --system init.defaultBranch main \
|
| 29 |
+
&& git config --system user.name 'Agent Manager' \
|
| 30 |
+
&& git config --system user.email 'agents@agent-manager.local'
|
| 31 |
+
|
| 32 |
+
# GitHub CLI (auths from a GH_TOKEN Space secret automatically).
|
| 33 |
+
RUN mkdir -p -m 755 /etc/apt/keyrings \
|
| 34 |
+
&& curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg -o /etc/apt/keyrings/githubcli-archive-keyring.gpg \
|
| 35 |
+
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
|
| 36 |
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list \
|
| 37 |
+
&& apt-get update && apt-get install -y --no-install-recommends gh \
|
| 38 |
+
&& rm -rf /var/lib/apt/lists/* \
|
| 39 |
+
|| echo "gh install failed"
|
| 40 |
|
| 41 |
ENV LANG=C.UTF-8
|
| 42 |
|
|
|
|
| 67 |
uv tool install --python /usr/bin/python3 "huggingface_hub[cli]" \
|
| 68 |
|| echo "hf cli install failed"
|
| 69 |
|
| 70 |
+
# Headless Chromium for Playwright, shared by every agent and both language
|
| 71 |
+
# bindings via PLAYWRIGHT_BROWSERS_PATH (world-writable so a binding pinned to
|
| 72 |
+
# a different build can add its revision without root).
|
| 73 |
+
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers
|
| 74 |
+
RUN npx -y playwright install --with-deps chromium \
|
| 75 |
+
&& chmod -R a+rwX /opt/pw-browsers \
|
| 76 |
+
|| echo "playwright chromium install failed"
|
| 77 |
+
|
| 78 |
+
# Batteries-included default python: a dedicated venv first on PATH (system
|
| 79 |
+
# python stays apt-owned/PEP-668 clean). One-off scripts get the data stack
|
| 80 |
+
# without setup; real projects still build their own uv env on $AM_LOCAL.
|
| 81 |
+
RUN uv venv /opt/py \
|
| 82 |
+
&& uv pip install --python /opt/py/bin/python \
|
| 83 |
+
numpy pandas matplotlib seaborn requests pillow huggingface_hub ipython \
|
| 84 |
+
&& chmod -R a+rX /opt/py \
|
| 85 |
+
|| echo "python stack install failed"
|
| 86 |
+
ENV MPLBACKEND=Agg
|
| 87 |
+
|
| 88 |
# Login shells source /etc/profile, which RESETS PATH — dropping the build-time
|
| 89 |
# ~/.local/bin and the user-install dirs under $AM_LOCAL (pip --user, npm
|
| 90 |
# prefix). profile.d runs after that reset, so restore them here.
|
| 91 |
RUN printf '%s\n' \
|
| 92 |
+
'PATH="/home/node/.local/bin:/opt/py/bin:$PATH"' \
|
| 93 |
'[ -n "$AM_LOCAL" ] && PATH="$AM_LOCAL/py/bin:$AM_LOCAL/npm/bin:$AM_LOCAL/bin:$PATH"' \
|
| 94 |
'export PATH' \
|
| 95 |
> /etc/profile.d/agent-manager.sh
|
| 96 |
|
| 97 |
# Non-root user: the node base image already ships uid 1000 as "node" (HF runs as uid 1000).
|
| 98 |
ENV HOME=/home/node
|
| 99 |
+
ENV PATH=/home/node/.local/bin:/opt/py/bin:$PATH
|
| 100 |
WORKDIR /app
|
| 101 |
RUN chown node:node /app
|
| 102 |
|