やってみた 2026年7月4日

herdr とは|AIエージェント用ターミナル多重化ツールの使い方をDockerで試した

XECIN RustCLIターミナルOSS

GitHubのトレンドを流し見していたら、ogulcancelik/herdr というのが10位あたりに入っていた。説明に「run all your coding agents in one terminal」とあって、要はAIコーディングエージェントを何本も並べて走らせるためのターミナル多重化ツールらしい。READMEには「if you’ve used tmux: it’s that, rebuilt for agents(tmuxを使ったことがあるなら、それをエージェント向けに作り直したもの)」と書いてある。

tmuxのエージェント版、という煽りは正直ちょっと気になる。自分もエージェントを2〜3本同時に回すと、どれが入力待ちで止まっているのか分からなくなって結局ぜんぶ覗いて回る、みたいなことをやっているので。Rust製の単一バイナリでアカウントもテレメトリも無い、というのも好みなんですよね。ちょっと触ってみることにした。

herdr とは(AIエージェント向けのターミナル多重化ツール)

herdr(ogulcancelik/herdr)は、AIコーディングエージェントを複数同時に走らせるためのRust製ターミナル多重化ツールです。READMEは「if you’ve used tmux: it’s that, rebuilt for agents(tmuxを使ったことがあるなら、それをエージェント向けに作り直したもの)」と表現しています。単一バイナリで動きアカウントもテレメトリも持たないこと、各エージェントの状態(作業中/ブロック中など)をサイドバーで俯瞰できることが特徴です。

検証環境(Windows+使い捨てDockerコンテナ)

試した環境は、Windowsマシンの上に立てた使い捨てのDockerコンテナ(debian:bookworm-slim / Debian GNU/Linux 12)の中だけで完結させています。ホストを汚したくないので、ダウンロードも実行も全部コンテナ内で、外に残すのは検証ログだけ、という切り分けです。対象は herdr 0.7.1(socketのprotocolは14)。

herdr のインストール(Docker/Linux)——バイナリ1個・静的リンク

公式のインストールは curl -fsSL https://herdr.dev/install.sh | sh なんですが、中身を追うと結局はGitHub Releasesのバイナリを落としてくるだけなので、今回はリリースから herdr-linux-x86_64 を直接取ってきました。

curl -fsSL -o herdr \
  https://github.com/ogulcancelik/herdr/releases/download/v0.7.1/herdr-linux-x86_64
chmod +x herdr
file herdr
# => ELF 64-bit LSB pie executable, x86-64, static-pie linked, not stripped
ls -l herdr
# => 17342944 (約17MB)

filestatic-pie linked と出た通り、glibcのバージョンで揉めることもなく、debian:bookworm-slimにcurlとca-certificatesを足しただけの素の環境でそのまま動きました。17MBの1ファイルというのは、READMEの「single ~10MB rust binary」よりは太っていたけど、依存ゼロで置くだけというのは確かに気楽です。

いきなり herdr を叩いたらパニックで落ちた

で、READMEのクイックスタートは herdr と打つだけ、と書いてある。素直に叩いてみたら、これがコンテナ環境では落ちました。

thread 'main' panicked at ratatui-0.30.0/src/init.rs:299:16:
failed to initialize terminal: Os { code: 6, kind: Uncategorized, message: "No such device or address" }

終了コードは101。TUIフレームワークの ratatui がターミナルの初期化に失敗している。つまり herdr はフルスクリーンのTUIとして起動しようとするので、ちゃんとしたTTYがぶら下がっていないヘッドレスなコンテナ実行だと、そもそも画面を掴めずに死ぬわけです。ここは公式の「まず herdr と打て」だけを見ていると引っかかるところで、今思えばTUIツールなんだから当たり前なんですが、最初は「バイナリ壊れてる?」と一瞬疑いました。

じゃあこのツール、対話端末が無いと何もできないのか……と思いきや、herdr --help を眺めていて気づいた。herdr server(ヘッドレスサーバ)と、workspace / pane / tab / agent といったsocket API越しのサブコマンド群がちゃんと生えている。READMEにも「a local socket api and cli that agents can drive」とある通り、エージェント自身に操作させる想定の入り口が別にあるんですね。TUIを開かずに、こっちのCLIだけで検証を続けることにしました。

herdr の使い方:herdr server + socket CLI で操作する

サーバはバックグラウンドで起こしておいて、別コマンドで状態を問い合わせる形になります。起動直後のメッセージがちょっと面白くて、「did you mean to open the Herdr TUI? run herdr; you do not need herdr server」と、わざわざ「普通の人はserver要らないよ」と諭してくる。今回はまさにその「普通じゃない」使い方をしているわけです。

