Gateway-Multiplexing ist jetzt standardmäßig aktiv


Montagmorgen, und im Gruppenchat antwortet niemand. Auf einer Maschine laufen bei dir drei Hermes-Profile — default, coder, research — und jedes hat seine eigene systemd-Unit, seinen eigenen Port und sein eigenes hermes -p coder gateway start, das du dir merken sollst. Der Neustart letzte Nacht hat nur zwei davon zurückgebracht, und der Telegram-Token eines Profils wurde am Ende von zwei Prozessen gleichzeitig abgefragt, also bekam jede Nachricht zwei Antworten. Geändert hast du nichts: Du hast nur für jeden zusätzlichen Bot eine Sache mehr zu betreuen. Hermes antwortet darauf mit einem einzigen Gateway-Prozess, der alle Profile auf der Maschine bedient, und seit dem 2026-09-16 ist das der Standard — mit einem Guard, damit keine bestehende Installation überraschend umgestellt wird.

Was ein multiplexendes Gateway ist

Zuerst drei Begriffe. Ein Profil ist ein in sich geschlossener Hermes-Agent: eigene Konfiguration, eigene Credentials, eigenes Gedächtnis, eigene Skills und Cron-Jobs unter ~/.hermes/profiles/<name>. Das Gateway ist der dauerhaft laufende Prozess, der deine Bots verbunden hält: Es fragt deinen Telegram-Bot ab, beantwortet deinen Webhook, weckt Cron-Jobs und übergibt jede eingehende Nachricht an einen Agent-Turn. Multiplexing heißt, dass ein einziger Gateway-Prozess mehr als ein Profil bedient.

Bisher war die übliche Form ein Prozess pro Profil (in der Doku standalone genannt, und genau das stellt --standalone wieder her): Jedes Profil besitzt seine eigene Unit, seinen eigenen Port und seine eigene PID-Datei. Ein Multiplexer ersetzt diese Flotte durch einen einzigen Prozess — das Gateway des default-Profils wird der einzige eingehende Prozess und bedient Nachrichten für alle Profile auf der Maschine, indem es jede eingehende Nachricht an das zugehörige Profil weiterleitet. Die Profile bleiben getrennte Agents; geteilt wird nur der Prozess.

Die Variante mit einem Prozess pro Profil bleibt vollständig unterstützt, und der Leitfaden zu Multi-Instanz-Profilen zeigt, wie mehrere Profile nebeneinander laufen.

Was sich geändert hat: standardmäßig an, aber bei jedem Start neu entschieden

gateway.multiplex_profiles ist jetzt standardmäßig aktiv. Die Stelle, die man zweimal lesen sollte, ist der Fall, dass du den Wert nie gesetzt hast: Ein ungesetzter Wert gilt als Anfrage, nicht als Urteil, und das default-Gateway entscheidet diese Anfrage bei jedem Start aufs Neue.

Beim Hochfahren läuft dieselbe Vorprüfung wie bei hermes gateway migrate --multiplex, und multiplexiert wird nur, wenn das Zusammenführen sicher gewesen wäre:

  • das default-Profil existiert und es gibt zwei oder mehr Profile auf der Maschine;
  • kein sekundäres Profil betreibt noch sein eigenes Gateway, weder als laufender Prozess noch als installierter Dienst;
  • keine zwei Profile teilen sich ein Bot-Credential;
  • keine Plattform, die einen Port belegt, entbehrt ihren /p/<profile>/-Ingress;
  • der Host ist einer, den die Migration versteht: kein s6-Container, keine Windows Scheduled Tasks.

Schlägt einer dieser Punkte fehl, startet das Gateway genau wie bisher und bedient nur das default-Profil; dabei schreibt es eine WARNING, die den Blocker benennt und dir den hermes gateway migrate --multiplex-Einzeiler mitgibt. Auf der Platte wird nichts verändert.

Ein explizit gesetzter Wert wird nie angezweifelt:

  • gateway.multiplex_profiles: true (was die Migration schreibt) multiplexiert unabhängig von der Vorprüfung — die Entscheidung hast du oder die Migration getroffen;
  • gateway.multiplex_profiles: false (was --standalone wiederherstellt) behält dauerhaft ein Gateway pro Profil; ist der Wert aus, bleibt alles Folgende wirkungslos;
  • GATEWAY_MULTIPLEX_PROFILES in der Prozessumgebung überstimmt beides.

