GUIを捨てた先にあったもの
前回の記事で、CursorからZedに乗り換えた話を書きました。「重い器に軽い中身」の違和感を解消するために、エディタを軽くした話です。
今回はさらに一歩進みます。エディタすら手放して、iPhoneの黒い画面からClaude Codeを動かす環境を作った話です。
きっかけは単純でした。外出先でもClaude Codeに指示を出したい。それだけです。
前提:私はコードを読むだけの開発者です
前回の記事と同じ前提ですが、改めて。
私の開発フローは3つしかありません。
- コードを 読む(レビュー)
- Claude Codeに 指示を出す
- 生成されたコードを 確認する
エディタに求めるのは「高速に表示すること」だけ。コード補完やスニペットは使いません。
この前提を突き詰めると、ある疑問にたどり着きます。
「読む」すらiPhoneの画面でできるのでは?
Chrome Remote Desktopという最初の誤り
最初に思いついたのは、iPhoneからMacの画面を遠隔操作することでした。Chrome Remote Desktopなら無料で使える。
App Storeで検索しました。出てこない。
Geminiに聞くと、GoogleがiOS版のネイティブアプリを終了し、Webアプリ(PWA)に移行したとのこと。Safariから remotedesktop.google.com にアクセスすれば使えるらしい。
一応使えるが、ここで冷静になりました。Claude Codeを操作するのに、画面の映像を丸ごと転送する必要があるか?
ターミナルの黒い画面を「映像」として送るのは、帯域の無駄です。文字が滲むし、入力の遅延も気になる。しかもiPhoneの小さな画面にMacのデスクトップを映したら、文字が豆粒になる。
Geminiの提案はこうでした。
画面を映像として転送する「リモートデスクトップ」は、CLI操作には最適な方法ではありません。テキストデータだけを送るSSH接続の方が、通信量は1/100以下で、文字も鮮明です。
なるほど。映像ではなく、テキストだけを送ればいい。
Geminiが描いた設計図
Geminiが提案した構成はこうです。
Mac(自宅・常時起動)
├─ Tailscale(VPN)
├─ SSH(リモートログイン)
├─ tmux(セッション永続化)
└─ Claude Code
iPhone(外出先)
├─ Tailscale(VPN)
└─ Termius(SSHクライアント)
Tailscale はゼロコンフィグのVPN。iPhoneとMacを仮想のLANケーブルで直結する。ポート開放不要、無料。
Termius はiOS対応のSSHクライアント。iPhoneからMacのターミナルに接続する。
tmux はセッション永続化ツール。電波が切れてもMac側のプロセスは生き続け、再接続すれば画面がそのまま復活する。
コストは月額 $0。VPSも不要。自宅のMacをそのまま使う。
設計図は美しかった。問題は、ここから先の実装でした。
実際には、この設計図にたどり着くまでに1週間かかっています。
2月7日:初挑戦と撤退
最初にTermiusを試したのは2月7日でした。
TailscaleでVPNを繋ぎ、TermiusからMacにSSH接続。ここまでは順調。Claude Codeを起動すると「ブラウザで認証してください」。
ブラウザが開かない。当たり前です。SSH経由なのでブラウザが開くのはリモート先のMac。手元のiPhoneには何も表示されない。
画面に c to copy と出ていたので c キーを押しました。「コピーしました」と表示される。iPhoneのSafariに切り替えて貼り付け。何も出ない。
Geminiに聞きました。
c to copyはリモートMac側のクリップボードにコピーされています。iPhoneのクリップボードには反映されません。
Mac側のクリップボードの内容をターミナルに出力する pbpaste コマンドを教えてもらいましたが、そこからURLを長押しで選択して…と手順が増えていく。
「ややこしすぎる」と思いました。
この日は撤退しました。Geminiの結論は明快でした。
Macの前にいるときに一度
claudeを実行してログインしておく。それだけで、以降Termiusからも認証済みの状態で使えます。
ただ、それは「外出先から初めて使う」というシナリオでは解決になっていません。
2月12-13日:再挑戦
5日後、改めて挑戦しました。今度はGeminiに設計図から描いてもらい、体系的に進めることにしました。
7つのつまずき
1. Node.jsが入っていない
CursorのExtensionではClaude Codeが動くのに、ターミナルで claude と打つと動かない。なぜか。
Geminiに聞くと、答えは単純でした。
Cursorはアプリ内部に独自のNode.js環境を持っています。システムのターミナルにはNode.jsがインストールされていません。
npm install -g @anthropic-ai/claude-code を実行しようとしたら zsh: command not found: npm。npmすらない。
brew install node
npm install -g @anthropic-ai/claude-code
これで claude コマンドが使えるようになりました。Cursorの内部に隠れていた依存関係が、ターミナルで露呈した形です。
2. OAuth認証でブラウザが開かない
Claude Codeを起動してログインしようとすると、「ブラウザで認証してください」と言われる。普通ならブラウザが開いて認証画面が表示される。
しかし、これはTermius経由のリモート接続です。ブラウザが開くのはリモート先のMac側。手元のiPhoneには何も表示されません。
ターミナルに表示されたURLを手動でコピーして、iPhoneのSafariで開く必要がありました。
3. URLが小さすぎてコピーできない
問題はここからです。OAuth認証のURLは100文字以上ある長い文字列。iPhoneのTermius画面は小さく、指で正確に選択するのが困難でした。
GeminiにスクリーンショットからURLを読み取ってもらいました。リンクをタップしてSafariで開く。ログインする。
「無効なAuth要求です」とエラーが出ました。
GeminiのOCRで1文字ズレたか、URLの有効期限が切れたか。OAuthのURLは暗号を含むため、1文字でも違うとエラーになります。
結局 /login で再発行し、Termiusの長押しコピー機能で自力コピーして解決しました。
認証問題の根本解決: OAuth認証のトラブルは、後述する「tmux方式」で完全に回避できます。Mac側で一度ログインしてtmuxセッションを作っておきましょう。iPhone側で認証フローに触れること自体がなくなります。
4. Tailscaleは緑なのに繋がらない
Tailscaleアプリを開くと、iPhoneとMacの両方が緑色で「Connected」。VPNのトンネルは開通している。
なのに、Termiusから接続すると 「Connection timed out」。
「iPhoneがMacをネットワーク上で見つけられていない」のではなく、「Macの玄関まで辿り着いているが、ドアが施錠されている」状態でした。
犯人はMacのファイアウォール。SSH(TCP 22)がブロックされていました。
システム設定 > ネットワーク > ファイアウォール > オプション で「リモートログイン(SSH)」を許可。
5. 外出先でMacがスリープ
ファイアウォールの設定を直す前に外出してしまい、MacBookの蓋は開けたままでしたが、時間が経ってスリープに入っていました。
Geminiの提案した最後の手段。
「探す(Find My)」アプリでMacに「サウンドを再生」を送信すれば、強制的にスリープから復帰します。その隙にSSHで接続してください。
結局この日は諦めて帰宅しました。
帰宅後に学んだ教訓です。
-
システム設定 > ディスプレイ > 詳細 > 電源アダプタ接続時にスリープさせない→ ON - 外出前:Macの蓋を開けたまま、電源ケーブルを繋いで、
Ctrl + Cmd + Qでロック - ロック画面でもSSH/Tailscaleは完全に動作する
補足: 「API Usage Billing」の表示について
Claude Codeの起動画面に「API Usage Billing」と表示されて焦りました。しかしこれはMaxプランでも表示されるデフォルト文言です。実際の課金はMaxプラン枠内で、/costコマンドで確認すると $0 でした。
6. SSH接続のたびに再ログイン
接続には成功しました。しかし新たな問題が。SSH経由でClaude Codeを起動するたびに、毎回OAuthログインを求められる。
Geminiに聞くと、これはmacOSのKeychain問題でした。
Claude CodeのOAuthトークンはmacOS Keychainに保存されます。ローカルでログインしている場合はKeychainが自動的にアンロックされますが、SSH接続ではGUIログインセッションを経由しないため、Keychainがロックされたままです。
対策として .zshrc にKeychainアンロックのラッパー関数を追加してみました。
claude() {
if [ -n "$SSH_CONNECTION" ] && [ -z "$KEYCHAIN_UNLOCKED" ]; then
security unlock-keychain ~/Library/Keychains/login.keychain-db
export KEYCHAIN_UNLOCKED=true
fi
command claude "$@"
}
パスワード入力画面が出ました。しかしカーソルが動かない。文字が表示されない。
これはセキュリティ上の仕様で、パスワード入力中は画面に一切表示されません。そのまま打ってEnter。
The user name or passphrase you entered is not correct と返されました。
Termiusのキーボードで意図しない文字が入ったのか、何度試しても通りませんでした。
7. tmuxが全てを解決した
Geminiの提案は、発想の転換でした。
Mac側で一度ローカルにログインした状態でtmuxセッション内にClaude Codeを起動しておけば、iPhoneからはそのセッションにアタッチするだけです。再認証は不要です。
つまり、Keychainのアンロック自体をスキップする。
# Mac側でローカルに一度だけ実行
tmux new -s cc
claude
# iPhone側(何回でも)
tmux attach -t cc
Claude Codeはローカルで起動済み。iPhoneからはその「窓」を覗くだけ。Keychainは関係ない。
「じゃあ新しいセッション立ち上げられないのか?コンテキストをリセットしたい時がある」
tmux内で
/exitで終了してclaudeで再起動すれば、新しいコンテキストのセッションが始まります。tmuxは単なる器なので、中身は自由に入れ替えられます。
なるほど。tmuxはMac上で動き続けるターミナルの箱。iPhone側はその箱の中を操作しているだけ。ローカルで直接触っているのと全く同じことができる。
「Cursorは起動できないのか?」
接続が成功した後、ふとGeminiに聞きました。
「Cursorは起動できないのか?」と聞くと、こう返ってきました。
Termiusは文字(CLI)しか扱えません。CursorはGUI(映像)です。SSHで
cursor .と打っても、自宅のMacの画面上でCursorが開くだけで、iPhoneには何も表示されません。
なるほど。では、Cursorなしでどうやってコードを読むのか。
Claude Code自身がファイルビューアの代わりになります。「main.swiftの中身を見せて」と言えば表示しますし、差分の確認もできます。
「まあやってることは同じか」
そう返した後、もう少し考えて、こう言いました。
「どっちも結局テキストしか見てないしな」。これが今回の核心です。
Cursorでファイルを開いてコードを読む。Claude Codeに「このファイルを見せて」と頼む。見ているものは同じテキストです。指示を出すのも、Cursorの横のターミナルに打つか、SSHのターミナルに打つかの違いでしかない。
GUIは「飾り(スキン)」に過ぎない。テキストこそが本体。
iPhoneの小さな画面では、ボタンやウィンドウで画面を占有するGUIより、テキストだけのCLIの方がむしろ情報密度は高い。
完成した環境
最終的な構成と運用ルールです。
構成
| レイヤー | ツール | 役割 |
|---|---|---|
| VPN | Tailscale(無料) | iPhoneとMacを暗号化接続 |
| SSHクライアント | Termius(無料) | iPhoneからMacに接続 |
| セッション管理 | tmux | 切断してもプロセス維持 |
| 開発ツール | Claude Code | コード生成・レビュー・実行 |
外出前のルーティン
- Macに電源ケーブルを繋ぐ
-
Ctrl + Cmd + Qでロック画面にする - 蓋は開けたままにして家を出る
iPhoneからの接続手順
# Termiusで My mac をタップ → 自動で tmux attach(Startup Snippet)
# セッションがあればそのまま復帰。なければ新規作成。
# Claude Codeの新規セッション
/exit # 現在のセッション終了
claude # 新規起動(再認証不要)
Termiusの設定Tips
-
Startup Snippet:
tmux attach -t cc || tmux new -s ccを設定。接続と同時にtmuxに入る - ライブアクティビティ: OFF推奨。tmuxがあるので接続維持の通知は不要。バッテリー節約
- Mosh: 最初はOFF。SSH + tmuxで不満が出たらONに
コスト
| 項目 | 月額 |
|---|---|
| Tailscale | $0 |
| Termius | $0 |
| VPS | 不要($0) |
| Claude Code | Maxプラン(既存) |
| 合計 | $0(Claude Maxプラン以外) |
SSH vs Mosh — まだSSHで十分
Geminiに「Moshにした方がいいか」と聞きました。
Moshは接続維持プロトコルで、電波が途切れても自動復旧し、入力ラグもローカルエコーで解消される。理論上は上位互換です。
しかし、UDPポート(60000-61000)を使うため、ファイアウォールの追加設定が必要。セットアップで散々ファイアウォールに苦しめられた身としては、動いている環境を壊したくない。
Geminiの助言が的確でした。
まず数日、SSH + tmux で運用してみてください。「再接続が面倒くさい!」「文字入力の遅延が気になる!」と感じた時に初めて、Moshに進むのが最もスマートです。
不満が出てからアップグレードする。正しい判断でした。
正直な感想:iPhoneは「リモコン」
数日運用してみて、正直に書きます。
iPhoneでのターミナル操作はかなり厳しい体験です。
画面幅が狭いのでコードの全体像が見えない。長文のプロンプトをフリック入力で打つのも辛い。
スクロールも一工夫必要です。tmux内ではiPhoneのスワイプが効かず、Ctrl+b → [ でコピーモードに入ってから矢印キーで操作します。マウスモードを有効にすればタッチ操作でスクロールできるようになりますが、根本的な画面の狭さは変わりません。
# タッチスクロールを有効にする
echo "set -g mouse on" >> ~/.tmux.conf
tmux source-file ~/.tmux.conf
ただし、用途を割り切れば十分実用的でした。
- Claude Codeの進捗確認
- 承認プロンプトで y を押して続行させる
- 短い指示を追加で投げる
本格的なレビューはMacに戻ってからやる。iPhoneはあくまで「リモコン」です。
脱GUIの三部作
振り返ると、3つの記事が「GUIからの脱却」という一本の線で繋がっています。
| 記事 | 何を手放したか | 何が残ったか |
|---|---|---|
| ECC Journey | コーディングそのもの | Claude Codeへの指示 |
| Cursor → Zed | 重いエディタ | 軽いエディタ + ターミナル |
| Termius + Claude Code(本記事) | エディタのGUI | ターミナルだけ |
最初は「AI時代にコードを書く必要はない」という話でした。次に「重いエディタは要らない」。そして今回「GUIすら要らない」。
残ったのは、iPhoneの画面に映る黒い背景と白い文字。そしてClaude Codeとの対話。
どっちも結局テキストしか見てないしな。
だったら、テキストを最も効率よく送受信できる環境が最適解です。それがSSHでした。
おまけ:Geminiに助けてもらった話
今回の環境構築は、始終Geminiに教えてもらいながら進めました。
Claude Codeのセットアップをするのに、Geminiへ相談する。メタな構図ですが、実際にはこれが最も効率的でした。Claude Codeはまだ起動していないので、起動するまでのトラブルシューティングは別のAIに頼るしかない。
OAuthのURLをスクリーンショットから読み取ってもらったら1文字ズレていたり、「探す」アプリでMacを叩き起こす裏技を教えてくれたり。GUIとCLIの本質的な違いを一言で説明してくれたのもGeminiでした。
GUIは映像(ビデオ通話)、CLIはテキスト(電話)。iPhone + SSH環境でCLIが最適なのは、テキストの伝送に映像は不要だからです。
AIがAIの環境構築を助ける。2026年の開発風景です。
まとめ
- iPhoneからMac上のClaude Codeを操作するには、Tailscale + Termius + tmux の3点セットで十分
- VPS不要。自宅Macをそのまま使えば月額 $0
- GUIとCLIの本質は同じで、「テキストをAIに渡して書き換えてもらう」だけ
- ファイアウォールとスリープ設定を忘れると詰む。外出前に確認すること
- まずSSHで始めて、不満が出たらMoshにアップグレード
外出先でiPhoneの黒い画面を開いてClaude Codeに指示を出す。電車の中でプロジェクトが進む。
GUIの飾りを全部捨てた先にあったのは、最も軽くて、最も速い開発環境でした。