記事をどれだけ読んだかを示します

SSHler:ウィンドウの混沌なしで複数マシンを管理する

アクティブなプロジェクトが動いているマシンが4台ある。ワークステーションでは Claude Code のセッションが動いている。ホームサーバーではテストが走っている。VPS では何かをビルドしている。sshler を作る前のワークフロー:ターミナルエミュレータを開く、SSH 接続、cd でプロジェクトに移動、tmux attach、作業、デタッチ、別のターミナルを開く、別のマシンに SSH、繰り返し。6 つのターミナルウィンドウ、Alt-Tab、サーバーはどれだっけ。

十分うんざりしたので作った。


問題

Android の JuiceSSH はまともだがファイルブラウジングができない。VS Code Remote は強力だが重い;ログファイルを確認するだけでフル IDE は要らない。ウィンドウの山に溺れずに 1 つのインターフェースからマシン間をジャンプできるものが何もなかった。

sshler は ~/.ssh/config を読み取り、すべてのボックスを表示し、SFTP でファイルを閲覧し、ブラウザで tmux セッションを開けるローカル専用 Web UI。pip install 一発、コマンド一つ。

それが最初のスコープ。実際に起きたことの方が面白い。


実際の使い方

マルチエージェント調整

典型的な午後はこんな感じ。ワークステーションのブラウザタブで sshler を開いている。3〜4 つのボックスがアクティブ。各ボックスで Claude Code、テスト、ビルドの tmux セッションが 1〜2 個動いている。

ワークフロー:sshler タブをちらっと見る、全ボックスを確認、必要なボックスをクリック、ターミナルをチェック、Claude Code に新しい指示を出すか出力を確認、別のボックスに切り替え、テスト結果を確認、戻る。ターミナルはリモートホスト上の永続的な tmux セッション — ブラウザを閉じてもページをリロードしても、セッションはそのまま。再接続して中断したところから続けられる。

具体的な例:ワークステーションで sqler のベンチマーク、サーバーで sshler のフロントエンド改善を同時に進めている。Claude Code インスタンスが 2 つ、リポジトリが 2 つ、マシンが 2 つ。sshler を開いて両方のターミナルを見られる。sqler-Claude に指示を出し、タブを切り替えて sshler-Claude に指示を出し、戻る。エージェントがマシン間で並行して作業し、1 つのブラウザタブから調整している。

計画したことじゃない。SSH をもっと便利にしたくて sshler を作った。マルチエージェント調整は毎日使っているうちに自然に生まれた — すべてのマシンの永続ターミナルが 1 つのインターフェースにあれば、並行エージェントセッションは自然な次のステップだ。

モバイルについて

デスクトップがメインの使い方だ。ただ、スマホからテスト結果を確認したり、ハングしたプロセスを再起動したり、Claude に素早く指示を出したりすることも実際にある。

モバイルで SSH するときの問題は SSH 自体じゃない;キーボードだ。矢印キー、Escape、Ctrl+C — スマホのキーボードでは打ちにくいか、そもそもない。だから sshler にはそれらのキーへのクイックアクセスボタン付きのカスタム入力バーがある。Claude Code メニューのナビゲーション用の矢印キー。エージェントターン中断用の Escape。暴走プロセス停止用の Ctrl+C。シェルオートコンプリート用の Tab。ターミナルスペースを最大化するための小さなヘッダー(14px、CPU とメモリ統計付き)。

その入力バーのボタンは全部、スマホで何かしようとして失敗した経験から生まれた。iPhone のキーボードで Ctrl+C を打とうとしてイライラしたことがきっかけ。実用的な UX であり、機能している — ただしこれはセカンダリな使い方であって、ツールを作った主な理由ではない。


なぜ定着したか

作っては一週間で放置したツールはたくさんある。sshler が定着したのは、リモートマシンで実際にやることにおいて代替手段より速いから。

ファイルブラウジング:ボックスをクリック、ディレクトリを辿る、ファイルをプレビュー。対して:ターミナルを開く、SSH、cd、cd、cd、less。sshler なら 2 クリック。

ターミナルアクセス:任意のディレクトリで「ここでターミナルを開く」をクリック。対して:SSH、ディレクトリに cd、tmux new か attach。そのディレクトリで tmux セッションをワンクリックで開ける。

コンテキストスイッチ:すべてのボックスが名前とテーマカラー付きで 1 つのインターフェースに。赤は本番。緑はステージング。一度、開発サーバーだと思って rm -rf を打ったことがある。本番だった。同日にカラーコードターミナルを追加した。

個別には小さな勝利。一日中マシンとエージェントセッションの間を飛び回ると、積み重なる。


ドッグフーディングループ

sshler を使う;摩擦に当たる;修正する;改善版を使う。ユーザーと開発者が同一人物だからサイクルが速い。

このループから生まれたもの:

  • Frecency 検索:同じディレクトリに何度も移動していた。最も頻繁に訪れるディレクトリを学習して優先表示する frecency ベースの検索を構築。ローカルボックスは zoxide をクエリ;リモートボックスは SQLite で訪問を追跡。
  • ボックス別ターミナルテーマ:本番に rm -rf を打った。同日にカラーコードターミナルを追加。二度と起きない。
  • コマンドスニペット:同じ長いコマンドを何度も打っていた(uv run pytest tests/ -v --tb=short -x)。ボックスごとに保存してワンクリック入力できるスニペットパネルを構築。
  • ポートフォワーディング UI:手動で ssh -L コマンドを実行していた。sshler にビジュアルトンネルマネージャーを内蔵。クリックで作成、クリックで破棄。
  • モバイル入力バー:すべてのボタンが、スマホで何かしようとして失敗した経験から生まれた。実際の苛立ち、実際の修正。

LLM ファーストの哲学を自分のワークフローに適用したもの:自分が作ったツールを使い、そのツールの中でエージェントを動かしてツール自体を改善する。sshler の中で Claude Code を動かして sshler を改善する。再帰的ドッグフーディング。


はじめる

pip install sshler
sshler serve

~/.ssh/config を読み取り、ボックスを表示し、ブラウザで開く。Python 3.12+、リモートホストに tmux、リモートインストール不要。

ソースは github.com/gabu-quest/sshler。232 テスト、MIT ライセンス。