feat: add Hermes Agent LXC

Adds container scripts for Hermes Agent (Nous Research), a self-improving
AI agent with LLM provider integration, terminal execution, web browsing,
and multi-platform messaging support.

Files:
- ct/hermes-agent.sh
- install/hermes-agent-install.sh
- json/hermes-agent.json
- ct/headers/hermes-agent

Deviations from standard patterns (justified):

1. Uses upstream installer (curl-pipe) instead of fetch_and_deploy_gh_release:
   Hermes is a uv-managed Python application with complex dependency
   resolution, virtualenv management, and binary placement—not a single
   binary or tarball from GitHub Releases.

2. Dedicated 'hermes' service user (not running as root):
   The agent executes arbitrary terminal commands on behalf of the user.
   Running as root would give the AI unrestricted system access. This
   follows the protonmail-bridge service-user pattern for isolation.

3. Dashboard (port 9119) bound to localhost only, requiring SSH tunnel:
   The web UI provides admin access to an AI that can execute commands.
   SSH tunnel provides an authentication/authorization boundary.

4. /usr/bin/hermes shim script:
   The hermes CLI validates cwd permissions; running 'hermes' as root
   from /root fails. The shim cd's to /home/hermes and exec's as the
   hermes user via runuser.

5. setsid --wait wrapping of upstream installer:
   The upstream installer probes /dev/tty for interactive prompts even
   with --skip-setup; setsid detaches the controlling terminal.
This commit is contained in:
Stephen Chin
2026-05-02 06:25:28 -07:00
parent b0cb194bd5
commit adbfd66056
4 changed files with 247 additions and 0 deletions

6
ct/headers/hermes-agent Normal file
View File

@@ -0,0 +1,6 @@
__ __ ___ __
/ / / /__ _________ ___ ___ _____ / | ____ ____ ____ / /_
/ /_/ / _ \/ ___/ __ `__ \/ _ \/ ___/ / /| |/ __ `/ _ \/ __ \/ __/
/ __ / __/ / / / / / / / __(__ ) / ___ / /_/ / __/ / / / /_
/_/ /_/\___/_/ /_/ /_/ /_/\___/____/ /_/ |_\__, /\___/_/ /_/\__/
/____/

