Files
containers/images/hermes/Containerfile
grenade d53e06d784
All checks were successful
images / hermes (push) Successful in 1m55s
hermes: two-stage build, make /opt/hermes writable by uid 10000
Upstream ships /opt/hermes (app + .venv + scripts) read-only root, which
blocks the agent self-modifying and the gateway auto-installing the
WhatsApp bridge's node_modules in place. Add a derived Containerfile layer
(FROM the upstream build) that chowns/chmods /opt/hermes writable by the
runtime hermes user. Done in the image, not a volume: a volume over
/opt/hermes copies-up once then freezes the app, silently defeating
AutoUpdate=registry. Persistence stays on the /opt/data volume.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011D3YeWKpjg5bT488fVanCH
2026-06-23 18:31:32 +03:00

21 lines
1.1 KiB
Docker

# Derived layer over the upstream NousResearch/hermes-agent image.
#
# Upstream ships /opt/hermes (the app: Python source + .venv + scripts) as a
# read-only tree owned by root (0555/0444). That stops the runtime `hermes`
# user (uid 10000) from self-modifying and, concretely, stops the gateway from
# auto-installing the WhatsApp Node bridge's node_modules in place.
#
# We make the whole app tree writable by uid 10000 so the agent has "untied
# hands". This is done in the IMAGE (not a volume) on purpose: a volume over
# /opt/hermes would copy-up once and then freeze the app, silently defeating
# AutoUpdate=registry. As a baked layer it ships hands-free on every pull AND
# refreshes cleanly on every update. Anything that must PERSIST across updates
# belongs on the /opt/data volume (skills, memory, sessions, the WhatsApp
# bridge via the gateway's `bridge_script` config), not in /opt/hermes.
#
# BASE is the upstream image the `images` workflow builds from the git context.
ARG BASE
FROM ${BASE}
USER root
RUN chown -R 10000:10000 /opt/hermes && chmod -R u+w /opt/hermes