HuggingClaw / Dockerfile
chandrakant-s4's picture
v4.5 - update Dockerfile, sync_hf.py; add local-whisper skill
e82ae2b
Raw
History Blame Contribute Delete
11.2 kB
# OpenClaw on Hugging Face Spaces β€” Pre-built image (v4.4)
# Changelog:
# v4.2 β€” sudo access, Homebrew (brew), uv, Go added for agent tooling
# v4.3 β€” skill dependencies added (wrong go paths β€” fixed in v4.4)
# v4.4 β€” FIXED: correct go module paths (all tools are by @steipete);
# gh via official GitHub apt repo; gemini via npm; nano-pdf via pip;
# steipete/tap added for brew; OpenClaw always pulls :latest
# ── Stage 1: Pull pre-built OpenClaw ─────────────────────────────────────────
# :latest always fetches the newest release on every rebuild.
# If you ever need to pin a version use e.g. :2026.3.13
FROM ghcr.io/openclaw/openclaw:latest AS openclaw-prebuilt
# ── Stage 2: Runtime ─────────────────────────────────────────────────────────
FROM node:22-bookworm
SHELL ["/bin/bash", "-c"]
# ── System deps + apt-installable skill tools (root) ─────────────────────────
# Skills unlocked by apt: session-logs+trello (jq, ripgrep), tmux, video-frames (ffmpeg)
# gh added via official GitHub apt repo β€” more reliable than brew on Linux
RUN echo "[build] Installing system deps + gh..." && START=$(date +%s) \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
git ca-certificates curl wget python3 python3-pip \
sudo build-essential procps file \
jq ripgrep tmux ffmpeg \
poppler-utils tesseract-ocr \
# ── GitHub CLI (gh) via official apt repo ──
&& mkdir -p -m 755 /etc/apt/keyrings \
&& wget -qO /etc/apt/keyrings/githubcli-archive-keyring.gpg \
https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& 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 \
&& apt-get update \
&& apt-get install -y --no-install-recommends gh \
&& rm -rf /var/lib/apt/lists/* \
&& gh --version \
# ── Python + pip skill tools ──
&& pip3 install --no-cache-dir --break-system-packages \
huggingface_hub requests nano-pdf openai-whisper ffmpeg-python \
&& corepack enable \
&& mkdir -p /app/openclaw \
&& chown -R node:node /app \
&& mkdir -p /home/node/.openclaw/workspace /home/node/.openclaw/credentials \
&& chown -R node:node /home/node \
# ── Passwordless sudo for node user ──
&& echo "node ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/node \
&& chmod 0440 /etc/sudoers.d/node \
&& echo "[build] System deps: $(($(date +%s) - START))s"
# ── Go language + Go-based skill tools (root) ─────────────────────────────────
# All CLIs are by Peter Steinberger (@steipete) β€” correct module paths:
# gifgrep β†’ github.com/steipete/gifgrep/cmd/gifgrep
# blucli β†’ github.com/steipete/blucli/cmd/blu
# eightctl β†’ github.com/steipete/eightctl/cmd/eightctl
# songsee β†’ github.com/steipete/songsee/cmd/songsee
# gog β†’ github.com/steipete/gogcli (binary: gog)
RUN echo "[build] Installing Go + Go-based skill CLIs..." && START=$(date +%s) \
&& GO_VER=$(curl -fsSL "https://go.dev/VERSION?m=text" | head -1) \
&& curl -fsSL "https://dl.google.com/go/${GO_VER}.linux-amd64.tar.gz" -o /tmp/go.tar.gz \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& rm /tmp/go.tar.gz \
&& /usr/local/go/bin/go version \
&& GOBIN=/usr/local/bin /usr/local/go/bin/go install \
github.com/steipete/gifgrep/cmd/gifgrep@latest 2>&1 || echo "[go] WARN: gifgrep" \
&& GOBIN=/usr/local/bin /usr/local/go/bin/go install \
github.com/steipete/blucli/cmd/blu@latest 2>&1 || echo "[go] WARN: blucli/blu" \
&& GOBIN=/usr/local/bin /usr/local/go/bin/go install \
github.com/steipete/eightctl/cmd/eightctl@latest 2>&1 || echo "[go] WARN: eightctl" \
&& GOBIN=/usr/local/bin /usr/local/go/bin/go install \
github.com/steipete/songsee/cmd/songsee@latest 2>&1 || echo "[go] WARN: songsee" \
&& GOBIN=/usr/local/bin /usr/local/go/bin/go install \
github.com/steipete/gogcli@latest 2>&1 || echo "[go] WARN: gogcli/gog" \
&& echo "[build] Go ${GO_VER} + CLIs: $(($(date +%s) - START))s"
# ── uv (fast Python package manager by Astral) ───────────────────────────────
RUN echo "[build] Installing uv..." && START=$(date +%s) \
&& curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh \
&& uv --version \
&& echo "[build] uv: $(($(date +%s) - START))s"
# ── npm skill tools (root) ────────────────────────────────────────────────────
# Skills unlocked: clawhub, mcporter, oracle, gemini
RUN echo "[build] Installing npm skill tools..." && START=$(date +%s) \
&& npm install -g \
@anthropic-ai/claude-code \
acpx@latest \
clawhub \
mcporter \
@steipete/oracle \
@google/gemini-cli \
&& echo "[build] npm tools: $(($(date +%s) - START))s"
# ── Copy pre-built OpenClaw ───────────────────────────────────────────────────
COPY --from=openclaw-prebuilt --chown=node:node /app /app/openclaw
# ── Switch to node user ───────────────────────────────────────────────────────
USER node
ENV HOME=/home/node
WORKDIR /app
# ── Homebrew (Linux) β€” must run as non-root ───────────────────────────────────
RUN echo "[build] Installing Homebrew..." && START=$(date +%s) \
&& NONINTERACTIVE=1 /bin/bash -c \
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" \
&& echo "[build] Homebrew: $(($(date +%s) - START))s"
ENV HOMEBREW_PREFIX=/home/node/.linuxbrew
ENV HOMEBREW_CELLAR=/home/node/.linuxbrew/Cellar
ENV HOMEBREW_REPOSITORY=/home/node/.linuxbrew/Homebrew
ENV HOMEBREW_NO_ANALYTICS=1
ENV HOMEBREW_NO_AUTO_UPDATE=1
# ── Brew skill tools (steipete/tap + standard formulas) ──────────────────────
# - First add steipete/tap (source of gifgrep, songsee, blucli etc.)
# - Then install formulas β€” each is soft-fail (|| echo) so build never breaks
# if a formula isn't available on Linux homebrew-core
RUN echo "[build] Installing brew skill tools..." && START=$(date +%s) \
&& BREW=/home/node/.linuxbrew/bin/brew \
&& $BREW tap steipete/tap 2>&1 || echo "[brew] WARN: steipete/tap tap failed" \
&& install_brew() { \
$BREW install "$@" \
&& echo "[brew] βœ“ $*" \
|| echo "[brew] βœ— $* (skipped)"; \
} \
# Standard homebrew-core formulas
&& install_brew himalaya \
&& install_brew 1password-cli \
&& install_brew gogcli \
&& install_brew openhue \
&& install_brew ordercli \
&& install_brew wacli \
&& install_brew xurl \
&& install_brew summarize \
&& install_brew obsidian-cli \
&& install_brew camsnap \
&& install_brew openai-whisper \
# steipete/tap formulas (fallback if go install above didn't work)
&& install_brew steipete/tap/gifgrep \
&& install_brew steipete/tap/songsee \
&& install_brew steipete/tap/blucli \
&& install_brew steipete/tap/eightctl \
&& echo "[build] brew skill tools: $(($(date +%s) - START))s"
# ── A2A Gateway Extension ─────────────────────────────────────────────────────
RUN echo "[build] Installing A2A gateway..." && START=$(date +%s) \
&& git clone --depth 1 https://github.com/win4r/openclaw-a2a-gateway.git /app/openclaw/extensions/a2a-gateway \
&& cd /app/openclaw/extensions/a2a-gateway \
&& npm install --production \
&& echo "[build] A2A gateway: $(($(date +%s) - START))s"
# ── Coding Agent Extension ────────────────────────────────────────────────────
COPY --chown=node:node extensions/coding-agent /app/openclaw/extensions/coding-agent
# ── Pre-configure acpx ────────────────────────────────────────────────────────
RUN mkdir -p /home/node/.acpx \
&& echo '{"defaultAgent":"claude","defaultPermissions":"approve-all","format":"text"}' \
> /home/node/.acpx/config.json
# ── npm user-local prefix ─────────────────────────────────────────────────────
RUN mkdir -p /home/node/.npm-global \
&& npm config set prefix /home/node/.npm-global
# ── Prepare runtime dirs ──────────────────────────────────────────────────────
RUN mkdir -p /app/openclaw/empty-bundled-plugins \
&& node -e "try{console.log(require('/app/openclaw/package.json').version)}catch(e){console.log('unknown')}" > /app/openclaw/.version \
&& echo "[build] OpenClaw version: $(cat /app/openclaw/.version)"
# ── Scripts + Config + Frontend ───────────────────────────────────────────────
COPY --chown=node:node scripts /home/node/scripts
COPY --chown=node:node frontend /home/node/frontend
COPY --chown=node:node workspace-templates /home/node/workspace-templates
COPY --chown=node:node openclaw.json /home/node/scripts/openclaw.json.default
RUN chmod +x /home/node/scripts/entrypoint.sh /home/node/scripts/sync_hf.py \
&& VERSION_TS=$(date +%s) \
&& sed "s/{{VERSION_TIMESTAMP}}/${VERSION_TS}/g" /home/node/frontend/electron-standalone.html > /home/node/frontend/index.html \
&& echo "[build] Frontend index.html generated (timestamp=${VERSION_TS})"
# ── Environment ───────────────────────────────────────────────────────────────
ENV NODE_ENV=production
ENV OPENCLAW_BUNDLED_PLUGINS_DIR=/app/openclaw/empty-bundled-plugins
ENV OPENCLAW_PREFER_PNPM=1
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV GOPATH=/home/node/go
# Full explicit PATH β€” user bins first, then system
ENV PATH=/home/node/.npm-global/bin:/home/node/.linuxbrew/bin:/home/node/.linuxbrew/sbin:/home/node/.local/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
WORKDIR /home/node
CMD ["/home/node/scripts/entrypoint.sh"]