AgentBar はローカルログからマルチエージェントの呼び出し関係をどう再構成するか
Claude が codex exec を呼び、その Codex が claude -p を呼ぶ。フックもデーモンも入れずに、AgentBar がログから呼び出し関係と現在状態をどう再構成し、どこを推定として区別するか。
執筆 tsuvic · 公開 2026/08/01 · 読了約6分
Claude Code にリファクタを依頼したら、途中で別のエージェントが必要だと判断し、シェルで codex exec を実行しました。その Codex は、差分の確認のために claude -p を呼びました。依頼は1つ、エージェントは3つ、プロセスの境界は2回、自分の関与なしに越えられた。
あとから知りたいのは全体像です。誰が誰を、どのコマンドで呼び、今それぞれ何をしているのか。サービスバックエンドなら、これは分散トレーシングの担当領域です。トレースコンテキストがホップごとに伝播し、コレクタがスパンを組み立て、UI がウォーターフォールを描く。ただし条件があります。コンテキストを注入し、コレクタを動かす誰かが要る。
あなたは何も入れていません。エージェントにフックを仕込んでもいないし、トレイサーライブラリもデーモンも無い。それなのに、なぜトレースが存在できるのか。
率直に言えば、トレーシングの意味では存在していません。境界で捕捉されたものは何も無い。AgentBar は事後にグラフを再構成します。エージェントが自分自身の理由で書いた記録から組み立て、推定が必要だった接続にはすべて印を付けます。
記録はエージェント自身が書いている
コーディングエージェントはトランスクリプトを残します。Claude Code は ~/.claude/projects/**/*.jsonl、Codex は ~/.codex/sessions/ 配下の日付別 JSONL、Qwen と Gemini はそれぞれの JSONL、Cursor は SQLite データベースに状態を持ち、AgentBar は sqlite3 の C API で直接読み取ります。Cursor には何も問い合わせません。
これらのファイルは、エージェントがセッションを再開し、履歴を表示するために存在します。監視されているからではなく、動いている副産物として書かれる。AgentBar はそれだけを読み、他には何も読みません。CLI を起動せず、フックを仕込まず、トレイサーを注入しない。ファイルを読むことの意味は別の記事に譲ります。ここで狭く言うのは、トレースの原料が最初からディスクにあったという点です。
この方法で組んだトレースは法医学的です。すでに起きたことを、残された痕跡から復元する。ライブのテレメトリが境界を跨ぐ真実を報告するのに対し、再構成は領収書を読んで、最も起きたらしいことを推定します。この構えが、期待の置き方を正しくします。
呼び出しの瞬間を見つける
最初の仕事は、境界の通過に気づくことです。AgentBar の EdgeDetector は親 Run の会話ターンを走査します。見るのは tool ターンと assistant ターンだけ。user と system ターンはコマンドを実行しないからです。ターンの内側では、各行をシェルの区切り(&&、;、|、単独の &)で分割し、各セグメントが実際に何を実行するかを問います。
トークナイザーは意図的に浅く作ってあります。先頭の環境代入(FOO=bar)とコマンドラッパー(nohup、sudo、env、time など)を飛ばし、最初の実トークンを取ってパスを剥がす。nohup codex exec "…" は codex と読まれ、/usr/local/bin/claude -p "…" は claude と読まれます。detached や sudo 越しに起動されるエージェントこそ追跡したいので、ラッパーの透過は重要です。
これはシェルパーサーではありませんし、そうである必要もありません。やることは1つ、起動コマンドを散文と区別すること。codex exec "fix the tests" ではエージェント名がコマンドトークンです。「claude にレビューを頼んだ」という文では、エージェント名はコマンドトークンにならない。この1つの区別が、相関を走らせる前に誤検出の大半を取り除きます。
検出はそれぞれ起動(invocation)になります。境界を越えたコマンド、対象エージェント、それを含むターンの時刻、親の作業ディレクトリ、そしてコマンドがツール結果由来なら親のツール呼び出し id。
推定辺ができるまで
起動は、親が別のエージェントを宣言したことを示します。しかし、そのエージェントがどのセッションを始めたかまでは示しません。バイナリは同じターン内で起動して終了したかもしれないし、対応するセッションは複数あるかもしれない。AgentBar は相関を取ります。
起動ごとに候補セッションを絞ります。セッションが候補になるのは、プロバイダーが対象エージェントと一致し、起動より後かつ60秒の窓以内に開始し、両方がディレクトリを持つときはプロジェクトが起動の作業ディレクトリと一致するときです。どちらかのディレクトリが欠けている場合は、不一致ではなく不明として扱います。複数が該当すれば、最も早く始まったものが勝つ。
結果は辺(edge)です。そしてデータモデルは、それがどの種の辺かを明示します。この経路が生成する辺はすべて .inferred の信頼度を持ち、破線で描かれます。モデルには confirmed の信頼度も定義されています。環境変数やセッション id で境界をまたいで受け渡された結合のためのものです。ファイルだけの経路は、これを一切出しません。確定の根拠になるプロセス間シグナルが存在せず、あるのは時刻とディレクトリの一致だけだからです。AgentBar は、持っていない確実性を主張しません。
実線は、結合が観測されたことを意味します。破線は、起動コマンドを見て、対応するセッションが直後に同じ場所で現れるのを見て、一方が他方を引き起こしたと結論したことを意味します。たいてい、この結論は正しい。ラベルは、正しくないときのために存在します。
グラフが描くもの
Graph ウィンドウはメニューバーの Active タブから開き、1つの人間依頼を左から右へ、X-Ray や Datadog のトレースマップ風に配置します。形が種別を運び、色が状態を運ぶ。この2つは競合しません。
丸はアクターの点です。人間のプロンプト、エージェント実行、終端マーカー。四角はツール呼び出し。三角はモデルの思考、システム注記、承認待ちです。エージェント実行は、プロバイダー別の縁取りと6pt の状態ドットを持つ丸として描かれ、5つの状態のいずれかで色が付きます。実行中、承認待ち、完了、失敗、アイドル。
ノードはセッションではなく Run です。1つのセッションは複数の Run を含み、--resume やスレッドの再実行のたびに増える。親子の辺は Run に紐づくため、会話を再開しても子は孤立しません。
子エージェントは起動地点にインライン展開されます。bash が codex exec … を実行すると、その Codex は単なるツール呼び出しではなく子レーンとして描かれ、親レーンは子フローへ降りて、完了後に合流します。ネストが深いほどレーンも深くなる。同種の思考が連続すると ×N ノードに集約され、クリックすれば集約分がすべて開きます。形をクリックするとインスペクタが開き、思考ならその内容、ツール呼び出しならコマンドと出力、エージェント実行ならモデル・トークン数・キャッシュヒット率・変更ファイル・イベント全件を読めます。巨大なグラフは2方向スクロール、35〜200% のズーム、フィットボタンで操作できます。
状態はログ末尾の純粋関数
誰が誰を呼んだかは、問いの半分です。もう半分は、各エージェントが今何をしているか。AgentBar はこれにも、グラフと同じ方法で答えます。ファイルを読んで、計算する。
各プロバイダーはログ末尾を小さなシグナルへ縮約します。最終レコードの時刻、最終イベントの種別、未応答のツール提案があるか、終端の成功または失敗を見たか。純粋な分類器がこのシグナルを固定の優先順位で状態へ変換します。失敗が最優先で、新しさに関係なく失敗は失敗。新しいログに未応答のツール提案があれば承認待ち。新しいログに開いた質問があれば入力待ち。新しくて終端レコードが無ければ実行中。冷めた終端停止は完了。それ以外はアイドル。
鮮度の窓が効いてきます。承認待ちはログが新しいあいだだけ意味を持つ。ログが古くなったら、分類器は「ユーザーはこのエージェントに応答義務を負う」という主張をやめます。
精度はプロバイダーで異なり、UI はそれを明言します。Claude の承認待ちは生 JSONL の末尾から読み取ります。未完了の tool_use があり、対応する result レコードが無いこと。Codex・Qwen・Gemini・Cursor では会話ターンからの最善推定で、状態の注記はその留保を運びます。メニューバーの Active タブはセッションディレクトリを10秒スロットルでポーリングし、ライブグラフを直近3日・各プロバイダー25件に絞り、変更の無い要約と会話末尾をメモリキャッシュから再利用し、承認待ちを最上位に固定します。
再構成が手放すもの
領収書を読むことにも代償があります。それを名指すことが、モニターとデモを分けます。
相関は外れ得ます。同じ起動から1分以内に、同じディレクトリで2つの Codex セッションが始まれば、両方が候補に見え、たとえもう一方が本当の子でも、最も早いものが勝ちます。60秒の窓とディレクトリ照合はこれを稀にしますが、不可能にはしません。クラッシュしたエージェントと承認待ちのエージェントは、似たログ末尾を残し得ます。だから状態は保証ではなく注記を携えます。Gemini は起動コマンドとして検出されますが、セッションへ相関しません。照合先の Gemini プロバイダーを AgentBar がまだ持たないためです。起動は記録され、辺は記録されません。
そして全体像は、材料となるファイルの新しさを超えることはできません。AgentBar が見るのはエージェントがディスクへ書き出したものまでで、ライブのプロセスの真実ではありません。1秒前に終わった Run でも、終端レコードをまだ書いていなければ、まだ動いているように見えます。
このどれも、描画に隠れていません。推定辺は破線。推定状態は注記付き。グラフ上の純粋関数である Analysis ペインは、プロバイダー別のトークン・推定コスト・キャッシュヒット率・Run 数に加え、グラフの健全性を報告します。深すぎる連鎖を警告する最大深度、孤児 Run、辺数、そしてボトルネックとして最長 Run。見たものを記述し、推定した場所に旗を立てます。
トレースは収集されたことがありません。エージェントが、自分の領収書を誰かがグラフへ組み立てるとは知らずに、1行の JSONL ずつ残していったものです。AgentBar の仕事は、その領収書を注意深く読み、証拠が支える場所だけで接続し、推定せざるを得なかった場所を率直に言うこと。あなたが欲しかった因果の鎖は、ディスクの上にあります。そのどれだけが推定かという正直さも、同じくディスクの上にあります。