Das Urteil wird festgehalten und nicht nur geloggt: Die gateway_state.json des default-Homes führt multiplex_standalone_reason, und hermes gateway status gibt es als ⚠ Serving the default profile only (gateway.multiplex_profiles unset): <reason> samt beider Auswege aus. Ein Start, der tatsächlich multiplexiert, löscht den Eintrag.

Auch andere Prozesse raten das Urteil nicht mehr aus dem zusammengeführten Standardwert: hermes -p coder setup, das Dashboard, die Port-Auflösung beim Cron-Feuern und hermes gateway migrate lesen zuerst den served_profiles-Eintrag des laufenden Gateways und greifen nur dann auf den expliziten Schalter zurück, wenn gar kein Gateway läuft.

So findest du heraus, in welchem Modus du bist

Ein Befehl beantwortet das:

hermes gateway status
  • Steht dort eine Zeile, die mit Serving the default profile only beginnt, läufst du standalone, und der Text hinter dem Doppelpunkt nennt den Grund, aus dem der Boot-Guard sich zurückgehalten hat.
  • Fehlt diese Zeile, läuft das Gateway als Multiplexer. Sein eigener Eintrag — served_profiles in der gateway_state.json des default-Homes — listet jedes bediente Profil auf, und genau diesen Eintrag lesen die anderen Werkzeuge.

Im Dashboard stehen dieselben Informationen auf der System-Seite, und auf API-Ebene liefert /api/status?profile=coder die Liste als gateway_shared_with (null, wenn dieses Profil ein eigenes Gateway hat).

Du kannst es auch praktisch prüfen: Versuche, das Gateway eines sekundären Profils zu starten. Im Multiplex-Modus lehnt die CLI ab, im Standalone-Modus startet es.

Ein Gateway oder ein Prozess pro Profil?

Multiplexing lohnt sich, wenn:

  • du in einem Container oder auf einem VPS deployst, wo N Supervisor-Units, N Ports und N PID-Dateien eine Last sind;
  • du viele Profile mit wenig Verkehr betreibst, die jeweils keinen vollen Prozess rechtfertigen;
  • du genau eine Sache starten, überwachen und neu starten willst.

Ein zusätzliches Profil kostet dann nur einen Bot-Token — das laufende Gateway nimmt ihn auf — statt eines weiteren Dienstes zum Betreuen. Unser Leitfaden zum Bedienen von Profilen auf einem laufenden Gateway beschreibt diesen heißen Weg.

Bleib bei einem Prozess pro Profil, wenn du harte Isolation auf Prozessebene zwischen den Profilen brauchst: getrennte Speicherbedarfe, unabhängige Absturzdomänen und die Möglichkeit, ein Profil neu zu starten, ohne die anderen anzufassen. Wenn ein aus dem Ruder gelaufener Skill eines Profils den ganzen Prozess mitreißen kann, wiegt das mehr als ein paar gesparte Units.

Die Flotte bewusst zusammenführen

Statt das default-Gateway neu zu starten und zu hoffen, dass der Boot-Guard zustimmt, führe die Migration aus:

hermes gateway migrate --multiplex

Der Reihe nach: Sie schreibt gateway.multiplex_profiles: true im default-Profil, stoppt und deinstalliert jede installierte Unit der sekundären Profile, bringt das default-Gateway als Multiplexer hoch und bestätigt anhand des Live-Eintrags served_profiles dieses Gateways, dass wirklich jedes migrierte Profil bedient wird.

Die Migration ist transaktional. Der Schalter wird zuerst gesetzt, deshalb ist ein Abbruch an jeder späteren Stelle fortsetzbar: Ein erneuter Aufruf liest das Manifest, das die Migration geschrieben hat, und setzt aus dem Live-Zustand fort — die served_profiles des laufenden default-Gateways müssen jedes im Manifest migrierte Profil abdecken, bevor sie sich als fertig betrachtet. Schlägt ein späterer Schritt fehl (das Stoppen eines sekundären Profils, ein daemon-reload nach dem Entfernen einer Unit, das Schreiben der Konfiguration), werden die bereits entfernten sekundären Profile wieder installiert und der Schalter zurückgesetzt. Ein Rollback, der nicht vollständig durchläuft, behält das Manifest und sagt das auch, damit du von Hand fertig werden kannst.

