Compare commits

...

11 Commits

Author SHA1 Message Date
46f3b23a3f Merge pull request 'fix: remove venv volume mount conflicting with entrypoint.sh' (#49) from fix/remove-venv-mount into master
Some checks failed
Build Hermes agent / build (push) Has been cancelled
Build ollama (gfx906) / build (push) Has been cancelled
Reviewed-on: #49
2026-05-22 17:05:52 +00:00
567850bd13 feat: bake Matrix bridge deps into Docker image instead of volume mount
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
- Add libolm-dev system dep (required by mautrix[encryption])
- Add mautrix[encryption] + openai pip packages to build
- These were previously installed inline at container startup and
  persisted via the fragile venv volume mount (now removed)
2026-05-22 13:04:49 -04:00
2d59bb44c3 fix: remove venv volume mount conflicting with upstream entrypoint.sh
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
The volume mount /mnt/HoardingCow_docker_data/Hermes/venv overrides the
container's built-in .venv with whatever is on the host. On a fresh start
or after a clean build, an empty/missing venv directory causes entrypoint.sh
line 62 (source .venv/bin/activate) to fail with set -e.

The Docker image already builds a complete venv — persisting it on the host
is unnecessary and fragile.
2026-05-22 13:03:51 -04:00
bf56d4be8b Merge pull request 'fix: resolve Docker build errors and add Traefik routing for Hermes web UI' (#33) from fix/hermes-build into master
Some checks failed
Build Hermes agent / build (push) Has been cancelled
Build ollama (gfx906) / build (push) Has been cancelled
Reviewed-on: #33
2026-05-22 16:36:23 +00:00
1c8efb1090 Merge remote-tracking branch 'origin/master' into fix/hermes-build
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
# Conflicts:
#	ai/compose.yml
2026-05-22 12:34:39 -04:00
7725830e6c feat: wire up HERMES_PROFILES to multi-gateway launcher script
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
- Add run-multi-gateways.sh to /opt/data/hermes-tools/ that reads
  HERMES_PROFILES env var and spawns one gateway per profile
- Update entrypoint to call the script before the main entrypoint
- Set HERMES_PROFILES=ashley,claire,finn,matt,paul (was default)

Closes PR #47 (feat/multi-profile-gateways). Builds on 548e15d's cleaner
env-var-driven approach — compose.yml stays declarative, logic in script.
2026-05-22 12:27:47 -04:00
548e15d6b4 feat(compose): add HERMES_PROFILES env var for multi-gateway mode
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
2026-05-20 20:02:26 -04:00
35aa466e87 fix: Matrix bridge ModuleNotFoundError - install deps to venv with persistence
Some checks failed
Build Hermes agent / build (push) Has been cancelled
Build ollama (gfx906) / build (push) Has been cancelled
fix: Matrix bridge ModuleNotFoundError - install deps to venv with persistence
2026-05-20 18:47:28 +00:00
ebad994d60 feat(hermes): enable dashboard (HERMES_DASHBOARD=1) + Authelia auth
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
2026-05-20 14:06:23 -04:00
5f25c87775 fix: add missing USER root before chown step
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
The chown -R hermes:hermes was running as non-root user 'hermes'
since USER hermes was set earlier. The new upstream base image
(v0.12.0+) has tools/ owned by root, so the chown fails.
Previous base image happened to have tools/ owned by hermes,
making the chown a silent no-op.
2026-05-20 13:32:18 -04:00
4e566b2408 fix: resolve Docker build errors and add Traefik routing for Hermes web UI
Some checks failed
Build Hermes agent / build (pull_request) Has been cancelled
Build ollama (gfx906) / build (pull_request) Has been cancelled
- Replace rsync with cp -a (rsync unavailable in latest upstream base image)
- Remove npm run build step (fork's package.json has no build script)
- Remove himalaya-ro.sh from build context (deployed via install.sh)
- Add hermes to ai_net network for Traefik access
- Add Traefik labels routing hermes.lazyworkhorse.net to dashboard port 9119
2026-05-20 13:14:10 -04:00
3 changed files with 40 additions and 88 deletions

View File

@@ -32,11 +32,16 @@ services:
- default - default
container_name: hermes container_name: hermes
entrypoint: ["/bin/bash", "-c", entrypoint: ["/bin/bash", "-c",
"bash /opt/data/hermes-tools/install.sh && . /opt/hermes/.venv/bin/activate && uv pip install openai 'mautrix[encryption]' -q && exec /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh \"$@\"", "bash /opt/data/hermes-tools/install.sh && bash /opt/data/hermes-tools/run-multi-gateways.sh && exec /usr/bin/tini -g -- /opt/hermes/docker/entrypoint.sh \"$@\"",
"hermes-entrypoint"] "hermes-entrypoint"]
restart: always restart: always
environment: environment:
- OLLAMA_HOST=http://ollama:11434 - OLLAMA_HOST=http://ollama:11434
- HERMES_DASHBOARD=1
# Multi-profile: comma-separated list of profiles to run as gateways.
# The entrypoint reads this and starts one gateway per profile.
# Add profiles here when they exist on disk (e.g. default,researcher,writer)
- HERMES_PROFILES=ashley,claire,finn,matt,paul
- API_SERVER_ENABLED=true - API_SERVER_ENABLED=true
- API_SERVER_PORT=8642 - API_SERVER_PORT=8642
- API_SERVER_HOST=0.0.0.0 - API_SERVER_HOST=0.0.0.0
@@ -56,8 +61,6 @@ services:
- /mnt/HoardingCow_docker_data/Syncthing/telos-ro:/opt/data/telos-ro:ro - /mnt/HoardingCow_docker_data/Syncthing/telos-ro:/opt/data/telos-ro:ro
# Syncthing-shared inbox — write tasks here, they sync to user's laptop # Syncthing-shared inbox — write tasks here, they sync to user's laptop
- /mnt/HoardingCow_docker_data/Syncthing/telos-rw:/opt/data/telos-rw:rw - /mnt/HoardingCow_docker_data/Syncthing/telos-rw:/opt/data/telos-rw:rw
# Persist Python venv across container recreation (Matrix bridge deps, etc.)
- /mnt/HoardingCow_docker_data/Hermes/venv:/opt/hermes/.venv
devices: devices:
- /dev/kfd:/dev/kfd - /dev/kfd:/dev/kfd
- /dev/dri:/dev/dri - /dev/dri:/dev/dri
@@ -66,6 +69,30 @@ services:
- "26" - "26"
networks: networks:
- ai_backend - ai_backend
- ai_net
labels:
- "traefik.enable=true"
- "traefik.docker.network=ai_net"
# Router for HTTP + redirection to HTTPS
- "traefik.http.routers.hermes-web-http.rule=Host(`hermes.lazyworkhorse.net`)"
- "traefik.http.routers.hermes-web-http.entrypoints=web"
- "traefik.http.routers.hermes-web-http.middlewares=redirect-to-https"
# Router for HTTPS with TLS — protected by Authelia
- "traefik.http.routers.hermes-web-https.rule=Host(`hermes.lazyworkhorse.net`)"
- "traefik.http.routers.hermes-web-https.entrypoints=websecure"
- "traefik.http.routers.hermes-web-https.tls=true"
- "traefik.http.routers.hermes-web-https.tls.certresolver=njalla"
- "traefik.http.routers.hermes-web-https.middlewares=hermes-auth"
# Authelia forwardAuth
- "traefik.http.middlewares.hermes-auth.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.lazyworkhorse.net/"
- "traefik.http.middlewares.hermes-auth.forwardauth.trustforwardheader=true"
- "traefik.http.middlewares.hermes-auth.forwardauth.authresponseheaders=X-Forwarded-User,X-Forwarded-Groups"
# Service Loadbalancer (dashboard port 9119)
- "traefik.http.services.hermes-web.loadbalancer.server.port=9119"
syncthing: syncthing:
image: syncthing/syncthing:latest image: syncthing/syncthing:latest

View File

@@ -20,16 +20,10 @@ RUN --mount=type=ssh \
GIT_SSH_COMMAND='ssh -p 2222 -o StrictHostKeyChecking=no' \ GIT_SSH_COMMAND='ssh -p 2222 -o StrictHostKeyChecking=no' \
git clone --depth 1 --branch main \ git clone --depth 1 --branch main \
git@code.lazyworkhorse.net:gortium/hermes-agent.git fork && \ git@code.lazyworkhorse.net:gortium/hermes-agent.git fork && \
rsync -a --delete fork/ /opt/hermes/ \ rm -rf fork/node_modules fork/.venv fork/.git && \
--exclude node_modules \ cp -a fork/. /opt/hermes/ && \
--exclude .venv \
--exclude .git && \
rm -rf /tmp/fork /root/.ssh/ rm -rf /tmp/fork /root/.ssh/
# ---------- Rebuild web UI ----------
# Source files changed; node_modules (from base image) reused.
RUN cd /opt/hermes && npm run build
# ---------- Reinstall Python package (editable) ---------- # ---------- Reinstall Python package (editable) ----------
# Picks up source changes from our fork. # Picks up source changes from our fork.
RUN . /opt/hermes/.venv/bin/activate && \ RUN . /opt/hermes/.venv/bin/activate && \
@@ -40,6 +34,7 @@ USER root
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
libportaudio2 ca-certificates poppler-utils imagemagick \ libportaudio2 ca-certificates poppler-utils imagemagick \
libolm-dev \
texlive-latex-base texlive-latex-extra texlive-fonts-recommended \ texlive-latex-base texlive-latex-extra texlive-fonts-recommended \
texlive-xetex texlive-science \ texlive-xetex texlive-science \
qemu-user-static binfmt-support emacs-nox && \ qemu-user-static binfmt-support emacs-nox && \
@@ -48,6 +43,12 @@ RUN apt-get update && \
# ---------- UV ---------- # ---------- UV ----------
COPY --chmod=0755 --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/ COPY --chmod=0755 --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/
# ---------- Matrix bridge + extra pip deps ----------
# Previously installed inline at container startup and persisted via volume mount.
# Now baked into the image so the fragile venv volume mount can be removed.
RUN . /opt/hermes/.venv/bin/activate && \
uv pip install --no-cache-dir 'mautrix[encryption]' openai
# ---------- Piper TTS ---------- # ---------- Piper TTS ----------
RUN . /opt/hermes/.venv/bin/activate && \ RUN . /opt/hermes/.venv/bin/activate && \
uv pip install --no-cache-dir piper-tts sounddevice numpy && \ uv pip install --no-cache-dir piper-tts sounddevice numpy && \
@@ -75,10 +76,6 @@ os.remove(tgz)
print('himalaya v1.2.0 installed') print('himalaya v1.2.0 installed')
PYEOF PYEOF
# ---------- Install himalaya-ro wrapper ----------
COPY --chmod=0755 himalaya-ro.sh /usr/local/bin/himalaya-ro
# ---------- Runtime ---------- # ---------- Runtime ----------
USER hermes USER hermes
ENV HERMES_HOME=/opt/data ENV HERMES_HOME=/opt/data
@@ -88,6 +85,7 @@ ENV CHROME_EXECUTABLE=/opt/hermes/.playwright/chromium/chrome-linux/chrome
# Ensure tools directory and toolsets.py are writable by the hermes runtime user # Ensure tools directory and toolsets.py are writable by the hermes runtime user
# so custom tools can be injected from the persistent volume at startup. # so custom tools can be injected from the persistent volume at startup.
USER root
RUN chown -R hermes:hermes /opt/hermes/tools /opt/hermes/toolsets.py RUN chown -R hermes:hermes /opt/hermes/tools /opt/hermes/toolsets.py
VOLUME [ "/opt/data" ] VOLUME [ "/opt/data" ]

View File

@@ -1,73 +0,0 @@
#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────
# himalaya-ro — Read-only wrapper for himalaya
#
# Blocks destructive commands and logs audit trail.
# Pass-through for read-only commands (list, read, search).
#
# Usage: himalaya-ro [options] <command> [args...]
#
# Install: place in PATH before the real himalaya, or use
# `ln -sf himalaya-ro /usr/local/bin/himalaya`
# ─────────────────────────────────────────────────────────────
set -o pipefail
# ── Configuration ───────────────────────────────────────────
HIMALAYA_BIN="${HIMALAYA_BIN:-/usr/local/bin/himalaya}"
AUDIT_LOG="${HIMALAYA_AUDIT_LOG:-/var/log/himalaya-audit.log}"
# ── Destructive commands we block ──────────────────────────
BLOCKED_CMDS=(
"message move"
"message delete"
"message copy"
"flag add"
"flag remove"
"folder create"
"folder delete"
"folder rename"
"template send"
"account configure"
"account delete"
)
# ── Determine the subcommand being invoked ─────────────────
# Strip leading options (--account, --output, etc.) to find the verb
ARGS=()
SKIP_NEXT=false
for arg in "$@"; do
if $SKIP_NEXT; then
SKIP_NEXT=false
continue
fi
if [[ "$arg" == --* ]]; then
case "$arg" in
--account|--output|--page|--page-size|--folder|--color|--format)
SKIP_NEXT=true ;;
esac
continue
fi
ARGS+=("$arg")
done
# Build subcommand string and check against blocklist
CMD_STR=""
for ((i=0; i<${#ARGS[@]}; i++)); do
if [ -z "$CMD_STR" ]; then
CMD_STR="${ARGS[$i]}"
else
CMD_STR="$CMD_STR ${ARGS[$i]}"
fi
for blocked in "${BLOCKED_CMDS[@]}"; do
if [[ "$CMD_STR" == "$blocked" ]]; then
TS=$(date '+%Y-%m-%d %H:%M:%S')
echo "[AUDIT] $TS BLOCKED: himalaya $*" >> "$AUDIT_LOG"
echo "ERROR: Command 'himalaya $CMD_STR ...' is blocked by read-only policy." >&2
echo " Audit log: $AUDIT_LOG" >&2
exit 100
fi
done
done
# ── Allow pass-through ─────────────────────────────────────
exec "$HIMALAYA_BIN" "$@"