何を見つけたか
tmux-first / tmux-clean(containers/base/ から /usr/local/bin へ焼き込み。ホストでは ~/.local/bin に同じ中身)は、同じベース名のセッション群をまとめて片付ける作りで、1 つのセッションを名指しする操作ができない。素の tmux コマンドには落とし穴がある。
日常でよく使うのに、今の道具では手間がかかる操作は次の 3 つである。
| やりたいこと |
今の道具でできない理由 |
| 狙ったセッションへ強制 attach する(既に attach している端末は外してよい) |
tmux-first は常に「ベース名で一番番号の小さいもの」を選ぶ。devbase-3 を名指しできない。操作中の端末を外すには -f が要る |
| 他の端末が attach しているセッションで、何が動いているかを調べる |
道具が無い。pane_current_command はフォアグラウンドのコマンドしか出さない(例: devbase list の TUI が uv とだけ見える) |
| 狙ったセッションを、attach の有無に関係なく落とす |
tmux-clean は keeper(残す 1 つ)以外を消す作りで、名指しできない。アタッチ中・実行中は -f が要り、-f では keeper 以外がすべて消える |
素の tmux での手順(tmux 3.7b で確認)
セッション名の前の = は完全一致の指定で、devbase-1 が devbase-10 に前方一致で当たるのを防ぐ。
1. 強制 attach
# tmux の外から: -d で他の端末を外してから attach する
tmux attach -d -t =devbase-3
# tmux の中から: 先に相手の端末を外し、それから自分が移る
tmux detach-client -s =devbase-3
tmux switch-client -t =devbase-3
- tmux の中では順序が逆だと自分も外れる(先に移ってから
detach-client -s すると、自分も対象のセッションの端末になっている)
detach-client -a は「自分以外のすべての端末」で、関係のない別のセッションの端末まで外す
2. 中身を調べる(attach しない)
S=devbase-2
tmux list-clients -t "=$S" -F '#{client_tty} 最終操作 #{t:client_activity}'
tmux list-panes -s -t "=$S" -F '#{window_index}.#{pane_index} #{pane_current_command} pid=#{pane_pid} #{pane_current_path}'
tmux capture-pane -p -t "=$S" -S -40 # 画面の直近 40 行(-e で色付き)
pgrep -P <pane_pid> -lf # シェルの子プロセス(& で起動したものも出る)
tmux attach -r -t "=$S" # 読み取り専用で覗く(-r = read-only,ignore-size。相手の画面サイズも変えない)
3. 名指しで落とす
tmux kill-session -t =devbase-3 # attach 中でも落ちる(相手は [exited])
tmux kill-session -a # 今いるセッション以外すべて
中のプロセスには SIGHUP が届く。nohup で起動したものは残る。
直し方
2 層に分ける。土台に名指しのコマンドを置き、TUI は tmux 自身の UI 機能で薄く載せる。
| 層 |
中身 |
依存 |
| 土台 |
名指しの 3 操作をシェルのコマンドにする(例: tmux-go <名前> / tmux-peek <名前> / tmux-kill <名前>...、または tmux-first -t <名前> の追加) |
sh のみ |
| TUI |
tmux の choose-tree / display-menu / display-popup で「一覧 → 操作」のメニューを組み、操作は土台のコマンドを呼ぶ |
0(tmux のみ) |
土台だけでも 3 つの操作は完結する。TUI が使えない場面(tmux の外・非対話)でも土台が残る。
土台: 強制 attach の注意
tmux-first が「実行元のクライアントを特定できない」ときに止まるのと同じ配慮が要る。自分の端末を #{client_name} で除外してから相手を外す。
me=$(tmux display -p '#{client_name}')
tmux list-clients -t "=$1" -F '#{client_name}' | grep -vxF "$me" | xargs -n1 tmux detach-client -t
tmux switch-client -t "=$1"
TUI: tmux の組み込み機能で組む
3 つの操作のうち 2 つは choose-tree が既に持っている。
| やりたいこと |
tmux の機能 |
足す量 |
| 一覧から選ぶ・中身を見る |
choose-tree -s が全セッションの一覧と、選んでいるセッションの画面のライブなプレビューを出す(v で表示の切り替え、f で絞り込み) |
0 |
| 落とす |
choose-tree の中で x(確認あり)。t で複数に印を付けて X でまとめて |
0 |
| 強制 attach |
choose-tree の template から土台の tmux-go を呼ぶ |
キーの割り当て |
| プロセスの木まで見る |
display-popup -E で浮いた窓に tmux-peek の結果を出す |
キーの割り当て |
形のイメージ(スケッチ。未実行):
# prefix S: セッションを選んで操作のメニューを出す(devbase の TUI と同じ「一覧 → 操作」の形)
bind-key S choose-tree -Zs -O name "run-shell 'tmux-session-menu \"%%\"'"
# tmux-session-menu: 選んだセッションに対する操作を tmux のメニューで出す
s=${1%:}
tmux display-menu -T "#[align=centre]$s" \
"移る(他の端末を外す)" a "run-shell 'tmux-go $s'" \
"中身を見る" p "display-popup -E -w 90% -h 80% 'tmux-peek $s; read -r _'" \
"落とす" k "confirm-before -p '$s を落としますか? (y/n)' 'kill-session -t =$s'"
%% が選んだ項目にどう展開されるか(末尾の : の有無)と、メニューの中の引用符の入れ子は、実装で確かめる。
tmux の UI を採る理由:
- 追加の依存が 0。 置き場所も今と同じで、
/etc/tmux.conf(base へ焼き込み済み)と /usr/local/bin(tmux-first と同じ)に収まる
- コンテナとホストで同じ UI になる。 ホストの tmux は 3.7b で、
~/.tmux.conf に同じ割り当てを書けば動く
- 使う機能はコンテナの tmux 3.6 ですべて使える(
display-menu は 3.0 以降、display-popup は 3.2 以降)
弱点: tmux の外からは呼べない。VS Code の端末が常に tmux の中で開く運用なら実害は小さい。
検討した他の作り方
base イメージに入っているかを、イメージの中で確かめた(2026-09-22、devbase-base:latest arm64)。
| 候補 |
base に入っているか |
判断 |
| tmux 3.6 の組み込み機能 |
あり |
採る(上) |
Python 3.14 の標準ライブラリ curses |
あり(import curses が通る) |
tmux の外からも使いたくなったときの次の手。追加 0 だが、描画・キー操作・端末サイズの変化・日本語の表示幅を自前で扱い、200〜300 行ほどになる見込み |
devbase の TUI と同じ questionary(その下は prompt_toolkit) |
なし(import prompt_toolkit が ModuleNotFoundError。devbase の CLI もコンテナに無い) |
採らない。下の「questionary の重さ」 |
bash の select |
あり |
番号で選ぶだけでプレビューが無い。curses も使えない環境の最後の受け皿 |
| Node 24 |
あり。ただし TUI のライブラリは無い(グローバルは gemini-cli・codex・playwright など) |
採らない。ink などを npm で足す必要がある |
whiptail / dialog / fzf / gum / Perl の Curses |
なし |
採らない |
questionary の重さ
ライブラリ自体は重くない。 採らないのは、コンテナに無く、プレビュー窓も無いためである。
| 項目 |
実測(2026-09-22) |
| devbase の依存の木 |
questionary 2.1.1 → prompt-toolkit 3.0.52 → wcwidth 0.8.1 |
import の時間(ホスト、uv run 経由、温まった状態) |
0.10〜0.17 秒 |
base イメージの apt python3-prompt-toolkit |
3.0.52-2 / Installed-Size 1466 KB / 依存 python3-wcwidth |
base イメージの apt python3-questionary |
2.1.1-2 / Installed-Size 1269 KB。Depends に libjs-jquery / libjs-sphinxdoc / sphinx-rtd-theme-common(文書の生成物)が付く |
- コンテナへ入れるなら apt で入るが、
python3-questionary は文書の生成物を Depends で連れてくる
questionary の select にはプレビュー窓が無い。プレビューを出すなら prompt_toolkit を直接使って全画面のアプリにすることになる
- ホストでは devbase の venv に既に入っているため、
devbase の TUI にカテゴリとして足すなら追加 0。ただしコンテナとホストで UI が分かれる
修正レイヤー
現象レイヤー: tmux のセッションを名指しで扱う操作が、素の tmux の組み合わせでしかできない。
修正レイヤー: containers/base/tmux-first / tmux-clean(と新設する名指しのコマンド)、containers/base/tmux.conf(キーの割り当て)。ホストの ~/.local/bin の同じ中身は手で置かれたもので、配布の経路が無い。
決めること
- 名指しの操作を
tmux-first / tmux-clean の引数として足すか、別のコマンド(tmux-go / tmux-peek / tmux-kill など)にするか
- TUI のキー割り当て(
prefix S は既定で割り当てが無いか、既存の割り当てと衝突しないか)
- ホストの
~/.local/bin と ~/.tmux.conf へ配る経路を作るか
- tmux の外からも使う要求が出たら
curses で作るか(今は作らない)
由来
v3.7.0 の作業中に、ホストの tmux で devbase-2〜-4 を閉じる操作をしたとき。
進行
モード: standard / 作業ツリー: /Users/takemi_ohama/devbase/.worktrees/feature/plan69-tmux-named-session / 計画: issues/PLAN69_tmux-named-session.md
振り返り: #262 (comment)
何を見つけたか
tmux-first/tmux-clean(containers/base/から/usr/local/binへ焼き込み。ホストでは~/.local/binに同じ中身)は、同じベース名のセッション群をまとめて片付ける作りで、1 つのセッションを名指しする操作ができない。素のtmuxコマンドには落とし穴がある。日常でよく使うのに、今の道具では手間がかかる操作は次の 3 つである。
tmux-firstは常に「ベース名で一番番号の小さいもの」を選ぶ。devbase-3を名指しできない。操作中の端末を外すには-fが要るpane_current_commandはフォアグラウンドのコマンドしか出さない(例:devbase listの TUI がuvとだけ見える)tmux-cleanは keeper(残す 1 つ)以外を消す作りで、名指しできない。アタッチ中・実行中は-fが要り、-fでは keeper 以外がすべて消える素の tmux での手順(tmux 3.7b で確認)
セッション名の前の
=は完全一致の指定で、devbase-1がdevbase-10に前方一致で当たるのを防ぐ。1. 強制 attach
detach-client -sすると、自分も対象のセッションの端末になっている)detach-client -aは「自分以外のすべての端末」で、関係のない別のセッションの端末まで外す2. 中身を調べる(attach しない)
3. 名指しで落とす
中のプロセスには SIGHUP が届く。
nohupで起動したものは残る。直し方
2 層に分ける。土台に名指しのコマンドを置き、TUI は tmux 自身の UI 機能で薄く載せる。
tmux-go <名前>/tmux-peek <名前>/tmux-kill <名前>...、またはtmux-first -t <名前>の追加)choose-tree/display-menu/display-popupで「一覧 → 操作」のメニューを組み、操作は土台のコマンドを呼ぶ土台だけでも 3 つの操作は完結する。TUI が使えない場面(tmux の外・非対話)でも土台が残る。
土台: 強制 attach の注意
tmux-firstが「実行元のクライアントを特定できない」ときに止まるのと同じ配慮が要る。自分の端末を#{client_name}で除外してから相手を外す。TUI: tmux の組み込み機能で組む
3 つの操作のうち 2 つは
choose-treeが既に持っている。choose-tree -sが全セッションの一覧と、選んでいるセッションの画面のライブなプレビューを出す(vで表示の切り替え、fで絞り込み)choose-treeの中でx(確認あり)。tで複数に印を付けてXでまとめてchoose-treeの template から土台のtmux-goを呼ぶdisplay-popup -Eで浮いた窓にtmux-peekの結果を出す形のイメージ(スケッチ。未実行):
%%が選んだ項目にどう展開されるか(末尾の:の有無)と、メニューの中の引用符の入れ子は、実装で確かめる。tmux の UI を採る理由:
/etc/tmux.conf(base へ焼き込み済み)と/usr/local/bin(tmux-firstと同じ)に収まる~/.tmux.confに同じ割り当てを書けば動くdisplay-menuは 3.0 以降、display-popupは 3.2 以降)弱点: tmux の外からは呼べない。VS Code の端末が常に tmux の中で開く運用なら実害は小さい。
検討した他の作り方
base イメージに入っているかを、イメージの中で確かめた(2026-09-22、
devbase-base:latestarm64)。cursesimport cursesが通る)questionary(その下はprompt_toolkit)import prompt_toolkitがModuleNotFoundError。devbase の CLI もコンテナに無い)selectcursesも使えない環境の最後の受け皿inkなどを npm で足す必要があるwhiptail/dialog/fzf/gum/ Perl のCursesquestionary の重さ
ライブラリ自体は重くない。 採らないのは、コンテナに無く、プレビュー窓も無いためである。
questionary 2.1.1→prompt-toolkit 3.0.52→wcwidth 0.8.1uv run経由、温まった状態)python3-prompt-toolkitpython3-wcwidthpython3-questionaryDependsにlibjs-jquery/libjs-sphinxdoc/sphinx-rtd-theme-common(文書の生成物)が付くpython3-questionaryは文書の生成物をDependsで連れてくるquestionaryのselectにはプレビュー窓が無い。プレビューを出すならprompt_toolkitを直接使って全画面のアプリにすることになるdevbaseの TUI にカテゴリとして足すなら追加 0。ただしコンテナとホストで UI が分かれる修正レイヤー
現象レイヤー: tmux のセッションを名指しで扱う操作が、素の tmux の組み合わせでしかできない。
修正レイヤー:
containers/base/tmux-first/tmux-clean(と新設する名指しのコマンド)、containers/base/tmux.conf(キーの割り当て)。ホストの~/.local/binの同じ中身は手で置かれたもので、配布の経路が無い。決めること
tmux-first/tmux-cleanの引数として足すか、別のコマンド(tmux-go/tmux-peek/tmux-killなど)にするかprefix Sは既定で割り当てが無いか、既存の割り当てと衝突しないか)~/.local/binと~/.tmux.confへ配る経路を作るかcursesで作るか(今は作らない)由来
v3.7.0 の作業中に、ホストの tmux で
devbase-2〜-4を閉じる操作をしたとき。進行
モード: standard / 作業ツリー:
/Users/takemi_ohama/devbase/.worktrees/feature/plan69-tmux-named-session/ 計画:issues/PLAN69_tmux-named-session.md振り返り: #262 (comment)