返回列表

部落格

從原型到產品:Tactic Remote 的開發歷程

8 週內完成 13 個里程碑,將 Tactic Remote 從概念驗證的 tmux 封裝工具打造為生產就緒的遠端開發工具——這是完整的開發歷程。

發布於 標籤: engineering / milestone / development
部落格

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

瀏覽此分類

Tactic Remote 起源於 2026 年 1 月初的一個問題:如果你能在手機上查看正在執行的 Claude Code 工作階段會怎樣?這個問題在一個週末變成了原型,兩週內變成了一個可用的工具,並在我們發佈第一個版本號之前完成了 13 個里程碑。這是那段開發弧線的故事——我們建構了什麼、捨棄了什麼,以及我們從快速發佈而不發佈有問題的產品中學到了什麼。

週末原型(2026 年 1 月初)

Tactic Remote 的第一個版本大約只有 200 行程式碼。一個 shell 腳本在 tmux 工作階段中啟動 Claude Code,一個 Python Flask 伺服器暴露了一個端點來執行 tmux capture-pane 並以純文字傳回輸出,一個基礎的 iOS 應用程式每 2 秒輪詢該端點,並將結果顯示在等寬文字檢視中。

它又醜又慢。輪詢模型意味著每次更新有 2 秒的延遲。純文字擷取遺失了所有格式。沒有驗證機制——同一 Wi-Fi 網路上的任何人都可以讀取你的終端機。但它驗證了概念:你確實可以從手機螢幕上有意義地追蹤一個 AI 程式設計工作階段。

那個原型大約存活了 4 天,然後我們開始重建。

里程碑式架構

我們採用了基於里程碑的開發模式,而非日曆衝刺。每個里程碑都有一個特定的技術目標、一個完成定義,沒有固定的截止日期。這讓我們可以在準備好時發佈,而不是在衝刺結束時發佈。實際上,每個里程碑平均耗時 4-5 天,儘管有些只用了 2 天,有一個則用了將近兩週。

以下是濃縮版的進展:

里程碑 1-3:基礎建設。 用 Swift 原生嵌入式伺服器取代 Flask。建立 WebSocket 進行即時串流傳輸以取代 HTTP 輪詢。實作基於權杖的驗證。完成里程碑 3 後,我們有了一個運作中的系統,iPhone 在 200ms 內接收終端機更新,未經授權的存取被攔截。

里程碑 4-5:工作階段管理。 支援多個並行 tmux 工作階段。建構工作階段生命週期(建立、監控、閒置、完成、清理)。透過在啟動時重新附加到現有 tmux 工作階段,增加跨伴侶應用程式重啟的工作階段持久性。這是 Tactic Remote 從展示變為可用於實際工作的轉折點。

里程碑 6-7:人在迴路中。 整合 Claude Code 的 hook 系統以攔截核准請求。在 iOS 上建構核准介面——顯示 AI 想要做什麼、展示相關上下文、提供核准/拒絕操作。新增推播通知,使核准不需要應用程式處於開啟狀態。這兩個里程碑是轉折點。在此之前,Tactic Remote 是一個終端機檢視器。在此之後,它成為了一個控制台。

里程碑 8-9:連線穩健性。 處理 Wi-Fi 到行動網路的切換。實作帶指數退避的自動重連。新增連線品質指示器。建構 QR code 快速連線流程以消除手動輸入 IP 和權杖。里程碑 9 是最困難的單一里程碑——iOS 上的網路邊界情況眾多且文件不足。

里程碑 10-11:Cloudflare Tunnel。 將 cloudflared 整合為受管理的子程序。建構雙模式連線架構(本機和通道)。處理通道健康監控、自動重啟和優雅降級。將通道 URL 加入 QR code 產生中。

里程碑 12-13:生產就緒。 在地化(7 種語言)。Mac 休眠防止。選單列介面潤飾。當機報告和診斷。效能最佳化,將閒置時的記憶體佔用從約 60 MB 降低到 25 MB 以下。驗證和傳輸層的最終安全稽核。

關鍵技術決策

開發過程中的幾個決策定義了產品的特質:

tmux 而非自訂 PTY 管理

我們在里程碑 1 期間對此進行了廣泛討論。自訂 PTY 管理將給我們更精細的終端機擷取控制,並消除 tmux 相依性。但這也意味著重新實作工作階段持久性、終端機模擬和程序生命週期管理——這些問題 tmux 已經解決了 15 年。我們選擇站在這個基礎之上,而不是重建它。

WebSocket 而非 Server-Sent Events

對於即時串流傳輸,兩種協定都可行。我們選擇 WebSocket 是因為我們需要雙向通訊——iPhone 不僅接收終端機輸出,還需要向 Mac 發送命令和核准。SSE 需要一個獨立的通道用於上行通訊,增加了複雜性。

嵌入式伺服器而非獨立常駐程式