# サーバ起動前
./herdr status server
# => status: not running

# ヘッドレスサーバを起動(別プロセス)
./herdr server &

# 起動後
./herdr status server
# => status: running / version: 0.7.1 / protocol: 14 / compatible: yes

サーバが立ったので、workspaceを1つ作ってみます。socket APIの応答はJSONで返ってきました。

./herdr workspace create --label demo --no-focus
{"result":{"workspace":{"workspace_id":"w1","label":"demo","tab_count":1,"pane_count":1,"agent_status":"unknown"},
 "root_pane":{"pane_id":"w1:p1","tab_id":"w1:t1","terminal_id":"term_655c7e6c79b731","cwd":"/root"}}}

workspaceを1個作ると、タブ(w1:t1)と最初のpane(w1:p1)、そして実体のターミナル(term_...)まで一式できる。ここが「アプリが描いた偽物の端末じゃなくて本物のターミナル」を売りにしているところで、実際 pane run でコマンドを流し込んで、pane read で中身を読み返せます。

./herdr pane run w1:p1 "echo hello-from-herdr && uname -sm && ls /work"
./herdr pane read w1:p1 --source visible --lines 40
# echo hello-from-herdr && uname -sm && ls /work
hello-from-herdr
Linux x86_64
herdr  server.out
#

裏で本物のシェルが動いているのは pane process-info でも確認できて、フォアグラウンドが /bin/sh(pid 3103)だと返ってきました。ペインを縦に割る(pane split --direction down)と w1:p2 が別のterminal_id付きで生えて、これも想定通り。

ひとつ細かいハマりどころ。最初 pane read--source recent で読んだら、ls の結果と # のプロンプトしか出てこなくて「echoの出力どこ行った?」となりました。サーバログを見ると分割後のペインは rows=23 cols=54 と小さめに立っていて、recent は直近の可視行だけを返す挙動のようです。全体を見たいときは --source visible を明示する、というのが正解でした。ここは好みが分かれるところですが、デフォルトがもう少し寛容でもいい気はします。

目玉の「状態が一目で分かる」を試す

herdrの一番のウリは、各エージェントが 🔴 blocked / 🟡 working / 🔵 done / 🟢 idle のどれなのかをサイドバーで俯瞰できる、という点です。ただ今回のコンテナには Claude Code だの Codex だのの実物は入れていないので、状態を自動検出させることはできない。

そこで、プラグインやエージェントが状態を報告するのに使う pane report-agent を直接叩いて、ロールアップの挙動だけを確かめました(=本物のエージェントを動かして観測したわけではなく、状態通知の仕組みを手で叩いた、という点は正直に書いておきます)。

./herdr pane report-agent w1:p1 --source demo1 --agent claude-code \
  --state working --message "running tests"
./herdr workspace list
# => workspaces[0].agent_status: "working"

./herdr pane report-agent w1:p1 --source demo1 --agent claude-code \
  --state blocked --message "needs approval"
./herdr workspace list
# => workspaces[0].agent_status: "blocked"

paneに付けた状態が、そのままtab・workspaceのレベルまで巻き上がってくる。agent list で見ると、claude-code と報告したはずのラベルが claude に正規化されて、agent_status: working の1エントリとして並んでいました。この「pane→tab→workspaceへ状態が伝播する」ところが、複数エージェントを束ねたときに「どのグループに手当てが要るか」を一目で出す土台なんだろうな、というのは触ってみて腑に落ちました。

最後に herdr server stop でサーバはきれいに落ちて(status: not running に戻る)、コンテナごと破棄して終わりです。

試してみての所感

ヘッドレスのコンテナでTUIツールを検証する、という筋の悪い入り方をしたわりに、herdr server + socket CLI という抜け道がしっかり用意されていたおかげで、workspace作成・pane操作・ターミナルの読み書き・状態のロールアップまで一通り観測できました。JSONで素直に返ってくるので、スクリプトやエージェントから叩く前提の設計になっているのは納得感があります。

一方で、本来の主役であるインタラクティブなTUIそのものは今回まったく触れていない(そもそも動かせなかった)ので、マウスでペインをドラッグ、みたいな体験の良し悪しは自分にはまだ何とも言えません。そこは実機のターミナルで改めて試したいところ。

自分の使い方としては、tmuxの完全な置き換えというより、「エージェントを何本も回すときの状態ダッシュボード+socket API」の部分に一番惹かれました。CIやスクリプトからペインを立てて状態を拾う、みたいな用途なら、TTYが無い環境でも今日みたいに回せるのは強い。しばらく手元のエージェント運用で report-agent まわりを実物と繋いで様子を見てみようと思います。もっと良い使い方があったら教えてください。