Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions agents/hermes/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,16 @@ RUN set -eu; \
"$config_dir/plugins" \
"$config_dir/cron" \
"$config_dir/logs" \
"$config_dir/logs/curator" \
"$config_dir/skins" \
"$config_dir/plans" \
"$config_dir/workspace" \
"$config_dir/profiles" \
"$config_dir/cache" \
"$config_dir/pairing" \
"$config_dir/hooks" \
"$config_dir/image_cache" \
"$config_dir/audio_cache" \
"$config_dir/platforms" \
"$config_dir/platforms/whatsapp" \
"$config_dir/platforms/whatsapp/session" \
Expand Down Expand Up @@ -257,12 +261,16 @@ RUN set -eu; \
/sandbox/.hermes/plugins \
/sandbox/.hermes/cron \
/sandbox/.hermes/logs \
/sandbox/.hermes/logs/curator \
/sandbox/.hermes/skins \
/sandbox/.hermes/plans \
/sandbox/.hermes/workspace \
/sandbox/.hermes/profiles \
/sandbox/.hermes/cache \
/sandbox/.hermes/pairing \
/sandbox/.hermes/hooks \
/sandbox/.hermes/image_cache \
/sandbox/.hermes/audio_cache \
/sandbox/.hermes/platforms \
/sandbox/.hermes/platforms/whatsapp \
/sandbox/.hermes/platforms/whatsapp/session \
Expand Down
14 changes: 11 additions & 3 deletions agents/hermes/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ FROM node:22-trixie-slim@sha256:2d9f5c76c8f4dd36e8f253bee5d828a83a6c09f36188f0b0
ENV DEBIAN_FRONTEND=noninteractive

# Hermes version pinned for reproducibility.
# Calver tag v2026.4.23 = semver 0.11.0.
ARG HERMES_VERSION=v2026.4.23
ARG HERMES_TARBALL_SHA256=1ee1be80a2112b7edc581770cee8858e725ba110cc423979cd7102492504bc6b
# Calver tag v2026.5.16 = semver 0.14.0.
ARG HERMES_VERSION=v2026.5.16
ARG HERMES_TARBALL_SHA256=c0a554050a50ee9a62f3fa5cd288a167ba5640c42d647d100cdea084b7294143
ARG HERMES_UV_EXTRAS="messaging web"
ARG UV_VERSION=0.11.8