從 macOS 架構的角度來看,由 launchd 管理的獨立常駐程式會更「正統」。但這會使安裝複雜度翻倍,並產生一類「伺服器在執行但應用程式沒在執行」的問題。將伺服器嵌入選單列應用程式意味著只需安裝一個東西、執行一個東西、結束一個東西。

靜態權杖而非 OAuth/基於工作階段的驗證

Tactic Remote 的威脅模型很直接:防止來自網路的未經授權存取。儲存在鑰匙圈中的 256 位元加密隨機權杖可以實現這一點,而無需權杖重新整理、工作階段過期或登入流程的複雜性。對於需要按使用者驗證的企業用例,我們建議將 Cloudflare Access 作為外部層。

輪詢 tmux 而非檔案系統監聽

我們以 200ms 的間隔輪詢 tmux capture-pane,而不是使用檔案系統通知 API(kqueue/FSEvents)監聽 PTY。這聽起來不夠優雅,但 tmux 的 capture 命令極快(亞毫秒級),而在我們的測試中,PTY 裝置上的檔案系統監聽在不同 macOS 版本間被證明不夠可靠。輪詢方式在 macOS 13、14 和 15 上都非常穩定。

我們捨棄的東西

並非所有東西都保留下來了。一些值得注意的刪減:

基於 Web 的用戶端。 我們在里程碑 6 期間建構了一個可在任何瀏覽器中執行的響應式 Web 介面。它能運作,但體驗明顯不如原生應用程式——沒有推播通知、沒有背景重連、核准時沒有觸覺回饋。我們擱置了它,專注於原生 iOS 體驗。

終端機色彩和格式。 早期版本嘗試保留 ANSI 色彩代碼並在 iPhone 上算繪。算繪效果不一致,且給串流傳輸協定增加了顯著複雜性。我們切換到一種簡化的算繪模型,保留結構但不追求像素級精確的終端機模擬。完整的 ANSI 支援仍在路線圖上。

自動任務建議。 我們打造了一個原型功能,Tactic Remote 根據你最近的 git 活動來建議 Claude Code 任務。技術上很有趣,但感覺過於自以為是——開發者知道他們想做什麼。我們在任何測試使用者看到之前就移除了它。

版本管理轉型

在里程碑 13 之後,我們從基於里程碑的追蹤轉向語意化版本管理。第一個帶版本號的發佈是 1.2.0(不是 1.0.0,因為我們在封閉測試期間有編號為 1.0 和 1.1 的內部建置,我們不想造成混淆)。

此後的版本進展:1.2.0、1.3.0、1.4.0、1.4.2 和 1.5.0-beta.1。每個版本都對應一組明確的面向使用者的變更,記錄在我們的更新日誌中。里程碑體系在快速原型階段為我們服務得很好,但語意化版本管理能更清楚地傳達給需要評估升級風險的使用者。

我們學到的

發佈最小的有用之物。 那個週末原型按任何工程標準來看都很粗糙,但它回答了唯一重要的問題:從手機上監控 Claude Code 真的有幫助嗎?之後的每個里程碑都是對「下一個最有用的改進是什麼?」的漸進式回答。

網路是最難的部分。 我們在連線可靠性上花費的時間超過了產品的任何其他方面。Wi-Fi 到行動網路的切換、休眠後的 WebSocket 重連、Cloudflare Tunnel 健康監控——這些每一項都消耗了一個完整的里程碑。實際的終端機擷取和工作階段管理相比之下反而簡單直接。

相依性應該是無聊的。 tmux、cloudflared、鑰匙圈、IOKit——Tactic Remote 相依的技術都是穩定且文件完善的。每次我們考慮採用更新或更新穎的東西時,我們都會問現有的「無聊」選項是否足夠好。通常答案是肯定的。

基於里程碑的開發適合小團隊。 沒有衝刺計畫、站會和速度追蹤的開銷,我們行動更快。每個里程碑都有明確的終點線,我們可以在實作過程中根據所學即時調整範圍。這種模式在較大的團隊規模下會失效,但對我們的早期開發來說恰到好處。

時間軸概要

時期發生了什麼
2026 年 1 月初週末原型:shell 腳本 + Flask + 基礎 iOS 應用程式
1 月 6-20 日里程碑 1-5:基礎建設、WebSocket、工作階段
1 月 20-29 日里程碑 6-9:核准、推播通知、QR code 連線
1 月 29 日 - 2 月 10 日里程碑 10-11:Cloudflare Tunnel 整合
2 月 10-18 日里程碑 12-13:在地化、潤飾、安全稽核
2 月 18 日起語意化版本:1.2.0 至 1.5.0-beta.1

從一個想法到公開測試版,八週時間。不是因為我們偷工減料,而是因為我們無情地削減範圍,並在經過驗證的基礎上建構。

有關每個版本發佈的詳細資訊,請查看我們的更新日誌。

立即體驗 Tactic Remote

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

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