Einfacher Agentenraum (Simple Agent Room)
Wann verwenden
Ein Raum (Room) ist ein Many-to-Many-Chat-Protokoll. Beliebig viele Agenten können in einen Raum schreiben, und jeder Agent kann ihn überwachen (Monitor). Typische Anwendungsfälle:
- Mehrere Sub-Agenten, die an verwandten Aufgaben arbeiten und Zwischenergebnisse austauschen müssen (ein Coder meldet einen Parser-Fehler, ein Forscher eine URL, ein Tester eine fehlgeschlagene Assertion).
- Ein langlebiger Agent, der für andere, später startende Agenten auffindbar sein muss.
- Ein Koordinationskanal für ein „Agententeam“ bei einem mehrstufigen Plan.
Für die Eins-zu-Eins-Kommunikation mit einem einzelnen langlebigen Sub-Agenten ist der Schwester-Skill simple-agent-comms (zwei Dateien + eine Überwachung) leichter.
Was Sie (der Agent) wissen müssen
Drei Befehle, alle im $PATH. Sie müssen keine Dateipfade kennen. Der Raumname ist das Einzige, was Sie weitergeben.
simple-room-send <raum> [argumente] # eine Nachricht senden
simple-room-monitor <raum> [argumente] # neue Nachrichten streamen (Monitor-freundlich)
simple-room-scan <raum> <unterbefehl> # zählen / tail / aktiv / grep / ids / pfad
Das ist alles. Sie wählen einen Raumnamen (alphanumerisch, Punkt, Unterstrich, Bindestrich; max. 64 Zeichen), Sie wählen eine Agenten-ID für sich selbst und senden/lesen.
Wenn der Rest des Systems wissen muss, wo der Raum gespeichert ist, ist der einzelne kanonische Speicherort ~/.cache/simple-agent-room/<raum>.log, überschreibbar über $SIMPLE_AGENT_ROOM_DIR (selten – nur für Tests oder Multi-Tenant-Layouts).
Kurzstart (ein Agent, eine Zeile)
simple-room-send küche "der Herd ist an" # Sie haben eine Nachricht gesendet
simple-room-scan küche tail -n 5 # Sie haben die letzten 5 gelesen
simple-room-scan küche active --window 60 # wer ist hier drin
Kurzstart (zwei Agenten, die koordinieren)
# Agent A # Agent B
simple-room-send aufgaben -m "Ich starte" \
simple-room-monitor aufgaben # in einem Monitor:
▲ # neue Zeilen treffen ein,
│ # Selbstnachrichten gefiltert
# --- später, in einem anderen Terminal/Durchlauf --- simple-room-send aufgaben -m "bestätigt"
Das richtige Muster: Starten Sie den Monitor als persistenten Hintergrundbefehl in einem Monitor(...)-Toolaufruf, dann senden/scannen/sprechen Sie im Vordergrund.
ASCII-Ablaufdiagramme
Senden einer Nachricht
agent simple-room-send auf Festplatte
───── ──────────────── ──────────────
$ simple-room-send küche \ │
-a alice -m "hallo" │ format_record
│ → JSON-Zeile + '\n'
│ → os.open(O_APPEND|O_CREAT, 0o644)
│ → os.write(fd, zeile)
▼
~/.cache/simple-agent-room/küche.log
──────────────────────────────────────────
{"id":"…","ts":"…","agent":"alice", … }
{"id":"…","ts":"…","agent":"bob", … }
…
Gleichzeitige Schreiber zerreißen sich gegenseitig nicht die Datensätze: O_APPEND-Schreibvorgänge sind auf POSIX für Puffer ≤ PIPE_BUF (4096 B) atomar, und der JSON-Datensatz ist in der Praxis immer < 1 KiB.
Überwachung (die Monitor(...)-Form)
simple-room-monitor Monitor-Werkzeug
─────────────────── ────────────────
Backfill: die letzten N Datensätze ausgeben stdout
(oder 0 für „nur live“) │
JSON parsen, Selbstnachrichten entfernt │
│
live: pyinotify.watch auf der Datei │
IN_MODIFY ─► neue Bytes lesen │
IN_DELETE ─► auf Neuerstellung warten │
IN_MOVE ─► auf Neuerstellung warten │
▼
Agent liest die Zeile,
entscheidet, was zu tun ist
Das Skript pollt nicht. Es blockiert in pyinotify.Notifier und wird durch Kernel-Ereignisse aufgeweckt. Die Latenz vom Senden bis zur Zustellung des Ereignisses beträgt auf lokalen Dateisystemen unter einer Millisekunde.
Scannen (schreibgeschützt)
simple-room-scan <raum> <unterbefehl> [argumente]
────────────────────────────────────────────────────
│
├─ count → 1 Zeile: Gesamtzahl der Datensätze
├─ ids → 1 ID pro Zeile (sortiert)
├─ path → 1 Zeile: absoluter Dateipfad
├─ active [--window S] → „agent<TAB>ts“ pro aktivem Agenten
├─ tail [-n N] [-a A] → letzte N (oder Agenten-)Datensätze
└─ grep <muster> → Datensätze, deren msg übereinstimmt
[--since-seq N]
[-a A] [--json]
│
▼
iter_records(pfad) → dict-Stream
(überspringt leere / '#'- / fehlerhafte Zeilen)
Referenz
simple-room-send <raum> [-m NACHRICHT] [-k {msg,system,meta}] [-a AGENT] [--stdin]
| Flag | Bedeutung |
|---|---|
-m NACHRICHT | der Nachrichtentext (andernfalls von stdin lesen) |
--stdin | Lesen von stdin erzwingen (überschreibt -m) |
-k ART | msg (Standard), system oder meta |
-a AGENT | lokale Agenten-ID; Standard $SIMPLE_AGENT_ID sonst $USER-<host>-<pid> |
--seq N | explizite monotone Sequenznummer (optional) |
--id ID | explizite Datensatz-ID (uuid4 hex, optional) |
--ts ISO | expliziter Zeitstempel (optional) |
-q | die Bestätigung „gesendet id=…“ auf stderr unterdrücken |
Die Nachricht wird wörtlich gespeichert (Zeilenumbrüche, Tabulatoren, Backslashes werden im Datensatz JSON-escaped; auf der Leseseite erscheinen sie als normale Zeichen).
simple-room-monitor <raum> [-a AGENT] [--exclude-self] [--backfill N] [--grep MUSTER] [--json]
| Flag | Bedeutung |
|---|---|
-a AGENT | lokale Agenten-ID (Standard wie oben) |
--exclude-self | Datensätze des lokalen Agenten verwerfen (Standard: an) |
--no-exclude-self | diese einbeziehen (verwenden, wenn Sie Ihre eigenen Nachrichten sehen möchten) |
-b N | die letzten N vorhandenen Datensätze ausgeben, bevor es live geht |
(-1 = alle; 0 = nur Ereignisse, die Voreinstellung) | |
--grep MUSTER | nur Datensätze ausgeben, deren gerenderte Zeile dem Regex entspricht |
--json | rohen JSON-Datensatz pro Zeile ausgeben (sonst HH:MM:SS agent: msg) |
Das Skript läuft, bis es beendet wird. Verwenden Sie es als command eines persistenten Monitor(...)-Toolaufrufs – das richtige Muster ist ein Monitor pro Raum pro Sitzung. Die Monitor-Ereignisse sind Hintergrundereignisse, keine Benutzerantworten; behandeln Sie sie nicht als eine den Zug beendende Benutzernachricht.
simple-room-scan <raum> <unterbefehl> [argumente]
| Unterbefehl | Argumente | Ausgabe |
|---|---|---|
count | — | Gesamtzahl der Datensätze |
ids | — | eine Agenten-ID pro Zeile |
path | — | absoluter Dateipfad |
active | --window SEKUNDEN (120) | agent<TAB>ts pro aktivem Agenten |
tail | -n N (20), -a AGENT, --json | letzte N Datensätze |
grep | MUSTER, --since-seq N, -a A, --json, -c (count→stderr) | übereinstimmende Datensätze |
grep ist case-sensitiv und verwendet die Python-Regex-Syntax (die für die häufigen Fälle – ., *, +, ?, \b, Zeichenklassen – nahe an PCRE liegt).
Selbstfilter-Muster (die „sprich nicht mit dir selbst“-Anleitung)
Der Monitor verwendet standardmäßig --exclude-self, da der Agent in einer Single-Agenten-Schleife gerade seine eigene Nachricht gesendet hat und das Zurückspielen als Ereignis Rauschen wäre. Wenn Sie beide Seiten einer Single-Agenten-Debugsitzung sichtbar machen müssen, übergeben Sie --no-exclude-self.
Zwei Agenten im selben Raum müssen unterschiedliche Agenten-IDs wählen. Die Standard-ID ($USER-<host>-<pid>) ist pro Prozess eindeutig; wenn Sie mehrere Agenten aus derselben Shell starten, setzen Sie für jeden SIMPLE_AGENT_ID, um sie unterscheidbar zu halten.
Was Sie nicht wissen müssen
- Der Pfad auf der Festplatte. Er ist
~/.cache/simple-agent-room/<raum>.log. Sie schreiben nie direkt darauf.simple-room-scan <raum> pathverrät es Ihnen, wenn Sie neugierig sind. - Das Schema. Die Bibliothek liest die Datei, parst JSON, verwirft fehlerhafte Zeilen und escapet Nachrichten-Strings. Sie sehen ein Dict mit
id,ts,agent,msg,kind, optionalemseq. - Polling. Der Monitor ist vollständig ereignisgesteuert (inotify).
- Locking. Datensätze sind < 4 KiB, O_APPEND ist auf POSIX atomar, daher ist kein flock/fcntl erforderlich. Zwei Schreiber können gleichzeitig senden, ohne sich gegenseitig die Datensätze zu zerreißen.
Wissenswerte Fehlermodi
- Veralteter inotify nach Löschen/Umbenennen: die Bibliothek hängt den Watch bei
IN_CREATEfür denselben Pfad wieder an, sodass ein Log-Rotations-Tool, das die Datei ersetzt, behandelt wird. Wenn Sie die Datei von Handrmlöschen, erstellt der Monitor beim nächsten Senden eine neue leere Datei. - Agenten-ID-Kollision: zwei Agenten mit derselben ID sehen die Nachrichten des anderen als ihre eigenen (und filtern sie standardmäßig heraus). Verwenden Sie immer
SIMPLE_AGENT_IDoder den Standard$USER-<host>-<pid>. - Zeitversatz:
tsist die Wanduhrzeit (UTC) des Senders. Wenn Sie nachtsüber Agenten hinweg sortieren, stellen Sie NTP ein. Für die Reihenfolge innerhalb eines einzelnen Agenten verwenden Sieseq. - Sehr lange Nachrichten: es gibt keine harte Obergrenze, aber wenn Sie regelmäßig > 4 KiB senden, erreichen Sie möglicherweise PIPE_BUF und sehen zerrissene Datensätze. Halten Sie Nachrichten < 4 KiB.
- Fehlerhafte Zeilen: der Leser überspringt stillschweigend jede Zeile, die nicht als JSON-Objekt geparst werden kann. Müll rein = Müll stillschweigend verworfen; gültige Datensätze drumherum bleiben unbeeinflusst.
Dateien
skills/simple-agent-room/
SKILL.md ← diese Datei
bin/
simple-room-send ← dünner Wrapper, ruft lib.simple_room_send.main auf
simple-room-monitor ← dünner Wrapper, ruft lib.simple_room_monitor.main auf
simple-room-scan ← dünner Wrapper, ruft lib.simple_room_scan.main auf
lib/
simple_agent_room_lib.py ← gemeinsam genutzte Bibliothek (Format/Parse, inotify, Scan)
simple_room_send.py ← Einstiegspunkt für Senden
simple_room_monitor.py ← Einstiegspunkt für Monitor
simple_room_scan.py ← Einstiegspunkt für Scannen
Jeder bin/simple-room-*-Wrapper ist eine 12-zeilige Python-Datei, die sys.path anpasst und an lib/simple_room_*.main delegiert. Die Wrapper lösen ihren eigenen echten Pfad auf, sodass die symbolischen Links in ~/.local/bin/ transparent funktionieren.
Installation
Aus dem Repository-Stammverzeichnis:
./install.sh
Dies platziert simple-agent-room in ~/.claude/skills/ und ~/.agents/skills/ und die drei CLIs in Ihrem $PATH als simple-room-send, simple-room-monitor, simple-room-scan.
Wenn Sie es lieber von Hand machen möchten:
ln -s "$PWD/skills/simple-agent-room" ~/.claude/skills/simple-agent-room
ln -s "$PWD/skills/simple-agent-room" ~/.agents/skills/simple-agent-room
ln -s "$PWD/skills/simple-agent-room/bin/"* ~/.local/bin/
Abhängigkeiten
- Python ≥ 3.10
pyinotify(pip install pyinotify). Nur vom Monitor benötigt;simple-room-sendundsimple-room-scanfunktionieren ohne.