Simple agent room
Quand l'utiliser
Une room est un journal de chat multipartite. N'importe quel nombre d'agents peut poster dans une room, et n'importe quel agent peut la Monitor (surveiller). Utilisations typiques :
- Plusieurs sous-agents travaillant sur des tâches connexes et ayant besoin de partager des résultats intermédiaires (un codeur signalant un bug d'analyseur, un chercheur rapportant une URL, un testeur signalant une assertion échouée).
- Un agent durable qui doit être découvrable par d'autres agents pouvant apparaître plus tard.
- Un canal de coordination pour une "équipe d'agents" exécutant un plan en plusieurs étapes.
Pour les communications en tête-à-tête avec un seul sous-agent durable, la compétence sœur simple-agent-comms (deux fichiers + un moniteur) est plus légère.
Ce que vous (l'agent) devez savoir
Trois commandes, toutes sur le $PATH. Vous n'avez pas besoin de connaître les chemins de fichiers. Le nom de la room est la seule chose que vous manipulez.
simple-room-send <room> [args] # poster un message
simple-room-monitor <room> [args] # diffuser les nouveaux messages (compatible Monitor)
simple-room-scan <room> <subcmd> # compter / tail / actifs / grep / ids / chemin
C'est tout. Vous choisissez un nom de room (alphanumérique, point, underscore, tiret ; max 64 caractères), vous choisissez un identifiant d'agent pour vous-même, et vous envoyez / lisez.
Si le reste du système a besoin de savoir où la room est stockée, l'emplacement canonique unique est ~/.cache/simple-agent-room/<room>.log, surmontable via $SIMPLE_AGENT_ROOM_DIR (rare — uniquement pour les tests ou les configurations multi-locataires).
Démarrage rapide (un agent, une ligne)
simple-room-send kitchen "la cuisinière est allumée" # vous avez posté un message
simple-room-scan kitchen tail -n 5 # vous avez lu les 5 derniers
simple-room-scan kitchen active --window 60 # qui est ici
Démarrage rapide (deux agents en coordination)
# agent A # agent B
simple-room-send tasks -m "Je commence" \
simple-room-monitor tasks # dans un Monitor :
▲ # les nouvelles lignes arrivent,
│ # les messages de soi-même sont filtrés
# --- plus tard, dans un autre terminal/tour --- simple-room-send tasks -m "accusé réception"
Le bon schéma : lancer le moniteur comme une commande d'arrière-plan persistante dans un appel d'outil Monitor(...), puis envoyer / analyser / parler au premier plan.
Diagrammes ASCII
Poster un message
agent simple-room-send sur le disque
───── ──────────────── ───────────
$ simple-room-send kitchen \ │
-a alice -m "salut" │ format_record
│ → ligne JSON + '\n'
│ → os.open(O_APPEND|O_CREAT, 0o644)
│ → os.write(fd, ligne)
▼
~/.cache/simple-agent-room/kitchen.log
─────────────────────────────────────────
{"id":"…","ts":"…","agent":"alice", … }
{"id":"…","ts":"…","agent":"bob", … }
…
Les posteurs concurrents ne déchirent pas leurs enregistrements : les écritures O_APPEND sont atomiques sur POSIX pour les tampons ≤ PIPE_BUF (4096 octets), et l'enregistrement JSON fait toujours moins de 1 Ko en pratique.
Surveillance (la forme Monitor(...))
simple-room-monitor Outil Monitor
─────────────────── ─────────────
backfill : lire les N derniers enregistrements stdout
(ou 0 pour "live uniquement") │
analyser JSON, ignorer soi-même ──────►│ chaque ligne est un
│ événement d'arrière-plan,
live : pyinotify.watch sur le fichier │ pas une réponse utilisateur
IN_MODIFY ─► lire les nouveaux octets
IN_DELETE ─► attendre la recréation
IN_MOVE ─► attendre la recréation
▼
l'agent lit la ligne,
décide quoi faire
Le script ne scrute pas. Il bloque dans pyinotify.Notifier et se réveille sur les événements du noyau. La latence entre l'envoi et la livraison de l'événement est inférieure à la milliseconde sur les systèmes de fichiers locaux.
Analyse (lecture seule)
simple-room-scan <room> <subcmd> [args]
────────────────────────────────────────
│
├─ count → 1 ligne : nombre total d'enregistrements
├─ ids → 1 id par ligne (trié)
├─ path → 1 ligne : chemin absolu du fichier
├─ active [--window S] → "agent<TAB>ts" par agent actif
├─ tail [-n N] [-a A] → N derniers (ou d'un agent) enregistrements
└─ grep <pattern> → enregistrements dont msg correspond
[--since-seq N]
[-a A] [--json]
│
▼
iter_records(chemin) → flux de dictionnaires
(ignore les lignes vides / '#' / malformées)
Référence
simple-room-send <room> [-m MSG] [-k {msg,system,meta}] [-a AGENT] [--stdin]
| drapeau | signification |
|---|---|
-m MESSAGE | le texte du message (sinon lire stdin) |
--stdin | forcer la lecture depuis stdin (remplace -m) |
-k KIND | msg (défaut), system, ou meta |
-a AGENT | identifiant de l'agent local ; défaut $SIMPLE_AGENT_ID sinon $USER-<host>-<pid> |
--seq N | séquence monotone explicite (optionnel) |
--id ID | identifiant d'enregistrement explicite (uuid4 hex, optionnel) |
--ts ISO | horodatage explicite (optionnel) |
-q | supprimer la confirmation "envoyé id=…" sur stderr |
Le message est stocké textuellement (les sauts de ligne, tabulations, barres obliques inverses sont échappés JSON à l'intérieur de l'enregistrement ; vous les voyez du côté lecture comme des caractères normaux).
simple-room-monitor <room> [-a AGENT] [--exclude-self] [--backfill N] [--grep PATTERN] [--json]
| drapeau | signification |
|---|---|
-a AGENT | identifiant de l'agent local (défaut comme ci-dessus) |
--exclude-self | ignorer les enregistrements de l'agent local (défaut : activé) |
--no-exclude-self | les inclure (utilisez-le quand vous voulez voir vos propres messages) |
-b N | émettre les N derniers enregistrements existants avant de passer en direct |
(-1 = tous ; 0 = événements uniquement, le défaut) | |
--grep PATTERN | n'émettre que les enregistrements dont la ligne rendue correspond à l'expression régulière |
--json | émettre l'enregistrement JSON brut par ligne (sinon HH:MM:SS agent: msg) |
Le script tourne jusqu'à être tué. Utilisez-le comme command d'un appel d'outil Monitor(...) persistant — le bon schéma est un moniteur par room par session. Les événements du moniteur sont des événements d'arrière-plan, pas des réponses utilisateur ; ne les traitez pas comme un message utilisateur qui termine un tour.
simple-room-scan <room> <subcommand> [args]
| sous-commande | args | sortie |
|---|---|---|
count | — | nombre total d'enregistrements |
ids | — | un identifiant d'agent par ligne |
path | — | chemin absolu du fichier |
active | --window SECONDS (120) | agent<TAB>ts par agent actif |
tail | -n N (20), -a AGENT, --json | N derniers enregistrements |
grep | PATTERN, --since-seq N, -a A, --json, -c (count→stderr) | enregistrements correspondants |
grep est sensible à la casse et utilise la syntaxe des expressions régulières Python (qui est proche de PCRE pour les cas courants — ., *, +, ?, \b, classes de caractères).
Le motif d'auto-filtrage (la recette "ne pas se parler à soi-même")
Le moniteur utilise par défaut --exclude-self car dans une boucle de tour d'agent unique, l'agent vient d'envoyer son propre message, et le rejouer comme événement est du bruit. Si vous avez besoin des deux côtés d'une session de débogage à agent unique visible, passez --no-exclude-self.
Deux agents dans la même room doivent choisir des identifiants d'agent différents. La valeur par défaut ($USER-<host>-<pid>) est unique par processus ; si vous lancez plusieurs agents depuis le même shell, définissez SIMPLE_AGENT_ID pour chacun afin de les distinguer.
Ce que vous n'avez pas besoin de savoir
- Le chemin sur le disque. Il est
~/.cache/simple-agent-room/<room>.log. Vous n'écrivez jamais directement dedans.simple-room-scan <room> pathvous le dira si vous êtes curieux. - Le schéma. La bibliothèque lit le fichier, analyse le JSON, ignore les lignes malformées et déséchappe les chaînes msg. Vous voyez un dictionnaire avec
id,ts,agent,msg,kind,seqoptionnel. - La scrutation. Le moniteur est entièrement piloté par événements (inotify).
- Le verrouillage. Les enregistrements font < 4 Ko, O_APPEND est atomique sur POSIX, donc aucun flock / fcntl n'est nécessaire. Deux rédacteurs peuvent poster simultanément sans déchirer leurs enregistrements.
Modes de défaillance à connaître
- inotify obsolète après suppression/renommage : la bibliothèque rattache la surveillance sur
IN_CREATEpour le même chemin, donc un outil de rotation de logs qui remplace le fichier est géré. Si vousrmle fichier manuellement, le moniteur créera un nouveau fichier vide à l'envoi suivant. - Collision d'identifiant d'agent : deux agents avec le même identifiant verront les messages de l'autre comme les leurs (et les filtreront par défaut). Utilisez toujours
SIMPLE_AGENT_IDou la valeur par défaut$USER-<host>-<pid>. - Décalage d'horloge :
tsest l'heure UTC de l'horloge murale de l'expéditeur. Si vous triez partsentre agents, réglez NTP. Pour l'ordre au sein d'un seul agent, utilisezseq. - Messages très longs : il n'y a pas de limite stricte, mais si vous postez régulièrement > 4 Ko, vous pourriez atteindre PIPE_BUF et commencer à voir des enregistrements déchirés. Gardez les messages < 4 Ko.
- Lignes malformées : le lecteur ignore silencieusement toute ligne qui ne s'analyse pas comme un objet JSON. Déchets entrants = déchets silencieusement ignorés ; les enregistrements valides autour ne sont pas affectés.
Fichiers
skills/simple-agent-room/
SKILL.md ← ce fichier
bin/
simple-room-send ← wrapper léger, appelle lib.simple_room_send.main
simple-room-monitor ← wrapper léger, appelle lib.simple_room_monitor.main
simple-room-scan ← wrapper léger, appelle lib.simple_room_scan.main
lib/
simple_agent_room_lib.py ← bibliothèque partagée (format/analyse, inotify, scan)
simple_room_send.py ← point d'entrée d'envoi
simple_room_monitor.py ← point d'entrée de moniteur
simple_room_scan.py ← point d'entrée d'analyse
Chaque wrapper bin/simple-room-* est un fichier Python de 12 lignes qui ajuste sys.path et délègue à lib/simple_room_*.main. Les wrappers résolvent leur propre chemin réel, donc les liens symboliques dans ~/.local/bin/ fonctionnent de manière transparente.
Installation
Depuis la racine du dépôt :
./install.sh
Cela place simple-agent-room dans ~/.claude/skills/ et ~/.agents/skills/, et les trois CLI sur votre $PATH en tant que simple-room-send, simple-room-monitor, simple-room-scan.
Si vous préférez le faire manuellement :
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/
Dépendances
- Python ≥ 3.10
pyinotify(pip install pyinotify). Requis uniquement par le moniteur ;simple-room-sendetsimple-room-scanfonctionnent sans.