A small dynamic terminal UI for managing Hermes Agent's Gateway / Telegram and Web Dashboard as systemd --user services under WSL2 or Linux.


hermes executable automatically.journalctl --follow.HERMES_HOME.~/.config/systemd/user/ unit files.hermes gateway run --external-supervisor so systemd owns restart behavior.WSL2 must be using systemd:
ps -p 1 -o comm=
Expected:
systemd
Hermes must already be installed and available in PATH:
command -v hermes
Run the staged launcher from the repository root:
./hermes-service-tui.sh
It validates the host before changing anything:
systemd as PID 1 and an available systemctl --user manager.PATH and Python 3.10+..venv when missing and installs/updates the package dependencies there.To remove this TUI's OS-level user services and its local virtual environment:
./hermes-service-tui.sh --uninstall
The uninstall command stops/disables and removes only these user unit files:
~/.config/systemd/user/hermes-gateway.service
~/.config/systemd/user/hermes-dashboard.service
~/.config/systemd/user/hermes.target
It does not remove Hermes Agent or ~/.hermes. Use --yes for a non-interactive uninstall.
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
python -m hermes_service_tui
| Key | Action |
|---|---|
↑ / ↓ | Select Gateway or Dashboard |
i | Install/update systemd units using the selected profile and port |
s | Start selected service |
x | Stop selected service |
e | Restart selected service |
l | Start/stop the selected service's live journal stream |
p | Focus the dashboard port editor; press Apply Port to save/restart |
d | Show Telegram, port-owner, and WSL auto-start diagnostics |
r | Refresh status |
q | Quit |
The same actions are available through buttons.
./hermes-service-tui.sh
↑ / ↓.i to create or update the three systemd user unit files.s to start the selected service. Repeat for the other service.The TUI writes these user-level units and does not edit Hermes configuration, .env, tokens, or config.yaml:
~/.config/systemd/user/hermes-gateway.service
~/.config/systemd/user/hermes-dashboard.service
~/.config/systemd/user/hermes.target
Use the target to control both services together:
# Start both
systemctl --user start hermes.target
# Stop both
systemctl --user stop hermes.target
# Show current state
systemctl --user status hermes.target
Manage one service when needed:
# Restart the dashboard after a problem
systemctl --user restart hermes-dashboard.service
# Follow Gateway / Telegram logs
journalctl --user -u hermes-gateway.service -f
# Read the latest dashboard logs
journalctl --user -u hermes-dashboard.service -n 80 --no-pager
The TUI enables the units during Install/Update. Enable lingering if you also want the user service manager to run without an active interactive login:
sudo loginctl enable-linger "$USER"
Verify it:
loginctl show-user "$USER" -p Linger
Remove only the systemd units managed by this project and the project-local Python environment:
./hermes-service-tui.sh --uninstall
For scripts or CI, bypass the confirmation prompt:
./hermes-service-tui.sh --uninstall --yes
This preserves the Hermes CLI and ~/.hermes data. It does not delete tokens, profiles, or Hermes configuration.
The launcher exits without making changes when PID 1 is not systemd. In your WSL distribution, add this to /etc/wsl.conf:
# /etc/wsl.conf
[boot]
systemd=true
Then run this from Windows PowerShell, not WSL:
wsl --shutdown
Open a new WSL terminal and confirm:
ps -p 1 -o comm=
# expected: systemd
Hermes CLI is required but was not foundInstall or repair Hermes Agent, then open a new shell and confirm it is discoverable:
command -v hermes
hermes --help
Check its state, recent logs, and whether port 9119 listens locally:
systemctl --user status hermes-dashboard.service
journalctl --user -u hermes-dashboard.service -n 80 --no-pager
ss -ltnp | grep ':9119'
Restart it after resolving the reported issue:
systemctl --user restart hermes-dashboard.service
Read the service log first. Fix the Hermes configuration error it reports, then restart the service:
journalctl --user -u hermes-gateway.service -n 80 --no-pager
systemctl --user restart hermes-gateway.service
.venv/bin/python -m pytest -q
hermes profile use or change your normal CLI default.1 to 65535 and select Apply Port. The TUI rejects a port owned by another visible process and shows its PID/process name.l on either service to follow its journal live. Press l again to stop.d to inspect the selected profile's local Telegram credential presence, the dashboard port owner, and WSL auto-start readiness. Credential values never appear in the TUI.Profiles use Hermes' documented HERMES_HOME isolation. Selecting coder, for example, writes HERMES_HOME=~/.hermes/profiles/coder to both generated unit files.
Build a self-contained Linux/WSL executable with PyInstaller:
./scripts/build-binary.sh
The script installs only the build extra into this project's .venv, then produces:
dist/hermes-service-tui
release/hermes-service-tui-<version>-linux-x86_64.tar.gz
release/hermes-service-tui-<version>-linux-x86_64.tar.gz.sha256
Run the artifact on the same target family used to build it:
./dist/hermes-service-tui
For deployment, copy the versioned archive to the target Linux/WSL x86-64 system,
verify it with sha256sum -c <archive>.sha256, extract it, and run the bundled
hermes-service-tui executable. The archive also includes the README and license.
PyInstaller binaries are OS-specific. Build separately on Linux/WSL, macOS, and Windows if you add support for those targets.
5 commits
Python
81.5%
Shell
18.5%
A small dynamic terminal UI for managing Hermes Agent's Gateway / Telegram and Web Dashboard as systemd --user services under WSL2 or Linux.