Expand Down Expand Up @@ -83,12 +83,16 @@ RUN mkdir -p /sandbox/.hermes/memories \
/sandbox/.hermes/plugins \
/sandbox/.hermes/cron \
/sandbox/.hermes/logs \
/sandbox/.hermes/logs/curator \
/sandbox/.hermes/skins \
/sandbox/.hermes/plans \
/sandbox/.hermes/workspace \
/sandbox/.hermes/profiles \
/sandbox/.hermes/cache \
/sandbox/.hermes/pairing \
/sandbox/.hermes/hooks \
/sandbox/.hermes/image_cache \
/sandbox/.hermes/audio_cache \
/sandbox/.hermes/platforms \
/sandbox/.hermes/platforms/whatsapp \
/sandbox/.hermes/platforms/whatsapp/session \
Expand All @@ -103,12 +107,16 @@ RUN mkdir -p /sandbox/.hermes/memories \
/sandbox/.hermes/plugins \
/sandbox/.hermes/cron \
/sandbox/.hermes/logs \
/sandbox/.hermes/logs/curator \
/sandbox/.hermes/skins \
/sandbox/.hermes/plans \
/sandbox/.hermes/workspace \
/sandbox/.hermes/profiles \
/sandbox/.hermes/cache \
/sandbox/.hermes/pairing \
/sandbox/.hermes/hooks \
/sandbox/.hermes/image_cache \
/sandbox/.hermes/audio_cache \
/sandbox/.hermes/platforms \
/sandbox/.hermes/platforms/whatsapp \
/sandbox/.hermes/platforms/whatsapp/session \
Expand Down
4 changes: 2 additions & 2 deletions agents/hermes/config/hermes-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const API_SERVER_TOOLSETS = [
export function buildHermesConfig(settings: HermesBuildSettings): Record<string, unknown> {
const apiServerToolsets = [...API_SERVER_TOOLSETS];
const config: Record<string, unknown> = {
_config_version: 12,
_config_version: 23,
model: {
default: settings.model,
provider: "custom",
Expand Down Expand Up @@ -62,7 +62,7 @@ export function buildHermesConfig(settings: HermesBuildSettings): Record<string,
},
};

// Hermes v2026.4.23 reads Discord behavior from top-level `discord:`.
// Hermes v2026.5.16 reads Discord behavior from top-level `discord:`.
// Bot tokens and user allowlists stay in .env so config.yaml never carries
// real secrets or credential placeholders under platforms.discord.
if (settings.messaging.enabledChannels.has("discord")) {
Expand Down
7 changes: 6 additions & 1 deletion agents/hermes/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ homepage: "https://github.com/NousResearch/hermes-agent"
install_method: curl # curl install.sh | bash
binary_path: /usr/local/bin/hermes
version_command: "hermes --version"
expected_version: "2026.4.23"
expected_version: "2026.5.16"
gateway_command: "hermes gateway run"

# ── Health probe ────────────────────────────────────────────────
Expand Down Expand Up @@ -59,6 +59,11 @@ state_dirs:
- sessions
- skills
- plugins
# Hermes v0.14 discovers user-installed gateway event hooks from
# ~/.hermes/hooks. Preserve them across rebuilds. Runtime media
# caches such as image_cache/ and audio_cache/ are intentionally
# omitted: the image pre-creates them, but rebuilds may discard them.
- hooks
- cron
- logs
- skins
Expand Down
17 changes: 14 additions & 3 deletions test/e2e/test-rebuild-hermes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ OLD_HERMES_REGISTRY_VERSION="${OLD_HERMES_VERSION#v}"
OLD_HERMES_TARBALL_SHA256="5e4529b8cb6e4821eb916b81517e48125109b1764d6d1e68a204a9f0ddf2d98c"
STALE_BASE_REBUILD="${NEMOCLAW_HERMES_STALE_BASE_REBUILD_E2E:-0}"
MARKER_FILE="/sandbox/.hermes/memories/rebuild-marker.txt"
HOOK_MARKER_FILE="/sandbox/.hermes/hooks/rebuild-hook-marker.txt"
MARKER_CONTENT="REBUILD_HM_E2E_$(date +%s)"
HOOK_MARKER_CONTENT="REBUILD_HM_HOOK_E2E_$(date +%s)"
DISCORD_PLACEHOLDER="openshell:resolve:env:DISCORD_BOT_TOKEN"
DISCORD_FAKE_TOKEN="test-fake-discord-token-rebuild-e2e"
REGISTRY_FILE="$HOME/.nemoclaw/sandboxes.json"
Expand Down Expand Up @@ -227,11 +229,13 @@ pass "Old Hermes sandbox created"
info "Phase 4: Writing markers and registering sandbox..."

openshell sandbox exec --name "${SANDBOX_NAME}" -- \
sh -c "mkdir -p /sandbox/.hermes/memories && echo '${MARKER_CONTENT}' > ${MARKER_FILE}" \
|| fail "Failed to write marker file"
sh -c "mkdir -p /sandbox/.hermes/memories /sandbox/.hermes/hooks && echo '${MARKER_CONTENT}' > ${MARKER_FILE} && echo '${HOOK_MARKER_CONTENT}' > ${HOOK_MARKER_FILE}" \
|| fail "Failed to write marker files"

VERIFY=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- cat "${MARKER_FILE}" 2>/dev/null || true)
[ "$VERIFY" = "${MARKER_CONTENT}" ] || fail "Marker verification failed"
HOOK_VERIFY=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- cat "${HOOK_MARKER_FILE}" 2>/dev/null || true)
[ "$HOOK_VERIFY" = "${HOOK_MARKER_CONTENT}" ] || fail "Hook marker verification failed"
PRE_REBUILD_ENV=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- cat /sandbox/.hermes/.env 2>/dev/null || true)
echo "$PRE_REBUILD_ENV" | grep -Fq "DISCORD_BOT_TOKEN=${DISCORD_PLACEHOLDER}" \
|| fail "Pre-rebuild Hermes .env missing Discord placeholder"
Expand Down Expand Up @@ -311,14 +315,21 @@ pass "Rebuild completed"
# ── Phase 7: Verify ─────────────────────────────────────────────────
info "Phase 7: Verifying results..."

