The previous approach used a /usr/bin/hermes shim to proxy commands from root
to the hermes user, and a hand-crafted system-level systemd unit for the
gateway. This worked for the default profile but broke down for named profiles:
- hermes profile create <name> generates an alias script in
~/.local/bin/<name> that calls hermes with -p <name>. These aliases live
in the hermes user's PATH, not root's, so root could not invoke them.
- Maintaining parity would require per-profile shims, a watcher daemon to
create/remove them, and system-unit mirrors for each profile gateway — all
of which would need to stay in sync with hermes internals across updates.
New approach — work with hermes, not around it:
- loginctl enable-linger hermes: ensures the hermes user's systemd session
starts at boot and persists without login. All user-unit gateways (default
and per-profile) now survive reboots automatically.
- Gateway service management delegated entirely to hermes: 'hermes gateway
install' / 'hermes setup' create and enable the user unit natively.
The install script no longer pre-installs the gateway; hermes prompts the
user to do so at the end of 'hermes setup'.
- hermes-dashboard.service remains a system unit (no native install command
exists for it). Its After= no longer references hermes-gateway.service
since there is no system-unit gateway to depend on.
- /usr/bin/hermes shim removed. Root is guided to 'su - hermes' via a two-
line /etc/profile.d/hermes-hint.sh message on login, with a one-liner to
make the switch automatic. Once logged in as hermes, all hermes commands,
profile aliases, and gateway management work natively.
- update_script simplified: only hermes-dashboard (our unit) is stopped and
restarted. hermes update --yes handles gateway service lifecycle itself.
The hermes service account has no password or SSH keys and cannot
be used to log in. Access is via root (standard PVE Helper Scripts
pattern). Also add -fN flags to the dashboard tunnel command so it
runs in the background without opening a shell session.
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.
- drop redundant curl of default.yml (file is part of release tarball)
- stop creating /opt/authentik-data dirs in install (mounted later as separate volume)
- enable services without --now in install (started after data volume is attached)
Introduce GitLab release helpers and use them to conditionally update Storyteller.
- misc/tools.func: add get_latest_gitlab_release and check_for_gl_release functions (GitLab API calls, token support, pinning, error handling, requires jq).
- ct/storyteller.sh: wrap update sequence with check_for_gl_release so rebuild/deploy only runs when a new GitLab release is detected; update author metadata.
- install/storyteller-install.sh: remove python3 from apt dependencies and drop NODE_OPTIONS export; minor whitespace cleanup.
These changes prevent unnecessary rebuilds by detecting upstream GitLab releases and improve robustness of release detection and error reporting.
Download authentik's lib/default.yml for the specified AUTHENTIK_VERSION before running go mod/download and build (added curl to ct/authentik.sh and install/authentik-install.sh to write to /opt/authentik/authentik/lib/default.yml). Also normalize Bitfocus Companion app name to "Bitfocus-Companion" in ct/bitfocus-companion.sh.
Use literal 'Squid' in msg_* labels, add missing msg_ok and spacing in
update_script. Replace install_packages_with_retry/enable_and_start_service/
safe_service_restart helpers with plain apt and systemctl commands. Merge
auth setup and config validation into a single msg block. Drop the custom
/etc/profile.d MOTD heredoc and trailing htpasswd echo.