Sie verweigert außerdem früh, bevor irgendein funktionierendes Gateway gestoppt wird, wenn der Plan schon zeigt, dass das Zusammenführen nicht klappen kann: eine Flotte aus Root-System-Units ohne festgehaltenen User=, ein eingetragener Benutzer, den das System nicht auflösen kann, oder eine config.yaml, die nicht schreibbar ist. Das User= einer System-Unit bleibt erhalten: Die Migration liest es aus, bevor sie etwas entfernt, und führt es beim Hochfahren des default-Gateways und im Rollback mit.

Wenn du nicht migrierst, sondern neu anfängst, ist es einfacher: Hermes installieren, das default-Gateway starten lassen — die Vorprüfung beim Boot erledigt den Rest.

Was sich mit aktiviertem Multiplexing anders verhält

Der Multiplexer ist der einzige eingehende Prozess, ein zweites Gateway für dasselbe Profil würde dessen Plattformen also doppelt binden. Alles Folgende passiert automatisch und ist wirkungslos, sobald der Schalter aus ist.

Ein sekundäres Profil kann sein eigenes Gateway nicht starten. hermes -p coder gateway run, start, install und restart sind ein harter Fehler mit Exit-Code 78, der dich zurück zum Multiplexer schickt: „The default gateway is running as a profile multiplexer and already serves profile ‘coder’.“ Die Ablehnung erfolgt in der CLI, bevor irgendein Dienstmanager angefasst wird, sodass ein bedientes Profil nie mit einer dauerhaft fehlgeschlagenen systemd-Unit oder einer launchd-Respawn-Schleife endet. hermes -p coder gateway stop lehnt genauso ab (Exit 78), wenn coder kein eigenes Gateway hat — es gibt nichts zu stoppen außer dem Multiplexer, und hermes gateway stop im default-Profil fährt ihn für alle bedienten Profile herunter.

Dashboard und Desktop folgen der CLI. Für ein bedientes Profil antworten Start und Stop mit 409 und derselben Erklärung, dargestellt als Hinweis auf der System-Seite, und Restart startet den Multiplexer neu — den Prozess, der das Profil tatsächlich bedient — statt einen -p coder-Restart zu erzeugen, der nur scheitern könnte. Weil dieses Neustarten jeden Bot auf dem Gerät neu verbindet, fragen beide Apps vorher nach: „Restart the shared gateway? All bots on this device reconnect: default, coder, research“ — die Liste ist der served_profiles-Eintrag des laufenden Gateways — und melden danach „Shared gateway restarted (3 bots)“. Ein Standalone-Profil behält den gewohnten Neustart. Auf API-Ebene liefert /api/status?profile=coder dieselbe Liste als gateway_shared_with (null bei einem Standalone-Gateway).

Das Setup überspringt den Hintergrunddienst. hermes -p coder setup gateway, hermes -p coder setup, hermes -p coder gateway setup und hermes -p coder import konfigurieren weiterhin die Bots dieses Profils, überspringen für ein bedientes Profil aber den Schritt „den Gateway-Hintergrunddienst installieren“ und geben stattdessen „Profile ‘coder’ is already served by the default multiplexer“ aus, anstatt eine überflüssige Unit oder ein Plist zu registrieren, das nur tot herumliegen würde. Bot-Token hinzufügen, und der laufende Multiplexer nimmt ihn auf.

Plattformen, die einen Port belegen, wandern unter ein URL-Präfix. Eine Plattform, die auf einem Port lauscht, wird auf dem Listener des default-Gateways unter /p/<profile>/ bedient, ein Webhook, der früher auf den eigenen Port dieses Profils zeigte, zeigt also jetzt auf den gemeinsamen Listener plus dieses Präfix, in einer Form wie /p/<profile>/webhooks/.... Genau das prüft die Vorprüfung beim Boot: „keine Plattform, die einen Port belegt, ohne ihren /p/<profile>/-Ingress“.

Tokens bleiben pro Profil, Credentials werden nie geteilt. Jedes bediente Profil bringt seine Plattformen mit seinen eigenen Bot-Credentials hoch, und jeder Turn löst Konfiguration, Skills, Gedächtnis, SOUL und Provider-Keys des gerouteten Profils auf. Ein bedientes Profil erbt auch nie die Credentials des startenden Profils — mit oder ohne gesetzten Schalter: Bei einem Kindprozess, der auf ein anderes Home geroutet wird, werden die Tier-1/Tier-2-Credentials des Startprofils entfernt, bevor sein eigener Scope darübergelegt wird, und ein ungescopter Credential-Lesezugriff für ein sekundäres Profil wirft einen Fehler, statt still den Wert des default-Profils zurückzugeben. Gib jedem Profil einen eigenen Bot-Token — zwei Profile mit demselben Token sind genau das, was die Vorprüfung ablehnt.

