在 iPhone、iPad 上跑 Claude Code
可以,但 Claude Code 不會跑在你的 iPhone 上。它跑在你自己擁有的 Mac 或 Linux 機器上,手機只負責帶著終端機。做法是:打開遠端登入,用 Tailscale 取代對外開放的 port,開一個有名字的 tmux session,在裡面啟動 claude。鎖定螢幕之後,agent 照樣繼續跑。
「在手機上跑 Claude Code」這句話聽起來很直白,實際上講的是兩台機器、兩種工作。把它們分開之後,問題都變短了:斷線之後什麼還會活著、為什麼同一條指令在 SSH 裡找不到、agent 能不能在你搭捷運的時候自己回答權限提示。
Claude Code 是跑在手機上嗎?
Claude Code 是你某台機器硬碟裡的一個程式,由 shell 啟動。它透過那台機器的檔案系統讀你的專案,跑 git,跑測試,把改好的內容寫回同一個目錄。很容易以為它有一部分現在住在你口袋裡,但上面這些事沒有一項發生在手機上。
從手機連過去,線上只跑兩樣東西:你按的鍵出去,session 印出的字元回來。手機上沒有裝任何 agent 的元件,你的 repo 也不必搬到任何地方。手機顯示的,只是另一台電腦上那個 session 現在的樣子。
- 手機上。按鍵、畫面、你的拇指。鎖定螢幕、把 app 滑掉、走進電梯,停掉的只有畫面。
- 機器上。process、正在被改的檔案、正在跑的測試、它已經讀過和決定過的一切。你的螢幕變暗,這一切都不會停。
有兩個後果。機器必須一直開著、而且要連得到:蓋著蓋子收在抽屜裡的筆電什麼都不會跑。手機那一邊最便宜,換一支手機就恢復了。
先決定的三件事,順序不能換
少任何一件都不成立,所以照這個順序做。
- 一個進得去那台機器的門。Mac 上是「系統設定 → 一般 → 共享 → 遠端登入」;Linux 上是 SSH 服務,一個叫
sshd的 daemon。 - 一個私有網路,不要對外開放的 port。機器和手機都裝 Tailscale,登入同一個帳號,然後連那台機器的 MagicDNS 名稱或
100.x位址,不要連192.168.1.23這種區網位址,因為手機切到行動網路之後,那個位址什麼都不是。另一條路是把 port 22 轉向公網,那等於把機器攤在公網上,誰都能過來試你的密碼。 - 一個有名字的 tmux session,而且 agent 在裡面。
tmux new -s work # 取名為 work
claude # 在 session 裡面啟動
之後從手機、從另一個網路接回去的時候:
tmux ls # 現在有哪些 session
tmux attach -t work # 開一個窗看進去
名字不是裝飾:沒有名字,你就沒有可以指名要的那個 session,只打 tmux attach 會接上最近的一個,那是在猜你的意思。機器上還沒有 tmux 的話,Agentmux 會自己裝。
只用一個 SSH 視窗,鎖定螢幕那一刻 agent 就死了
假設你跳過 tmux:從手機 SSH 進去,跑 claude,看它開始讀專案,然後把手機放進口袋、鎖定螢幕。
手機不再送封包,連線逾時、關閉。機器上的 sshd 跟著關掉那條連線所使用的 pseudo-terminal,kernel 對還掛在上面的每一個 process 送出 SIGHUP:你的 shell,還有 shell 裡面的 Claude Code。它們預設的反應就是結束。agent 停在改到一半的地方,之前讀了二十分鐘的專案也一起沒了。
讓 app 開著救不了它:Wi-Fi 換一個網路、行動網路斷訊、一個 Ctrl-C 按錯地方,連線都照樣斷。tmux 把 session 從連線上搬到機器本身,所以你斷線時消失的是窗,不是 process(機制在那篇 tmux 文章)。結論只有一條:agent 要在開始做事之前就在 session 裡面,因為一個正在跑的 process 沒辦法之後搬進去。
用手機工作實際上是什麼樣子?
手機適合一次只做一個決定,而 agent 的工作循環就是這樣:它提出一個計畫,你用一句話核准或打回;它問要不要順便處理 migration,你選第二個。你回兩行修正:「serializer 不要動,export 那支在用它」,然後把手機收起來。
螢幕鍵盤是第一筆真實的成本。backtick、pipe、引號、反斜線、代表家目錄的 tilde,全部藏在兩層之後,所以 ~/src/auth/session.ts 這種路徑打起來比想像中久,打錯一段就是一個來回。長的 prompt 在手機上比較難寫也比較難檢查,很多人先在備忘錄裡寫好,再貼進來。
讀 diff 是手機真正不夠用的地方:兩個檔案改了四十行,加上周圍的 context,在六吋螢幕上就是兩三個畫面的捲動;而且換行會讓你看不出某個改動落在行尾還是行中,而那正是你要 review 的東西。把 iPad 橫過來,同一個 diff 就不用換行。
一個馬上回本的習慣:把吵的部分放進第二個 session,測試就不會蓋掉 agent 自己的提示。
tmux new -s tests -d # -d 建立後立刻 detach
tmux attach -t tests # 看完再 detach
agent 可以自己回答權限提示嗎?
Claude Code 不是想到什麼就跑。它跑每一條指令之前都會先停下來;依照設定,改檔案之前也會停。它把問題擱在畫面上:這是它要跑的指令,可以嗎?工作就在這裡等,而如果只有你能回答,要等多久就看你什麼時候抬頭。離開書桌之後,權限提示不再是不方便,而是整件事的瓶頸。
AI 自動權限審查只做這件事:讀畫面上目前那一則提示,然後給你建議、或幫你按下那個鍵。檢查有固定的順序。黑名單擋掉危險指令,命中的一定交給你。白名單放行你原本就信任的指令,直接在裝置上決定,不用等。AI 判斷只處理兩邊都沒命中的,結果是允許、拒絕、或不確定,後面兩種一樣回到你手上。最後由這個 session 的模式決定它是只建議那個鍵,還是直接幫你按。
人不在旁邊,責任還是你的。一條在行動網路上核准的指令,跑在那台機器上,那裡存著你的 .env、你的金鑰,還有一個不只你一個人在用的 repo。AI 判斷看到的是畫面,它不知道 agent 為什麼走到這一步。所以先選只給建議的模式,把你每天都會核准的指令放進白名單;訊號和注意力都不好的時候,先讀畫面上那條指令再按。黑名單會存在,是因為「全部核准」是一個壞的預設,而距離不會讓它比較安全:指向家目錄的 rm -rf,不會因為你人在月台上就比較溫和。
claude: command not found,但在 Terminal 裡跑得好好的
同一台機器、同一個帳號,兩種結果:在 Terminal 裡打 claude 會跑,透過 SSH 就給你 claude: command not found。看起來像遠端那套設定壞了,但這其實是從手機連進去最常撞到的問題。
Claude Code 如果是用 npm 裝的,或是裝在 nvm 釘選的 node 版本底下,它的安裝目錄會寫進一個啟動檔。只有互動式 login shell 會讀那個啟動檔,PATH 裡才有那一筆。ssh host claude 這種只跑一條指令的連線,啟動的是非互動式 shell,它根本不會讀那個檔案。
最穩的做法是不靠 PATH。在原本跑得動的 Terminal 裡:
which claude
# /Users/you/.nvm/versions/node/v20.11.0/bin/claude
把那個絕對路徑整串當成 agent 指令,或直接打在 session 裡。nvm 換了 node 版本,這個路徑就會失效。之後要更穩,得看你的 shell 和發行版,那些寫在疑難排解那頁。
跑一整晚可以,重開機不行
機器不睡,session 就能跑一整晚:十一點丟一個重構給它,早上配著咖啡看結果。有三件事會卡住。
機器要維持清醒。Mac 閒置進入睡眠時,網路介面跟著休眠,遠端登入開不開都沒用,因為沒有東西在回應。「系統設定 → 電池」(筆電)或「系統設定 → 節能」(長期開機當伺服器用的桌機):把閒置睡眠的時間調長或關掉,有「喚醒以供網路存取」這個選項就打開。
重開機會把 session 一起帶走。tmux 不會在重開機之後還原 session,系統更新要重開機時也不會問你。收工之前先 commit,最壞的情況就從損失整個任務變成損失一個小時。
在等你的 agent 不是當掉的 agent。先接回去看一眼。一個全新的 shell 提示字元代表 process 已經結束,跑完了或是死了,上面幾行會告訴你是哪一種。另一個 session 如果停在一個問題上,它已經等你一個字等了六小時,也沒花掉什麼。從鎖定螢幕看,這兩種一模一樣,而且只有一種需要你動手。
什麼歸手機,什麼歸書桌
| 在手機上做 | 在書桌前做 |
|---|---|
| 讀完那條指令之後回答權限提示 | 看一段你沒預期會看到的 diff |
| 在它給的兩個做法之間選一個 | 判斷一個橫跨好幾個檔案的改動 |
| 讀一段短的 diff、commit、push | 讀一段長的 diff,或一個你沒開過的檔案 |
| 在第二個 session 裡看測試跑完 | 追那些測試印出來的失敗 |
| 睡前把下一個任務丟給它 | 寫一段必須很精確的 prompt |
| 連線斷了十次,再接回來 | 修連線本身,或它後面的 PATH 問題 |
三樣東西:一台不會睡的機器、一個有名字的 session、一條只有你進得去的路。少一樣,setup 那頁會先問你三個問題,再照你那台機器給一份清單。