MulmoTerminal が踏んだ tmux 3.7 の不具合:クライアント起動位置で回避し、完了扱いの Issue が実は未修正だった話

MulmoTerminal が踏んだ tmux 3.7 の不具合:クライアント起動位置で回避し、完了扱いの Issue が実は未修正だった話

ソフトウェアを他人の土台の上に載せると、その土台の不具合も借りることになります。しかも、直す権利はこちらにありません。

ターミナルを何枚も並べて、閉じても消えないようにする仕組みを作るとき、選択肢は二つあります。全部自分で書くか、すでにあるものを借りるか。

tmux は後者の代表です。ターミナルの中身を生かしたまま置いておくための道具で、20 年近く使われています。ブラウザを閉じてもプロセスが死なない、という性質はこれが持っています。

借りると安く済みます。そのかわり、借りたものの不具合が、自分の製品の不具合として利用者の前に出ます。

並列にすると、当たる面積が増える

AI にコードを書かせるようになって、この構図の重みが変わりました。

1 体に頼んで待つだけなら、セッションが消えても打ち直せば済みます。9 体を並列で回していて、そのうち 3 体が 30 分の作業の途中だと、消えることの意味が変わります。借りる理由が強くなりました。

同時に、借り物に当たる面積も増えました。セッションを 1 つ作るところで踏まない不具合を、1 日に何十回作れば踏みます。

MulmoTerminal は tmux を裏方にしている

MulmoTerminal は、ターミナルで動く AI を何枚ものマスに並べて見張るための画面です。ターミナルで一行打つと立ち上がり、ブラウザで開くと格子が出ます。無料で、オープンソースとして公開されています。

置き換えではなく、裏方として tmux を借りています。-L mulmoterminal という専用のソケットで自分用の tmux サーバーを動かし、マスを開くたびにこう打ちます。

tmux -L mulmoterminal new-session -A -s mt-<番号> -c <そのマスのフォルダ>

-c が、そのマスをどのフォルダで始めるかの指定です。git の作業フォルダを分けて並列で動かすので、マスごとに違うフォルダを渡します。

踏んだ不具合

tmux 3.7 には、こういう挙動があります。new-session のたびに、サーバーの作業フォルダがクライアントのそれに移り、そして戻りません。

それだけなら害がありません。問題は、ペインを作る側のコードです。

/* tmux の spawn.c */
if (getcwd(path, sizeof path) != NULL) {
        if (chdir(new_wp->cwd) == 0) ...        /* -c で渡された場所 */
        else if (home != NULL && chdir(home) == 0) ...
        else if (chdir("/") == 0) ...
}

-c に移る処理と、それが駄目だったときの退避先が二つ、全部 getcwd() の成功の内側にあります。サーバーの作業フォルダが消えていると getcwd() が失敗して、このブロックごと飛ばされます。

そして MulmoTerminal は、作業フォルダを消す機能を自分で持っています。

つながると、こうなります。作業フォルダの中からクライアントを起動すると、サーバーがそこに座ります。そのあと MulmoTerminal がその作業フォルダを片付けます。以後に開くマスは全部 -c を無視して、消えたフォルダで始まります。

起動するときに getcwd() を呼ぶプログラムは、そこで即座に死にます。Claude Code がそうです。tmux サーバーを殺すまで、新しいセッションが全部壊れます。すでに動いているものは平気なので、気づくのが遅れます。

tmux 3.6 以前には、この挙動がありません。

上流を待たずに打てた一手

直す権利はこちらにありません。それでも、自分の側でできることが一つありました。

tmux のクライアントを、消せない場所から起動します。MulmoTerminal はホームディレクトリを使っています。サーバーはクライアントのフォルダに移るので、クライアントが消えない場所にいれば、サーバーも消えない場所に座ります。

ペインは影響を受けません。マスをどのフォルダで始めるかを決めているのは new-session -c のほうで、そちらは今までどおりそのマスのフォルダです。

ここで一つ、間違えやすいところがあります。サーバーを安全な場所から起動するのでは、代わりになりません。最初の new-session でまた動くからです。動かせるのはクライアントの側です。

報告した不具合が、完了で閉じられて、直っていなかった

この不具合は上流にも報告されています。

8 月 7 日に別の方が起票し、15 日にこちらから実測を足しました。サーバーの作業フォルダは起動した場所に留まるのではなく、new-session のたびにクライアントに追従して戻らない、という測定です。17 日にメンテナが修正の差分を出して、これで直るかと聞きました。31 日に、完了として閉じられました。

9 月 29 日に、また別の方が書き込みました。「まだ再現する」と。

確かめました。spawn.c の該当箇所は、いまも getcwd() の内側にあります。そして spawn.c はその後も変更されているのに、どれも作業フォルダの扱いを触っていません。17 日の差分は、ツリーに入っていませんでした。

「直した」と「直っている」は別のことで、確かめられるのは実際に使っている側だけです。

借りないという選択もあります

tmux を借りなければ、この不具合はそもそも来ません。かわりに、閉じても消えないセッションの仕組みを自分で書くことになります。20 年ぶん試された道具を捨てて、同じものを作り直す判断です。

利用者に「tmux 3.6 を使ってください」と言う道もあります。ただ、手元に何が入っているかは選べません。

MulmoTerminal がやったのは、借り続けたまま、自分の側で打てる一手を打つことでした。上流には、確かめた事実を添えて返しています。

使ってみる

MulmoTerminal は、次の一行で立ち上がります。ターミナル(Windows なら PowerShell、Mac ならターミナル)を開いて、そのまま貼り付けます。

npx mulmoterminal@latest

ブラウザが開いて http://localhost:34567 が表示されれば成功です。インストールという作業はなく、合わなければ閉じるだけで終わります。止めるときは、打ったターミナルで Ctrl + C を押します。

動かない場合、足りないものは次の二つのどちらかです。

確かめ方 無ければ
Node.js 22.12 以上 node -v nodejs.org/ja/download の LTS。入れたらターミナルを閉じて開き直す
Claude Code claude --version macOS は curl -fsSL https://claude.ai/install.sh | bash、Windows は irm https://claude.ai/install.ps1 | iex。そのあと claude でログイン

Claude Code は、AI をターミナルから使うためのコマンドです。使うには Claude の有料プラン(Pro / Max / Team / Enterprise)か API のアカウントが必要で、無料プランには含まれていません。MulmoTerminal 自体は無料で、AI の使用量はその契約から引かれます。

この記事の話は、設定が要りません。tmux があれば自動で使われ、無ければ使いません。

tmux -V

3.7 以降が出たなら、上に書いた挙動を持つ版です。MulmoTerminal の側の手当ては最初から入っているので、こちら側で何かする必要はありません。

いま自分の tmux サーバーがどのフォルダに座っているかは、こう見られます。

# macOS
lsof -a -p "$(tmux -L mulmoterminal display -p '#{pid}')" -d cwd -Fn | tail -1

ホームディレクトリが返れば、手当てが効いています。作業フォルダの名前が返ったら、それは MulmoTerminal 以外の経路で立ったサーバーです。

まとめ

MulmoTerminal は tmux を裏方に借りています。20 年試された永続化を借りられるかわりに、その不具合も借ります。今回当たったのは、サーバーの作業フォルダが消えると新しいマスが全部壊れる、というものでした。

直す権利はこちらにありません。それでも、クライアントを消せない場所から起動するという一手は打てました。上流には、閉じられた不具合がまだ残っていることを、確かめた事実を添えて返しています。

この記事をシェア

関連記事

記事一覧に戻る