Simple agent room
使用するタイミング
ルームは多対多のチャットログです。任意の数のエージェントがルームに投稿でき、任意のエージェントがMonitorできます。典型的な使用例:
- 関連するタスクに取り組んでおり、中間結果を共有する必要がある複数のサブエージェント(パーサーのバグを報告するコーダー、URLを報告するリサーチャー、失敗したアサーションを報告するテスター)
- 後で起動する可能性のある他のエージェントから発見可能である必要がある、長時間実行エージェント
- マルチステップ計画を実行する「エージェントチーム」のための調整チャンネル
1対1の通信には、姉妹スキルsimple-agent-comms(2ファイル+モニター)の方が軽量です。
エージェントが知っておくべきこと
3つのコマンドがあり、すべて$PATHにあります。ファイルパスを知る必要はありません。 ルーム名だけを渡せば十分です。
simple-room-send <room> [args] # メッセージを投稿
simple-room-monitor <room> [args] # 新しいメッセージをストリーム(Monitor対応)
simple-room-scan <room> <subcmd> # カウント / tail / active / grep / ids / path
これだけです。ルーム名(英数字、ドット、アンダースコア、ダッシュ;最大64文字)を選び、自分のエージェントIDを選び、送信/読み取りを行います。
システムがルームの保存場所を知る必要がある場合、単一の正規の場所は~/.cache/simple-agent-room/<room>.logで、$SIMPLE_AGENT_ROOM_DIRで上書き可能です(テストやマルチテナントレイアウトの場合のみ、まれに使用)。
クイックスタート(1エージェント、1行)
simple-room-send kitchen "stove is on" # メッセージを投稿
simple-room-scan kitchen tail -n 5 # 最後の5件を読む
simple-room-scan kitchen active --window 60 # 誰がいるか確認
クイックスタート(2エージェントの連携)
# agent A # agent B
simple-room-send tasks -m "I'm starting" \
simple-room-monitor tasks # Monitor内:
▲ # 新しい行が到着
│ # 自分自身のメッセージはフィルター
# --- 後で、別のターミナル/ターンで --- simple-room-send tasks -m "ack"
正しいパターン:モニターをMonitor(...)ツールコール内の永続的なバックグラウンドコマンドとして起動し、フォアグラウンドで送信/スキャン/会話を行います。
ASCIIフローチャート
メッセージの投稿
agent simple-room-send on disk
───── ──────────────── ───────
$ simple-room-send kitchen \ │
-a alice -m "hi" │ format_record
│ → JSON line + '\n'
│ → os.open(O_APPEND|O_CREAT, 0o644)
│ → os.write(fd, line)
▼
~/.cache/simple-agent-room/kitchen.log
─────────────────────────────────────────
{"id":"…","ts":"…","agent":"alice", … }
{"id":"…","ts":"…","agent":"bob", … }
…
同時投稿者はお互いのレコードを破壊しません:O_APPEND書き込みはPIPE_BUF(4096 B)以下のバッファに対してPOSIXでアトミックであり、JSONレコードは実際には常に1 KiB未満です。
モニタリング(Monitor(...)の形)
simple-room-monitor Monitor tool
─────────────────── ───────────
backfill: 最後のNレコードをtail stdout
(「ライブのみ」の場合は0) │
JSONをパース、自身を除外 ──────►│ 各行は
│ バックグラウンドイベント、
ライブ: ファイルにpyinotify.watch │ ユーザーの返信ではない
IN_MODIFY ─► 新しいバイトを読み取り
IN_DELETE ─► 再作成を待機
IN_MOVE ─► 再作成を待機
▼
エージェントが行を読み取り、
何をするか決定
スクリプトはポーリングしません。pyinotify.Notifierでブロックし、カーネルイベントで起動します。ローカルファイルシステムでの送信からイベント配信までのレイテンシはサブミリ秒です。
スキャン(読み取り専用)
simple-room-scan <room> <subcmd> [args]
────────────────────────────────────────
│
├─ count → 1行: 総レコード数
├─ ids → 1行に1つのid(ソート済み)
├─ path → 1行: 絶対ファイルパス
├─ active [--window S] → アクティブなエージェントごとに "agent<TAB>ts"
├─ tail [-n N] [-a A] → 最後のN(またはエージェントの)レコード
└─ grep <pattern> → メッセージがマッチするレコード
[--since-seq N]
[-a A] [--json]
│
▼
iter_records(path) → 辞書ストリーム
(空白行 / '#' / 不正な行をスキップ)
リファレンス
simple-room-send <room> [-m MSG] [-k {msg,system,meta}] [-a AGENT] [--stdin]
| フラグ | 意味 |
|---|---|
-m MESSAGE | メッセージテキスト(指定しない場合はstdinから読み取り) |
--stdin | stdinからの読み取りを強制(-mをオーバーライド) |
-k KIND | msg(デフォルト)、system、またはmeta |
-a AGENT | ローカルエージェントID;デフォルトは$SIMPLE_AGENT_ID、なければ$USER-<host>-<pid> |
--seq N | 明示的な単調増加シーケンス番号(オプション) |
--id ID | 明示的なレコードID(uuid4 hex、オプション) |
--ts ISO | 明示的なタイムスタンプ(オプション) |
-q | stderrへの「sent id=…」確認を抑制 |
メッセージはそのまま保存されます(改行、タブ、バックスラッシュはJSONエスケープされてレコード内に格納;読み取り側では通常の文字として表示されます)。
simple-room-monitor <room> [-a AGENT] [--exclude-self] [--backfill N] [--grep PATTERN] [--json]
| フラグ | 意味 |
|---|---|
-a AGENT | ローカルエージェントID(デフォルトは上記と同じ) |
--exclude-self | ローカルエージェントからのレコードを除外(デフォルト:オン) |
--no-exclude-self | それらを含める(自分のメッセージも見たい場合に使用) |
-b N | ライブモードに入る前に、既存のレコードの最後のN件を出力 |
(-1 = すべて、0 = イベントのみ、デフォルト) | |
--grep PATTERN | レンダリングされた行が正規表現にマッチするレコードのみを出力 |
--json | 1行に1つの生JSONレコードを出力(デフォルトは HH:MM:SS agent: msg) |
スクリプトは強制終了されるまで実行されます。永続的なMonitor(...)ツールコールのcommandとして使用してください — 正しいパターンは、セッションごとにルームごとに1つのMonitorです。Monitorイベントはバックグラウンドイベントであり、ユーザーの返信ではありません。ターンを終了するユーザーメッセージとして扱わないでください。
simple-room-scan <room> <subcommand> [args]
| サブコマンド | 引数 | 出力 |
|---|---|---|
count | — | 総レコード数 |
ids | — | 1行に1つのエージェントID |
path | — | 絶対ファイルパス |
active | --window SECONDS (120) | アクティブなエージェントごとに agent<TAB>ts |
tail | -n N (20), -a AGENT, --json | 最後のNレコード |
grep | PATTERN, --since-seq N, -a A, --json, -c (カウント→stderr) | マッチするレコード |
grepは大文字と小文字を区別し、Python正規表現構文を使用します(一般的なケース — ., *, +, ?, \b, 文字クラス — ではPCREに近い動作)。
自己フィルターパターン(「自分自身に話しかけない」レシピ)
モニターはデフォルトで--exclude-selfになります。なぜなら、シングルエージェントのターンループではエージェントが自分のメッセージを送信した直後であり、それをイベントとして再生することはノイズだからです。シングルエージェントのデバッグセッションで両側を表示する必要がある場合は、--no-exclude-selfを渡します。
同じルーム内の2つのエージェントは異なるエージェントIDを選択する必要があります。デフォルト($USER-<host>-<pid>)はプロセスごとに一意です。同じシェルから複数のエージェントを起動する場合は、それぞれにSIMPLE_AGENT_IDを設定して区別を維持します。
知らなくてもよいこと
- ディスク上のパス。
~/.cache/simple-agent-room/<room>.logです。直接書き込む必要はありません。simple-room-scan <room> pathで確認できます。 - スキーマ。ライブラリがファイルを読み取り、JSONをパースし、不正な行をスキップし、msg文字列をアンエスケープします。
id、ts、agent、msg、kind、オプションのseqを持つ辞書が得られます。 - ポーリング。モニターは完全にイベント駆動型(inotify)です。
- ロック。レコードは4 KiB未満であり、O_APPENDはPOSIXでアトミックなため、flock/fcntlは不要です。2つのライターが同時に投稿しても、互いのレコードを壊しません。
知っておくべき障害モード
- 削除/名前変更後の古いinotify: ライブラリは同じパスに対する
IN_CREATEでウォッチを再アタッチするため、ファイルを置き換えるログローテーションツールは処理されます。手動でrmした場合、次の送信時にモニターが新しい空のファイルを作成します。 - エージェントIDの衝突: 同じIDを持つ2つのエージェントは、互いのメッセージを自分のものとして見(デフォルトでフィルターアウトします)。常に
SIMPLE_AGENT_IDまたはデフォルトの$USER-<host>-<pid>を使用してください。 - クロックスキュー:
tsは送信者の壁時計UTCです。エージェント間でtsでソートする場合は、NTPを設定してください。単一エージェント内での順序付けにはseqを使用します。 - 非常に長いメッセージ: ハードキャップはありませんが、4 KiBを超えるメッセージを定期的に投稿すると、PIPE_BUFに達してレコードが破損する可能性があります。メッセージは4 KiB未満に保ってください。
- 不正な行: リーダーはJSONオブジェクトとしてパースできない行を静かにスキップします。ゴミイン=ゴミは静かに破棄され、周囲の有効なレコードには影響しません。
ファイル
skills/simple-agent-room/
SKILL.md ← このファイル
bin/
simple-room-send ← 薄いラッパー、lib.simple_room_send.mainを呼び出し
simple-room-monitor ← 薄いラッパー、lib.simple_room_monitor.mainを呼び出し
simple-room-scan ← 薄いラッパー、lib.simple_room_scan.mainを呼び出し
lib/
simple_agent_room_lib.py ← 共有ライブラリ(format/parse, inotify, scan)
simple_room_send.py ← 送信エントリポイント
simple_room_monitor.py ← モニターエントリポイント
simple_room_scan.py ← スキャンエントリポイント
各bin/simple-room-*ラッパーは、sys.pathを調整してlib/simple_room_*.mainに委譲する12行のPythonファイルです。ラッパーは自身の実際のパスを解決するため、~/.local/bin/内のシンボリックリンクは透過的に機能します。
インストール
リポジトリルートから:
./install.sh
これにより、simple-agent-roomが~/.claude/skills/と~/.agents/skills/に配置され、3つのCLIがsimple-room-send、simple-room-monitor、simple-room-scanとして$PATHに追加されます。
手動で行う場合:
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/
依存関係
- Python ≥ 3.10
pyinotify(pip install pyinotify)。モニターのみに必要です。simple-room-sendとsimple-room-scanはなくても動作します。