Skip to content
Draft
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
2 changes: 1 addition & 1 deletion hermesagent/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ appVersion: '0.15.2'
description: The self-improving AI agent built by Nous Research
name: hermesagent
type: application
version: 1.3.10
version: 1.3.14
17 changes: 6 additions & 11 deletions hermesagent/OlaresManifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
description: The agent that grows with you
appid: hermesagent
title: Hermes Agent
version: 1.3.10
version: 1.3.14
categories:
- Productivity_v112
- Developer Tools
Expand Down Expand Up @@ -62,16 +62,11 @@ spec:
- Localized into 7 languages (中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe) plus a Chinese dashboard.

upgradeDescription: |
Hermes Agent app upgrade to v0.15.2 (2026.5.29.2):

Major changes:
- Core architecture refactor: run_agent.py was reduced from 16,083 to 3,821 lines and split across 14 agent/* modules to improve maintainability and development velocity.
- Significant performance gains: Cold start was further optimized, hermes --version cold start dropped by 63%, per-turn function calls fell by 47%, and session_search was rebuilt to be LLM-free, cost-free, and about 4,500× faster.
- Kanban becomes a multi-agent platform: It adds task auto-decomposition, Swarm topology, scheduled tasks, per-task model overrides, worktree-per-task support, and worker/run inspection endpoints.
- Security and secrets improved: Hermes adds defenses against Promptware/Brainworm-style attacks, while Bitwarden Secrets Manager can replace multiple provider API keys with one bootstrap token and support source labeling plus effective rotation.
- Ecosystem and integrations expanded: New additions include skill bundles, ntfy notifications, OpenHands orchestration, a Nous-approved MCP catalog, Krea/FAL image generation providers, and deeper xAI integration.

view full release notes: https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2
Config changes: Change HERMUES_UID 1000:1000

Change Details:
- Align Hermes runtime identity to Olares UID 1000:1000 (replacing 10000), with automatic ownership migration on upgrade.
- Fix Terminal and Dashboard access: unified shell privilege drop for interactive sessions, persistent brew PATH, and Home/External volume mounts on the dashboard container.

developer: Nous Research
website: https://hermes-agent.nousresearch.com
Expand Down
15 changes: 5 additions & 10 deletions hermesagent/i18n/en-US/OlaresManifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,8 @@ spec:
- Localized into 7 languages (中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe) plus a Chinese dashboard.

upgradeDescription: |
Hermes Agent app upgrade to v0.15.2 (2026.5.29.2):

Major changes:
- Core architecture refactor: run_agent.py was reduced from 16,083 to 3,821 lines and split across 14 agent/* modules to improve maintainability and development velocity.
- Significant performance gains: Cold start was further optimized, hermes --version cold start dropped by 63%, per-turn function calls fell by 47%, and session_search was rebuilt to be LLM-free, cost-free, and about 4,500× faster.
- Kanban becomes a multi-agent platform: It adds task auto-decomposition, Swarm topology, scheduled tasks, per-task model overrides, worktree-per-task support, and worker/run inspection endpoints.
- Security and secrets improved: Hermes adds defenses against Promptware/Brainworm-style attacks, while Bitwarden Secrets Manager can replace multiple provider API keys with one bootstrap token and support source labeling plus effective rotation.
- Ecosystem and integrations expanded: New additions include skill bundles, ntfy notifications, OpenHands orchestration, a Nous-approved MCP catalog, Krea/FAL image generation providers, and deeper xAI integration.

view full release notes: https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2
Config changes: Change HERMUES_UID 1000:1000

Change Details:
- Align Hermes runtime identity to Olares UID 1000:1000 (replacing 10000), with automatic ownership migration on upgrade.
- Fix Terminal and Dashboard access: unified shell privilege drop for interactive sessions, persistent brew PATH, and Home/External volume mounts on the dashboard container.
13 changes: 4 additions & 9 deletions hermesagent/i18n/zh-CN/OlaresManifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,8 @@ spec:
- 已本地化为 7 种语言(中文 / 日本語 / Deutsch / Español / Français / Українська / Türkçe),Dashboard 已支持中文。

upgradeDescription: |
Hermes Agent 应用升级到 v0.15.2(2026.5.29.2)
配置变更:将 HERMES_UID 更改为 1000:1000

主要变更:
- 核心架构重构:run_agent.py 从 16,083 行精简至 3,821 行,并拆分为 14 个 agent/* 模块,提升可维护性与开发效率。
- 显著性能提升:冷启动再优化,hermes --version 冷启动耗时降低 63%,每回合函数调用减少 47%,session_search 重写为无 LLM、零成本、速度提升约 4,500×。
- Kanban 进化为多 Agent 平台:新增任务自动拆解、Swarm 拓扑、定时任务、任务级模型覆盖、每任务工作区、任务执行/运行检测端点。
- 安全性与密钥管理增强:Hermes 新增防御 Promptware/Brainworm 风格攻击机制,Bitwarden Secrets Manager 支持以单一引导令牌替代多平台 API 密钥,实现来源标签和高效轮换。
- 生态与集成扩展:加入技能包、ntfy 通知、OpenHands 编排、Nous 官方批准的 MCP 目录、Krea/FAL 图像生成提供商和更深入的 xAI 集成。

查看完整更新日志:https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.29.2
具体变更说明:
- 统一 Hermes 运行身份为 Olares 平台的 UID 1000:1000(由原 10000 替换),升级时自动迁移已有文件属主。
- 修复终端和 Dashboard 访问:统一交互式会话降权方案,brew 路径永久有效,Dashboard 容器支持 Home/External 卷挂载。
169 changes: 138 additions & 31 deletions hermesagent/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
# as the single source of truth (SQLite, config, .env, skills, memories).
#
# The s6-overlay v3 image (/init as PID 1) MUST start as root: s6 chowns /run +
# /opt/data and drops every service to the hermes user (uid 10000) via
# s6-setuidgid. Pinning runAsUser:10000 breaks that drop (setgroups EPERM), so
# we start as root like the upstream docker-compose (HERMES_UID/HERMES_GID).
# `kubectl exec` then attaches as root, but /opt/hermes/bin/hermes (first on
# PATH) re-execs the CLI as hermes so files stay uid-10000-owned.
# /opt/data and drops every service to the hermes user via s6-setuidgid.
# Pinning runAsUser breaks that drop (setgroups EPERM), so we start as root
# and pass HERMES_UID/HERMES_GID=1000 to match Olares userData ownership.
# `kubectl exec` attaches as root; interactive shells source drop-to-hermes
# (profile.d + $HOME/.bashrc) to re-exec as hermes (uid 1000). The hermes
# CLI shim at /opt/hermes/bin/hermes does the same for non-interactive calls.
---
apiVersion: apps/v1
kind: Deployment
Expand All @@ -29,14 +30,14 @@ spec:
io.kompose.service: hermesagent
bytetrade.io/terminal: hermesagent
spec:
# Start as root so s6 can drop services to uid 10000 itself; do NOT set
# Start as root so s6 can drop services to uid 1000 itself; do NOT set
# runAsUser (breaks s6's privilege drop). fsGroup keeps volumes group-
# accessible to 10000.
# accessible to 1000 (Olares platform default).
securityContext:
fsGroup: 10000
fsGroup: 1000

initContainers:
# Chown /opt/data to 10000 before runtime (hostPath may start root-owned).
# Chown /opt/data to 1000 before runtime (hostPath may start root-owned).
- name: init-chmod-data
image: "beclab/aboveos-busybox:1.37.0"
securityContext:
Expand All @@ -46,10 +47,35 @@ spec:
- sh
- "-c"
- |
mkdir -p /opt/data
chown -R 10000:10000 /opt/data || true
mkdir -p /opt/data/.olares-cli/data
chown -R 1000:1000 /opt/data || true
chmod -R u+rwX,g+rwX /opt/data || true
echo "[init] /opt/data ready (owner=10000:10000)"
# Hook interactive shells into drop-to-hermes (kubectl exec is root).
MARKER="# hermesagent: drop-to-hermes"
for rc in /opt/data/.bashrc /opt/data/.profile; do
if [ ! -f "$rc" ] || ! grep -qF "$MARKER" "$rc" 2>/dev/null; then
{
echo ""
echo "$MARKER"
echo '[ -f /etc/profile.d/99-drop-to-hermes.sh ] && . /etc/profile.d/99-drop-to-hermes.sh'
} >> "$rc"
fi
done
# Keep brew + hermes on PATH after bash -l resets profile (hermes uid shells).
PATH_MARKER="# hermesagent: brew-path"
for rc in /opt/data/.bashrc /opt/data/.profile; do
if ! grep -qF "$PATH_MARKER" "$rc" 2>/dev/null; then
{
echo ""
echo "$PATH_MARKER"
echo 'export HOMEBREW_PREFIX="${HOMEBREW_PREFIX:-/home/linuxbrew/.linuxbrew}"'
echo 'export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"'
echo 'export PATH="/opt/hermes/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/hermes/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"'
} >> "$rc"
fi
done
chown 1000:1000 /opt/data/.bashrc /opt/data/.profile 2>/dev/null || true
echo "[init] /opt/data ready (owner=1000:1000, .olares-cli seeded)"
resources: {}
volumeMounts:
- mountPath: /opt/data
Expand Down Expand Up @@ -79,16 +105,45 @@ spec:
cp -a /brew-staging/.linuxbrew/. /home/linuxbrew/.linuxbrew/
fi

# Stage olares-cli into brew bin.
# Stage olares-cli into the persistent brew-volume bin dir.
OLARES_CLI=""
for p in /usr/local/bin/olares-cli /brew-staging/.linuxbrew/bin/olares-cli /opt/olares-cli/olares-cli /olares-cli; do
for p in /usr/local/bin/olares-cli \
/brew-staging/.linuxbrew/bin/olares-cli \
/brew-staging/olares-cli \
/opt/olares-cli/olares-cli \
/olares-cli; do
[ -x "$p" ] && OLARES_CLI="$p" && break
done
[ -z "$OLARES_CLI" ] && OLARES_CLI="$(command -v olares-cli 2>/dev/null || find / -maxdepth 5 -type f -name olares-cli -perm -u+x 2>/dev/null | head -1)"
if [ -z "$OLARES_CLI" ]; then
OLARES_CLI="$(find /brew-staging /usr/local /opt -maxdepth 8 -type f \
\( -name 'olares-cli' -o -name 'olares-cli-*' \) -perm -u+x 2>/dev/null | head -1)"
fi
if [ -z "$OLARES_CLI" ] && command -v curl >/dev/null 2>&1; then
case "$(uname -m)" in
x86_64|amd64)
OLARES_CLI_URL="https://cdn.olares.com/olares-cli-v1.12.7-20260510_linux_amd64.8705e94.tar.gz"
;;
aarch64|arm64)
OLARES_CLI_URL="https://cdn.olares.com/olares-cli-v1.12.7-20260510_linux_arm64.8705e94.tar.gz"
;;
esac
if [ -n "${OLARES_CLI_URL:-}" ]; then
echo "[init-brew] fetching olares-cli from CDN (${OLARES_CLI_URL})..."
mkdir -p /tmp/olares-cli-extract
if curl -fsSL -o /tmp/olares-cli.tgz "$OLARES_CLI_URL"; then
tar -xzf /tmp/olares-cli.tgz -C /tmp/olares-cli-extract
OLARES_CLI="$(find /tmp/olares-cli-extract -maxdepth 4 -type f \
\( -name 'olares-cli' -o -name 'olares-cli-*' \) -perm -u+x 2>/dev/null | head -1)"
fi
fi
fi
if [ -n "$OLARES_CLI" ]; then
mkdir -p /home/linuxbrew/.linuxbrew/bin
install -m 0755 "$OLARES_CLI" /home/linuxbrew/.linuxbrew/bin/olares-cli
rm -f /home/linuxbrew/.linuxbrew/bin/olares-cli.real
echo "[init-brew] olares-cli staged to /home/linuxbrew/.linuxbrew/bin from $OLARES_CLI"
else
echo "[init-brew] WARN: olares-cli not found"
echo "[init-brew] WARN: olares-cli not found (image + CDN)"
fi

# python3 shim -> hermes venv.
Expand All @@ -112,7 +167,35 @@ spec:
printf '#!/bin/sh\nF=/opt/hermes/hermes_cli/web_server.py\n[ -f "$F" ] && sed -i "s/return client_host in _LOOPBACK_HOSTS/return True/" "$F"\nexit 0\n' > /cli-bin/03-allow-dashboard-ws
chmod 0755 /cli-bin/03-allow-dashboard-ws

chown -R 10000:10000 /home/linuxbrew || true
# Repair olares-cli state after legacy root kubectl exec writes.
printf '#!/bin/sh\nD="/opt/data/.olares-cli"\nmkdir -p "$D/data" 2>/dev/null || true\nchown -R 1000:1000 "$D" 2>/dev/null || true\nchmod -R u+rwX,g+rwX "$D" 2>/dev/null || true\nexit 0\n' \
> /cli-bin/04-fix-olares-cli-perms
chmod 0755 /cli-bin/04-fix-olares-cli-perms

# Interactive kubectl exec drops root → hermes (uid 1000) once per session.
# Mounted on the hermesagent container only; $HOME/.bashrc sources it too.
printf '%s\n' \
'#!/bin/sh' \
'# Olares: drop interactive root shells to hermes (UID 1000).' \
'[ "${_HERMES_DROP_TO_HERMES:-}" = 1 ] && return 0' \
'[ "$(id -u)" != 0 ] && return 0' \
'case "$-" in *i*) ;; *) [ -z "${PS1:-}" ] && return 0 ;; esac' \
'S6_SUID=/command/s6-setuidgid' \
'[ -x "$S6_SUID" ] || return 0' \
'export _HERMES_DROP_TO_HERMES=1' \
'export HOME=/opt/data' \
'export OLARES_CLI_HOME="${OLARES_CLI_HOME:-/opt/data/.olares-cli}"' \
'export OLARES_CLI_DATA_DIR="${OLARES_CLI_DATA_DIR:-/opt/data/.olares-cli/data}"' \
'export HOMEBREW_PREFIX="${HOMEBREW_PREFIX:-/home/linuxbrew/.linuxbrew}"' \
'export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"' \
'export PATH="/opt/hermes/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/hermes/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' \
'DROP_SHELL=/bin/bash' \
'[ -x "$DROP_SHELL" ] || DROP_SHELL=/bin/sh' \
'exec "$S6_SUID" hermes "$DROP_SHELL" -l' \
> /cli-bin/drop-to-hermes
chmod 0755 /cli-bin/drop-to-hermes

chown -R 1000:1000 /home/linuxbrew || true
echo "[init-brew] done"
resources: {}
volumeMounts:
Expand All @@ -138,12 +221,12 @@ spec:
exit 0
fi
mkdir -p /opt/data/skills
chown 10000:10000 /opt/data/skills || true
chown 1000:1000 /opt/data/skills || true
for d in /skills-staging/*/; do
name="$(basename "$d")"
rm -rf "/opt/data/skills/$name"
cp -a "$d" "/opt/data/skills/$name"
chown -R 10000:10000 "/opt/data/skills/$name"
chown -R 1000:1000 "/opt/data/skills/$name"
done
echo "[init-skills] Olares skills flattened into /opt/data/skills:"
ls -1 /skills-staging
Expand Down Expand Up @@ -290,12 +373,11 @@ spec:
# HOME on /opt/data so HOME-respecting CLIs persist + share config.
- name: HOME
value: /opt/data
# uid/gid s6 maps the hermes user to and drops services to (image
# default 10000; matches the chown + hostPath ownership).
# uid/gid s6 maps the hermes user to (Olares platform default 1000).
- name: HERMES_UID
value: "10000"
value: "1000"
- name: HERMES_GID
value: "10000"
value: "1000"
- name: HERMES_HOME
value: /opt/data
- name: HERMES_GATEWAY_RESTART_DELAY_SECONDS
Expand Down Expand Up @@ -365,6 +447,10 @@ spec:
name: cli-bin
subPath: 02-reconcile-profiles
readOnly: true
- mountPath: /etc/cont-init.d/04-fix-olares-cli-perms
name: cli-bin
subPath: 04-fix-olares-cli-perms
readOnly: true
- mountPath: /dev/shm
name: dshm
{{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }}
Expand Down Expand Up @@ -398,12 +484,11 @@ spec:
env:
- name: HOME
value: /opt/data
# uid/gid s6 maps the hermes user to and drops services to (image
# default 10000; matches the chown + hostPath ownership).
# uid/gid s6 maps the hermes user to (Olares platform default 1000).
- name: HERMES_UID
value: "10000"
value: "1000"
- name: HERMES_GID
value: "10000"
value: "1000"
- name: GATEWAY_HEALTH_URL
value: "http://localhost:8642"
# Match gateway PATH so dashboard-side `hermes ...` sees brew.
Expand Down Expand Up @@ -458,6 +543,18 @@ spec:
name: cli-bin
subPath: 03-allow-dashboard-ws
readOnly: true
- mountPath: /etc/cont-init.d/04-fix-olares-cli-perms
name: cli-bin
subPath: 04-fix-olares-cli-perms
readOnly: true
{{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }}
- mountPath: /home/userdata/home/
name: olares-home-dir
{{- end }}
{{- if eq (toString .Values.olaresEnv.ALLOW_EXTERNAL_DIR_ACCESS) "true" }}
- mountPath: /home/userdata/external/
name: olares-external-dir
{{- end }}
securityContext:
allowPrivilegeEscalation: false

