實戰背景
這個範例寫給第一次接觸 Oh My OpenAgent (OMO) 的開發者。我們刻意把需求縮到最小,讓你可以把注意力全部放在「多代理協同到底怎麼運作」這件事上,而不是被業務邏輯干擾。
痛點與問題描述:
我們在一個電商 side project 裡,需要新增一個 formatPrice 工具函式。規格很單純:
- 輸入:金額(以整數 cents 表示)與幣別代碼(如
TWD、USD)。 - 輸出:人類可讀的顯示字串,例如
formatPrice(1299, "TWD")應回傳"NT$12.99"。
如果走傳統流程,你會先打開 src/utils/format.ts 寫完函式,等編譯通過後再切到 tests/utils/format.test.ts 補測試。開發與測試是兩個分開的步驟。
OMO 給的另一條路是:把實作與測試丟給兩個並行的代理,讓它們在同一個 worktree 內各自推進。本範例就帶你走完這條路。
安裝與環境確認
第一次使用,依照 theme.yaml 提供的官方指令安裝(任選一個平台):
# OpenCode 平台
bunx oh-my-openagent install
# Codex CLI 平台
npx lazycodex-ai install
# 同時安裝到兩個平台
bunx oh-my-openagent install --platform=both
安裝完成後,OMO 會自動掛載 11 個內建專業代理與相關 MCP(包含 Exa、Context7、Grep.app 等),並把命令註冊進你的 CLI。
端到端 6 輪 AI 協作紀錄
以下是 You 與 OMO 之間的第一次協作歷程。
── 第 1 輪:用 explore 描述需求 ──
- You:
/opsx:explore "我需要新增 formatPrice(cents, currency) 工具函式,並配齊單元測試。請幫我用 OMO Team Mode 平行交付。" - AI:
收到。這個任務結構很適合 Team Mode 雙代理平行交付。
我規劃的分工是:
- Sisyphus 在
src/utils/format.ts實作formatPrice。 - Athena 在
tests/utils/format.test.ts平行撰寫單元測試。 - 兩邊會共用
src/types/money.ts的型別定義,我會自動啟用 Hash-Anchored Edit 保護這個檔案。
準備好就可以啟動 Team Mode。
- Sisyphus 在
── 第 2 輪:第一次啟動 Team Mode ──
- You:
啟動 Team Mode,指派 Sisyphus 實作、Athena 寫測試,開兩個 worker。 - AI:
[OMO] Team Mode Initialized
已在背景啟動兩個 worker:
Worker: impl指派 Sisyphus,負責src/utils/format.ts。Worker: tests指派 Athena,負責tests/utils/format.test.ts。
兩個 worker 的 context 完全隔離,不會互相污染。共用檔案
src/types/money.ts已加上 Hash-Anchored Edit 控制器。
第一次啟動 Team Mode 時,你會注意到 OMO 沒有要求你手動建立分支或 worktree,背景的 Git Worktree 配置是自動完成的。
── 第 3 輪:觀察 Sisyphus 的實作 ──
- You:
報告一下 Sisyphus 目前的進度。 - AI:
Sisyphus 已完成兩件事:
- 在共用檔
src/types/money.ts加上Currency型別:export type Currency = "TWD" | "USD" | "JPY"; - 在
src/utils/format.ts實作主邏輯:import type { Currency } from "../types/money"; const SYMBOLS: Record<Currency, string> = { TWD: "NT$", USD: "$", JPY: "¥", }; export function formatPrice(cents: number, currency: Currency): string { if (cents < 0) throw new RangeError("cents must be non-negative"); const symbol = SYMBOLS[currency]; const divisor = currency === "JPY" ? 1 : 100; const value = (cents / divisor).toFixed(divisor === 1 ? 0 : 2); return `${symbol}${value}`; }
Sisyphus 已提交本輪變更,等待 Athena 的測試對齊。
- 在共用檔
── 第 4 輪:Athena 平行寫測試,遇 Hash 鎖排隊 ──
- You:
Athena 在寫測試時,如果也想動到 money.ts 會怎樣? - AI:
這正是 Hash-Anchored Edit 的價值所在。
目前 Hash-Anchored Edit 的鎖定狀態顯示:
- 共用檔
src/types/money.ts由Worker: impl (Sisyphus)持有錨定鎖(鎖定第 1 到 3 行)。
Athena 原本想把
Currency加上一個EUR列舉值,但偵測到 Sisyphus 還在持有這個區塊的雜湊鎖,於是自動進入 queue 等待,不會強行覆蓋。等 Sisyphus 釋放鎖後,OMO 會通知 Athena 重新嘗試,或讓 Sisyphus 直接補上EUR。Athena 於是先在
tests/utils/format.test.ts完成主測試:import { formatPrice } from "../../src/utils/format"; test("formats TWD cents to display string", () => { expect(formatPrice(1299, "TWD")).toBe("NT$12.99"); }); test("JPY has no decimal places", () => { expect(formatPrice(1500, "JPY")).toBe("¥1500"); }); test("rejects negative cents", () => { expect(() => formatPrice(-1, "USD")).toThrow(RangeError); }); - 共用檔
── 第 5 輪:合併與執行測試 ──
- You:
合併兩個 worker 的成果,然後跑單元測試。 - AI:
Implementing: omo-beginner-formatprice
我已把兩個 worker 的變更合併回主分支。因為編輯期間全程使用 Hash-Anchored Edit 的區塊雜湊鎖,這次合併零衝突、所有錨定鎖均已釋放。
接著執行單元測試:
✔ formatPrice - formats TWD cents to display string (3ms) ✔ formatPrice - JPY has no decimal places (1ms) ✔ formatPrice - rejects negative cents (1ms) Tests: 3 passed, 3 total.
── 第 6 輪:歸檔與清理 ──
- You:
收尾,順便告訴我這次小任務花了多少時間。 - AI:
已執行驗證、合併主規格、關閉背景 worktree 與 tmux pane。
Archive Complete
計畫
omo-beginner-formatprice已歸檔。本次耗時約 7 分鐘(含安裝)。如果之後同類型的小工具函式變多,你可以一次把 Team Mode 開到 8 個 worker(Team Mode 的上限),讓多組 Sisyphus 與 Athena 平行交付。
關鍵學習點
- 第一次跑 Team Mode,最小的可運作單位就是兩個代理:一個負責實作、一個負責測試。不需要一開始就湊齊 11 個代理。
- Hash-Anchored Edit 在共用型別檔上特別有感。即使只動
src/types/money.ts一個檔案,鎖機制也會防止兩個 worker 同時改同一個區塊。 - 新手的第一個平行任務,只需要「啟動 Team Mode」與「合併成果」兩個動作,先記住這兩步就足以走完第一個平行任務。
- 新手不必先學 OpenSpec。本範例直接用
/opsx:explore描述需求就能開工,OpenSpec 的規格撰寫可以等任務規模變大後再引入。