返回列表

部落格

為什麼我們在 tmux 上構建 Tactic Remote:工作階段持久化與終端架構

Tactic Remote 使用 tmux 管理 Claude Code 工作階段,在網路斷線、Mac 休眠週期和應用程式重啟時提供持久化能力,同時實現終端輸出即時串流到你的 iPhone。

發布於 標籤: architecture / tmux / reliability / engineering
部落格

繼續查看該欄目下的產品與工程更新。

瀏覽此分類

當我們開始構建 Tactic Remote 時,面臨的第一個架構決策是根本性的:當控制裝置(你的 iPhone)連線不穩定時,如何讓 Claude Code 工作階段保持運行且可觀察?答案是 tmux,而這個決策幾乎塑造了產品的所有其他面向。

問題

Claude Code 以長時間運行的互動式程序方式執行。一個典型的工作階段持續 10 到 60 分鐘。在此期間,Claude 讀取檔案、提出修改建議、執行命令、等待審批,並根據回饋進行迭代。如果程序在工作階段中途終止,所有上下文都會遺失。Claude 必須重新開始、重新讀取檔案,並重建對任務的理解。

在本機終端上,這不是問題——你的 Mac 保持開啟,程序運行到完成。但 Tactic Remote 引入了行動端客戶端。iPhone 在 Wi-Fi 和行動網路之間切換。它們鎖定螢幕並暫停背景應用程式。使用者經過沒有訊號的區域。任何將 Claude Code 程序生命週期綁定到 iPhone 網路連線的架構從根本上就是行不通的。

我們需要 Claude Code 獨立於任何客戶端連線運行,並且客戶端可以隨時連接和斷開而不影響正在運行的工作階段。

為什麼選擇 tmux

tmux 是一個終端多工器,自 2007 年以來一直在生產環境中使用。它將終端工作階段的概念與顯示它的終端模擬器分離。tmux 工作階段作為主機上的伺服器程序運行。客戶端連接以檢視和互動工作階段,斷開連接時不影響正在運行的程序。

在確定使用 tmux 之前,我們評估了幾個替代方案:

screen ——最初的終端多工器。功能正常但維護不如 tmux 積極,腳本 API 也更有限。tmux 的結構化命令介面使程式化控制明顯更容易。

自訂 PTY 管理 ——我們用 node-pty 原型設計了一個使用原始虛擬終端的方案。它在基本場景下可以運作,但需要我們重新實作工作階段持久化、視窗管理和輸出緩衝。我們等於從零開始構建一個更差的 tmux。

基於容器的隔離 ——在 Docker 容器中運行 Claude Code 並附加 PTY。這增加了額外開銷,使檔案系統存取變得複雜(Claude Code 需要讀寫你的實際專案檔案),並引入了一層抽象,帶來的問題比解決的還多。

nohup / disown ——簡單的背景程序管理。沒有輸出擷取、沒有重新連接、沒有程式化控制。對互動式工作階段來說完全不足夠。

tmux 開箱即提供了我們所需的一切:工作階段持久化、程式化面板控制、輸出擷取,以及穩定且文件完善的 API。權衡之處在於 tmux 必須安裝在開發者的 Mac 上,但 brew install tmux 是一次性的設定成本,我們認為是可以接受的。

架構

Tactic Remote 的 tmux 整合跨越三個層次:

第一層:工作階段管理

當你透過 Tactic Remote 啟動一個 Claude Code 工作階段時,Mac 伴侶應用程式會建立一個帶有唯一識別碼的新 tmux 工作階段。Claude Code 在該工作階段的主面板中啟動。

tmux new-session -d -s claude-remote-{session-id} "claude-code --project /path/to/project"

-d 旗標至關重要——它以分離模式建立工作階段。不需要任何終端模擬器連接,工作階段就能存在並運行。Claude Code 立即啟動,Mac 伴侶應用程式從背景進行監控。

每個工作階段獲得一個專屬的 tmux 工作階段,而非共享工作階段中的一個面板。這提供了乾淨的隔離:工作階段專屬的環境變數、獨立的滾動緩衝區,以及零跨工作階段干擾的風險。

第二層:輸出擷取與串流

Mac 伴侶應用程式持續從 tmux 面板擷取終端輸出,並透過 WebSocket 串流到已連接的 iPhone 客戶端。這就是讓你能在手機上即時看到 Claude Code 輸出的機制。

輸出擷取使用 tmux capture-pane,座標覆蓋可見面板內容加上滾動緩衝區。伴侶應用程式運行一個擷取迴圈:

  1. 以可設定的間隔(預設:200ms)擷取目前面板內容。
  2. 將擷取的內容與上次已知狀態進行差異比對。
  3. 只將差異部分傳送給已連接的客戶端。
  4. 維護一個近期輸出的環形緩衝區,供重新連接後需要補齊進度的客戶端使用。

200ms 的擷取間隔代表了回應速度與 CPU 使用率之間的平衡。在這個頻率下,終端更新在 iPhone 上感覺近乎即時,同時在現代 Mac 上消耗不到 2% 的 CPU。偏好更快更新的使用者可以將間隔降低到 100ms;使用電池供電的使用者可以提高到 500ms。

第三層:輸入路由