hermes executable automatically.journalctl --follow.HERMES_HOME.~/.config/systemd/user/ unit files.hermes gateway run --external-supervisor so systemd owns restart behavior.WSL2 must be using systemd:
ps -p 1 -o comm=
Expected:
systemd
Hermes must already be installed and available in PATH:
command -v hermes
Run the staged launcher from the repository root:
./hermes-service-tui.sh
It validates the host before changing anything:
systemd as PID 1 and an available systemctl --user manager.PATH and Python 3.10+..venv when missing and installs/updates the package dependencies there.To remove this TUI's OS-level user services and its local virtual environment:
./hermes-service-tui.sh --uninstall
The uninstall command stops/disables and removes only these user unit files:
~/.config/systemd/user/hermes-gateway.service
~/.config/systemd/user/hermes-dashboard.service
~/.config/systemd/user/hermes.target
It does not remove Hermes Agent or ~/.hermes. Use --yes for a non-interactive uninstall.
python3 -m venv .venv
. .venv/bin/activate
python -m pip install -e '.[dev]'
python -m hermes_service_tui
| Key | Action |
|---|---|
↑ / ↓ | Select Gateway or Dashboard |
i | Install/update systemd units using the selected profile and port |
s | Start selected service |
x | Stop selected service |
e | Restart selected service |
l | Start/stop the selected service's live journal stream |
p | Focus the dashboard port editor; press Apply Port to save/restart |
d | Show Telegram, port-owner, and WSL auto-start diagnostics |
r | Refresh status |
q | Quit |
The same actions are available through buttons.
./hermes-service-tui.sh
↑ / ↓.i to create or update the three systemd user unit files.s to start the selected service. Repeat for the other service.The TUI writes these user-level units and does not edit Hermes configuration, .env, tokens, or config.yaml:
~/.config/systemd/user/hermes-gateway.service
~/.config/systemd/user/hermes-dashboard.service
~/.config/systemd/user/hermes.target
Use the target to control both services together:
# Start both
systemctl --user start hermes.target
# Stop both
systemctl --user stop hermes.target
# Show current state
systemctl --user status hermes.target
Manage one service when needed:
# Restart the dashboard after a problem
systemctl --user restart hermes-dashboard.service
# Follow Gateway / Telegram logs
journalctl --user -u hermes-gateway.service -f
# Read the latest dashboard logs
journalctl --user -u hermes-dashboard.service -n 80 --no-pager
The TUI enables the units during Install/Update. Enable lingering if you also want the user service manager to run without an active interactive login:
sudo loginctl enable-linger "$USER"
Verify it:
loginctl show-user "$USER" -p Linger
Remove only the systemd units managed by this project and the project-local Python environment:
./hermes-service-tui.sh --uninstall
For scripts or CI, bypass the confirmation prompt:
./hermes-service-tui.sh --uninstall --yes
This preserves the Hermes CLI and ~/.hermes data. It does not delete tokens, profiles, or Hermes configuration.
The launcher exits without making changes when PID 1 is not systemd. In your WSL distribution, add this to /etc/wsl.conf:
# /etc/wsl.conf
[boot]
systemd=true
Then run this from Windows PowerShell, not WSL:
wsl --shutdown
Open a new WSL terminal and confirm:
ps -p 1 -o comm=
# expected: systemd
Hermes CLI is required but was not foundInstall or repair Hermes Agent, then open a new shell and confirm it is discoverable:
command -v hermes
hermes --help
Check its state, recent logs, and whether port 9119 listens locally:
systemctl --user status hermes-dashboard.service
journalctl --user -u hermes-dashboard.service -n 80 --no-pager
ss -ltnp | grep ':9119'
Restart it after resolving the reported issue:
systemctl --user restart hermes-dashboard.service
Read the service log first. Fix the Hermes configuration error it reports, then restart the service:
journalctl --user -u hermes-gateway.service -n 80 --no-pager
systemctl --user restart hermes-gateway.service
.venv/bin/python -m pytest -q
hermes profile use or change your normal CLI default.1 to 65535 and select Apply Port. The TUI rejects a port owned by another visible process and shows its PID/process name.l on either service to follow its journal live. Press l again to stop.d to inspect the selected profile's local Telegram credential presence, the dashboard port owner, and WSL auto-start readiness. Credential values never appear in the TUI.Profiles use Hermes' documented HERMES_HOME isolation. Selecting coder, for example, writes HERMES_HOME=~/.hermes/profiles/coder to both generated unit files.
Build a self-contained Linux/WSL executable with PyInstaller:
./scripts/build-binary.sh
The script installs only the build extra into this project's .venv, then produces:
dist/hermes-service-tui
release/hermes-service-tui-<version>-linux-x86_64.tar.gz
release/hermes-service-tui-<version>-linux-x86_64.tar.gz.sha256
Run the artifact on the same target family used to build it:
./dist/hermes-service-tui
For deployment, copy the versioned archive to the target Linux/WSL x86-64 system,
verify it with sha256sum -c <archive>.sha256, extract it, and run the bundled
hermes-service-tui executable. The archive also includes the README and license.
PyInstaller binaries are OS-specific. Build separately on Linux/WSL, macOS, and Windows if you add support for those targets.
5 commits
Python
81.5%
Shell
18.5%