Theme / v0.21.4

Oh My Codex (OMX)

Codex CLI 工作流增強層

實戰範例

實戰範例 010:用 $team 平行拆解跨前後端的上傳功能

中階範例,展示 OMX 的 $team 平行協調能力,把一個觸及後端儲存、前端元件與整合測試的功能拆成三條 worktree,透過 tmux 同步執行,最後以 $ultragoal 的持久驗收迴圈收斂驗收。

實戰背景

當一個功能同時要動後端路由、前端元件與測試套件時,循序交給單一個 Codex 工作階段會很慢,因為這三塊彼此獨立的區域其實可以同時開工。

痛點與問題描述: 要做「使用者頭像上傳」功能,拆開來看是三條互不擋的線:

  1. 後端:新增 POST /api/users/:id/avatar,接到 S3 相容的儲存後端。
  2. 前端:在設定頁加上 <PhotoUpload> 元件,呼叫新端點。
  3. 測試:針對完整上傳流程補整合測試。

三條線各自可以獨立展開,唯一的匯合點是最終的合併與全測試。OMX 的 $team 正是為這類情境設計:在 tmux 與 worktree 上協調多個 Codex 工作階段平行跑。本範例只使用 theme.yaml 列出的能力:$team、worktree 啟動參數、HUD 多窗格監控、.omx/ 共享狀態,以及 $ultragoal 驗收迴圈。

平台前提$team 的 tmux 協調在 macOS 與 Linux 原生支援。Windows 屬 secondary path,需以 psmux 替代,或直接在 WSL2 中執行。


第 1 步:規劃三條平行線並啟動 worktree

先把功能拆成三個角色,連同收斂條件一起寫進 OMX 的目標敘述:

$ultragoal 實作使用者頭像上傳功能,以 $team 拆成三條平行線:
  - backend:  新增 POST /api/users/:id/avatar 串接 S3
  - frontend: 新增 <PhotoUpload> 元件呼叫該端點
  - tests:    補上傳流程整合測試
收斂條件:三條線全綠後由 $ultragoal 合併並跑全測試。

OMX 先以 $deep-interview 確認儲存後端的選型,接著以 worktree 模式啟動整個 session:

# theme.yaml 中 launchCommand 的形式:worktree + madmax + xhigh
omx --worktree=feat/photo-upload --madmax --xhigh

第 2 步:$team 在 tmux 開出三個窗格

$team 讀取設定後,在 tmux session 開出三個窗格,每個窗格是一個獨立的 Codex 工作階段,各自掛在自己的 worktree 分支上:

tmux session: omx-photo-upload
  pane 0 [backend]   worktree feat/photo-upload-backend
  pane 1 [frontend]  worktree feat/photo-upload-frontend
  pane 2 [tests]     worktree feat/photo-upload-tests

三條任務佇列同時寫入共享的 .omx/queue.json,HUD 也切換成多窗格模式,同時追蹤三條進度線:

┌─ HUD ─────────────────────────────────────────┐
│ backend   Queue: 3 | Active: 1 | Done: 1      │
│ frontend  Queue: 2 | Active: 1 | Done: 0      │
│ tests     Queue: 2 | Active: 0 | Done: 0      │
│ Session cost: $0.34   Shared state: .omx/     │
└───────────────────────────────────────────────┘

這就是 $team 與單一 Autopilot 的差別:HUD 同時追蹤多條進度線,而不是只有一條。


第 3 步:平行推進,backend 與 frontend 同時落地

backend 窗格在 routes/avatar.ts 落地端點:

router.post("/users/:id/avatar", upload.single("file"), async (req, res) => {
  await storage.put(`avatars/${req.params.id}`, req.file.buffer);
  return res.json({ ok: true });
});

同一時間,frontend 窗格在 components/PhotoUpload.tsx 落地元件:

export function PhotoUpload({ userId }: { userId: string }) {
  const [uploading, setUploading] = useState(false);
  const onPick = async (file: File) => {
    setUploading(true);
    const form = new FormData();
    form.append("file", file);
    await fetch(`/api/users/${userId}/avatar`, { method: "POST", body: form });
    setUploading(false);
  };
  return (
    <input
      type="file"
      disabled={uploading}
      onChange={(e) => e.target.files && onPick(e.target.files[0])}
    />
  );
}

兩條線互不等待,HUD 同步推進為 backend Done: 2 | frontend Done: 1


第 4 步:tests 窗格卡關,$team 重派相依

tests 窗格想先寫上傳的整合測試,但需要 backend 的儲存介面才 mock 得起來,於是它在共享狀態上標記自己 blocked:

[tests] blocked on backend: needs IStorage signature

$team 偵測到這條相依,把 backend 的「定義 IStorage 介面」任務提到最前面優先完成,再通知 tests 窗格解除阻塞。這就是平行協調的價值:相依交給排程器處理,你不必手動排順序。


第 5 步:三條線收齊,$ultragoal 進入驗收迴圈

三條 worktree 都自我宣告完成後,OMX 自動啟動 $ultragoal 的持久化完成與驗證迴圈:合併三條分支、跑全測試、失敗就把任務回派修補、再跑一次,直到全綠。

第一輪全測試有兩個前端測試失敗(上傳中狀態未覆蓋)。$ultragoal 把失敗任務回派給 frontend 窗格補修,第二輪全綠。HUD 收斂為三條線全 Done,session 成本停在可預期的範圍。


第 6 步:結果盤點

評估維度 循序單一工作階段(估計) $team 平行(實際)
三條線完成時間 約 90 分鐘(序列等待) 約 35 分鐘(重疊)
相依排程 人工排序 $team 自動偵測並重派
驗收迴圈 手動跑測試 $ultragoal 合併即驗證
進度可見度 單一指標 HUD 多窗格同步

關鍵學習點

  • 平行是結構性的$team 把功能拆成角色後,在獨立 worktree 平行跑,前後端不再互相等待,適合介面已經談定、實作可以獨立展開的功能。
  • 相依交給排程器:當一條線需要另一條線的產出(例如測試需要介面定義),$team 會在共享的 .omx/queue.json 上偵測阻塞並重派,不必人工排順序。
  • worktree 是平行的基礎:啟動參數 --worktree=feat/... 讓每條線有自己的分支,合併交給最後的 $ultragoal,避免中途互相覆寫。
  • 驗收仍是一個迴圈:不論跑了幾條平行線,最後都收斂到 $ultragoal 的合併加全測試迴圈,確保三條線合起來真的能跑。

v0.21.3~v0.21.4:長 Team Session 的兩個注意事項

1. tmux scrollback

Detached leader session 的預設 history ceiling 已從 500 提高到 5000 行,也可在建立新 pane 前設定:

export OMX_TMUX_HISTORY_LIMIT=5000

既有 pane 的 history-limit 不會動態改變;如果長 session 已經因舊 ceiling 丟失輸出,要建立新的 tmux pane / session 才能套用新值。

2. Astra 是 default,不是 override

v0.21.4 在未指定模型時會對多數 agent tiers 使用 gpt-6-astra;若你的 Team 已經在 profile、per-agent config 或 CLI 中 pin model,explicit choice 仍然優先。升級後不要看到 default 改名就誤以為所有 worker 都會被強制換模型。