當你從 iPhone 傳送輸入——無論是審批回應、輸入的訊息,還是工作階段控制命令——Mac 伴侶應用程式使用 tmux send-keys 將其路由到對應的 tmux 面板。這維持了直接終端連線的幻覺,而實際上輸入經由 WebSocket 跨越網路進入 tmux 工作階段。

審批回應是特殊情況。它們不是作為原始按鍵傳送,而是由 hook 系統處理,並作為 Claude Code 權限系統預期的結構化回應注入。這確保審批是原子性的,不會因部分網路傳送而損毀。

持久化的實際運作

tmux 架構在多個層面提供持久化:

iPhone 應用程式關閉。 tmux 工作階段繼續運行。Claude Code 持續工作,審批請求在 Mac 伴侶應用程式上排隊。當你重新開啟 iPhone 應用程式時,它重新連接到 WebSocket,接收緩衝的輸出,你就回到了之前的狀態。

iPhone 斷網。 從工作階段的角度來看,與應用程式關閉相同。WebSocket 斷開,輸出在 Mac 上緩衝,重新連接後恢復狀態。

Mac 進入休眠。 tmux 工作階段能夠存活於休眠和喚醒週期。當 Mac 喚醒時,tmux 伺服器程序恢復運行,任何正在執行中的 Claude Code 程序繼續進行。Mac 伴侶應用程式重新建立 WebSocket 監聽器並重新連接到 iPhone。

Mac 伴侶應用程式當機。 tmux 工作階段獨立存活。重啟 Mac 伴侶應用程式會偵測帶有 claude-remote- 前綴的現有 tmux 工作階段,重新連接它們,並恢復串流。不會遺失任何 Claude Code 上下文。

Mac 重新開機。 這是 tmux 工作階段無法存活的唯一情境,因為 tmux 工作階段僅存在於記憶體中。Claude Code 必須重新啟動。我們對此有明確的文件說明,並正在探索 tmux-resurrect 整合以用於未來版本,不過恢復互動式 AI 工作階段(不僅僅是 shell 狀態)的複雜性使這並非易事。

工作階段生命週期

一個 Tactic Remote 工作階段經歷以下狀態:

狀態tmux 狀態iPhone 狀態
啟動中工作階段已建立,Claude Code 啟動中載入動畫
活躍程序運行中,輸出流動中即時終端視圖
等待審批程序在 hook 處阻塞審批推播通知
暫停(客戶端已斷開)運行中,輸出緩衝中未連接
已完成程序已退出,工作階段保留中工作階段摘要
已過期保留期後工作階段銷毀已封存

已完成的工作階段在 tmux 中保留一段可設定的時間(預設:30 分鐘),以便你在 Claude Code 退出後仍能檢視最終輸出。保留期過後,tmux 工作階段被銷毀,輸出日誌被封存。

可觀測性

tmux 賦予我們用自訂 PTY 方案難以實現的內省能力:

  • 工作階段列表 —— tmux list-sessions 提供所有活躍 Tactic Remote 工作階段的即時清單。
  • 面板尺寸 —— 我們可以查詢和設定面板尺寸以匹配 iPhone 的顯示特性,確保輸出換行正確。
  • 程序監控 —— 帶有格式旗標的 tmux list-panes 命令讓我們能在不維護獨立 PID 追蹤系統的情況下監控 Claude Code 程序。
  • 滾動緩衝區存取 —— 完整的滾動緩衝區可用於搜尋和擷取,這驅動了 iPhone 上的工作階段歷史記錄視圖。

效能特性

透過 tmux 運行相比直接終端僅增加極少的額外開銷:

指標直接終端tmux 工作階段
程序啟動~800ms~850ms
按鍵延遲<1ms~2ms
每個工作階段記憶體開銷—~3MB
CPU 開銷(閒置工作階段)—<0.1%

這些額外開銷在實際使用中幾乎無法感知。tmux 經過近二十年的生產環境使用優化,它引入的額外間接層對使用者是完全透明的。

經驗教訓

基於 tmux 構建是正確的選擇,但並非沒有挑戰:

終端編碼的邊界情況。 Claude Code 的輸出偶爾包含 ANSI 跳脫序列,它們與 tmux 的終端模擬之間會產生意外的交互作用。我們維護了一個正規化層,在串流到 iPhone 之前清理輸出。

macOS tmux 安裝。 tmux 並非 macOS 預先安裝的。我們考慮過內建打包但最終放棄——開發者通常更傾向自行管理 tmux 安裝,而且打包會對已安裝 tmux 的使用者造成版本衝突。

大規模的 capture-pane 效能。 當並行工作階段眾多時,擷取迴圈的 CPU 使用率線性增長。我們實作了自適應擷取頻率,對沒有近期輸出變化的工作階段降低頻率。

tmux 是一種在運作良好時隱形的基礎設施。大多數 Tactic Remote 使用者不知道也不在意 tmux 參與其中——他們看到的是一個可靠的工作階段,無論手機或網路發生什麼都能存活。這正是我們追求的結果。

立即體驗 Tactic Remote

用手機遠端操作程式開發 Agent

連線到 Mac、Windows 或 Linux 電腦上的 Claude Code、Codex 等 Agent,在 iPhone 或 iPad 上查看進度並傳送下一個請求。