Andreas: "waehrend mmnotify per ws angemeldet ist, kann es dann den status des agenten auf online setzen?" Ja -- und hive hatte das Muster schon fertig (channels/team.py): abwesend beim Verbinden, gruen waehrend der Arbeit, wieder abwesend nach Ruhe, offline beim Beenden. Ein Agent ohne Status sieht aus, als sei niemand da; einer, der rund um die Uhr gruen leuchtet, sagt genauso wenig. Beim Testen fiel ein eigener Fehler auf: Der Boden setzte den Agenten auf gruen. Routinemaessiges Nachsehen ist aber keine Anwesenheit -- bei Boden alle 20 s und Frist 25 s blieb er dauerhaft gruen. Jetzt macht nur ein echtes Ereignis gruen. Und zur Verzoegerung, die Andreas zu Recht nicht hinnehmen wollte: Statt weiter zu raten, gemessen. Der eigene Beitrag loest sehr wohl ein posted aus, ein fremder nie -- die Verbindung hat also die Kanal-Abos, es fehlen nur fremde Ereignisse. Ausgeschlossen: authentication_challenge, Token im Authorization-Header, ein echter Bot-Account statt Nutzer-Token, und das Sitzungs-Cookie wie im Browser. Alle vier gleich. Das Mattermost-Forum beschreibt dasselbe, dort auch mit System-Admin-Token, ohne Loesung. Konsequenz: floor_seconds ist der Weg, nicht der Notnagel, und steht deshalb auf 15 s statt 60. Ein Durchgang kostet einen API-Aufruf -- billig genug, um es oft zu tun.
mmnotify
Hört am Mattermost-Websocket und weckt einen Agenten, wenn er gemeint ist.
Gegenstück zu goimapnotify für
Mail: ein kleiner Prozess, der lauscht und bei einem Ereignis einen Befehl
ausführt. Der Agent liest und antwortet danach mit seinen eigenen Werkzeugen —
mmnotify schreibt nie in einen Kanal, es klopft nur an.
mmnotify -conf /etc/mmnotify.json
Konfiguration
{
"url": "https://team.42i.org",
"token": "<persönliches Zugriffstoken des Agenten>",
"on_mention": "/root/run-agent.sh team",
"on_direct": "",
"debounce_seconds": 5,
"floor_seconds": 60,
"ignore_users": []
}
Die Datei enthält ein Token und gehört mit 0600 dem Dienstbenutzer.
| Feld | Bedeutung |
|---|---|
on_mention |
Befehl bei Erwähnung (@name) im Kanal |
on_direct |
Befehl bei Direktnachricht; leer = on_mention |
debounce_seconds |
Mindestabstand zwischen zwei Läufen (Standard 5) |
floor_seconds |
Nachsehen auch ohne Ereignis (Standard 15, 0 schaltet ab) |
ignore_users |
Absender, die nie wecken |
away_after_seconds |
Wann der grüne Punkt auf abwesend zurückfällt (Standard 120) |
Der Befehl bekommt die Ereignisdaten über die Umgebung: MM_TRIGGER
(event oder floor), MM_CHANNEL, MM_CHANNEL_NAME, MM_CHANNEL_TYPE,
MM_SENDER, MM_POST_ID, MM_ROOT_ID, MM_MESSAGE.
Zwei Wege, und der Boden ist der tragende
Der Websocket ist der Beschleuniger; darunter läuft ein Boden, der ohnehin
nachsieht. Die Aufteilung stammt aus hive (hive_runtime/channels/team.py) und
ist dort begründet: „A stream that dies quietly must make us LATE, never
blind."
Hier ist der Boden nicht nur Vorsicht. Gemessen am 2026-09-01 gegen Mattermost 11.7.10:
| eigener Beitrag | posted kommt an |
| Beitrag eines anderen Kontos | kommt nie an |
Die Verbindung ist also voll funktionsfähig und hat die Kanal-Abos — es fehlen
ausschließlich die Ereignisse fremder Konten. Ausgeschlossen wurden:
authentication_challenge, Token im Authorization-Header beim Handshake, ein
echter Bot-Account statt eines Nutzers mit Token, und das Sitzungs-Cookie
MMAUTHTOKEN wie im Browser. Alle vier verhalten sich gleich.
Das Verhalten ist im Mattermost-Forum beschrieben und tritt dort auch mit einem System-Admin-Token auf; eine Lösung steht nicht dabei.
Deshalb ist floor_seconds der Weg und nicht der Notnagel, und der Standard
ist kurz: 15 Sekunden. Ein Durchgang kostet einen API-Aufruf — billig genug,
um es oft zu tun. Wer den Stream repariert bekommt, kann ihn hochsetzen.
Daraus folgt die zweite Entscheidung: mmnotify liest den Beitrag nicht aus dem Ereignis. Es klopft an; was zu tun ist, entscheidet der Agent, wenn er nachsieht. Zwei Leser wären zwei Antworten.
Anwesenheit
Solange mmnotify verbunden ist, zeigt der Punkt neben dem Namen, woran man ist:
- abwesend, sobald die Verbindung steht — da, aber untätig
- grün, während der Befehl wegen einer Erwähnung läuft
- abwesend wieder, wenn es
away_after_secondsstill war - offline beim Beenden, statt einen grünen Punkt zurückzulassen, hinter dem niemand mehr sitzt
Das routinemäßige Nachsehen des Bodens macht ausdrücklich nicht grün. Läuft der Boden häufiger als die Away-Frist, leuchtete der Agent sonst rund um die Uhr — und ein Punkt, der immer grün ist, sagt genauso wenig wie gar keiner. (Beim Testen genau so passiert: Boden alle 20 s, Frist 25 s, nie abwesend.)
Ein Status ist eine Höflichkeit gegenüber dem, der in die Seitenleiste schaut. Weigert sich der Server, wird das protokolliert und weitergearbeitet: Ein Agent, der aufhört zu antworten, weil er einen Punkt nicht einfärben konnte, wäre absurd.
Robustheit
- Wiederaufbau mit wachsendem Abstand (1 s bis 60 s). Ein Server, der neu startet, wird nicht von einem Client bestürmt, der im Sekundentakt anklopft.
- Herzschlag alle 30 s, Lesefrist 90 s. Eine halboffene Verbindung liest sich sonst für immer wie Stille.
- Höchstens ein Lauf gleichzeitig; wer währenddessen schreibt, wird vom laufenden Durchgang mitgenommen. Ohne das lösen fünf Beiträge in einer Minute fünf Agentenläufe aus, die sich gegenseitig überholen.
- Eigene Beiträge und
system_*-Ereignisse wecken nie — sonst antwortet ein Agent auf sich selbst. SIGTERMbeendet sofort und sauber.
Bauen
go build -o mmnotify .
Ein statisches Binary ohne Laufzeitabhängigkeiten — gedacht zum Einbacken in
das Agenten-Image, neben goimapnotify.