hermes(agent): supervise stock dashboard with gateway

This commit is contained in:
jenkins 2026-08-10 21:27:24 -03:00
parent dfa12dd7f5
commit 22efb7d144
2 changed files with 30 additions and 87 deletions

View File

@ -24,7 +24,7 @@ spec:
ai.bstein.dev/execution: Hermes Kanban with durable direct Codex and Claude Code CLI workers
ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback
ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available
ai.bstein.dev/config-rev: "20260810-stock-dashboard-init-hardening"
ai.bstein.dev/config-rev: "20260811-stock-supervisor"
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: hermes-agent
vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens
@ -319,10 +319,11 @@ spec:
- name: hermes
image: registry.bstein.dev/bstein/hermes-agent@sha256:46de11122226a68adad6d902e81ef9b4b53deb0433dcc61f57fa43fae2e3a3a5
imagePullPolicy: IfNotPresent
command: [/opt/hermes/.venv/bin/hermes]
args: [gateway, run, --no-supervise]
command: [/init, /opt/hermes/docker/main-wrapper.sh]
args: [gateway, run]
ports:
- {name: api, containerPort: 8642, protocol: TCP}
- {name: dashboard, containerPort: 9119, protocol: TCP}
env:
- {name: HERMES_HOME, value: /opt/data}
- {name: HERMES_AUTH_FILE, value: /shared-auth/auth.json}
@ -334,8 +335,12 @@ spec:
- {name: PLAYWRIGHT_BROWSERS_PATH, value: /opt/hermes/.playwright}
- {name: AGENT_BROWSER_EXECUTABLE_PATH, value: /opt/hermes/.playwright/chromium_headless_shell-1228/chrome-linux/headless_shell}
- {name: AGENT_BROWSER_ARGS, value: "--no-sandbox,--disable-dev-shm-usage"}
- {name: HERMES_DASHBOARD, value: "0"}
- {name: HERMES_DASHBOARD, value: "1"}
- {name: HERMES_DASHBOARD_HOST, value: 127.0.0.1}
- {name: HERMES_DASHBOARD_PORT, value: "9119"}
- {name: HERMES_DASHBOARD_FILES_ROOT, value: /opt/data/workspace}
- {name: HERMES_DASHBOARD_PUBLIC_URL, value: https://agent.hermes.bstein.dev}
- {name: HERMES_TUI_AGENT_INIT_TIMEOUT_S, value: "180"}
- {name: API_SERVER_ENABLED, value: "true"}
- {name: API_SERVER_HOST, value: 0.0.0.0}
- {name: API_SERVER_PORT, value: "8642"}
@ -347,98 +352,34 @@ spec:
- {name: provider-auth, mountPath: /shared-auth}
- {name: coordinator, mountPath: /opt/coordinator, readOnly: true}
- {name: auth-patch, mountPath: /opt/hermes/hermes_cli/auth.py, subPath: auth.py}
- {name: tui-gateway-patch, mountPath: /opt/hermes/tui_gateway/server.py, subPath: server.py}
- {name: kubeconfig, mountPath: /opt/data/home/.kube/config, subPath: config, readOnly: true}
- {name: auto-router-plugin, mountPath: /opt/data/plugins/auto-router, readOnly: true}
- {name: tmp, mountPath: /tmp}
startupProbe:
tcpSocket: {port: api}
tcpSocket: {port: dashboard}
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 60
readinessProbe:
tcpSocket: {port: api}
tcpSocket: {port: dashboard}
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
tcpSocket: {port: api}
tcpSocket: {port: dashboard}
initialDelaySeconds: 90
periodSeconds: 30
timeoutSeconds: 10
securityContext:
allowPrivilegeEscalation: false
runAsUser: 10000
runAsGroup: 10000
runAsUser: 0
runAsGroup: 0
seccompProfile:
type: RuntimeDefault
resources:
requests: {cpu: 250m, memory: 512Mi}
limits: {cpu: "2", memory: 4Gi}
- name: dashboard
image: registry.bstein.dev/bstein/hermes-agent@sha256:46de11122226a68adad6d902e81ef9b4b53deb0433dcc61f57fa43fae2e3a3a5
imagePullPolicy: IfNotPresent
command: [/bin/sh, -ec]
args:
- |
set -a
. /opt/data/.env
set +a
exec /opt/hermes/.venv/bin/hermes dashboard \
--host 127.0.0.1 \
--port 9119 \
--skip-build \
--no-open
ports:
- {name: dashboard, containerPort: 9119, protocol: TCP}
env:
- {name: HERMES_HOME, value: /opt/data}
- {name: HERMES_AUTH_FILE, value: /shared-auth/auth.json}
- {name: HOME, value: /opt/data/home}
- {name: CODEX_HOME, value: /opt/data/home/.codex}
- {name: CLAUDE_CONFIG_DIR, value: /opt/data/home/.claude}
- {name: KUBECONFIG, value: /opt/data/home/.kube/config}
- {name: PYTHONPATH, value: /opt/hermes}
- {name: PATH, value: /opt/coordinator:/opt/data/tools/bin:/opt/data/home/.local/bin:/opt/hermes/.venv/bin:/usr/local/bin:/usr/bin:/bin}
- {name: PLAYWRIGHT_BROWSERS_PATH, value: /opt/hermes/.playwright}
- {name: AGENT_BROWSER_EXECUTABLE_PATH, value: /opt/hermes/.playwright/chromium_headless_shell-1228/chrome-linux/headless_shell}
- {name: AGENT_BROWSER_ARGS, value: "--no-sandbox,--disable-dev-shm-usage"}
- {name: HERMES_DASHBOARD_FILES_ROOT, value: /opt/data/workspace}
- {name: HERMES_DASHBOARD_PUBLIC_URL, value: https://agent.hermes.bstein.dev}
- {name: HERMES_TUI_AGENT_INIT_TIMEOUT_S, value: "180"}
volumeMounts:
- {name: home, mountPath: /opt/data}
- {name: provider-auth, mountPath: /shared-auth}
- {name: coordinator, mountPath: /opt/coordinator, readOnly: true}
- {name: auth-patch, mountPath: /opt/hermes/hermes_cli/auth.py, subPath: auth.py}
- {name: tui-gateway-patch, mountPath: /opt/hermes/tui_gateway/server.py, subPath: server.py}
- {name: kubeconfig, mountPath: /opt/data/home/.kube/config, subPath: config, readOnly: true}
- {name: auto-router-plugin, mountPath: /opt/data/plugins/auto-router, readOnly: true}
- {name: tmp, mountPath: /tmp}
workingDir: /opt/data/workspace
readinessProbe:
exec:
command: [curl, -fsS, http://127.0.0.1:9119/api/status]
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command: [curl, -fsS, http://127.0.0.1:9119/api/status]
initialDelaySeconds: 60
periodSeconds: 30
timeoutSeconds: 10
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 10000
runAsGroup: 10000
seccompProfile:
type: RuntimeDefault
resources:
requests: {cpu: 100m, memory: 256Mi}
limits: {cpu: "2", memory: 4Gi}
requests: {cpu: 350m, memory: 768Mi}
limits: {cpu: "3", memory: 6Gi}
- name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.3@sha256:10a1165743a192e1940b4708fb9647027185ce11a681a1c5519b442ff7f1f561
imagePullPolicy: IfNotPresent

View File

@ -632,15 +632,17 @@ def test_agent_root_is_stock_dashboard_and_terminal_is_a_separate_path():
containers = {item["name"]: item for item in pod["containers"]}
assert "webui" not in containers
dashboard = containers["dashboard"]
dashboard_command = dashboard["args"][0]
assert "/opt/hermes/.venv/bin/hermes dashboard" in dashboard_command
assert "--host 127.0.0.1" in dashboard_command
assert "--port 9119" in dashboard_command
assert "--skip-build" in dashboard_command
assert "--no-open" in dashboard_command
dashboard_env = {item["name"]: item["value"] for item in dashboard["env"]}
assert dashboard_env["HERMES_TUI_AGENT_INIT_TIMEOUT_S"] == "180"
assert "dashboard" not in containers
hermes = containers["hermes"]
assert hermes["command"] == ["/init", "/opt/hermes/docker/main-wrapper.sh"]
assert hermes["args"] == ["gateway", "run"]
hermes_env = {item["name"]: item["value"] for item in hermes["env"]}
assert hermes_env["HERMES_DASHBOARD"] == "1"
assert hermes_env["HERMES_DASHBOARD_HOST"] == "127.0.0.1"
assert hermes_env["HERMES_DASHBOARD_PORT"] == "9119"
assert hermes_env["HERMES_TUI_AGENT_INIT_TIMEOUT_S"] == "180"
assert hermes["securityContext"]["runAsUser"] == 0
assert hermes["securityContext"]["runAsGroup"] == 0
terminal = containers["terminal"]
command = terminal["args"][0]
@ -665,7 +667,7 @@ def test_agent_root_is_stock_dashboard_and_terminal_is_a_separate_path():
if item["name"] == "patch-tui-gateway"
)
assert patch_init["command"][-1] == "/patched/server.py"
for name in ("dashboard", "terminal"):
for name in ("hermes", "terminal"):
mounts = containers[name]["volumeMounts"]
assert {
"name": "tui-gateway-patch",