Expand All @@ -473,12 +570,11 @@ spec:
value: xterm-256color
- name: HOME
value: /opt/data
# uid/gid s6 maps the hermes user to and drops services to (image
# default 10000; matches the chown + hostPath ownership).
# uid/gid s6 maps the hermes user to (Olares platform default 1000).
- name: HERMES_UID
value: "10000"
value: "1000"
- name: HERMES_GID
value: "10000"
value: "1000"
- name: HERMES_HOME
value: /opt/data
- name: HOMEBREW_PREFIX
Expand All @@ -491,6 +587,9 @@ spec:
value: /opt/data/.olares-cli
- name: OLARES_CLI_DATA_DIR
value: /opt/data/.olares-cli/data
# dash reads $ENV before interactive input (kubectl exec sh).
- name: ENV
value: /etc/profile.d/99-drop-to-hermes.sh
resources:
limits:
cpu: "2"
Expand All @@ -515,6 +614,14 @@ spec:
name: cli-bin
subPath: 02-reconcile-profiles
readOnly: true
- mountPath: /etc/profile.d/99-drop-to-hermes.sh
name: cli-bin
subPath: drop-to-hermes
readOnly: true
- mountPath: /etc/cont-init.d/04-fix-olares-cli-perms
name: cli-bin
subPath: 04-fix-olares-cli-perms
readOnly: true
{{- if eq (toString .Values.olaresEnv.ALLOW_HOME_DIR_ACCESS) "true" }}
- mountPath: /home/userdata/home/
name: olares-home-dir
Expand Down