68
ct/hermes-agent.sh Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env bash
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func)
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Stephen Chin (steveonjava)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://hermes-agent.nousresearch.com/
APP="Hermes Agent"
var_tags="${var_tags:-ai;automation;agent}"
var_cpu="${var_cpu:-2}"
var_ram="${var_ram:-4096}"
var_disk="${var_disk:-20}"
var_os="${var_os:-debian}"
var_version="${var_version:-13}"
var_unprivileged="${var_unprivileged:-1}"
header_info "$APP"
variables
color
catch_errors
function update_script() {
header_info
check_container_storage
check_container_resources
if [[ ! -x /home/hermes/.local/bin/hermes ]]; then
msg_error "No ${APP} Installation Found!"
exit
fi
msg_info "Stopping Services"
systemctl stop hermes-dashboard
systemctl stop hermes-gateway
msg_ok "Stopped Services"
msg_info "Updating ${APP}"
$STD env \
HOME=/home/hermes \
HERMES_HOME=/home/hermes/.hermes \
/home/hermes/.local/bin/hermes update
chown -R hermes:hermes /home/hermes
msg_ok "Updated ${APP}"
msg_info "Starting Services"
systemctl start hermes-gateway
systemctl start hermes-dashboard
msg_ok "Started Services"
msg_ok "Updated successfully!"
exit
}
start
build_container
description
msg_ok "Completed successfully!\n"
echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}"
echo -e "${INFO}${YW} Connect via SSH and configure your LLM provider:${CL}"
echo -e "${TAB}${GATEWAY}${BGN}ssh hermes@${IP}${CL}"
echo -e "${TAB}${BGN}hermes setup${CL}"
echo -e "${INFO}${YW} API Server (OpenAI-compatible):${CL}"
echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:8642/v1${CL}"
echo -e "${INFO}${YW} API key stored at:${CL}"
echo -e "${TAB}${BGN}/home/hermes/.hermes/.env${CL}"
echo -e "${INFO}${YW} Web Dashboard (via SSH tunnel):${CL}"
echo -e "${TAB}${BGN}ssh -L 9119:localhost:9119 hermes@${IP}${CL}"
echo -e "${TAB}${BGN}Then open: http://localhost:9119${CL}"

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env bash
# Copyright (c) 2021-2026 community-scripts ORG
# Author: Stephen Chin (steveonjava)
# License: MIT | https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
# Source: https://hermes-agent.nousresearch.com/
source /dev/stdin <<<"$FUNCTIONS_FILE_PATH"
color
verb_ip6
catch_errors
setting_up_container
network_check
update_os
msg_info "Installing Dependencies"
$STD apt install -y \
git
msg_ok "Installed Dependencies"
NODE_VERSION="22" setup_nodejs
msg_info "Creating Hermes User"
useradd -m -s /bin/bash hermes
msg_ok "Created Hermes User"
msg_info "Installing Hermes Agent"
$STD setsid --wait env \
HOME=/home/hermes \
PATH=/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
bash <(curl -fsSL https://hermes-agent.nousresearch.com/install.sh) --skip-setup --hermes-home /home/hermes/.hermes --dir /home/hermes/.hermes/hermes-agent
if [[ ! -x /home/hermes/.local/bin/hermes ]]; then
msg_error "Hermes binary not found after installation"
exit 1
fi
chown -R hermes:hermes /home/hermes
git config --system --add safe.directory /home/hermes/.hermes/hermes-agent 2>/dev/null || true
msg_ok "Installed Hermes Agent"
msg_info "Installing Web Dashboard"
$STD runuser -u hermes -- \
env HOME=/home/hermes VIRTUAL_ENV=/home/hermes/.hermes/hermes-agent/venv \
/home/hermes/.local/bin/uv pip install 'hermes-agent[web,pty]'
msg_ok "Installed Web Dashboard"
msg_info "Configuring API Server"
API_SERVER_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | cut -c1-32)
cat <<EOF >/home/hermes/.hermes/.env
API_SERVER_ENABLED=true
API_SERVER_HOST=0.0.0.0
API_SERVER_PORT=8642
API_SERVER_KEY=${API_SERVER_KEY}
EOF
chmod 600 /home/hermes/.hermes/.env
chown hermes:hermes /home/hermes/.hermes/.env
msg_ok "Configured API Server"
msg_info "Creating Service"
cat <<EOF >/etc/systemd/system/hermes-gateway.service
[Unit]
Description=Hermes Agent Gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=hermes
Group=hermes
WorkingDirectory=/home/hermes
ExecStart=/home/hermes/.local/bin/hermes gateway run --replace
Environment="HERMES_HOME=/home/hermes/.hermes"
Environment="HOME=/home/hermes"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now hermes-gateway
msg_ok "Created Service"
msg_info "Creating Dashboard Service"
cat <<EOF >/etc/systemd/system/hermes-dashboard.service
[Unit]
Description=Hermes Agent Web Dashboard
After=network-online.target hermes-gateway.service
Wants=network-online.target
[Service]
Type=simple
User=hermes
Group=hermes
WorkingDirectory=/home/hermes
ExecStart=/home/hermes/.local/bin/hermes dashboard --host 127.0.0.1 --port 9119 --no-open
Environment="HERMES_HOME=/home/hermes/.hermes"
Environment="HOME=/home/hermes"
Environment="PATH=/home/hermes/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="NODE_OPTIONS=--max-old-space-size=3072"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl enable -q --now hermes-dashboard
msg_ok "Created Dashboard Service"
msg_info "Creating Hermes Shim"
cat <<'EOF' >/usr/bin/hermes
#!/bin/bash
cd /home/hermes
exec runuser -u hermes -- /home/hermes/.local/bin/hermes "$@"
EOF
chmod +x /usr/bin/hermes
msg_ok "Created Hermes Shim"
motd_ssh
customize
cleanup_lxc

52
json/hermes-agent.json Normal file
View File

@@ -0,0 +1,52 @@
{
"name": "Hermes Agent",
"slug": "hermes-agent",
"categories": [
20
],
"date_created": "2026-05-02",
"type": "ct",
"updateable": true,
"privileged": false,
"interface_port": 8642,
"documentation": "https://hermes-agent.nousresearch.com/docs",
"website": "https://hermes-agent.nousresearch.com",
"logo": "https://cdn.jsdelivr.net/gh/selfhst/icons@main/webp/hermes.webp",
"description": "Self-improving AI agent by Nous Research. Connects to 15+ LLM providers, executes terminal commands, browses the web, and learns from experience. Supports 16 messaging platforms (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, and more) with persistent memory and autonomous skill creation.",
"install_methods": [
{
"type": "default",
"script": "ct/hermes-agent.sh",
"config_path": "/home/hermes/.hermes/",
"resources": {
"cpu": 2,
"ram": 4096,
"hdd": 20,
"os": "debian",
"version": "13"
}
}
],
"default_credentials": {
"username": "hermes",
"password": null
},
"notes": [
{
"text": "Warning: Hermes can execute terminal commands. The agent runs as a dedicated 'hermes' service user for isolation.",
"type": "warning"
},
{
"text": "After container startup, SSH in as the 'hermes' user and run 'hermes setup' to configure your LLM provider (OpenRouter, Anthropic, OpenAI, Nous Portal, or custom endpoint).",
"type": "info"
},
{
"text": "OpenAI-compatible API server available at http://<container-ip>:8642/v1. API key is stored in /home/hermes/.hermes/.env.",
"type": "info"
},
{
"text": "Access the web dashboard via SSH tunnel: ssh -L 9119:localhost:9119 hermes@<container-ip>, then open http://localhost:9119",
"type": "info"
}
]
}