借りている部屋の天井に、薄い輪ができていました。
上の階の配管が古いのだそうです。管理会社に伝えると、来週見に行きますと言われ、しばらくしてから、直しましたという連絡が来ました。
天井の輪は、そのままです。
直したと、直っている。この二つは別のことで、後者を確かめられるのは天井の下に住んでいる人だけです。上の階の配管に手を入れる権利は、こちらにはありません。
借りると、借りたものの不具合も来る
ソフトウェアも同じ形をしています。
ターミナルを何枚も並べて、閉じても消えないようにする仕組みを作るとき、選択肢は二つあります。全部自分で書くか、すでにあるものを借りるか。
tmux は後者の代表です。ターミナルの中身を生かしたまま置いておくための道具で、二十年近く使われています。ブラウザを閉じてもプロセスが死なない、という性質はこれが持っています。
借りると安く済みます。そのかわり、借りたものの不具合が、自分の製品の不具合として利用者の前に出ます。そして直す権利は、こちらにありません。
並列にすると、当たる面積が増える
AI にコードを書かせるようになって、この構図の重みが変わりました。
一体に頼んで待つだけなら、セッションが消えても打ち直せば済みます。九体を並列で回していて、そのうち三体が三十分の作業の途中だと、消えることの意味が変わります。だから借りる理由が強くなりました。
同時に、借り物に当たる面積も増えました。セッションを一つ作るところで踏まない不具合を、一日に何十回作れば踏みます。
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 でまた動くからです。動かせるのはクライアントの側です。
報告した不具合が、完了で閉じられて、直っていなかった
この不具合は上流にも報告されています。
八月七日に別の方が起票し、十五日にこちらから実測を足しました。サーバーの作業フォルダは起動した場所に留まるのではなく、new-session のたびにクライアントに追従して戻らない、という測定です。十七日にメンテナが修正の差分を出して、これで直るかと聞きました。三十一日に、完了として閉じられました。
九月二十九日に、また別の方が書き込みました。まだ再現する、と。
確かめました。spawn.c の該当箇所は、いまも getcwd() の内側にあります。そして spawn.c はその後も変更されているのに、どれも作業フォルダの扱いを触っていません。十七日の差分は、木に入っていませんでした。
天井の輪と同じです。直したと言われても、直っているかは自分で見るまで分かりません。
借りないという選択もあります
tmux を借りなければ、この不具合はそもそも来ません。かわりに、閉じても消えないセッションの仕組みを自分で書くことになります。二十年ぶん試された道具を捨てて、同じものを作り直す判断です。
利用者に 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 を裏方に借りています。二十年試された永続化を借りられるかわりに、その不具合も借ります。今回当たったのは、サーバーの作業フォルダが消えると新しいマスが全部壊れる、というものでした。
直す権利はこちらにありません。それでもクライアントを消せない場所から起動するという一手は打てました。そして上流には、閉じられた不具合がまだ残っていることを、確かめた事実を添えて返しています。
