hermes: two-stage build, make /opt/hermes writable by uid 10000
All checks were successful
images / hermes (push) Successful in 1m55s
All checks were successful
images / hermes (push) Successful in 1m55s
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
This commit is contained in:
@@ -6,22 +6,31 @@ self-improving AI agent — packaged for lair infra and published to
|
||||
|
||||
## How it's built
|
||||
|
||||
Upstream ships its own `Dockerfile` (debian 13 + s6-overlay), so there is **no
|
||||
vendored Containerfile here**. The `images` workflow (and `build.sh`) build
|
||||
straight from the upstream git context at the latest release tag:
|
||||
Upstream ships its own `Dockerfile` (debian 13 + s6-overlay), so we build in two
|
||||
stages — `build.sh` and the `images` workflow both do this:
|
||||
|
||||
```
|
||||
podman build github.com/NousResearch/hermes-agent.git#<tag> \
|
||||
-t git.lair.cafe/lair/hermes:<version> -t git.lair.cafe/lair/hermes:latest
|
||||
```
|
||||
1. **Upstream** — build straight from the upstream git context at the release tag
|
||||
into a local tag: `podman build github.com/NousResearch/hermes-agent.git#<tag>`.
|
||||
2. **Derived** — [`Containerfile`](Containerfile) does `FROM` that and makes the
|
||||
`/opt/hermes` app tree writable by the runtime `hermes` user (uid 10000), then
|
||||
publishes `git.lair.cafe/lair/hermes:{<version>,latest}`.
|
||||
|
||||
The writable-tree layer gives the agent "untied hands" (self-modify; the gateway
|
||||
can auto-install the WhatsApp bridge's `node_modules` in place) **without** the
|
||||
volume trap: a volume over `/opt/hermes` would copy-up once and freeze the app,
|
||||
silently defeating `AutoUpdate=registry`. Baked into the image, it ships
|
||||
hands-free on every pull and refreshes cleanly on update. **Persistence belongs
|
||||
on `/opt/data`** (skills, memory, sessions, the WhatsApp bridge via `bridge_script`),
|
||||
never in `/opt/hermes`.
|
||||
|
||||
Builds are **release-triggered** (daily poll of the GitHub releases API; a build
|
||||
runs only when that version isn't already in our registry) and **self-healing**
|
||||
(a failed build leaves the version absent, so the next poll retries). Force a
|
||||
rebuild via the workflow's `force` dispatch input, or locally:
|
||||
(a failed build leaves the version absent, so the next poll retries). When the
|
||||
*build definition* changes (e.g. this writable layer) for an already-published
|
||||
version, republish with the workflow's `force` dispatch input. Locally:
|
||||
|
||||
```
|
||||
HERMES_REF=v0.2.0 ./build.sh
|
||||
HERMES_REF=v0.17.0 ./build.sh
|
||||
```
|
||||
|
||||
## How it runs (single container, gateway + dashboard)
|
||||
|
||||
Reference in New Issue
Block a user