-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathDockerfile
More file actions
72 lines (66 loc) · 3.91 KB
/
Dockerfile
File metadata and controls
72 lines (66 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# syntax=docker/dockerfile:1.7
#
# Hermes Agent on Render, pre-baked with Render tooling.
#
# Extends the upstream NousResearch/hermes-agent image with:
# - A bundle of Render-focused skills mounted via skills.external_dirs
# - A boot-time patcher that registers the Render MCP server in
# config.yaml (idempotent; never overwrites user edits)
#
# We deliberately do NOT install the `render` CLI. This image is configured
# around the Render MCP server; installing extra CLIs should be a conscious
# operator choice, not something the agent does as an automatic fallback.
#
# Pin the upstream tag here. Bump and redeploy to upgrade Hermes.
ARG HERMES_IMAGE=docker.io/nousresearch/hermes-agent:v2026.5.7
FROM ${HERMES_IMAGE}
# Workarounds for upstream issues that prevent the dashboard's Chat tab
# from connecting on hosted deploys. Baked into the image so the runtime
# command stays simple. See render.yaml comments + the README for context.
# - chown: dashboard runs as `hermes` but ui-tui/ + node_modules/ ship root-owned
# - touch ink-bundle.js: short-circuits _hermes_ink_bundle_stale()
# - touch entry.js: bumps mtime above source .ts files so _tui_build_needed() returns False
USER root
RUN chown -R hermes:hermes /opt/hermes/ui-tui /opt/hermes/node_modules \
&& mkdir -p /opt/hermes/ui-tui/packages/hermes-ink/dist /opt/hermes/ui-tui/dist \
&& touch /opt/hermes/ui-tui/packages/hermes-ink/dist/ink-bundle.js \
/opt/hermes/ui-tui/dist/entry.js \
&& chown -R hermes:hermes /opt/hermes/ui-tui
# Pull the official Render skill bundle from github.com/render-oss/skills
# at a pinned commit. Mounted via skills.external_dirs at boot, so the
# upstream Hermes skills-sync flow never touches these files. To upgrade,
# bump RENDER_SKILLS_REF (a commit SHA, tag, or branch) and rebuild.
ARG RENDER_SKILLS_REPO=render-oss/skills
ARG RENDER_SKILLS_REF=1b8496570748203351f628b2ae738805ac2c23d5
RUN set -eu; \
tmp="$(mktemp -d)"; \
url="https://codeload.github.com/${RENDER_SKILLS_REPO}/tar.gz/${RENDER_SKILLS_REF}"; \
curl -fsSL --retry 3 -o "${tmp}/skills.tar.gz" "${url}"; \
tar -xzf "${tmp}/skills.tar.gz" -C "${tmp}"; \
extracted="$(find "${tmp}" -maxdepth 2 -type d -name 'skills' | head -n 1)"; \
test -n "${extracted}" || { echo "could not find skills/ in tarball" >&2; exit 1; }; \
install -d -o hermes -g hermes -m 0755 /opt/render-tools/skills-upstream; \
cp -a "${extracted}/." /opt/render-tools/skills-upstream/; \
chown -R hermes:hermes /opt/render-tools/skills-upstream; \
rm -rf "${tmp}"; \
echo "${RENDER_SKILLS_REPO}@${RENDER_SKILLS_REF}" > /opt/render-tools/skills-upstream/.source
# Local overlay: a Hermes-specific `render-on-hermes` skill that tells
# the agent the MCP server is pre-wired (so skip "install MCP" from
# upstream skills) and that the CLI is deliberately absent (so don't
# try to invoke it). Listed FIRST in skills.external_dirs so same-named
# overlays would shadow upstream entries.
COPY --chown=hermes:hermes skills/ /opt/render-tools/skills-local/
# Boot-time wrapper: patches /opt/data/config.yaml, then hands off to
# the upstream entrypoint chain (tini → docker/entrypoint.sh).
COPY --chown=root:root scripts/bootstrap.sh /opt/render-tools/bootstrap.sh
COPY --chown=root:root scripts/patch-config.py /opt/render-tools/patch-config.py
RUN chmod 0755 /opt/render-tools/bootstrap.sh /opt/render-tools/patch-config.py
# Pre-create the dir the patcher writes to so chown works cleanly on
# first boot. The mounted disk replaces this empty dir at runtime;
# baking it just keeps the image self-contained for any non-disk use.
RUN install -d -o hermes -g hermes -m 0755 /opt/data
# Stay as root so the bootstrap can chown the mounted /opt/data on first
# boot, then `gosu hermes` for the config patch, then exec the upstream
# entrypoint (which also runs as root and does its own gosu drop).
ENTRYPOINT ["/usr/bin/tini", "-g", "--", "/opt/render-tools/bootstrap.sh"]
CMD ["gateway", "run"]