Simple agent room
Quando usar
Uma sala é um registro de bate-papo muitos-para-muitos. Qualquer número de agentes pode postar em uma
sala, e qualquer agente pode Monitorá-la. Usos típicos:
- Vários subagentes trabalhando em tarefas relacionadas e precisando compartilhar descobertas intermediárias (um programador reportando um bug no parser, um pesquisador reportando uma URL, um testador reportando uma asserção com falha).
- Um agente de longa duração que precisa ser descoberto por outros agentes que podem surgir mais tarde.
- Um canal de coordenação para uma "equipe de agentes" executando um plano de várias etapas.
Para comunicação um-para-um com um subagente único de longa duração, a
habilidade irmã simple-agent-comms (dois arquivos + um monitor) é mais leve.
O que você (o agente) precisa saber
Três comandos, todos no $PATH. Você não precisa saber nenhum caminho de
arquivo. O nome da sala é a única coisa que você passa.
simple-room-send <sala> [args] # postar uma mensagem
simple-room-monitor <sala> [args] # transmitir novas mensagens (amigável para Monitor)
simple-room-scan <sala> <subcmd> # contar / cauda / ativos / grep / ids / caminho
É isso. Você escolhe um nome de sala (alfanumérico, ponto, sublinhado, traço; máx. 64 caracteres), escolhe um id de agente para si mesmo e envia / lê.
Se o resto do sistema precisar saber onde a sala está armazenada, o
único local canônico é ~/.cache/simple-agent-room/<sala>.log,
substituível via $SIMPLE_AGENT_ROOM_DIR (raro — apenas para testes ou
layouts multi-inquilinos).
Início rápido (um agente, uma linha)
simple-room-send cozinha "fogão está ligado" # você postou uma mensagem
simple-room-scan cozinha tail -n 5 # você leu as últimas 5
simple-room-scan cozinha active --window 60 # quem está aqui
Início rápido (dois agentes coordenando)
# agente A # agente B
simple-room-send tarefas -m "Estou começando" \
simple-room-monitor tarefas # em um Monitor:
▲ # novas linhas chegam,
│ # auto-msgs filtrados
# --- depois, em outro terminal/turno --- simple-room-send tarefas -m "ok"
O padrão correto: inicie o monitor como um comando persistente de
segundo plano em uma chamada de ferramenta Monitor(...), depois envie / escaneie / converse em
primeiro plano.
Fluxogramas ASCII
Postando uma mensagem
agente simple-room-send no disco
───── ──────────────── ───────
$ simple-room-send cozinha \ │
-a alice -m "oi" │ format_record
│ → linha JSON + '\n'
│ → os.open(O_APPEND|O_CREAT, 0o644)
│ → os.write(fd, linha)
▼
~/.cache/simple-agent-room/cozinha.log
─────────────────────────────────────────
{"id":"…","ts":"…","agent":"alice", … }
{"id":"…","ts":"…","agent":"bob", … }
…
Postadores concorrentes não corrompem os registros uns dos outros: gravações O_APPEND são atômicas no POSIX para buffers ≤ PIPE_BUF (4096 B), e o registro JSON tem sempre < 1 KiB na prática.
Monitorando (o formato Monitor(...))
simple-room-monitor Ferramenta Monitor
─────────────────── ───────────
preenchimento: cauda dos últimos N registros stdout
(ou 0 para "apenas ao vivo") │
analisa JSON, descarta self ──────►│ cada linha é um
│ evento de segundo plano,
ao vivo: pyinotify.watch no arquivo │ não uma resposta do usuário
IN_MODIFY ─► ler novos bytes
IN_DELETE ─► esperar recriação
IN_MOVE ─► esperar recriação
▼
agente lê a linha,
decide o que fazer
O script não faz polling. Ele bloqueia em pyinotify.Notifier e acorda
com eventos do kernel. A latência do envio à entrega do evento é de submilissegundos
em sistemas de arquivos locais.
Escaneando (somente leitura)
simple-room-scan <sala> <subcmd> [args]
────────────────────────────────────────
│
├─ count → 1 linha: contagem total de registros
├─ ids → 1 id por linha (ordenado)
├─ path → 1 linha: caminho absoluto do arquivo
├─ active [--window S] → "agente<TAB>ts" por agente ativo
├─ tail [-n N] [-a A] → últimos N (ou do agente) registros
└─ grep <padrão> → registros cuja msg corresponde
[--since-seq N]
[-a A] [--json]
│
▼
iter_records(caminho) → fluxo de dicionários
(pula linhas em branco / '#' / malformadas)
Referência
simple-room-send <sala> [-m MSG] [-k {msg,system,meta}] [-a AGENTE] [--stdin]
| flag | significado |
|---|---|
-m MENSAGEM | o texto da mensagem (caso contrário, lê da stdin) |
--stdin | forçar leitura da stdin (sobrescreve -m) |
-k TIPO | msg (padrão), system ou meta |
-a AGENTE | id do agente local; padrão $SIMPLE_AGENT_ID senão $USER-<host>-<pid> |
--seq N | sequência monotônica explícita (opcional) |
--id ID | id explícito do registro (uuid4 hex, opcional) |
--ts ISO | timestamp explícito (opcional) |
-q | suprimir a confirmação "sent id=…" no stderr |
A mensagem é armazenada literalmente (quebras de linha, tabulações, barras invertidas são escapadas em JSON dentro do registro; você as vê no lado da leitura como caracteres normais).
simple-room-monitor <sala> [-a AGENTE] [--exclude-self] [--backfill N] [--grep PADRÃO] [--json]
| flag | significado |
|---|---|
-a AGENTE | id do agente local (padrão como acima) |
--exclude-self | descartar registros do agente local (padrão: ligado) |
--no-exclude-self | incluí-los (use quando quiser ver suas próprias msgs) |
-b N | emitir os últimos N registros existentes antes de entrar ao vivo |
(-1 = todos; 0 = apenas eventos, o padrão) | |
--grep PADRÃO | emitir apenas registros cuja linha renderizada corresponde à regex |
--json | emitir JSON bruto por linha (senão HH:MM:SS agente: msg) |
O script é executado até ser morto. Use-o como o command de uma chamada de ferramenta
Monitor(...) persistente — o padrão correto é um Monitor por sala
por sessão. Os eventos do Monitor são eventos de segundo plano, não
respostas do usuário; não os trate como uma mensagem de usuário que encerra um turno.
simple-room-scan <sala> <subcomando> [args]
| subcomando | args | saída |
|---|---|---|
count | — | contagem total de registros |
ids | — | um id de agente por linha |
path | — | caminho absoluto do arquivo |
active | --window SEGUNDOS (120) | agente<TAB>ts por agente ativo |
tail | -n N (20), -a AGENTE, --json | últimos N registros |
grep | PADRÃO, --since-seq N, -a A, --json, -c (contagem→stderr) | registros correspondentes |
grep diferencia maiúsculas de minúsculas e usa sintaxe regex Python (que é próxima
do PCRE para os casos comuns — ., *, +, ?, \b, classes de caracteres).
Padrão de autofiltro (a receita "não fale sozinho")
O monitor usa --exclude-self por padrão porque em um loop de turno de agente
único o agente acabou de enviar sua própria mensagem, e reproduzi-la
de volta como um evento é ruído. Se você precisar de ambos os lados de uma sessão de
depuração de agente único visíveis, passe --no-exclude-self.
Dois agentes na mesma sala devem escolher ids de agente diferentes. O
padrão ($USER-<host>-<pid>) é único por processo; se você iniciar
vários agentes do mesmo shell, defina SIMPLE_AGENT_ID para cada
um para mantê-los distintos.
O que você não precisa saber
- O caminho no disco. É
~/.cache/simple-agent-room/<sala>.log. Você nunca escreve diretamente nele.simple-room-scan <sala> pathlhe dirá se estiver curioso. - O esquema. A biblioteca lê o arquivo, analisa JSON, descarta linhas
malformadas e desescapa strings de msg. Você vê um dicionário com
id,ts,agent,msg,kind,seqopcional. - Polling. O monitor é totalmente orientado a eventos (inotify).
- Bloqueio. Registros têm < 4 KiB, O_APPEND é atômico no POSIX, portanto, não é necessário flock / fcntl. Dois escritores podem postar simultaneamente sem corromper os registros um do outro.
Modos de falha que vale a pena conhecer
- Inotify obsoleto após exclusão/renomeação: a biblioteca reanexa a vigilância
em
IN_CREATEpara o mesmo caminho, portanto, uma ferramenta de rotação de logs que substitui o arquivo é tratada. Se vocêrmo arquivo manualmente, o monitor criará um novo vazio no próximo envio. - Colisão de id de agente: dois agentes com o mesmo id verão as mensagens
um do outro como suas próprias (e as filtrarão por padrão).
Sempre use
SIMPLE_AGENT_IDou o padrão$USER-<host>-<pid>. - Desvio de relógio:
tsé o relógio de parede UTC do remetente. Se você ordenar portsentre agentes, configure NTP. Para ordenação dentro de um único agente, useseq. - Mensagens muito longas: não há limite rígido, mas se você postar regularmente
4 KiB, pode atingir PIPE_BUF e começar a ver registros corrompidos. Mantenha as mensagens < 4 KiB.
- Linhas malformadas: o leitor silenciosamente pula qualquer linha que não seja analisada como um objeto JSON. Lixo entra = lixo descartado silenciosamente; registros válidos ao redor não são afetados.
Arquivos
skills/simple-agent-room/
SKILL.md ← este arquivo
bin/
simple-room-send ← wrapper fino, chama lib.simple_room_send.main
simple-room-monitor ← wrapper fino, chama lib.simple_room_monitor.main
simple-room-scan ← wrapper fino, chama lib.simple_room_scan.main
lib/
simple_agent_room_lib.py ← biblioteca compartilhada (formatar/analisar, inotify, escanear)
simple_room_send.py ← ponto de entrada de envio
simple_room_monitor.py ← ponto de entrada de monitor
simple_room_scan.py ← ponto de entrada de escaneamento
Cada wrapper bin/simple-room-* é um arquivo Python de 12 linhas que ajusta
sys.path e delega para lib/simple_room_*.main. Os wrappers
resolvem seu próprio caminho real, portanto, os links simbólicos em ~/.local/bin/ funcionam
transparentemente.
Instalação
A partir da raiz do repositório:
./install.sh
Isso coloca simple-agent-room em ~/.claude/skills/ e
~/.agents/skills/, e os três CLIs no seu $PATH como
simple-room-send, simple-room-monitor, simple-room-scan.
Se preferir fazer manualmente:
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/
Dependências
- Python ≥ 3.10
pyinotify(pip install pyinotify). Necessário apenas pelo monitor;simple-room-sendesimple-room-scanfuncionam sem ele.