昨天我們剛討論過一件事:越來越多開發者把 Claude Code、CodeGraph 索引與 Ollama 遷到遠端 macOS 節點(見Cloud Mac vs 本機 Mac)。很多人以為「上雲之後,push 就會自動綠」——結果往往是:終端機裡 Agent 改得很勤,git push 之後 GitHub Actions 仍在 ubuntu-latest 上跑測試,xcodebuild 直接失敗,或 macOS job 在佇列裡等半小時。
這篇不是「GitHub Runner 是什麼」的百科,也不包含 actions/runner 註冊步驟(那留給下一篇教學)。我們要建立的不是單點賣點的「租一台 Mac」,而是一套可延展的方法論:Cloud Mac AI Stack——其中 L1 回答:為什麼必須先有執行引擎,而不是把 Cloud Mac 當成「能跑 Claude Code 的遠端電腦」就結束?
Cloud Mac AI Stack · 系列 Slogan
Claude Code 生產 Diff,GitHub Runner 生產 Fact。
別人講 Agent / Tool / CI / Automation;我們講 Context → Diff → Fact → Workflow。本篇是這套語言的 L1 入口。
L1 在 Stack 裡的職責
Claude Code(L3)解決「怎麼改程式碼」;GitHub Runner(L1)解決「改完之後能不能被組織驗收、簽章並交付」。 Agent 提出答案;Runner 在 CI 裡證明答案成立。沒有 L1,L3 的 Diff 不會自動變成團隊願意 merge 的 Fact。
Stack 語言:Context → Diff → Fact → Workflow
現在大量內容在講 Claude Code、Cursor、MCP、OpenHands,但很少講:Agent 改完程式碼之後,誰負責成為組織認可的結果? 業界常用詞是 Agent、Tool、CI、Automation——在 Cloud Mac AI Stack 裡,我們用四個產出物串起來(L2 推理層單獨見下表):
記憶鏈(與呼叫順序無關 · 見下文五層結構圖)
Context → Diff → Fact → Workflow
(MCP) (Claude Code) (Runner) (OpenHands)
| 層 | 職責層級 | 元件 | Stack 產出 |
|---|---|---|---|
| L0 | 基礎設施 | Cloud Mac | 可執行面(macOS 節點) |
| L1 | 執行層 | GitHub Runner | Fact |
| L2 | 推理層 | Ollama | Inference(私有 token,可選) |
| L3 | 編碼層 | Claude Code | Diff |
| L4 | 工具連接層 | MCP | Context |
| L5 | 自主執行層 | OpenHands | Workflow |
問題不在「AI 夠不夠聰明」,而在L1 是否獨立存在。沒有 Fact 層,Context 和 Diff 再漂亮,也不會變成 merge 按鈕上的綠勾。
編碼層與執行層:為什麼「上了 Cloud Mac」CI 仍可能斷檔
在執行層拆分裡,我們把「模型推理」和「Agent 執行」分開了:API 在廠商雲端,shell / Git / 測試在 macOS 上跑。再往下拆一層,很多團隊會忽略第二條執行鏈——不是 Agent 在終端機裡跑的那次 pnpm test,而是 push 之後由 CI 定義的、可重複、可稽核的建置。
| 層級 | 典型元件 | 觸發方式 | 回答的問題 |
|---|---|---|---|
| 編碼 / Agent 層 | Claude Code、Cursor Agent | 你在終端機或 IDE 裡下指令 | 「幫我把這個 PR 改完」 |
| 執行 / CI 層 | GitHub Actions + self-hosted Runner | git push、PR、排程任務 |
「這次提交在乾淨環境裡能建置、能測、能歸檔嗎」 |
斷層出現在這裡:你把 Claude Code 放在 Cloud Mac 上,SSH 裡跑測試全綠;但 workflow 仍指向 Linux runner,儲存庫的「官方真相」仍是紅的。對 iOS 團隊來說,這還不只是尷尬而已——TestFlight 流水線根本不會在 Linux 上啟動。執行層必須獨立存在,且往往必須和同一類 macOS 環境對齊。
典型誤判:Claude Code 說「測試全過」,PR 卻是紅的
下面是我們多次在客戶儲存庫裡見到的同一類事故——比架構圖更好記:
- 開發者在 Cloud Mac 的 SSH 裡跑 Claude Code,Agent 回覆:「所有測試已經通過。」
- 開發者
git push,信心滿滿去開會。 - GitHub Actions 觸發,workflow 裡仍是
runs-on: ubuntu-latest。 - 約 10 分鐘後,PR checks 紅了;日誌裡常見第一句:
xcodebuild: command not found(或根本沒有 iOS job,只有 Node 測試在 Linux 上綠著)。
問題不在 Claude Code,而在 Claude Code 的執行環境 ≠ CI 的執行環境。 Agent 在 macOS 上說的「通過」,沒有被組織認可的 Runner 在同一條 GitHub Actions 流水線裡重現。Runner 的價值,就是把「工作階段裡的結論」變成「每次 push 可稽核的 Fact」——必要時與 Claude Code 落在同一台 GitHub Actions self-hosted runner macOS 節點上。
Runner 不是「又租一台 Mac」
三個常見誤解,我們直接劃掉:
- 不是 Cloud Mac 產品介紹——租機器是 L0 底座;Runner 是在底座上常駐監聽 GitHub 任務的軟體與策略(label、並行、工作區清理)。
- 不是 GitHub 官方
macos-latest的說明書——託管 runner 是另一套計費、佇列與隔離模型;self-hosted 是你把 job 調度到自己的節點。 - 不是 OpenClaw / OpenHands——OpenClaw 手記講的是編排與回執(誰先觸發、命令序列、稽核日誌);Runner 是機器上真正執行
xcodebuild、fastlane的那雙腳。
一句話:Cloud Mac 提供 macOS 算力與出口;Runner 把這份算力接進 GitHub 的事件模型。
沒有 Runner,Cloud Mac 只是遠端電腦;有了 Runner,它才成為研發基礎設施。 若只能記一句系列 Slogan,請記:Diff → Fact(上框藍底引文)。
Cloud Mac AI Stack 五層結構圖(系列共用 · 回鏈請用 #stack-map)
後續 L2–L5 文章請統一回鏈:「見 Cloud Mac AI Stack 五層結構圖」(鏈到本篇 #stack-map)。這是在累積方法論 + 命名體系,而不只是單篇 SEO。
重要:Stack ≠ 呼叫順序
結構圖表示的是組織裡的職責層級,不是執行時誰先叫誰。 因此:
- Claude Code 不必依賴 Ollama——多數團隊 L3 走 Claude API,L2 是可選私有推理。
- MCP 在圖上高於 Claude Code,指的是 Context 層為編碼提供工具上下文,不是說 MCP Server 一定比 CLI 先啟動。
- 落地順序(先 L0→L1 再疊 AI)見 § 接入順序,與圖的自下而上「承重關係」不是一回事。
Cloud Mac AI Stack 五層結構圖(職責層級 · 自下而上)
┌──────────────┐
│ OpenHands │ L5 · Workflow
└──────┬───────┘
│
┌──────▼───────┐
│ MCP │ L4 · Context
└──────┬───────┘
│
┌──────▼───────┐
│ Claude Code │ L3 · Diff
└──────┬───────┘
│
┌──────▼───────┐
│ Ollama │ L2 · Inference(可選)
└──────┬───────┘
│
┌──────▼───────┐
│ GitHub Runner│ L1 · Fact ← 本篇
└──────┬───────┘
│
┌──────▼───────┐
│ Cloud Mac │ L0 · 基礎設施
└──────────────┘
讀圖方式:L0 托住一切算力;L1 托住一切「組織敢不敢信」的 Fact;其上才是 Diff、Context、Workflow。 Ollama 在 L2 表示「私有推理可疊在底座上」,與 L3 可並行,不必理解為「必須先跑 Ollama 才能開 Claude Code」。
為什麼叫「執行引擎」:職責與真實鏈路
在 Cloud Mac AI Stack 五層模型裡,Runner 固定佔 L1。它不是和 Claude Code 搶「誰更聰明」,而是承擔三件可重複執行的事:
- 承接儲存庫事件——
on: push、pull_request、workflow_dispatch把 job 派發到帶 label 的 self-hosted runner。 - 跑 macOS 原生工具鏈——
xcodebuild、swift test、notarytool、簽章與歸檔;這是 Linux runner 無法替代的硬需求。 - 與 AI 層解耦——Agent 改程式碼 ≠ 自動通過 CI;Runner 把「改完」變成「artifact + 測試報告 + 可部署套件」。
下面這條鏈路是我們給 iOS / Flutter(iOS 目標)團隊畫的真實交付路徑——不是抽象的 push → build,而是從 AI 編碼到 TestFlight 上發生了什麼:
Cloud Mac AI Stack · L1 執行鏈(概念)
Claude Code(L3 編碼層,SSH / 終端機)
│
│ git commit & push
▼
GitHub(webhook / Actions 調度)
│
▼
GitHub Actions workflow
│
▼
GitHub Runner(L1 · self-hosted · macOS · ARM64)
│
├── xcodebuild(Debug / Release)
├── 單元測試 / UI 測試
├── archive → .ipa
└── fastlane → TestFlight / 內測分發
這張圖的價值在於:別人可以抄「Runner 是什麼」的定義,但很難抄你整條 Stack 的層級關係。 編碼發生在 L3;真正把二進位送出去的是 L1。中間缺任何一環,都會出現「Agent 說完成了,App Store Connect 沒包」的落差。
workflow 裡你只會看到 Runner 的「標籤」,而不是註冊細節。下面片段用於說明 GitHub Actions iOS build 如何落到 macOS ARM64 self-hosted runner(token、launchd 等請等 L1-Q02):
# .github/workflows/ios-ci.yml(片段) jobs: build-ios: runs-on: [self-hosted, macOS, ARM64, cloud-mac] steps: - uses: actions/checkout@v4 - name: Build & Test run: xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 16' test
很多人搜的不是「GitHub Runner」,而是 iOS CI / Mac mini Runner
我們在 SEO 與客服工單裡看到:工程師很少輸入泛詞 GitHub Runner,更常搜的是同一類意圖的不同表述,例如:
- GitHub Actions self-hosted runner macOS / macOS ARM64 runner / Apple Silicon runner
- GitHub Runner Mac mini / GitHub Actions Mac mini / self-hosted runner Mac mini
- iOS CI/CD self-hosted runner / GitHub Actions iOS build
- Cloud Mac CI、Xcode on CI、TestFlight 自動化
這些查詢背後通常是同一個架構問題:如何讓 GitHub Actions 把 job 派發到自己的 Apple Silicon 節點,而不是預設的 Linux 池或排隊中的託管 macos-latest。Cloud Mac(或辦公室裡的 Mac mini)提供機器;在機器上註冊 Runner + 打 label,才完成「派單」。本篇講的是為什麼要先立這一層;L1-Q02 會寫具體註冊步驟。
若你正在對比「買 Mac mini 放機房」與「租 Cloud Mac」,Runner 邏輯相同,差異在 L0 維運與成本——可參考Mac mini vs Cloud Mac 團隊選型;L1-Q05 將單獨做 Runner 成本對照。
Linux 託管 Runner 不夠時;以及「根本不需要 macOS Runner」時
GitHub 的 ubuntu-latest 對 Web 後端極其友善,但對 Apple 交付鏈是硬邊界。對照表:
| 維度 | ubuntu-latest 託管 |
Cloud Mac self-hosted |
|---|---|---|
| Xcode / iOS 建置 | ❌ 不可用 | ✅ 原生 |
| Apple Silicon 與真機架構一致性 | 不一致 | 與 M 系列開發機一致 |
| 與 Claude Code 同機 | ❌ 異構環境 | ✅ 可選同節點 |
| 佇列與成本模型 | 按分鐘、高峰排隊 | 固定節點,適合日更 CI |
反過來,說明「不適用」和說明「適用」同樣重要——否則讀者會以為你在賣「萬物上 Cloud Mac」。下面這類專案,繼續用 Linux runner 通常就夠,不必為了 AI Stack 硬上 macOS Runner:
- Next.js / 純前端靜態站——建置在 Node 環境完成,無 Xcode。
- Node.js API、Python FastAPI、Go 微服務——Docker job 在 Linux 上更常見、映像生態更全。
- Docker 化後端——
docker build+ 部署到 K8s,與 macOS 無關。 - 小型個人儲存庫——每月偶爾跑一次 CI,託管 runner 的佇列成本往往低於自建節點。
需要 macOS Runner 的訊號很集中:workflow 裡出現 Xcode、簽章、notarize、iOS Simulator、TestFlight,或團隊已在評估 Mac mini vs Cloud Mac的 iOS 基礎設施。詳見該文的分工模型;本篇只強調 Runner 在其中的 L1 位置。
GitHub 託管 macos-latest vs Cloud Mac 自建
更適合託管 macos-latest |
更適合 Cloud Mac self-hosted |
|---|---|
| 偶爾 archive、每月 <5 次 macOS job | 日更 CI、固定憑證與 Provisioning |
| 能接受排隊與分鐘計費波動 | 要 AI(Claude Code)與 CI 同棧、可觀測同一台機器 |
| 無內網依賴、無固定出口 IP 要求 | 要靜態 IP、內網 artifact、或 Runner 與CodeGraph 同機錯峰 |
經驗閾值(非合約承諾):當團隊每週 macOS job 超過約 10 次,且其中一半與 iOS 簽章/歸檔相關,我們會建議把 L1 從「臨時排隊」改為「固定 Cloud Mac + self-hosted」。低於該頻率,先用託管 macOS 把流水線跑通往往更省事。
落地順序:先 Fact,再 Diff——與結構圖不是一回事
五層結構圖講的是職責層級;團隊落地時要另記一條部署順序(先讓組織有 Fact,再疊 AI)。很多文章按熱搜寫:先 Claude Code,再 MCP,最後才想起來 CI。我們更推薦:
- L0——Cloud Mac 底座(常駐 macOS、出口、SSH)。
- L1——GitHub Runner,先讓
push → 綠/紅可重複(本篇)。 - L2–L3——Ollama、Claude Code,在「已有客觀建置結果」之上疊 AI。
- L4–L5——MCP、OpenHands,接在穩定 CI 與編碼環境之後。
原因很樸素:CodeGraph + Agent 可以改 18 個檔案,但若儲存庫沒有穩定的 macOS CI,你永遠不知道漏改是否會在 archive 階段爆炸。Runner 先把「機器驗收」固定下來,AI 才不是在沙盒裡自嗨。
與Mac mini + Claude Code 一週手記的關係:那篇偏 L3 編碼體驗;本篇補 L1——同一台機器可以夜間跑 Runner、白天跑 Agent,但兩層職責不要混在一篇文章裡講。
決策:誰需要把 Runner 當作執行引擎
結尾不做「Cloud Mac 更好」的口號,只做可執行的判斷。
| 適合優先立 L1(self-hosted on Cloud Mac) | 不一定需要 |
|---|---|
| 原生 iOS / macOS App 團隊 | 純靜態站、無原生建置 |
| Flutter 需要打 iOS 包、走 Xcode 鏈路的團隊 | 僅 Android / Web 的 Flutter 專案 |
| 已在 Cloud Mac 跑 Claude Code,但 CI 仍在 Linux | Node / Python API,Docker 在 Linux 已綠 |
| TestFlight / 簽章 / notarize 要自動化 | 小型個人專案、月更幾次 |
| 需要固定出口、內網或同機 CodeGraph 索引 | 只偶爾 macos-latest 能接受的 archive |
如果你命中左欄兩條以上,下一步不是繼續加 MCP Server,而是把 L1 跑通。具體步驟見下文 L1 專題連載。
L1 專題連載:從「執行引擎」到可複製的 macOS CI
本篇是 Cloud Mac AI Stack · L1 基石(L1-Q01)。後續會把 Runner 從概念寫成可維運的 Topic Cluster,並與 L2–L5 銜接:
| 篇目 | qid / 方向 | 狀態 |
|---|---|---|
| L1-Q01 · 本篇 | 為什麼 Runner 是執行引擎(Diff → Fact) | ✅ 你正在讀 |
| L1-Q02 | Cloud Mac 上註冊 self-hosted Runner(逐步教學) | 下一篇 |
| L1-Q03 | 一台 Runner 如何同時服務 Claude Code 與 CI(錯峰與同機) | 計畫中 |
| L1-Q04 | Runner workspace 清理與安全隔離策略 | 計畫中 |
| L1-Q05 | Mac mini vs Cloud Mac Runner 成本與佇列 | 計畫中 |
Google 更容易把成組的 L1 文章理解為「GitHub Runner + macOS CI 專題」,而不是單篇教學。L2 起將接 Ollama(Inference)、Claude Code(Diff)、MCP(Context)、OpenHands(Workflow)——均建立在「push 已有 Fact」之上;全系列回鏈 Cloud Mac AI Stack 五層結構圖。
常見問題
Cloud Mac 和 self-hosted Runner 是什麼關係?
Cloud Mac 是 L0 底座;Runner 是跑在底座上的 L1 程序與策略。租機器 ≠ 自動有 Runner。
能不能只在 MacBook 上跑 Runner?
可以,但合蓋、記憶體與 Agent 搶占、IP 變動會影響穩定性。日更 macOS CI 更常見做法是 24/7 Cloud Mac 節點。
Runner 和 Claude Code 必須同機嗎?
不必須;同機可減少「SSH 裡綠了、Actions 裡紅了」的摩擦。
和 OpenClaw 的區別?
Runner 執行 step;OpenClaw 編排觸發與回執。可疊在同一 Cloud Mac,見OpenClaw 雲端自動化。
GitHub Actions self-hosted runner macOS 怎麼和 Cloud Mac 一起用?
在 Cloud Mac(L0)上安裝並註冊 Runner 程序,workflow 使用 runs-on: [self-hosted, macOS, ARM64] 等標籤,即可把 iOS CI/CD、xcodebuild、TestFlight 步驟派發到該節點。
Claude Code 生產 Diff,Runner 生產 Fact——什麼意思?
Diff(差異)是 Agent 工作階段裡的改動與主觀結論;Fact(事實)是 GitHub Checks 上的綠勾、日誌與可部署 artifact。組織 merge 的是後者。延伸:MCP 生產 Context,OpenHands 生產 Workflow;見 § Stack 語言。
結構圖裡 Ollama 在 Claude Code 下面,是否必須先跑 Ollama?
否。圖表示職責層級,不是呼叫鏈。Claude Code 常用 API;Ollama 是 L2 可選 Inference,見 § 五層結構圖 說明框。
L1 專題 · 下一篇 L1-Q02
在 Cloud Mac 上註冊 GitHub Actions self-hosted runner(macOS)
本篇已回答「為什麼必須有執行層」。下一篇寫 label、actions/runner、launchd 與 token 輪換——把 Diff 與 Fact 落到同一台 Apple Silicon 節點。再往後:L1-Q03 同機服務 Claude Code 與 CI,L1-Q04 workspace 策略,L1-Q05 Mac mini vs Cloud Mac 成本。