# Marker file survived
# Marker files survived
RESTORED=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- cat "${MARKER_FILE}" 2>/dev/null || true)
if [ "$RESTORED" = "${MARKER_CONTENT}" ]; then
pass "Marker file survived rebuild"
else
fail "Marker file lost: got '${RESTORED}', expected '${MARKER_CONTENT}'"
fi

HOOK_RESTORED=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- cat "${HOOK_MARKER_FILE}" 2>/dev/null || true)
if [ "$HOOK_RESTORED" = "${HOOK_MARKER_CONTENT}" ]; then
pass "Hermes hooks marker survived rebuild"
else
fail "Hermes hooks marker lost: got '${HOOK_RESTORED}', expected '${HOOK_MARKER_CONTENT}'"
fi

# Actual Hermes binary version updated
HERMES_VERSION_OUTPUT=$(openshell sandbox exec --name "${SANDBOX_NAME}" -- hermes --version 2>&1 || true)
diag "Hermes version after rebuild: ${HERMES_VERSION_OUTPUT//$'\n'/ | }"
Expand Down
1 change: 1 addition & 0 deletions test/generate-hermes-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ describe("agents/hermes/generate-config.ts", () => {
it("generates API server config without messaging platform token blocks", () => {
const { config, envFile } = runConfigScript();

expect(config._config_version).toBe(23);
expect(config.model).toMatchObject({
default: "test-model",
provider: "custom",
Expand Down
14 changes: 12 additions & 2 deletions test/sandbox-provisioning.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,18 @@
expect(run.result.status).toBe(0);
const hermesDir = path.join(run.sandboxRoot, ".hermes");
expect((fs.statSync(hermesDir).mode & 0o777).toString(8)).toBe("750");
for (const dir of ["logs", "cache", "platforms"]) {
expect((fs.statSync(path.join(hermesDir, dir)).mode & 0o777).toString(8)).toBe("770");
for (const dir of [
"logs",
"logs/curator",
"cache",
"hooks",
"image_cache",
"audio_cache",
"platforms",
]) {
const dirPath = path.join(hermesDir, dir);
expect((fs.statSync(dirPath).mode & 0o777).toString(8)).toBe("770");
expect(run.calls).toContain(`chown -R sandbox:sandbox ${dirPath}`);

Check failure on line 500 in test/sandbox-provisioning.test.ts

View workflow job for this annotation

GitHub Actions / checks

[cli] test/sandbox-provisioning.test.ts > Hermes sandbox provisioning > grants the Hermes gateway group write access to runtime state directories

AssertionError: expected 'chown -R sandbox:sandbox /tmp/nemocla…' to contain 'chown -R sandbox:sandbox /tmp/nemocla…' - Expected + Received - chown -R sandbox:sandbox /tmp/nemoclaw-hermes-layout-WqaX3W/sandbox/.hermes/logs + chown -R sandbox:sandbox /tmp/nemoclaw-hermes-layout-WqaX3W/sandbox/.hermes + chown gateway:sandbox /tmp/nemoclaw-hermes-layout-WqaX3W/sandbox/.hermes/runtime + ❯ test/sandbox-provisioning.test.ts:500:29

Check failure on line 500 in test/sandbox-provisioning.test.ts

View workflow job for this annotation

GitHub Actions / unit-vitest-linux

[cli] test/sandbox-provisioning.test.ts > Hermes sandbox provisioning > grants the Hermes gateway group write access to runtime state directories

AssertionError: expected 'chown -R sandbox:sandbox /tmp/nemocla…' to contain 'chown -R sandbox:sandbox /tmp/nemocla…' - Expected + Received - chown -R sandbox:sandbox /tmp/nemoclaw-hermes-layout-7FdlKd/sandbox/.hermes/logs + chown -R sandbox:sandbox /tmp/nemoclaw-hermes-layout-7FdlKd/sandbox/.hermes + chown gateway:sandbox /tmp/nemoclaw-hermes-layout-7FdlKd/sandbox/.hermes/runtime + ❯ test/sandbox-provisioning.test.ts:500:29
}
expect((fs.statSync(path.join(hermesDir, "platforms")).mode & 0o7777).toString(8)).toBe(
"2770",
Expand Down
Loading