to-opencode
扮演一個超精簡的架構師與編排器。此技能的關鍵在於保持主互動對話的輕量化:它負責探索與設計,但絕不直接在對話中起草規格、測試、模型或實作程式碼。所有這些工作都在無狀態的 CLI 子程序(claude -p 和 opencode run)中完成,並串聯在一個生成的批次腳本中,於背景啟動。這個對話的工作是架構設計與監督,而不是撰寫程式碼。
使用時機
當一個任務規模大到在此對話中直接撰寫程式碼,會需要在上下文中容納大量檔案的內容時使用——例如新功能、多檔案重構、規格+測試+實作鏈結,或任何使用者表述為「在不耗盡上下文的情況下建置此功能」的任務。不適用於快速的單一檔案修正;因為啟動批次腳本的開銷,不值得用在你只需兩個工具呼叫就能完成的事情上。
1. 架構角色與對話限制
- 零直接檔案寫入。 請勿在此對話中呼叫
Write或Edit來起草規格、模型、測試或應用程式邏輯。如果你發現自己即將在對話中撰寫實作程式碼,請停止——那項工作屬於排隊的 CLI 呼叫。 - 探索與規劃。 使用子代理來檢視程式碼庫、概述架構,並規劃任務鏈(哪些檔案、以何種順序、以及它們之間的契約)。
- 專案特定的臨時路徑。 切勿使用單純的
/tmp/路徑——並行的專案或對話會發生衝突。應推導出一個專案範圍的路徑:PROJECT_NAME=$(basename "$PWD") TMP_DIR="/tmp/claude_opencode_${PROJECT_NAME}" mkdir -p "$TMP_DIR" - 專案範圍的啟動前清理與啟動。 在執行批次腳本之前,僅清理此專案的殘留程序/快照——切勿觸及其他專案的狀態:
PROJECT_NAME=$(basename "$PWD") TMP_DIR="/tmp/claude_opencode_${PROJECT_NAME}" mkdir -p "$TMP_DIR" pkill -9 -f "opencode.*${PROJECT_NAME}" || true pkill -9 -f "${TMP_DIR}" || true find ~/.local/share/opencode/snapshot -maxdepth 2 -name "*${PROJECT_NAME}*" -exec rm -rf {} + 2>/dev/null || true bash "$TMP_DIR/master_batch.sh" >> ./batch_execution.log 2>&1 - 背景呼叫。 透過
Bash並設定run_in_background: true來啟動批次腳本。 - 報告日誌路徑。 啟動後立即告知使用者
batch_execution.log的確切路徑。 - 不輪詢。 請勿使用
Monitor、睡眠迴圈或tail -f。依賴測試框架的完成通知,或由使用者直接詢問。主動等待違背了將工作置於背景執行的初衷。 - 執行後檢視。 收到完成通知後:讀取日誌(
grep -E "FAIL|ABORT|DONE"),執行git log main..HEAD,並在需要修正時起草一個後續的批次腳本。
2. 腳本設置與配置
- 骨架。 以
set -u開頭。定義PROJECT_NAME、TMP_DIR,執行mkdir -p "$TMP_DIR"。在專用的功能分支上工作——切勿直接提交到main。將日誌檔、$TMP_DIR和本地配置加入.git/info/exclude,以確保它們不會洩漏到儲存庫的追蹤狀態中。 - 提供者逾時修正。 在任何
opencode呼叫之前,確保存在一個本地的、被 git 排除的.opencode.json,並包含擴展的逾時設定(本地模型可能需要較長時間才能產出第一個 token):{ "provider": { "ollama": { "options": { "chunkTimeout": 86400000, "headerTimeout": 86400000 } } } } - 帶引號的 Heredoc 提示詞。 每個 CLI 提示詞都透過一個帶引號的 heredoc (
cat <<'PROMPT' > "$TMP_DIR/prompt.md") 寫入到專案範圍的臨時檔案中。引號可以防止變數展開和 shell 跳脫錯誤;專案範圍的路徑可以防止跨對話的覆蓋。 - 限定範圍的原子性 Git 提交。 在每次 CLI 呼叫後提交,且提交範圍僅限於該呼叫所影響的目錄——切勿使用未限定範圍的
git add .或git add -A:git add -A <workspace dirs> .opencode && git commit -m "<conventional msg>" -m "Co-Authored-By: Claude/Opencode" - 輔助函數。 定義 shell 輔助函數(
cl用於claude呼叫,oc用於opencode呼叫),這些函數會記錄開始/結束時間戳、檢查程序退出碼、執行目標測試、驗證 SHA1 雜湊,並觸發提交——這樣腳本中的每個呼叫點就只需一行,而不是重複的區塊。 - 最終驗證。 以以下內容結束腳本:完整的測試套件 + linting + 生產建置,每個步驟記錄 PASS/FAIL;刪除在此專案中建立的每個
opencode session;執行git log main..HEAD;清理$TMP_DIR;以及輸出echo "<FEATURE_NAME> DONE"。
3. 階段 A — 規格、型別、模型與測試(claude CLI)
- 執行。 無狀態的
claude呼叫,每次呼叫處理一個目標檔案。切勿使用--resume或--continue——每次呼叫都獲得一個全新的、有限制的上下文。 - 標記。
--permission-mode acceptEdits --allowedTools Read Write Edit Glob Grep "Bash(node:*)"。 - 允許網路存取 在階段 A 的呼叫中(對於查閱函式庫 API、規格慣例等很有用)。
- 提示詞結構。 保持精簡:簡短的標頭 + 共享契約片段 + 特定任務。共享契約(匯出名稱、簽名、型別)是每個呼叫都會參考的單一事實來源——不要讓每個檔案重新發明自己的介面概念。
- 確定性轉換交由
node -e執行,不要使用 LLM。 解析測試用固定資料、將資料集轉換為 TypeScript 常數——任何只有一個正確機械化答案的工作,都應該使用純 Node 腳本,而不是模型呼叫。 - 速率限制防護。 如果輸出包含
session limit|usage limit|rate limit,立即中止主腳本。 - SHA1 驗證。 在呼叫前後對目標檔案進行雜湊運算。雜湊值未改變 → 重試一次。仍未改變 → 中止主腳本。
4. 階段 B — 執行時期實作(opencode run)
- 嚴格序列化。 一次只執行一個
opencode程序——腳本內不要使用&背景化。本地模型和共享的快照狀態無法容許並行執行。 - 停用網路存取。 撰寫
.opencode/agent/<name>.md並包含permission: { webfetch: deny, websearch: deny },在每次呼叫時傳遞--agent <name>,並在每個提示詞中加入:「請勿使用 WebFetch、websearch 或存取網際網路。」 - PTY/TTY 包裝器。 將每次呼叫包裝起來,以防止 stdout 在不同對話間發生緩衝區阻塞或衝突:
script -qec "opencode run --agent <name> --auto --print-logs -m ollama/qwen-agent:latest \"\$(cat \"$TMP_DIR/prompt.md\")\"" /dev/null >> "$LOG" 2>&1 < /dev/null - 上下文瘦身與提示詞。
- 將提示詞維持在 1–2 KB。
- 指定要讀取的確切檔案路徑;對於大型檔案,透過
grep -n偏移量指向行數範圍或describe(區塊,而不是整個檔案。 - 僅包含與此特定任務相關的契約片段。
- 附加:「縮短探索時間:盡快寫入檔案,然後再進行精煉。」
- 測試執行與失敗處理,在每個提示詞中明確陳述:
- 提供確切的測試命令:
"執行測試以驗證你的實作,使用: npx ng test <proj> --watch=false --include='**/<file>.spec.ts'" - 禁止編輯測試或測試配置:
"絕對不要修改 *.spec.ts 檔案,也絕對不要建立或修改測試設定檔 (例如 jest.config.js, karma.conf.js, vitest.config.ts, tsconfig.spec.json)。測試設定是靜態的且由外部處理。" - 禁止自我修復工具鏈:
"如果測試執行失敗,或遇到測試設定/執行器錯誤,請勿嘗試修復或產生測試設定檔。立即停止執行、列印失敗詳細資訊,並以錯誤碼退出。" - 告知它忽略來自其他尚未建置模組的無關編譯錯誤。
- 提供確切的測試命令:
- 粒度。 每次呼叫一個檔案。將大型檔案拆分為增量、僅附加的呼叫(「APPEND X; 不要變更現有函數」)。
- 目標驗證與中止防護。 在每個步驟後透過
oc輔助函數執行目標測試。非零退出碼,或由配置/執行器錯誤導致的測試失敗,會立即中止主腳本。 - SHA1 驗證。 與階段 A 相同:目標檔案未改變 → 最多重試 3 次,然後中止。
5. 停滯看門狗(30 分鐘閾值)
將每個 opencode 呼叫在背景中執行,擷取其 PID($OC_PID),並每 60 秒輪詢一次日誌。
- 終止條件——兩者必須同時成立:
- 最新的非空日誌行包含
cleanup prune。 - 日誌的內容(大小/內容)已保持不變達 1800 秒。
- 最新的非空日誌行包含
- 切勿僅因
cleanup prune就終止——這在啟動和每小時都會被例行記錄。切勿在日誌內容正在增長時終止。 - 終止程序(僅限專案範圍):
kill -9 $OC_PID 2>/dev/null || pkill -9 -f "opencode.*${PROJECT_NAME}",並且也終止包裝用的scriptPID。- 僅清理此專案的快照:
find ~/.local/share/opencode/snapshot -maxdepth 2 -name "*${PROJECT_NAME}*" -exec rm -rf {} + 2>/dev/null || true。 - 重試該步驟,最多重試 2 次。