--force gibt es weiterhin. run, start, install und restart akzeptieren --force, wenn du bewusst einen separaten Prozess für ein Profil willst — was nicht zu empfehlen ist, solange der Multiplexer läuft. Und das profilübergreifende Lifecycle-Wrapper-Skript aus Standalone-Setups wird im Multiplex-Modus nicht verwendet: Du verwaltest nur das default-Gateway.

Dauerhaft abschalten oder erzwingen

Setze den Schalter im default-Profil — es besitzt den Multiplexer — und starte dessen Gateway neu:

hermes config set gateway.multiplex_profiles false
hermes gateway restart

Gleichwertig in der ~/.hermes/config.yaml des default-Profils:

gateway:
  multiplex_profiles: false

(Der Schalter wird der Einfachheit halber auch als oberstes multiplex_profiles: true akzeptiert.)

false behält dauerhaft ein Gateway pro Profil: Ein false auf der Platte gilt als bewusster Rollback, und jedes oben beschriebene Verhalten wird wirkungslos. true erzwingt Multiplexing auch dort, wo die Vorprüfung sich zurückgehalten hätte, denn die Entscheidung liegt bei dir. GATEWAY_MULTIPLEX_PROFILES in der Prozessumgebung des default-Gateways überstimmt beides — im Container, wo du die Umgebung statt der Datei kontrollierst, ist das der bequeme Hebel.

Für den unbeaufsichtigten Weg gibt es einen weiteren Hebel: hermes update kann eine Flotte von sich aus in das default-Gateway überführen, und der Schlüssel dafür ist gateway.auto_multiplex_migration; hermes config set gateway.auto_multiplex_migration false macht diesen Verzicht explizit. Ein false aus dem verwalteten Scope schlägt ein true des Benutzers, und das Update weigert sich, eine Flotte in eine System-Unit des default-Profils zu überführen, deren User= es nicht auflösen kann.

Fehlersuche und Kurzfassung

  • hermes gateway status sagt, ein sekundäres Profil betreibe noch sein eigenes Gateway. Stoppe und deinstalliere es — auf eine laufende PID oder eine installierte Unit wartet der Guard — und führe hermes gateway migrate --multiplex erneut aus.
  • Zwei Profile teilen ein Bot-Credential. Gib einem davon einen eigenen Token; die Vorprüfung greift keine Tokens ab, die ein anderer Prozess noch hält.
  • Eine Plattform, die einen Port belegt, hat keinen /p/<profile>/-Ingress. Richte ihren Webhook mit diesem Präfix auf den default-Listener, oder bleib standalone.
  • In einem s6-Container oder bei Windows Scheduled Tasks wird nichts zusammengeführt. Dieser Host ist keiner, den die Migration versteht, der Boot-Guard kann es also nicht für dich tun; behalte dort ein Gateway pro Profil.
  • Du bekommst Exit-Code 78 beim Start eines sekundären Profils. Das ist der Vertrag, kein Bug: Verwalte das default-Gateway mit hermes gateway restart und greife nur dann zu --force, wenn du wirklich einen separaten Prozess willst.
  • Eine Migration ist auf halbem Weg gestorben. Führe hermes gateway migrate --multiplex erneut aus; sie setzt aus dem selbst geschriebenen Manifest fort, und ein unvollständiger Rollback behält das Manifest und sagt dir, was offen ist.

Die Kurzfassung: Multiplexing ist standardmäßig an, doch auf einer Maschine, die dafür nicht bereit ist, ändert sich nichts — ein ungesetzter Schalter wird bei jedem Start entschieden, das Urteil wird festgehalten und in hermes gateway status angezeigt, und ein explizites true oder false gewinnt immer. Wenn du mehrere Bots auf einer Maschine betreibst, ist hermes gateway status jetzt der eine Befehl, der dir sagt, in welcher Welt du bist. Die vollständige Liste der Flags steht in der hermes gateway Befehlsreferenz.