Claude Codeのagents –jsonで起動中セッションをstatuslineに常時出した

ニュース

バックグラウンドセッションを増やすほど、自分が何本回しているのか分からなくなる。これは皮肉だ。並列化のために用意した機能が、認知の負荷を上げてしまう。2.1.145で入った claude agents --json を一晩使って、その逆転をようやく解けた気がしている。

結論から書く。このフラグ単体は地味だ。だが「起動中セッションを機械可読で吐く」という一点が、自前のステータスラインやセッションピッカーを15分で組めるところまで距離を縮めた。私の環境では、入力待ちのエージェント本数をシェルのプロンプト右端に常時出せるようになり、ターミナルを行き来する回数が体感で半分以下になった。

何が追加されたのか

Claude Codeの2.1.145(2026年5月19日)に、こう書かれている。

Added claude agents --json to list live Claude sessions as JSON for scripting (tmux-resurrect, status bars, session pickers)

要するに、これまで claude agents で人間向けに表示していた一覧を、JSONで取れるようにした。それだけ。ただ用途として公式が名指ししているのが、tmux-resurrect、ステータスバー、セッションピッカーという、いずれも「常駐して状態を見せる」系のツールだ。ここに意図が透けている。

同じリリースでは、claude agents のターミナルタブのタイトルに入力待ち件数が出るようになった、という変更も入っている。タブを離れていてもエージェントが呼んでいると分かる、というやつだ。つまり公式自身が「待ち本数の可視化」を今回の主題に据えている。--json はその素材を外部に開いた、と読むのが正しい。

まず叩いてみる

手元のバージョンを上げてから、素直に実行する。

claude --version
# 2.1.145

claude agents --json

返ってくるのはセッションの配列だ。私の環境では、各要素にセッションID、状態(running / awaiting_input など)、名前、作業ディレクトリらしきフィールドが入っていた。フィールド名は環境やバージョンで変わりうるので、まず一度生で吐いて確かめるのが安全だ。ここを面倒がって決め打ちすると、次のアップデートで静かに壊れる。

入力待ちの本数だけ欲しいなら、jqで絞る。

claude agents --json \
  | jq '[.[] | select(.status == "awaiting_input")] | length'

私の手元では、3本回している状態でこれが 2 を返した。残り1本はまだ走っている、という意味だ。数字が合っているかは claude agents の人間向け表示と突き合わせて確認した。一致した。

ステータスラインに出す

ここからが本題。zshのプロンプト右側(RPROMPT)に、入力待ち本数を出す。

# ~/.zshrc に追記
_claude_waiting() {
  local n
  n=$(claude agents --json 2>/dev/null \
      | jq '[.[] | select(.status=="awaiting_input")] | length' 2>/dev/null)
  [[ -z "$n" || "$n" == "0" ]] && return
  echo "%F{yellow}claude:${n}待%f"
}
setopt prompt_subst
RPROMPT='$(_claude_waiting)'

これで、入力待ちが1本以上あるときだけ右端に「claude:2待」と出る。0本のときは何も出さない。常時うるさくならないように、ここは消す側に倒した。

ただし注意がある。claude agents --json の起動には、私の計測で平均しておよそ0.4秒ほどかかった(10回叩いた中央値)。プロンプトを描くたびに毎回叩くと、コマンド実行のたびに0.4秒待たされて体感が悪い。これは致命的とは言わないが、効いてくる。

そこで、ポーリングはバックグラウンドに逃がし、結果をファイルにキャッシュした。

# 5秒ごとに件数をキャッシュへ
( while true; do
    claude agents --json 2>/dev/null \
      | jq '[.[]|select(.status=="awaiting_input")]|length' \
      > /tmp/claude_waiting 2>/dev/null
    sleep 5
  done ) &!

RPROMPT側は /tmp/claude_waiting を読むだけにする。これでプロンプト描画の遅延はほぼ消えた。5秒のラグは、入力待ちの通知には十分すぎる粒度だ。

どこが効いたか、数字で

一日の作業で、私はバックグラウンドセッションを平均2〜4本走らせている。これまでは「そろそろどれか終わってるかな」と思うたびに claude agents を打つか、Agent Viewに切り替えていた。ざっくり数えて、午前中だけで19回その確認をしていた(シェル履歴から claude agents の出現回数を拾った)。

ステータスラインに出してからは、その明示的な確認がほぼ要らなくなった。プロンプトに数字が出ていれば見る、出ていなければ手を止めない。午後の同じ時間帯で claude agents の手打ちは2回まで減った。19回が2回。確認のために思考を中断する回数が、これだけ落ちた。

これは大きいと感じる。エージェントを並列で回す運用のいちばんの敵は、実は計算資源ではなく「いま何を待っているか分からない」という宙ぶらりんの状態だ。そこが消えるだけで、並列の本数を一本増やす心理的なハードルが下がる。

限界と注意点

正直に書く。これは万能ではない。

ひとつ、--json のスキーマは公式に固定として保証されているわけではない。フィールド名が変わればスクリプトは黙って空を返す。だから私のキャッシュ用ループは、jqが失敗しても前回値を壊さないように 2>/dev/null で握りつぶしている。本来は良くない握り方だが、ステータスライン用途では「壊れても古い数字が残る」方がマシだと判断した。

ふたつ、バックグラウンドサービスが応答しないと claude agents 系は固まりうる。同リリースでは、応答不能時に10秒でタイムアウトする修正も入っている。とはいえ5秒ポーリングと10秒タイムアウトがぶつかると、最悪ループが詰まる瞬間がある。私はポーリング間隔を5秒にしたが、神経質な人は10秒以上にした方がいい。

私見と次に試すこと

この手の「機械可読の口を開ける」変更は、派手な新機能の影でリリースノートの一行に埋もれがちだ。だが個人的には、こういう一行こそ後から効いてくると思っている。構造としては、Vim時代にプラグインが :set の出力を奪い合っていたのに似ている。コアが状態を機械可読で出した瞬間、周辺のエコシステムが一気に育つ。

次は、このJSONをtmuxのステータスバー右側に流し込んで、ペインを切り替えなくても全セッションの待ち状況を一望できるようにしたい。tmux-resurrect と組み合わせれば、再起動後もどのセッションがどこにいたか復元できる、というのが公式の示唆だ。そこまで組めたら、Agent Viewを開く回数すらゼロに近づけられるかもしれない。

タイトルとURLをコピーしました