From 5e054bef1a66d3b3b5edecd45266f0ffa734346c Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 17 Jun 2026 07:35:27 +0000 Subject: [PATCH 01/11] Add Hermes Agent Docker image build files - Add docker_hermes/hermes.Dockerfile - Add docker_hermes/demo/docker-compose.yml - Add docker_hermes/README.md --- docker_hermes/README.md | 71 +++++++++++++ docker_hermes/demo/docker-compose.yml | 34 +++++++ docker_hermes/hermes.Dockerfile | 141 ++++++++++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 docker_hermes/README.md create mode 100644 docker_hermes/demo/docker-compose.yml create mode 100644 docker_hermes/hermes.Dockerfile diff --git a/docker_hermes/README.md b/docker_hermes/README.md new file mode 100644 index 0000000..dffddef --- /dev/null +++ b/docker_hermes/README.md @@ -0,0 +1,71 @@ +# Hermes Agent Docker Image + +This directory contains the Dockerfile for building the [Hermes Agent](https://github.com/nousresearch/hermes-agent) Docker image. + +## Quick Start + +### Build Image + +```bash +docker build -f hermes.Dockerfile -t hermes-agent:latest . +``` + +### Run with Docker Compose + +```bash +cd demo +docker compose up -d +``` + +### Run Manually + +```bash +# Run gateway +docker run -d \ + --name hermes-gateway \ + --hostname hermes-gateway \ + --network host \ + -v /data/hermes:/opt/data \ + -e HERMES_UID=10000 \ + -e HERMES_GID=10000 \ + quay.io/labnow/hermes:latest \ + gateway run + +# Run dashboard (separate container) +docker run -d \ + --name hermes-dashboard \ + --hostname hermes-dashboard \ + --network host \ + -v /data/hermes:/opt/data \ + -e HERMES_UID=10000 \ + -e HERMES_GID=10000 \ + quay.io/labnow/hermes:latest \ + dashboard --host 127.0.0.1 --no-open +``` + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| HERMES_UID | 10000 | UID for the hermes user | +| HERMES_GID | 10000 | GID for the hermes user | +| HERMES_HOME | /opt/data | Home directory for hermes data | +| PLAYWRIGHT_BROWSERS_PATH | /opt/hermes/.playwright | Path for Playwright browsers | + +## Volumes + +- `/opt/data` - Persistent data directory for hermes configuration, memories, and skills + +## Build Arguments + +| Argument | Default | Description | +|----------|---------|-------------| +| HERMES_GIT_REF | main | Git branch/tag to clone | +| HERMES_REPO_URL | https://github.com/nousresearch/hermes-agent.git | Git repository URL | +| HERMES_GIT_SHA | (empty) | Git commit SHA for build info | + +## Documentation + +For more information about Hermes Agent, see: +- [Official Documentation](https://hermes-agent.nousresearch.com/docs/) +- [GitHub Repository](https://github.com/nousresearch/hermes-agent) diff --git a/docker_hermes/demo/docker-compose.yml b/docker_hermes/demo/docker-compose.yml new file mode 100644 index 0000000..881537c --- /dev/null +++ b/docker_hermes/demo/docker-compose.yml @@ -0,0 +1,34 @@ +name: "svc-hermes" + +services: + hermes-gateway: + container_name: svc-hermes-gateway + hostname: svc-hermes-gateway + image: "quay.io/labnow/hermes:latest" + pull_policy: if_not_present + restart: unless-stopped + network_mode: host + environment: + - TZ=Asia/Shanghai + - HERMES_UID=10000 + - HERMES_GID=10000 + volumes: + - /data/hermes:/opt/data + # command: ["tail", "-f", "/dev/null"] + + hermes-dashboard: + container_name: svc-hermes-dashboard + hostname: svc-hermes-dashboard + image: "quay.io/labnow/hermes:latest" + pull_policy: if_not_present + restart: unless-stopped + network_mode: host + depends_on: + - hermes-gateway + environment: + - TZ=Asia/Shanghai + - HERMES_UID=10000 + - HERMES_GID=10000 + volumes: + - /data/hermes:/opt/data + command: ["dashboard", "--host", "127.0.0.1", "--no-open"] diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile new file mode 100644 index 0000000..31a0dde --- /dev/null +++ b/docker_hermes/hermes.Dockerfile @@ -0,0 +1,141 @@ +# Distributed under the terms of the Modified BSD License. + +# Multi-stage Dockerfile for Hermes Agent +# Stage 1: Clone hermes-agent from GitHub +FROM debian:13.4 AS hermes_source + +ARG HERMES_GIT_REF=main +ARG HERMES_REPO_URL=https://github.com/nousresearch/hermes-agent.git + +WORKDIR /src +RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates curl && rm -rf /var/lib/apt/lists/* +RUN git clone --depth 1 --branch "${HERMES_GIT_REF}" "${HERMES_REPO_URL}" . + +# Stage 2: Full build +FROM ghcr.io/astral-sh/uv:0.11.6-python3.13-trixie@sha256:b3c543b6c4f23a5f2df22866bd7857e5d304b67a564f4feab6ac22044dde719b AS uv_source +FROM node:22-bookworm-slim@sha256:7af03b14a13c8cdd38e45058fd957bf00a72bbe17feac43b1c15a689c029c732 AS node_source +FROM debian:13.4 + +LABEL maintainer="postmaster@labnow.ai" + +# Disable Python stdout buffering to ensure logs are printed immediately +ENV PYTHONUNBUFFERED=1 + +# Store Playwright browsers outside the volume mount so the build-time +# install survives the /opt/data volume overlay at runtime. +ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright + +# Install system dependencies in one layer, clear APT cache. +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates curl iputils-ping python3 python-is-python3 ripgrep ffmpeg gcc g++ make cmake python3-dev python3-venv libffi-dev libolm-dev procps git openssh-client docker-cli xz-utils && \ + rm -rf /var/lib/apt/lists/* + +# ---------- s6-overlay install ---------- +ARG TARGETARCH +ARG S6_OVERLAY_VERSION=3.2.3.0 +ARG S6_OVERLAY_NOARCH_SHA256=b720f9d9340efc8bb07528b9743813c836e4b02f8693d90241f047998b4c53cf +ARG S6_OVERLAY_X86_64_SHA256=a93f02882c6ed46b21e7adb5c0add86154f01236c93cd82c7d682722e8840563 +ARG S6_OVERLAY_AARCH64_SHA256=0952056ff913482163cc30e35b2e944b507ba1025d78f5becbb89367bf344581 +ARG S6_OVERLAY_SYMLINKS_SHA256=a60dc5235de3ecbcf874b9c1f18d73263ab99b289b9329aa950e8729c4789f0e +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp/ +ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz /tmp/ +RUN set -eu; \ + case "${TARGETARCH:-amd64}" in \ + amd64) s6_arch="x86_64"; s6_arch_sha="${S6_OVERLAY_X86_64_SHA256}" ;; \ + arm64) s6_arch="aarch64"; s6_arch_sha="${S6_OVERLAY_AARCH64_SHA256}" ;; \ + *) echo "Unsupported TARGETARCH=${TARGETARCH} for s6-overlay" >&2; exit 1 ;; \ + esac; \ + curl -fsSL --retry 3 -o /tmp/s6-overlay-arch.tar.xz \ + "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${s6_arch}.tar.xz"; \ + { \ + printf '%s %s\n' "${S6_OVERLAY_NOARCH_SHA256}" /tmp/s6-overlay-noarch.tar.xz; \ + printf '%s %s\n' "${s6_arch_sha}" /tmp/s6-overlay-arch.tar.xz; \ + printf '%s %s\n' "${S6_OVERLAY_SYMLINKS_SHA256}" /tmp/s6-overlay-symlinks-noarch.tar.xz; \ + } > /tmp/s6-overlay.sha256; \ + sha256sum -c /tmp/s6-overlay.sha256; \ + tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz; \ + tar -C / -Jxpf /tmp/s6-overlay-arch.tar.xz; \ + tar -C / -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz; \ + rm /tmp/s6-overlay-*.tar.xz /tmp/s6-overlay.sha256; \ + ln -sf /init /usr/bin/tini + +# Non-root user for runtime; UID can be overridden via HERMES_UID at runtime +RUN useradd -u 10000 -m -d /opt/data hermes + +COPY --chmod=0755 --from=uv_source /usr/local/bin/uv /usr/local/bin/uvx /usr/local/bin/ + +# Node 22 LTS +COPY --chmod=0755 --from=node_source /usr/local/bin/node /usr/local/bin/ +COPY --from=node_source /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/npm +COPY --from=node_source /usr/local/lib/node_modules/corepack /usr/local/lib/node_modules/corepack +RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \ + ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \ + ln -sf /usr/local/lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack + +WORKDIR /opt/hermes + +# Copy source from cloned repo +COPY --from=hermes_source /src /opt/hermes + +# Layer-cached dependency install +COPY package.json package-lock.json ./ +COPY web/package.json web/ +COPY ui-tui/package.json ui-tui/ +COPY ui-tui/packages/hermes-ink/ ui-tui/packages/hermes-ink/ + +ENV npm_config_install_links=false + +RUN npm install --prefer-offline --no-audit && \ + npx playwright install --with-deps chromium --only-shell && \ + npm cache clean --force + +# Python dependency install +COPY pyproject.toml uv.lock ./ +RUN touch ./README.md && \ + uv sync --frozen --no-install-project --extra all --extra messaging --extra anthropic --extra bedrock --extra azure-identity --extra hindsight --extra matrix + +# Frontend build +COPY web/ web/ +COPY ui-tui/ ui-tui/ +RUN cd web && npm run build && \ + cd ../ui-tui && npm run build + +# Permissions +USER root +RUN chmod -R a+rX /opt/hermes && \ + chown -R hermes:hermes /opt/hermes/.venv /opt/hermes/ui-tui /opt/hermes/gateway /opt/hermes/node_modules + +# Link hermes-agent itself (editable) +RUN uv pip install --no-cache-dir --no-deps -e "." + +# Bake build-time git revision +ARG HERMES_GIT_SHA= +RUN if [ -n "${HERMES_GIT_SHA}" ]; then \ + printf '%s\n' "${HERMES_GIT_SHA}" > /opt/hermes/.hermes_build_sha && \ + chown hermes:hermes /opt/hermes/.hermes_build_sha; \ + fi + +# s6-overlay service wiring +COPY docker/s6-rc.d/ /etc/s6-overlay/s6-rc.d/ + +RUN mkdir -p /etc/cont-init.d && \ + printf '#!/command/with-contenv sh\nexec /opt/hermes/docker/stage2-hook.sh\n' \ + > /etc/cont-init.d/01-hermes-setup && \ + chmod +x /etc/cont-init.d/01-hermes-setup +COPY --chmod=0755 docker/cont-init.d/015-supervise-perms /etc/cont-init.d/015-supervise-perms +COPY --chmod=0755 docker/cont-init.d/02-reconcile-profiles /etc/cont-init.d/02-reconcile-profiles + +# Runtime +ENV HERMES_WEB_DIST=/opt/hermes/hermes_cli/web_dist +ENV HERMES_TUI_DIR=/opt/hermes/ui-tui +ENV HERMES_HOME=/opt/data + +COPY --chmod=0755 docker/hermes-exec-shim.sh /opt/hermes/bin/hermes + +ENV PATH="/opt/hermes/bin:/opt/hermes/.venv/bin:/opt/data/.local/bin:${PATH}" +RUN mkdir -p /opt/data +VOLUME [ "/opt/data" ] + +ENTRYPOINT [ "/init", "/opt/hermes/docker/main-wrapper.sh" ] +CMD [ ] From 191516bb909d9e5b4888bb7cca64848ca91ce79a Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 17 Jun 2026 07:36:51 +0000 Subject: [PATCH 02/11] Add hermes CI/CD job in build-docker workflow --- .github/workflows/build-docker.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 3fb2e10..0276584 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -149,6 +149,16 @@ jobs: source ./tool.sh build_image openclaw latest docker_openclaw/openclaw.Dockerfile && push_image openclaw + ## Hermes Agent + job-hermes: + name: "hermes" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - run: | + source ./tool.sh + build_image hermes latest docker_hermes/hermes.Dockerfile && push_image hermes + ## DevBox - base job-base-dev: name: "developer,base-dev" @@ -217,6 +227,7 @@ jobs: "job-base-dev", "job-nocobase", "job-openclaw", + "job-hermes", "job-logent", "job-storebox", "job-searxng", From 15ce87495bd95ba505711653b3d14276cf5510b4 Mon Sep 17 00:00:00 2001 From: Bibo Hao Date: Sat, 20 Jun 2026 03:23:01 +0800 Subject: [PATCH 03/11] remove files --- docker_devbox/dev.Dockerfile | 4 ---- docker_devbox/work/start-supervisord.sh | 6 ------ .../demo/docker-compose.searxng-standalone.yml | 6 +----- .../demo/docker-compose.searxng-with-proxy.yml | 9 ++------- 4 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 docker_devbox/work/start-supervisord.sh diff --git a/docker_devbox/dev.Dockerfile b/docker_devbox/dev.Dockerfile index 2d1fa1e..8eca792 100644 --- a/docker_devbox/dev.Dockerfile +++ b/docker_devbox/dev.Dockerfile @@ -40,10 +40,6 @@ RUN set -eux && source /opt/utils/script-utils.sh \ ## ----------------------------- If installing R IDEs: R_rstudio and R_rshiny && source /opt/utils/script-devbox-rstudio.sh \ && for profile in $(echo $ARG_PROFILE_R | tr "," "\n") ; do ( setup_R_${profile} ) ; done \ - ## ----------------------------- Install supervisord - && source /opt/utils/script-setup-sys.sh && setup_supervisord \ - ## ----------------------------- Install caddy - && source /opt/utils/script-setup-net.sh && setup_caddy 2.11.2 \ ## Clean up and display components version information... && list_installed_packages && install__clean diff --git a/docker_devbox/work/start-supervisord.sh b/docker_devbox/work/start-supervisord.sh deleted file mode 100644 index f81c589..0000000 --- a/docker_devbox/work/start-supervisord.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -[ $BASH ] && [ -f /etc/profile ] && [ -z $ENTER_PROFILE ] && . /etc/profile - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -LOG_FORMAT=json exec supervisord -c /etc/supervisord/supervisord.conf diff --git a/docker_searxng/demo/docker-compose.searxng-standalone.yml b/docker_searxng/demo/docker-compose.searxng-standalone.yml index bd47f84..0a60b67 100644 --- a/docker_searxng/demo/docker-compose.searxng-standalone.yml +++ b/docker_searxng/demo/docker-compose.searxng-standalone.yml @@ -4,7 +4,7 @@ networks: services: svc-searxng: container_name: svc-searxng - image: docker.io/labnow/searxng:latest + image: quay.io/labnow/searxng:latest restart: unless-stopped networks: - net-searxng @@ -13,8 +13,6 @@ services: # volumes: # - ./searxng/settings.yml:/etc/searxng/settings.yml:rw # - ./searxng/limiter.toml:/etc/searxng/limiter.toml:rw - # - ./searxng/Caddyfile:/etc/searxng/Caddyfile:rw - # - ./searxng/supervisord.conf:/etc/searxng/supervisord.conf:rw environment: - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost:8000}/ - SEARXNG_HOSTNAME=${SEARXNG_HOSTNAME:-http://localhost:8000} @@ -22,8 +20,6 @@ services: - UWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4} - UWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4} # user: root - # command: ["/opt/searxng/start-supervisord.sh"] - # command: ["tail", "-f", "/dev/null"] # cap_drop: ["ALL"] # cap_add: ["AUDIT_WRITE", "CHOWN", "SETGID", "SETUID", "NET_BIND_SERVICE"] logging: diff --git a/docker_searxng/demo/docker-compose.searxng-with-proxy.yml b/docker_searxng/demo/docker-compose.searxng-with-proxy.yml index 03814ea..fd001f2 100644 --- a/docker_searxng/demo/docker-compose.searxng-with-proxy.yml +++ b/docker_searxng/demo/docker-compose.searxng-with-proxy.yml @@ -5,7 +5,7 @@ services: svc-searxng: container_name: svc-searxng hostname: svc-searxng - image: docker.io/labnow/searxng:latest + image: quay.io/labnow/searxng:latest restart: unless-stopped networks: ["net-searxng"] ports: @@ -13,8 +13,6 @@ services: volumes: - ./searxng/settings.yml:/etc/searxng/settings.yml:rw # - ./searxng/limiter.toml:/etc/searxng/limiter.toml:rw - # - ./searxng/Caddyfile:/etc/searxng/Caddyfile:rw - # - ./searxng/supervisord.conf:/etc/searxng/supervisord.conf:rw environment: - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost:8000}/ - SEARXNG_HOSTNAME=${SEARXNG_HOSTNAME:-http://localhost:8000} @@ -22,7 +20,6 @@ services: - UWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4} - UWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4} # user: root - # command: ["/opt/searxng/start-supervisord.sh"] # command: ["tail", "-f", "/dev/null"] # cap_drop: ["ALL"] # cap_add: ["AUDIT_WRITE", "CHOWN", "SETGID", "SETUID", "NET_BIND_SERVICE"] @@ -33,7 +30,7 @@ services: max-file: "1" svc-clash: - image: docker.io/labnow/clash + image: quay.io/labnow/clash container_name: svc-clash hostname: svc-clash restart: unless-stopped @@ -47,5 +44,3 @@ services: - "9090:9090" # volumes: # - ./clash/config.yaml:/opt/clash/config/config.yaml - environment: - - PROXY_PROVIDER="https://subs.zeabur.app/clash" From c8ed5d6da675379b2abf434150ab7bcea497762e Mon Sep 17 00:00:00 2001 From: Bibo Hao Date: Sat, 20 Jun 2026 04:19:28 +0800 Subject: [PATCH 04/11] update hermes install script --- docker_hermes/hermes.Dockerfile | 164 +++++---------------- docker_hermes/work/install_list_hermes.apt | 10 ++ docker_hermes/work/start-hermes.sh | 161 ++++++++++++++++++++ 3 files changed, 207 insertions(+), 128 deletions(-) create mode 100644 docker_hermes/work/install_list_hermes.apt create mode 100644 docker_hermes/work/start-hermes.sh diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile index 31a0dde..976f095 100644 --- a/docker_hermes/hermes.Dockerfile +++ b/docker_hermes/hermes.Dockerfile @@ -1,141 +1,49 @@ # Distributed under the terms of the Modified BSD License. -# Multi-stage Dockerfile for Hermes Agent -# Stage 1: Clone hermes-agent from GitHub -FROM debian:13.4 AS hermes_source +ARG BASE_NAMESPACE +ARG BASE_IMG="node" ARG HERMES_GIT_REF=main ARG HERMES_REPO_URL=https://github.com/nousresearch/hermes-agent.git -WORKDIR /src -RUN apt-get update && apt-get install -y --no-install-recommends git ca-certificates curl && rm -rf /var/lib/apt/lists/* -RUN git clone --depth 1 --branch "${HERMES_GIT_REF}" "${HERMES_REPO_URL}" . - -# Stage 2: Full build -FROM ghcr.io/astral-sh/uv:0.11.6-python3.13-trixie@sha256:b3c543b6c4f23a5f2df22866bd7857e5d304b67a564f4feab6ac22044dde719b AS uv_source -FROM node:22-bookworm-slim@sha256:7af03b14a13c8cdd38e45058fd957bf00a72bbe17feac43b1c15a689c029c732 AS node_source -FROM debian:13.4 +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} LABEL maintainer="postmaster@labnow.ai" - -# Disable Python stdout buffering to ensure logs are printed immediately -ENV PYTHONUNBUFFERED=1 - -# Store Playwright browsers outside the volume mount so the build-time -# install survives the /opt/data volume overlay at runtime. -ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright - -# Install system dependencies in one layer, clear APT cache. -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates curl iputils-ping python3 python-is-python3 ripgrep ffmpeg gcc g++ make cmake python3-dev python3-venv libffi-dev libolm-dev procps git openssh-client docker-cli xz-utils && \ - rm -rf /var/lib/apt/lists/* - -# ---------- s6-overlay install ---------- -ARG TARGETARCH -ARG S6_OVERLAY_VERSION=3.2.3.0 -ARG S6_OVERLAY_NOARCH_SHA256=b720f9d9340efc8bb07528b9743813c836e4b02f8693d90241f047998b4c53cf -ARG S6_OVERLAY_X86_64_SHA256=a93f02882c6ed46b21e7adb5c0add86154f01236c93cd82c7d682722e8840563 -ARG S6_OVERLAY_AARCH64_SHA256=0952056ff913482163cc30e35b2e944b507ba1025d78f5becbb89367bf344581 -ARG S6_OVERLAY_SYMLINKS_SHA256=a60dc5235de3ecbcf874b9c1f18d73263ab99b289b9329aa950e8729c4789f0e -ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp/ -ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz /tmp/ -RUN set -eu; \ - case "${TARGETARCH:-amd64}" in \ - amd64) s6_arch="x86_64"; s6_arch_sha="${S6_OVERLAY_X86_64_SHA256}" ;; \ - arm64) s6_arch="aarch64"; s6_arch_sha="${S6_OVERLAY_AARCH64_SHA256}" ;; \ - *) echo "Unsupported TARGETARCH=${TARGETARCH} for s6-overlay" >&2; exit 1 ;; \ - esac; \ - curl -fsSL --retry 3 -o /tmp/s6-overlay-arch.tar.xz \ - "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${s6_arch}.tar.xz"; \ - { \ - printf '%s %s\n' "${S6_OVERLAY_NOARCH_SHA256}" /tmp/s6-overlay-noarch.tar.xz; \ - printf '%s %s\n' "${s6_arch_sha}" /tmp/s6-overlay-arch.tar.xz; \ - printf '%s %s\n' "${S6_OVERLAY_SYMLINKS_SHA256}" /tmp/s6-overlay-symlinks-noarch.tar.xz; \ - } > /tmp/s6-overlay.sha256; \ - sha256sum -c /tmp/s6-overlay.sha256; \ - tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz; \ - tar -C / -Jxpf /tmp/s6-overlay-arch.tar.xz; \ - tar -C / -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz; \ - rm /tmp/s6-overlay-*.tar.xz /tmp/s6-overlay.sha256; \ - ln -sf /init /usr/bin/tini - -# Non-root user for runtime; UID can be overridden via HERMES_UID at runtime -RUN useradd -u 10000 -m -d /opt/data hermes - -COPY --chmod=0755 --from=uv_source /usr/local/bin/uv /usr/local/bin/uvx /usr/local/bin/ - -# Node 22 LTS -COPY --chmod=0755 --from=node_source /usr/local/bin/node /usr/local/bin/ -COPY --from=node_source /usr/local/lib/node_modules/npm /usr/local/lib/node_modules/npm -COPY --from=node_source /usr/local/lib/node_modules/corepack /usr/local/lib/node_modules/corepack -RUN ln -sf /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \ - ln -sf /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \ - ln -sf /usr/local/lib/node_modules/corepack/dist/corepack.js /usr/local/bin/corepack - -WORKDIR /opt/hermes - -# Copy source from cloned repo -COPY --from=hermes_source /src /opt/hermes - -# Layer-cached dependency install -COPY package.json package-lock.json ./ -COPY web/package.json web/ -COPY ui-tui/package.json ui-tui/ -COPY ui-tui/packages/hermes-ink/ ui-tui/packages/hermes-ink/ - -ENV npm_config_install_links=false - -RUN npm install --prefer-offline --no-audit && \ - npx playwright install --with-deps chromium --only-shell && \ - npm cache clean --force - -# Python dependency install -COPY pyproject.toml uv.lock ./ -RUN touch ./README.md && \ - uv sync --frozen --no-install-project --extra all --extra messaging --extra anthropic --extra bedrock --extra azure-identity --extra hindsight --extra matrix - -# Frontend build -COPY web/ web/ -COPY ui-tui/ ui-tui/ -RUN cd web && npm run build && \ - cd ../ui-tui && npm run build - -# Permissions -USER root -RUN chmod -R a+rX /opt/hermes && \ - chown -R hermes:hermes /opt/hermes/.venv /opt/hermes/ui-tui /opt/hermes/gateway /opt/hermes/node_modules - -# Link hermes-agent itself (editable) -RUN uv pip install --no-cache-dir --no-deps -e "." - -# Bake build-time git revision -ARG HERMES_GIT_SHA= -RUN if [ -n "${HERMES_GIT_SHA}" ]; then \ - printf '%s\n' "${HERMES_GIT_SHA}" > /opt/hermes/.hermes_build_sha && \ - chown hermes:hermes /opt/hermes/.hermes_build_sha; \ - fi - -# s6-overlay service wiring -COPY docker/s6-rc.d/ /etc/s6-overlay/s6-rc.d/ - -RUN mkdir -p /etc/cont-init.d && \ - printf '#!/command/with-contenv sh\nexec /opt/hermes/docker/stage2-hook.sh\n' \ - > /etc/cont-init.d/01-hermes-setup && \ - chmod +x /etc/cont-init.d/01-hermes-setup -COPY --chmod=0755 docker/cont-init.d/015-supervise-perms /etc/cont-init.d/015-supervise-perms -COPY --chmod=0755 docker/cont-init.d/02-reconcile-profiles /etc/cont-init.d/02-reconcile-profiles - -# Runtime +ENV NODE_ENV=production +ENV PNPM_HOME=/opt/node/pnpm +ENV PNPM_STORE=/opt/node/pnpm/store +ENV HERMES_HOME=/opt/hermes +ENV HERMES_HOME=/opt/data ENV HERMES_WEB_DIST=/opt/hermes/hermes_cli/web_dist ENV HERMES_TUI_DIR=/opt/hermes/ui-tui -ENV HERMES_HOME=/opt/data -COPY --chmod=0755 docker/hermes-exec-shim.sh /opt/hermes/bin/hermes -ENV PATH="/opt/hermes/bin:/opt/hermes/.venv/bin:/opt/data/.local/bin:${PATH}" -RUN mkdir -p /opt/data -VOLUME [ "/opt/data" ] +ENV PATH="${PNPM_HOME}:${HERMES_HOME}/bin:${PATH}" +ENV HOME=/opt/hermes + +# Store Playwright browsers outside the volume mount so the build-time install survives the /opt/data volume overlay at runtime. +ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright -ENTRYPOINT [ "/init", "/opt/hermes/docker/main-wrapper.sh" ] -CMD [ ] +COPY work /opt/utils/ + +RUN set -eux \ + && git clone --depth 1 --branch "${HERMES_GIT_REF}" "${HERMES_REPO_URL}" . \ + && mv /opt/utils/start-hermes.sh /opt/hermes/ && chmod +x /opt/hermes/start-hermes.sh \ + && ln -sf /opt/hermes/start-hermes.sh /usr/local/bin/ \ + ## Install Node dependencies + && export npm_config_install_links=false \ + && npm install --prefer-offline --no-audit \ + && npx playwright install --with-deps chromium --only-shell \ + && npm cache clean --force \ + ## Frontend build + && cd web && npm run build && cd ../ui-tui && npm run build \ + ## Python dependency install + && uv sync --frozen --no-install-project --extra all --extra messaging --extra anthropic --extra bedrock --extra azure-identity --extra hindsight --extra matrix \ + ## Link hermes-agent itself (editable) + && uv pip install --no-cache-dir --no-deps -e "." \ + ## Install supervisord (Go version) + && source /opt/utils/script-setup-sys.sh && setup_supervisord \ + && /opt/utils/script-utils.sh && install_apt /opt/utils/install_list_hermes.apt \ + && install__clean + +CMD start-hermes.sh diff --git a/docker_hermes/work/install_list_hermes.apt b/docker_hermes/work/install_list_hermes.apt new file mode 100644 index 0000000..c7f60fd --- /dev/null +++ b/docker_hermes/work/install_list_hermes.apt @@ -0,0 +1,10 @@ +iputils-ping +ripgrep +ffmpeg +libffi-dev +libolm-dev +procps +openssh-client +docker-cli +xz-utils +gosu diff --git a/docker_hermes/work/start-hermes.sh b/docker_hermes/work/start-hermes.sh new file mode 100644 index 0000000..3dea75e --- /dev/null +++ b/docker_hermes/work/start-hermes.sh @@ -0,0 +1,161 @@ +#!/bin/bash +set -e + +# Support user/group remapping +HERMES_UID="${HERMES_UID:-${PUID:-}}" +HERMES_GID="${HERMES_GID:-${PGID:-}}" + +if [ -n "$HERMES_UID" ] && [ "$HERMES_UID" != "$(id -u hermes)" ]; then + echo "[start-hermes] Changing hermes UID to $HERMES_UID" + usermod -u "$HERMES_UID" hermes +fi +if [ -n "$HERMES_GID" ] && [ "$HERMES_GID" != "$(id -g hermes)" ]; then + echo "[start-hermes] Changing hermes GID to $HERMES_GID" + groupmod -o -g "$HERMES_GID" hermes 2>/dev/null || true +fi + +# Setup data directory +HERMES_HOME="${HERMES_HOME:-/opt/data}" +mkdir -p "$HERMES_HOME" + +# targeted chown and directory creation +chown hermes:hermes "$HERMES_HOME" 2>/dev/null || true +for sub in cron sessions logs hooks memories skills skins plans workspace home pairing platforms/pairing logs/gateways; do + mkdir -p "$HERMES_HOME/$sub" + chown -R hermes:hermes "$HERMES_HOME/$sub" 2>/dev/null || true +done + +# Reset ownership of hermes-owned top-level state files / profiles / cron +if [ -d "$HERMES_HOME/profiles" ]; then + chown -R hermes:hermes "$HERMES_HOME/profiles" 2>/dev/null || true +fi +if [ -d "$HERMES_HOME/cron" ]; then + chown -R hermes:hermes "$HERMES_HOME/cron" 2>/dev/null || true +fi +for f in auth.json auth.lock .env state.db state.db-shm state.db-wal hermes_state.db response_store.db response_store.db-shm response_store.db-wal gateway.pid gateway.lock gateway_state.json processes.json active_profile; do + if [ -e "$HERMES_HOME/$f" ]; then + chown hermes:hermes "$HERMES_HOME/$f" 2>/dev/null || true + fi +done +if [ -f "$HERMES_HOME/config.yaml" ]; then + chown hermes:hermes "$HERMES_HOME/config.yaml" 2>/dev/null || true + chmod 640 "$HERMES_HOME/config.yaml" 2>/dev/null || true +fi + +# Seed initial config files +seed_one() { + dest=$1 + src=$2 + if [ ! -f "$HERMES_HOME/$dest" ] && [ -f "/opt/hermes/$src" ]; then + cp "/opt/hermes/$src" "$HERMES_HOME/$dest" + chown hermes:hermes "$HERMES_HOME/$dest" 2>/dev/null || true + fi +} +seed_one ".env" ".env.example" +seed_one "config.yaml" "cli-config.yaml.example" +seed_one "SOUL.md" "docker/SOUL.md" + +if [ -f "$HERMES_HOME/.env" ]; then + chmod 600 "$HERMES_HOME/.env" 2>/dev/null || true +fi + +# Run schema migration +if [ -f "$HERMES_HOME/config.yaml" ]; then + gosu hermes "/opt/hermes/.venv/bin/python" "/opt/hermes/scripts/docker_config_migrate.py" || true +fi + +# Seed bootstrap auth.json and gateway_state.json +if [ ! -f "$HERMES_HOME/auth.json" ] && [ -n "${HERMES_AUTH_JSON_BOOTSTRAP:-}" ]; then + printf '%s' "$HERMES_AUTH_JSON_BOOTSTRAP" > "$HERMES_HOME/auth.json" + chown hermes:hermes "$HERMES_HOME/auth.json" 2>/dev/null || true + chmod 600 "$HERMES_HOME/auth.json" +fi +if [ ! -f "$HERMES_HOME/gateway_state.json" ] && [ "${HERMES_GATEWAY_BOOTSTRAP_STATE:-}" = "running" ]; then + printf '{"gateway_state":"running"}\n' > "$HERMES_HOME/gateway_state.json" + chown hermes:hermes "$HERMES_HOME/gateway_state.json" 2>/dev/null || true + chmod 644 "$HERMES_HOME/gateway_state.json" +fi + +# Sync bundled skills +if [ -d "/opt/hermes/skills" ]; then + gosu hermes "/opt/hermes/.venv/bin/python" "/opt/hermes/tools/skills_sync.py" || true +fi + +# Find agent-browser Playwright binary and set env +if [ -z "${AGENT_BROWSER_EXECUTABLE_PATH:-}" ] && [ -n "${PLAYWRIGHT_BROWSERS_PATH:-}" ] && [ -d "$PLAYWRIGHT_BROWSERS_PATH" ]; then + browser_bin=$(find "$PLAYWRIGHT_BROWSERS_PATH" -type f -executable \( -name 'chrome' -o -name 'chromium' -o -name 'chrome-headless-shell' -o -name 'headless_shell' -o -name 'chromium-browser' \) 2>/dev/null | head -n 1) + if [ -n "$browser_bin" ]; then + export AGENT_BROWSER_EXECUTABLE_PATH="$browser_bin" + echo "[start-hermes] Set AGENT_BROWSER_EXECUTABLE_PATH=$browser_bin" + fi +fi + +# Configure environments for command invocation +export HOME=/opt/data +cd /opt/data + +# If arguments are passed, route them +if [ $# -gt 0 ]; then + # If the first argument is an executable in PATH, execute it directly (e.g. bash, sh, sleep) + if command -v "$1" >/dev/null 2>&1; then + if [ "$(id -u)" = 0 ] && [ "${HERMES_DOCKER_EXEC_AS_ROOT:-}" != "1" ] && [ "$1" != "bash" ] && [ "$1" != "sh" ]; then + exec gosu hermes "$@" + else + exec "$@" + fi + else + # Otherwise, pass to hermes CLI + if [ "$(id -u)" = 0 ] && [ "${HERMES_DOCKER_EXEC_AS_ROOT:-}" != "1" ]; then + exec gosu hermes hermes "$@" + else + exec hermes "$@" + fi + fi +fi + +# No arguments: start supervisord to run both gateway and dashboard (if requested) +# Set up dashboard parameters +dash_host="${HERMES_DASHBOARD_HOST:-0.0.0.0}" +dash_port="${HERMES_DASHBOARD_PORT:-9119}" + +insecure="" +case "${HERMES_DASHBOARD_INSECURE:-}" in + 1|true|TRUE|True|yes|YES|Yes) insecure="--insecure" ;; +esac + +dashboard_autostart="false" +case "${HERMES_DASHBOARD:-}" in + 1|true|TRUE|True|yes|YES|Yes) dashboard_autostart="true" ;; +esac + +# Generate /etc/supervisord.conf +cat < /etc/supervisord.conf +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:gateway] +command=gosu hermes hermes gateway run --replace +directory=/opt/data +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 + +[program:dashboard] +command=gosu hermes hermes dashboard --host ${dash_host} --port ${dash_port} --no-open ${insecure} +directory=/opt/data +autostart=${dashboard_autostart} +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 +EOF + +echo "[start-hermes] Starting supervisord..." +exec supervisord -c /etc/supervisord.conf From 40da6e273d66216671691cccacf1311833214dca Mon Sep 17 00:00:00 2001 From: Bibo Hao Date: Sat, 20 Jun 2026 04:22:49 +0800 Subject: [PATCH 05/11] fix arg env --- docker_hermes/hermes.Dockerfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile index 976f095..b0c68d8 100644 --- a/docker_hermes/hermes.Dockerfile +++ b/docker_hermes/hermes.Dockerfile @@ -3,9 +3,6 @@ ARG BASE_NAMESPACE ARG BASE_IMG="node" -ARG HERMES_GIT_REF=main -ARG HERMES_REPO_URL=https://github.com/nousresearch/hermes-agent.git - FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} LABEL maintainer="postmaster@labnow.ai" @@ -17,7 +14,6 @@ ENV HERMES_HOME=/opt/data ENV HERMES_WEB_DIST=/opt/hermes/hermes_cli/web_dist ENV HERMES_TUI_DIR=/opt/hermes/ui-tui - ENV PATH="${PNPM_HOME}:${HERMES_HOME}/bin:${PATH}" ENV HOME=/opt/hermes @@ -27,7 +23,7 @@ ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright COPY work /opt/utils/ RUN set -eux \ - && git clone --depth 1 --branch "${HERMES_GIT_REF}" "${HERMES_REPO_URL}" . \ + && git clone --depth 1 --branch main https://github.com/nousresearch/hermes-agent.git . \ && mv /opt/utils/start-hermes.sh /opt/hermes/ && chmod +x /opt/hermes/start-hermes.sh \ && ln -sf /opt/hermes/start-hermes.sh /usr/local/bin/ \ ## Install Node dependencies From c63c1c9289a5968dca211f18345740131ff258a8 Mon Sep 17 00:00:00 2001 From: Bibo Hao Date: Sat, 20 Jun 2026 04:34:35 +0800 Subject: [PATCH 06/11] debug build hermes --- docker_hermes/demo/docker-compose.yml | 26 +---- docker_hermes/hermes.Dockerfile | 17 ++-- docker_hermes/work/install_list_hermes.apt | 1 - docker_hermes/work/start-hermes.sh | 106 ++------------------- docker_hermes/work/supervisord.sh | 49 ++++++++++ 5 files changed, 70 insertions(+), 129 deletions(-) create mode 100644 docker_hermes/work/supervisord.sh diff --git a/docker_hermes/demo/docker-compose.yml b/docker_hermes/demo/docker-compose.yml index 881537c..b095988 100644 --- a/docker_hermes/demo/docker-compose.yml +++ b/docker_hermes/demo/docker-compose.yml @@ -1,34 +1,16 @@ name: "svc-hermes" services: - hermes-gateway: - container_name: svc-hermes-gateway - hostname: svc-hermes-gateway + hermes: + container_name: svc-hermes + hostname: svc-hermes image: "quay.io/labnow/hermes:latest" pull_policy: if_not_present restart: unless-stopped network_mode: host environment: - TZ=Asia/Shanghai - - HERMES_UID=10000 - - HERMES_GID=10000 + - HERMES_DASHBOARD=true # Set to true to start the dashboard alongside the gateway volumes: - /data/hermes:/opt/data - # command: ["tail", "-f", "/dev/null"] - hermes-dashboard: - container_name: svc-hermes-dashboard - hostname: svc-hermes-dashboard - image: "quay.io/labnow/hermes:latest" - pull_policy: if_not_present - restart: unless-stopped - network_mode: host - depends_on: - - hermes-gateway - environment: - - TZ=Asia/Shanghai - - HERMES_UID=10000 - - HERMES_GID=10000 - volumes: - - /data/hermes:/opt/data - command: ["dashboard", "--host", "127.0.0.1", "--no-open"] diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile index b0c68d8..99bbf41 100644 --- a/docker_hermes/hermes.Dockerfile +++ b/docker_hermes/hermes.Dockerfile @@ -9,22 +9,21 @@ LABEL maintainer="postmaster@labnow.ai" ENV NODE_ENV=production ENV PNPM_HOME=/opt/node/pnpm ENV PNPM_STORE=/opt/node/pnpm/store -ENV HERMES_HOME=/opt/hermes ENV HERMES_HOME=/opt/data ENV HERMES_WEB_DIST=/opt/hermes/hermes_cli/web_dist ENV HERMES_TUI_DIR=/opt/hermes/ui-tui -ENV PATH="${PNPM_HOME}:${HERMES_HOME}/bin:${PATH}" -ENV HOME=/opt/hermes - -# Store Playwright browsers outside the volume mount so the build-time install survives the /opt/data volume overlay at runtime. +ENV PATH="/opt/node/bin:${PNPM_HOME}:/opt/conda/bin:/opt/hermes/.venv/bin:/opt/data/.local/bin:${PATH}" +ENV HOME=/opt/data ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright +WORKDIR /opt/hermes + COPY work /opt/utils/ RUN set -eux \ && git clone --depth 1 --branch main https://github.com/nousresearch/hermes-agent.git . \ - && mv /opt/utils/start-hermes.sh /opt/hermes/ && chmod +x /opt/hermes/start-hermes.sh \ + && chmod +x /opt/utils/*.sh && mv /opt/utils/start-hermes.sh ./ \ && ln -sf /opt/hermes/start-hermes.sh /usr/local/bin/ \ ## Install Node dependencies && export npm_config_install_links=false \ @@ -32,14 +31,14 @@ RUN set -eux \ && npx playwright install --with-deps chromium --only-shell \ && npm cache clean --force \ ## Frontend build - && cd web && npm run build && cd ../ui-tui && npm run build \ + && (cd web && npm run build) && (cd ui-tui && npm run build) \ ## Python dependency install && uv sync --frozen --no-install-project --extra all --extra messaging --extra anthropic --extra bedrock --extra azure-identity --extra hindsight --extra matrix \ ## Link hermes-agent itself (editable) && uv pip install --no-cache-dir --no-deps -e "." \ ## Install supervisord (Go version) && source /opt/utils/script-setup-sys.sh && setup_supervisord \ - && /opt/utils/script-utils.sh && install_apt /opt/utils/install_list_hermes.apt \ + && source /opt/utils/script-utils.sh && install_apt /opt/utils/install_list_hermes.apt \ && install__clean -CMD start-hermes.sh +CMD ["start-hermes.sh"] diff --git a/docker_hermes/work/install_list_hermes.apt b/docker_hermes/work/install_list_hermes.apt index c7f60fd..48ac66a 100644 --- a/docker_hermes/work/install_list_hermes.apt +++ b/docker_hermes/work/install_list_hermes.apt @@ -7,4 +7,3 @@ procps openssh-client docker-cli xz-utils -gosu diff --git a/docker_hermes/work/start-hermes.sh b/docker_hermes/work/start-hermes.sh index 3dea75e..afc377a 100644 --- a/docker_hermes/work/start-hermes.sh +++ b/docker_hermes/work/start-hermes.sh @@ -1,54 +1,20 @@ -#!/bin/bash -set -e - -# Support user/group remapping -HERMES_UID="${HERMES_UID:-${PUID:-}}" -HERMES_GID="${HERMES_GID:-${PGID:-}}" - -if [ -n "$HERMES_UID" ] && [ "$HERMES_UID" != "$(id -u hermes)" ]; then - echo "[start-hermes] Changing hermes UID to $HERMES_UID" - usermod -u "$HERMES_UID" hermes -fi -if [ -n "$HERMES_GID" ] && [ "$HERMES_GID" != "$(id -g hermes)" ]; then - echo "[start-hermes] Changing hermes GID to $HERMES_GID" - groupmod -o -g "$HERMES_GID" hermes 2>/dev/null || true -fi +#!/usr/bin/env bash +set -eu # Setup data directory HERMES_HOME="${HERMES_HOME:-/opt/data}" mkdir -p "$HERMES_HOME" -# targeted chown and directory creation -chown hermes:hermes "$HERMES_HOME" 2>/dev/null || true for sub in cron sessions logs hooks memories skills skins plans workspace home pairing platforms/pairing logs/gateways; do mkdir -p "$HERMES_HOME/$sub" - chown -R hermes:hermes "$HERMES_HOME/$sub" 2>/dev/null || true done -# Reset ownership of hermes-owned top-level state files / profiles / cron -if [ -d "$HERMES_HOME/profiles" ]; then - chown -R hermes:hermes "$HERMES_HOME/profiles" 2>/dev/null || true -fi -if [ -d "$HERMES_HOME/cron" ]; then - chown -R hermes:hermes "$HERMES_HOME/cron" 2>/dev/null || true -fi -for f in auth.json auth.lock .env state.db state.db-shm state.db-wal hermes_state.db response_store.db response_store.db-shm response_store.db-wal gateway.pid gateway.lock gateway_state.json processes.json active_profile; do - if [ -e "$HERMES_HOME/$f" ]; then - chown hermes:hermes "$HERMES_HOME/$f" 2>/dev/null || true - fi -done -if [ -f "$HERMES_HOME/config.yaml" ]; then - chown hermes:hermes "$HERMES_HOME/config.yaml" 2>/dev/null || true - chmod 640 "$HERMES_HOME/config.yaml" 2>/dev/null || true -fi - # Seed initial config files seed_one() { - dest=$1 - src=$2 + local dest=$1 + local src=$2 if [ ! -f "$HERMES_HOME/$dest" ] && [ -f "/opt/hermes/$src" ]; then cp "/opt/hermes/$src" "$HERMES_HOME/$dest" - chown hermes:hermes "$HERMES_HOME/$dest" 2>/dev/null || true fi } seed_one ".env" ".env.example" @@ -61,24 +27,22 @@ fi # Run schema migration if [ -f "$HERMES_HOME/config.yaml" ]; then - gosu hermes "/opt/hermes/.venv/bin/python" "/opt/hermes/scripts/docker_config_migrate.py" || true + "/opt/hermes/.venv/bin/python" "/opt/hermes/scripts/docker_config_migrate.py" || true fi # Seed bootstrap auth.json and gateway_state.json if [ ! -f "$HERMES_HOME/auth.json" ] && [ -n "${HERMES_AUTH_JSON_BOOTSTRAP:-}" ]; then printf '%s' "$HERMES_AUTH_JSON_BOOTSTRAP" > "$HERMES_HOME/auth.json" - chown hermes:hermes "$HERMES_HOME/auth.json" 2>/dev/null || true chmod 600 "$HERMES_HOME/auth.json" fi if [ ! -f "$HERMES_HOME/gateway_state.json" ] && [ "${HERMES_GATEWAY_BOOTSTRAP_STATE:-}" = "running" ]; then printf '{"gateway_state":"running"}\n' > "$HERMES_HOME/gateway_state.json" - chown hermes:hermes "$HERMES_HOME/gateway_state.json" 2>/dev/null || true chmod 644 "$HERMES_HOME/gateway_state.json" fi # Sync bundled skills if [ -d "/opt/hermes/skills" ]; then - gosu hermes "/opt/hermes/.venv/bin/python" "/opt/hermes/tools/skills_sync.py" || true + "/opt/hermes/.venv/bin/python" "/opt/hermes/tools/skills_sync.py" || true fi # Find agent-browser Playwright binary and set env @@ -98,64 +62,12 @@ cd /opt/data if [ $# -gt 0 ]; then # If the first argument is an executable in PATH, execute it directly (e.g. bash, sh, sleep) if command -v "$1" >/dev/null 2>&1; then - if [ "$(id -u)" = 0 ] && [ "${HERMES_DOCKER_EXEC_AS_ROOT:-}" != "1" ] && [ "$1" != "bash" ] && [ "$1" != "sh" ]; then - exec gosu hermes "$@" - else - exec "$@" - fi + exec "$@" else # Otherwise, pass to hermes CLI - if [ "$(id -u)" = 0 ] && [ "${HERMES_DOCKER_EXEC_AS_ROOT:-}" != "1" ]; then - exec gosu hermes hermes "$@" - else - exec hermes "$@" - fi + exec hermes "$@" fi fi # No arguments: start supervisord to run both gateway and dashboard (if requested) -# Set up dashboard parameters -dash_host="${HERMES_DASHBOARD_HOST:-0.0.0.0}" -dash_port="${HERMES_DASHBOARD_PORT:-9119}" - -insecure="" -case "${HERMES_DASHBOARD_INSECURE:-}" in - 1|true|TRUE|True|yes|YES|Yes) insecure="--insecure" ;; -esac - -dashboard_autostart="false" -case "${HERMES_DASHBOARD:-}" in - 1|true|TRUE|True|yes|YES|Yes) dashboard_autostart="true" ;; -esac - -# Generate /etc/supervisord.conf -cat < /etc/supervisord.conf -[supervisord] -nodaemon=true -user=root -logfile=/var/log/supervisord.log -pidfile=/var/run/supervisord.pid - -[program:gateway] -command=gosu hermes hermes gateway run --replace -directory=/opt/data -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -stdout_logfile_maxbytes=0 -stderr_logfile_maxbytes=0 - -[program:dashboard] -command=gosu hermes hermes dashboard --host ${dash_host} --port ${dash_port} --no-open ${insecure} -directory=/opt/data -autostart=${dashboard_autostart} -autorestart=true -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -stdout_logfile_maxbytes=0 -stderr_logfile_maxbytes=0 -EOF - -echo "[start-hermes] Starting supervisord..." -exec supervisord -c /etc/supervisord.conf +exec /opt/utils/supervisord.sh diff --git a/docker_hermes/work/supervisord.sh b/docker_hermes/work/supervisord.sh new file mode 100644 index 0000000..601b51d --- /dev/null +++ b/docker_hermes/work/supervisord.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Generate /etc/supervisord.conf dynamically and run supervisord +set -eu + +# Set up dashboard parameters +dash_host="${HERMES_DASHBOARD_HOST:-0.0.0.0}" +dash_port="${HERMES_DASHBOARD_PORT:-9119}" + +insecure="" +case "${HERMES_DASHBOARD_INSECURE:-}" in + 1|true|TRUE|True|yes|YES|Yes) insecure="--insecure" ;; +esac + +dashboard_autostart="false" +case "${HERMES_DASHBOARD:-}" in + 1|true|TRUE|True|yes|YES|Yes) dashboard_autostart="true" ;; +esac + +# Generate /etc/supervisord.conf +cat < /etc/supervisord.conf +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisord.log +pidfile=/var/run/supervisord.pid + +[program:gateway] +command=exec hermes gateway run --replace +directory=/opt/data +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 + +[program:dashboard] +command=exec hermes dashboard --host ${dash_host} --port ${dash_port} --no-open ${insecure} +directory=/opt/data +autostart=${dashboard_autostart} +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 +EOF + +echo "[start-hermes] Starting supervisord..." +exec supervisord -c /etc/supervisord.conf From c376252ddd4af4cff04e6458b7cb55e8d97e547f Mon Sep 17 00:00:00 2001 From: haobibo <1.59735e+06+haobibo@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:17:56 +0000 Subject: [PATCH 07/11] fix(docker): install devDependencies for frontend build --- docker_hermes/hermes.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile index 99bbf41..4a21341 100644 --- a/docker_hermes/hermes.Dockerfile +++ b/docker_hermes/hermes.Dockerfile @@ -27,7 +27,7 @@ RUN set -eux \ && ln -sf /opt/hermes/start-hermes.sh /usr/local/bin/ \ ## Install Node dependencies && export npm_config_install_links=false \ - && npm install --prefer-offline --no-audit \ + && npm install --include=dev --prefer-offline --no-audit \ && npx playwright install --with-deps chromium --only-shell \ && npm cache clean --force \ ## Frontend build From f77b8c3465dae2095cd4bbba1af3e84c24ebf89e Mon Sep 17 00:00:00 2001 From: haobibo <1.59735e+06+haobibo@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:31:11 +0000 Subject: [PATCH 08/11] feat(docker): optimize with multi-stage build and update persistence path --- docker_hermes/README.md | 46 ++++++++------------ docker_hermes/hermes.Dockerfile | 70 ++++++++++++++++++++---------- docker_hermes/work/start-hermes.sh | 10 ++--- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/docker_hermes/README.md b/docker_hermes/README.md index dffddef..1ecc71c 100644 --- a/docker_hermes/README.md +++ b/docker_hermes/README.md @@ -2,6 +2,12 @@ This directory contains the Dockerfile for building the [Hermes Agent](https://github.com/nousresearch/hermes-agent) Docker image. +## Optimization Features + +- **Multi-stage Build**: Significantly reduces image size by separating the build environment from the runtime environment. +- **Persistent Storage**: All user data, configurations, and logs are stored in `/root/workspace`. +- **Runtime Environment**: Uses the base Python environment instead of a virtual environment for simplicity and efficiency. + ## Quick Start ### Build Image @@ -20,49 +26,33 @@ docker compose up -d ### Run Manually ```bash -# Run gateway -docker run -d \ - --name hermes-gateway \ - --hostname hermes-gateway \ - --network host \ - -v /data/hermes:/opt/data \ - -e HERMES_UID=10000 \ - -e HERMES_GID=10000 \ - quay.io/labnow/hermes:latest \ - gateway run - -# Run dashboard (separate container) +# Run with persistent volume docker run -d \ - --name hermes-dashboard \ - --hostname hermes-dashboard \ - --network host \ - -v /data/hermes:/opt/data \ - -e HERMES_UID=10000 \ - -e HERMES_GID=10000 \ - quay.io/labnow/hermes:latest \ - dashboard --host 127.0.0.1 --no-open + --name hermes \ + --hostname hermes \ + -p 8000:8000 \ + -v /path/to/your/data:/root/workspace \ + hermes-agent:latest ``` ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| HERMES_UID | 10000 | UID for the hermes user | -| HERMES_GID | 10000 | GID for the hermes user | -| HERMES_HOME | /opt/data | Home directory for hermes data | -| PLAYWRIGHT_BROWSERS_PATH | /opt/hermes/.playwright | Path for Playwright browsers | +| HERMES_HOME | `/root/workspace` | Home directory for hermes data | +| HOME | `/root/workspace` | System HOME environment variable | +| PLAYWRIGHT_BROWSERS_PATH | `/opt/hermes/.playwright` | Path for Playwright browsers | ## Volumes -- `/opt/data` - Persistent data directory for hermes configuration, memories, and skills +- `/root/workspace` - Persistent data directory for hermes configuration, memories, and skills. This should be mapped to a host directory for data persistence. ## Build Arguments | Argument | Default | Description | |----------|---------|-------------| -| HERMES_GIT_REF | main | Git branch/tag to clone | -| HERMES_REPO_URL | https://github.com/nousresearch/hermes-agent.git | Git repository URL | -| HERMES_GIT_SHA | (empty) | Git commit SHA for build info | +| BASE_NAMESPACE | (empty) | Namespace for the base image | +| BASE_IMG | `node` | Base image name (expected to have Node and Python) | ## Documentation diff --git a/docker_hermes/hermes.Dockerfile b/docker_hermes/hermes.Dockerfile index 4a21341..51fcfc0 100644 --- a/docker_hermes/hermes.Dockerfile +++ b/docker_hermes/hermes.Dockerfile @@ -3,42 +3,64 @@ ARG BASE_NAMESPACE ARG BASE_IMG="node" +# --- Building Stage --- +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} AS builder + +LABEL maintainer="postmaster@labnow.ai" + +# Build-time environment +ENV NODE_ENV=development +WORKDIR /build + +# Clone source +RUN git clone --depth 1 --branch main https://github.com/nousresearch/hermes-agent.git . + +# Install Node dependencies and build frontend +RUN set -eux \ + && export npm_config_install_links=false \ + && npm install --include=dev --prefer-offline --no-audit \ + && (cd web && npm run build) \ + && (cd ui-tui && npm run build) \ + && mkdir -p hermes_cli/tui_dist && cp ui-tui/dist/entry.js hermes_cli/tui_dist/ + +# Build Python wheel +RUN set -eux \ + && python3 -m pip install --upgrade pip build \ + && python3 -m build --wheel --outdir dist + +# --- Runtime Stage --- FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} LABEL maintainer="postmaster@labnow.ai" + +# Production environment ENV NODE_ENV=production -ENV PNPM_HOME=/opt/node/pnpm -ENV PNPM_STORE=/opt/node/pnpm/store -ENV HERMES_HOME=/opt/data -ENV HERMES_WEB_DIST=/opt/hermes/hermes_cli/web_dist -ENV HERMES_TUI_DIR=/opt/hermes/ui-tui - -ENV PATH="/opt/node/bin:${PNPM_HOME}:/opt/conda/bin:/opt/hermes/.venv/bin:/opt/data/.local/bin:${PATH}" -ENV HOME=/opt/data +ENV HERMES_HOME=/root/workspace +ENV HERMES_WEB_DIST=/usr/local/lib/python3.12/dist-packages/hermes_cli/web_dist +ENV HERMES_TUI_DIR=/usr/local/lib/python3.12/dist-packages/hermes_cli/tui_dist +ENV PATH="/opt/node/bin:/opt/conda/bin:/root/.local/bin:${PATH}" +ENV HOME=/root/workspace +WORKDIR /root/workspace ENV PLAYWRIGHT_BROWSERS_PATH=/opt/hermes/.playwright -WORKDIR /opt/hermes - +# Copy utilities and tools COPY work /opt/utils/ +RUN chmod +x /opt/utils/*.sh && cp /opt/utils/start-hermes.sh /usr/local/bin/start-hermes.sh +# Copy build artifacts from builder +COPY --from=builder /build/dist/*.whl /tmp/ + +# Install Runtime dependencies RUN set -eux \ - && git clone --depth 1 --branch main https://github.com/nousresearch/hermes-agent.git . \ - && chmod +x /opt/utils/*.sh && mv /opt/utils/start-hermes.sh ./ \ - && ln -sf /opt/hermes/start-hermes.sh /usr/local/bin/ \ - ## Install Node dependencies - && export npm_config_install_links=false \ - && npm install --include=dev --prefer-offline --no-audit \ + && pip install --no-cache-dir /tmp/*.whl \ && npx playwright install --with-deps chromium --only-shell \ - && npm cache clean --force \ - ## Frontend build - && (cd web && npm run build) && (cd ui-tui && npm run build) \ - ## Python dependency install - && uv sync --frozen --no-install-project --extra all --extra messaging --extra anthropic --extra bedrock --extra azure-identity --extra hindsight --extra matrix \ - ## Link hermes-agent itself (editable) - && uv pip install --no-cache-dir --no-deps -e "." \ ## Install supervisord (Go version) && source /opt/utils/script-setup-sys.sh && setup_supervisord \ && source /opt/utils/script-utils.sh && install_apt /opt/utils/install_list_hermes.apt \ - && install__clean + && install__clean \ + && rm -rf /tmp/*.whl + +# Data persistence +VOLUME /root/workspace CMD ["start-hermes.sh"] diff --git a/docker_hermes/work/start-hermes.sh b/docker_hermes/work/start-hermes.sh index afc377a..4b66cbb 100644 --- a/docker_hermes/work/start-hermes.sh +++ b/docker_hermes/work/start-hermes.sh @@ -2,7 +2,7 @@ set -eu # Setup data directory -HERMES_HOME="${HERMES_HOME:-/opt/data}" +HERMES_HOME="${HERMES_HOME:-/root/workspace}" mkdir -p "$HERMES_HOME" for sub in cron sessions logs hooks memories skills skins plans workspace home pairing platforms/pairing logs/gateways; do @@ -27,7 +27,7 @@ fi # Run schema migration if [ -f "$HERMES_HOME/config.yaml" ]; then - "/opt/hermes/.venv/bin/python" "/opt/hermes/scripts/docker_config_migrate.py" || true + python3 -m scripts.docker_config_migrate || true fi # Seed bootstrap auth.json and gateway_state.json @@ -42,7 +42,7 @@ fi # Sync bundled skills if [ -d "/opt/hermes/skills" ]; then - "/opt/hermes/.venv/bin/python" "/opt/hermes/tools/skills_sync.py" || true + python3 -m tools.skills_sync || true fi # Find agent-browser Playwright binary and set env @@ -55,8 +55,8 @@ if [ -z "${AGENT_BROWSER_EXECUTABLE_PATH:-}" ] && [ -n "${PLAYWRIGHT_BROWSERS_PA fi # Configure environments for command invocation -export HOME=/opt/data -cd /opt/data +export HOME=/root/workspace +cd /root/workspace # If arguments are passed, route them if [ $# -gt 0 ]; then From cf6384a5946ea142288b9b3536f22ee4635f5c31 Mon Sep 17 00:00:00 2001 From: haobibo <1.59735e+06+haobibo@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:36:25 +0000 Subject: [PATCH 09/11] feat(docker): add docker_litellm with multi-stage build --- docker_litellm/README.md | 47 ++++++++++++++ docker_litellm/litellm.Dockerfile | 66 ++++++++++++++++++++ docker_litellm/work/install_list_litellm.apt | 1 + docker_litellm/work/start-litellm.sh | 32 ++++++++++ 4 files changed, 146 insertions(+) create mode 100644 docker_litellm/README.md create mode 100644 docker_litellm/litellm.Dockerfile create mode 100644 docker_litellm/work/install_list_litellm.apt create mode 100644 docker_litellm/work/start-litellm.sh diff --git a/docker_litellm/README.md b/docker_litellm/README.md new file mode 100644 index 0000000..ea6e4f3 --- /dev/null +++ b/docker_litellm/README.md @@ -0,0 +1,47 @@ +# LiteLLM Docker Image + +This directory contains the Dockerfile for building the [LiteLLM](https://github.com/BerriAI/litellm) Docker image, following the LabNow optimized multi-stage build pattern. + +## Optimization Features + +- **Multi-stage Build**: Separates the UI compilation and Python packaging from the runtime environment to keep the final image slim. +- **Persistent Storage**: Uses `/root/workspace` for all configurations and data. +- **Ready to Use**: Includes the LiteLLM Proxy with the Admin UI pre-compiled. + +## Quick Start + +### Build Image + +```bash +docker build -f litellm.Dockerfile -t litellm-labnow:latest . +``` + +### Run Manually + +```bash +# Run with persistent volume +docker run -d \ + --name litellm \ + -p 4000:4000 \ + -v /path/to/your/config:/root/workspace \ + litellm-labnow:latest +``` + +By default, it will look for a `config.yaml` in the workspace. If not found, a basic one will be created. + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| LITELLM_HOME | `/root/workspace` | Home directory for LiteLLM data | +| HOME | `/root/workspace` | System HOME environment variable | + +## Volumes + +- `/root/workspace` - Persistent directory for `config.yaml` and other LiteLLM data. + +## Documentation + +For more information about LiteLLM, see: +- [Official Documentation](https://docs.litellm.ai/) +- [GitHub Repository](https://github.com/BerriAI/litellm) diff --git a/docker_litellm/litellm.Dockerfile b/docker_litellm/litellm.Dockerfile new file mode 100644 index 0000000..6ee0115 --- /dev/null +++ b/docker_litellm/litellm.Dockerfile @@ -0,0 +1,66 @@ +# Distributed under the terms of the Modified BSD License. + +ARG BASE_NAMESPACE +ARG BASE_IMG="node" + +# --- Building Stage --- +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} AS builder + +LABEL maintainer="postmaster@labnow.ai" + +# Build-time environment +ENV NODE_ENV=development +WORKDIR /build + +# Clone source +RUN git clone --depth 1 --branch main https://github.com/BerriAI/litellm.git . + +# Build UI (Dashboard) +RUN set -eux \ + && cd ui/litellm-dashboard \ + && npm install \ + && npm run build \ + && mkdir -p ../../litellm/proxy/_experimental/out \ + && cp -r out/* ../../litellm/proxy/_experimental/out/ + +# Build Python wheel +RUN set -eux \ + && python3 -m pip install --upgrade pip build \ + && python3 -m build --wheel --outdir dist + +# --- Runtime Stage --- +FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} + +LABEL maintainer="postmaster@labnow.ai" + +# Production environment +ENV NODE_ENV=production +ENV LITELLM_HOME=/root/workspace +ENV PATH="/opt/node/bin:/opt/conda/bin:/root/.local/bin:${PATH}" +ENV HOME=/root/workspace + +WORKDIR /root/workspace + +# Copy utilities and tools +COPY work /opt/utils/ +RUN chmod +x /opt/utils/*.sh && cp /opt/utils/start-litellm.sh /usr/local/bin/start-litellm.sh + +# Copy build artifacts from builder +COPY --from=builder /build/dist/*.whl /tmp/ + +# Install Runtime dependencies +RUN set -eux \ + && pip install --no-cache-dir /tmp/*.whl \ + && pip install --no-cache-dir 'litellm[proxy]' \ + ## Install supervisord (Go version) if needed or use simple entrypoint + && source /opt/utils/script-setup-sys.sh && setup_supervisord \ + && source /opt/utils/script-utils.sh && install_apt /opt/utils/install_list_litellm.apt \ + && install__clean \ + && rm -rf /tmp/*.whl + +# Data persistence +VOLUME /root/workspace + +EXPOSE 4000 + +CMD ["start-litellm.sh"] diff --git a/docker_litellm/work/install_list_litellm.apt b/docker_litellm/work/install_list_litellm.apt new file mode 100644 index 0000000..fe2c6b7 --- /dev/null +++ b/docker_litellm/work/install_list_litellm.apt @@ -0,0 +1 @@ +# Add any apt packages here diff --git a/docker_litellm/work/start-litellm.sh b/docker_litellm/work/start-litellm.sh new file mode 100644 index 0000000..c4739f4 --- /dev/null +++ b/docker_litellm/work/start-litellm.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -eu + +# Setup workspace directory +LITELLM_HOME="${LITELLM_HOME:-/root/workspace}" +mkdir -p "$LITELLM_HOME" + +export HOME="$LITELLM_HOME" +cd "$LITELLM_HOME" + +# Default config if not exists +if [ ! -f "config.yaml" ]; then + echo "Creating default config.yaml..." + cat < config.yaml +model_list: + - model_name: gpt-3.5-turbo + litellm_params: + model: gpt-3.5-turbo +EOF +fi + +# If arguments are passed, route them +if [ $# -gt 0 ]; then + if command -v "$1" >/dev/null 2>&1; then + exec "$@" + else + exec litellm "$@" + fi +fi + +# No arguments: start litellm proxy +exec litellm --config config.yaml --port 4000 --host 0.0.0.0 From e637f6c9dbb6880587f169fa3962c8cb822e2a75 Mon Sep 17 00:00:00 2001 From: haobibo <1.59735e+06+haobibo@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:45:39 +0000 Subject: [PATCH 10/11] optimize(gui): move pixelflux build to builder stage --- docker_gui/gui_linux.Dockerfile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docker_gui/gui_linux.Dockerfile b/docker_gui/gui_linux.Dockerfile index c8c861f..a1f3233 100644 --- a/docker_gui/gui_linux.Dockerfile +++ b/docker_gui/gui_linux.Dockerfile @@ -27,7 +27,11 @@ RUN set -eux && chmod +x /opt/utils/*.sh \ fi \ && mv /opt/utils/docker-entrypoint.sh /opt/selkies/docker-entrypoint.sh \ && mv /opt/utils/install_list_selkies.apt /opt/selkies/ \ - && chmod +x /opt/selkies/docker-entrypoint.sh + && chmod +x /opt/selkies/docker-entrypoint.sh \ + ## Build pixelflux wheel + && apt install -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ + && mkdir -p /opt/wheels \ + && pip wheel --no-cache-dir --no-binary :all: pixelflux -w /opt/wheels # Stage 2: runtime image @@ -36,13 +40,12 @@ FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} LABEL maintainer="postmaster@labnow.ai" COPY --from=builder /opt/selkies /opt/selkies +COPY --from=builder /opt/wheels /opt/wheels RUN set -eux && cd /opt/selkies \ && source /opt/utils/script-utils.sh \ && install_apt /opt/selkies/install_list_selkies.apt \ - && apt install -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ - && pip install --no-cache-dir --no-binary :all: pixelflux \ - && apt purge -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ + && pip install --no-cache-dir /opt/wheels/*.whl \ && pip install --no-cache-dir ./*.whl \ && if [ -f /opt/selkies/lib/selkies_joystick_interposer.so ]; then \ ln -sf /opt/selkies/lib/selkies_joystick_interposer.so /usr/lib/selkies_joystick_interposer.so ; \ @@ -52,6 +55,7 @@ RUN set -eux && cd /opt/selkies \ && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so.1 \ && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so ; \ fi \ + && rm -rf /opt/wheels \ && list_installed_packages && install__clean ENV PATH=/opt/selkies:/opt/conda/bin:${PATH} From 3f663485647b024c5785e857f51608d3e3655e27 Mon Sep 17 00:00:00 2001 From: haobibo <1.59735e+06+haobibo@users.noreply.github.com> Date: Sat, 20 Jun 2026 04:50:19 +0000 Subject: [PATCH 11/11] fix(gui): resolve pip wheel execution error and simplify COPY --- docker_gui/gui_linux.Dockerfile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docker_gui/gui_linux.Dockerfile b/docker_gui/gui_linux.Dockerfile index a1f3233..9c5a779 100644 --- a/docker_gui/gui_linux.Dockerfile +++ b/docker_gui/gui_linux.Dockerfile @@ -28,10 +28,9 @@ RUN set -eux && chmod +x /opt/utils/*.sh \ && mv /opt/utils/docker-entrypoint.sh /opt/selkies/docker-entrypoint.sh \ && mv /opt/utils/install_list_selkies.apt /opt/selkies/ \ && chmod +x /opt/selkies/docker-entrypoint.sh \ - ## Build pixelflux wheel + ## Build pixelflux wheel into /opt/selkies && apt install -y build-essential cmake pkg-config libx11-dev libxext-dev libxfixes-dev libjpeg-dev libx264-dev libyuv-dev libavcodec-dev libavutil-dev libva-dev \ - && mkdir -p /opt/wheels \ - && pip wheel --no-cache-dir --no-binary :all: pixelflux -w /opt/wheels + && cd / && pip wheel --no-cache-dir --no-binary :all: pixelflux -w /opt/selkies # Stage 2: runtime image @@ -40,12 +39,10 @@ FROM ${BASE_NAMESPACE:+$BASE_NAMESPACE/}${BASE_IMG} LABEL maintainer="postmaster@labnow.ai" COPY --from=builder /opt/selkies /opt/selkies -COPY --from=builder /opt/wheels /opt/wheels RUN set -eux && cd /opt/selkies \ && source /opt/utils/script-utils.sh \ && install_apt /opt/selkies/install_list_selkies.apt \ - && pip install --no-cache-dir /opt/wheels/*.whl \ && pip install --no-cache-dir ./*.whl \ && if [ -f /opt/selkies/lib/selkies_joystick_interposer.so ]; then \ ln -sf /opt/selkies/lib/selkies_joystick_interposer.so /usr/lib/selkies_joystick_interposer.so ; \ @@ -55,7 +52,7 @@ RUN set -eux && cd /opt/selkies \ && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so.1 \ && ln -sf /opt/selkies/lib/libudev.so.1.0.0-fake /usr/lib/libudev.so ; \ fi \ - && rm -rf /opt/wheels \ + && rm -f /opt/selkies/*.whl \ && list_installed_packages && install__clean ENV PATH=/opt/selkies:/opt/conda/bin:${PATH}