Command not found im Terminal des Agenten: Wie Hermes einen von Login-Shells zurückgesetzten PATH repariert

Du bittest den Agenten, in seinem Terminal hermes cron list auszuführen, damit er sieht, warum ein geplanter Job nie gefeuert hat. Zurück kommt eine einzige Zeile: bash: hermes: command not found. Du öffnest dein eigenes SSH-Fenster, tippst dasselbe, und es funktioniert. Zurück in der Session liefert auch command -v node nichts — obwohl du node mit nvm installiert hast.
Das ist kein Rechteproblem, und Hermes ist nicht kaputt. Irgendetwas hat PATH zurückgesetzt, still und vollständig.
Wer PATH zurückgesetzt hat
Hinter dem Terminal-Tool steckt eine bash. Damit die nvm-, asdf- und pyenv-Setups, auf die du dich verlässt, auch für den Agenten funktionieren, startet Hermes beim Anlegen der Session einmal eine Login-Shell und friert die daraus resultierende Umgebung ein — ~/.profile, ~/.bash_profile und ~/.bashrc zu sourcen ist genau der Weg, über den diese Version-Manager sich selbst in PATH eintragen. Dieser Teil ist Absicht und sinnvoll.
Das Problem ist /etc/profile unter Debian und Ubuntu: Es erweitert PATH nicht, es schreibt ihn auf eine feste Liste um (typischerweise /usr/local/bin:/usr/bin:/bin plus ein paar Spiele-Verzeichnisse). Sobald die Login-Shell fertig ist, zementiert der eingefrorene Snapshot diesen zurückgesetzten PATH. Alles, was Hermes beim Start hatte, ist weg: ~/.local/bin, /opt/hermes/bin, /opt/hermes/.venv/bin und jedes nvm-Shim-Verzeichnis.
Im Docker-Image ist das Symptom am deutlichsten: einmal mit bash -l in einen Container springen oder docker exec … bash -l ausführen, und ein blankes hermes endet mit Exit-Code 127. Hintergrundbefehle trifft es genauso, weil sie über bash -lic laufen.
Der Fix: wieder anhängen, was das Profil verworfen hat
Die Reparatur überschreibt nicht, was die Login-Shell entschieden hat. Sie bringt beides in Einklang:
- nach dem Lauf des Login-Profils wird jedes Verzeichnis aus der Startumgebung, das jetzt fehlt, angehängt — in seiner ursprünglichen relativen Reihenfolge;
- bereits vorhandene Verzeichnisse werden nie doppelt eingetragen;
- nur absolute Einträge werden auf Existenz geprüft — ein relativer Eintrag wird gegen das Arbeitsverzeichnis der Shell aufgelöst, eine Prüfung aus Python heraus wäre also sinnlos;
- fehlende Verzeichnisse werden übersprungen, statt als Ballast in PATH zu landen.
Das Anhängen am Ende ist die entscheidende Wahl. Was dein nvm- oder pyenv-Init entschieden hat, bleibt genau dort, wo es war: Ein Befehl, der vorher aufgelöst wurde, landet weiterhin auf derselben Binary; nur Befehle, die vorher gar keinen Treffer hatten, bekommen einen.
Hintergrundbefehle (spawn_local aus process_registry, bash -lic) stellen dasselbe Restore-Snippet voran, damit Vorder- und Hintergrund nicht uneins darüber sein können, welches python oder hermes existiert.
Das Docker-Image legt eine zweite Ebene darüber: /etc/profile.d/hermes.sh wird ins Image installiert, sodass jede Login-Shell die drei Image-Verzeichnisse wieder ergänzt — bereits gelistete bleiben, wo sie sind.
# /etc/profile.d/hermes.sh (im Image)
for __hermes_p in /opt/data/.local/bin /opt/hermes/.venv/bin /opt/hermes/bin; do
case ":$PATH:" in
*":$__hermes_p:"*) ;;
*) PATH="$__hermes_p:$PATH" ;;
esac
done
unset __hermes_p
export PATH
Prüfen, was PATH wirklich ist
Drei Zeilen im Terminal des Agenten erzählen die ganze Geschichte:
echo $PATH # was der Agent tatsächlich bekommt
command -v hermes # leer heißt: nicht gefunden
bash -lc 'echo $PATH' # der zurückgesetzte PATH der Login-Shell, zum Vergleich
Tabelle von Symptom zu Ursache:
| Symptom | Echte Ursache | Was tun |
|---|---|---|
hermes: command not found in Docker |
Login-Shell hat PATH zurückgesetzt; dem Image fehlt der profile.d-Patch | Image oder Hermes-Build aktualisieren |
node / python fehlt, obwohl auf dem Host installiert |
/etc/profile hat das nvm/pyenv-Init aus ~/.profile überschrieben |
Im neuen Build automatisch behoben; in älteren Builds die Init-Dateien explizit auflisten |
| Nur Hintergrundbefehle scheitern | Älterer Build hat das Restore-Snippet nicht mit dem Hintergrundpfad geteilt | Aktualisieren, oder vorerst Vordergrundbefehle nutzen |
| Dein eigenes Skript findet ein Tool nicht | Das Skript verließ sich auf ein Verzeichnis, das nur eine interaktive Shell hat | Absolute Pfade nutzen oder die Datei in shell_init_files eintragen |
Wenn du eigene Umgebungsdateien hast — etwa eine interne Toolchain —, sag Hermes genau, was gesourct werden soll, statt zu hoffen, dass es das Richtige rät:
terminal:
auto_source_bashrc: true # Standard; eine explizite shell_init_files-Liste übernimmt
shell_init_files:
- ~/.profile
- ~/.config/hermes/env.sh
Grenzen, die man kennen sollte
- Nur Verzeichnisse, die in der Umgebung vorhanden waren, mit der Hermes gestartet wurde, werden wiederhergestellt. Was dein Parent-Prozess nie hatte, wird nicht erfunden.
- Wenn du ein Verzeichnis in deinem Profil bewusst aus PATH entfernt hast, es aber noch im Start-PATH stand, kommt es zurück. Das ist der beabsichtigte Kompromiss: funktionierende Befehle funktionierend halten.
- Windows ist nicht betroffen — der native PATH wird mit Semikolon verbunden, und bash sieht eine konvertierte Kopie.
- Reihenfolge ist Vorrang. Weil wiederhergestellte Einträge am Ende landen, kommen Systemverzeichnisse weiterhin vor deinen eigenen; PATH-Probleme also nicht dadurch „reparieren“, dass man ein beschreibbares Verzeichnis nach vorne stellt.
Für einen breiteren Umgebungscheck hermes doctor ausführen. Das Scratch-Verhalten im Terminal steht in temporäre Terminal-Verzeichnisse, Container-Layouts in shared container mode, und wie man die Shell komplett austauscht in Terminal-Backend-Plugins.
Release-Status
Der Fix ist am 29. Oktober 2026 in main gemerged (PR #146080). Das aktuelle Release v0.22.5 (23. Oktober 2026) enthält ihn nicht, ältere Builds können also weiterhin auf command not found laufen.
PATH-Bugs sind genau deshalb unangenehm, weil sie nie einen Fehler werfen — ein paar Verzeichnisse fehlen einfach. Immerhin kommen sie jetzt dorthin zurück, wo sie hingehören.