diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json
index c0cbcbe..a79edb2 100644
--- a/.claude-plugin/marketplace.json
+++ b/.claude-plugin/marketplace.json
@@ -339,16 +339,6 @@
"source": "./plugins/cli-tools",
"category": "development"
},
- {
- "name": "parallel-ai-agents",
- "version": "2.5.1",
- "description": "平行派發任務給多個 AI agent(Claude + Codex),獨立執行後交叉比對結果。Codex 改走直接 HTTP wrapper(bin/codex-call,Swift script)取代 codex exec subprocess,解決 hang 問題且避開 Python 版本飄移",
- "author": {
- "name": "Che Cheng"
- },
- "source": "./plugins/parallel-ai-agents",
- "category": "development"
- },
{
"name": "macdoc",
"version": "1.1.0",
diff --git a/plugins/parallel-ai-agents/.claude-plugin/plugin.json b/plugins/parallel-ai-agents/.claude-plugin/plugin.json
deleted file mode 100644
index bf3cac4..0000000
--- a/plugins/parallel-ai-agents/.claude-plugin/plugin.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "name": "parallel-ai-agents",
- "description": "平行派發任務給多個 AI agent(Claude + Codex),獨立執行後交叉比對結果。Codex 改走直接 HTTP wrapper(bin/codex-call,Swift script)取代 codex exec subprocess,解決 hang 問題且避開 Python 版本飄移",
- "version": "2.5.1",
- "author": {
- "name": "Che Cheng"
- }
-}
diff --git a/plugins/parallel-ai-agents/CHANGELOG.md b/plugins/parallel-ai-agents/CHANGELOG.md
deleted file mode 100644
index effaaad..0000000
--- a/plugins/parallel-ai-agents/CHANGELOG.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-> ⚠ This file was bootstrapped by `changelog-tools:changelog-init` from the
-> `plugin.json` description field. Section categorization is best-effort —
-> review and refine `Added` / `Changed` / `Fixed` etc. as needed.
-
-## [Unreleased]
-
-## [2.3.0] - 2026-05-07
-
-### Added
-- **`--auto-iterate` mode for `/ensemble-academic-review` (#34)**: round → fix → round 自治收斂迴圈,內部沿用 mix N 的 alternating independent/hybrid pattern,但加上每輪結束的:
- - **Verdict parsing**: Codex prompt 強制要求 `PERMANENT_CONVERGENCE | CONVERGED | NEEDS_ITER_N` 結構化 tag,skill 用 regex 解析,不靠語意判斷
- - **HIGH-only fix application**: 從 `review-round-{N}.md` 解 HIGH-severity findings 自動套到 working tree;ambiguous fix skip + log to `skipped_fixes.log`
- - **Auto-commit per round**: `iter-{N}: apply HIGH fixes from ensemble round {N}`,user 可隨時 `git revert iter-{N}`
- - **Rotate-focus heuristic**: 連續 K=3 同 focus CONVERGED 才 switch (focus pool: method-section / proofs / typography / cross-references / boundary-cases)
- - **Stop conditions**: 達 `--converge-on` (default `PERMANENT_CONVERGENCE`) 或 `--max-rounds` (default 12, max 30)
-- **8 cumulative methodological lessons** in SKILL.md tail — 來自實戰 23-round campaign (`PsychQuantHsu/psychophysic_representations_manuscript/docs/rounds/INDEX.md`),作為 rare-audited section / hypothesis-inheritance / verdict-tier 等坑的 reference
-
-### Notes
-- Self-contained Bash while + state machine,**不**依賴 ralph-loop 的 Stop-hook 機制
-- 與 ralph-loop 同時跑時 skill 偵測並警告(雙 Stop-hook 衝突風險)
-- Spec-only PR — agent 讀 SKILL.md 後在 user 顯式傳 `--auto-iterate` 才觸發,既有 mode 行為不變
-
-## [2.2.0] - 2026-05-03
-
-### Added
-- **`number-verifier` reviewer**: 5th ensemble reviewer that checks every
- number in a doc against ground-truth artifacts (`.rds`, `.npz`, `.csv`,
- R/Python scripts). Catches hallucinated numbers that other reviewers
- miss. Verified by ASSG3 review pipeline (Canadian GDP ARIMA + Australian
- yields VAR/VECM) where it caught wrong y_T, drift omission, Ljung-Box
- fitdf errors, and ARIMA(1,1,1) reference p-value mistakes across 4 rounds.
-- `--no-numeric` flag to disable number-verifier (pure theoretical papers)
-- `--no-references` flag to disable reference-verifier (technical notes)
-- Auto-detect: number-verifier enables when `analysis/`, `*.rds`, `*.ipynb`,
- `*.Rmd`, or `data/*.csv` are present near the doc
-- Hybrid mode: `prior_number_issues` watch list passed to number-verifier
- in subsequent rounds (analogous to `prior_ref_issues`)
-
-### Changed
-- Reviewer count: 4 → 5 Claude teammates + Codex
-- Tool-call rule: "5 calls in one message" → "N+1 calls (N ∈ {3,4,5})"
-- Ironclad rules: HIGH-priority bucket now includes hallucinated numbers
- alongside hallucinated references
-
-## [2.1.1] - (date unknown — please fill in)
-
-### Changed
-- 平行派發任務給多個 AI agent(Claude + Codex),獨立執行後交叉比對結果
diff --git a/plugins/parallel-ai-agents/CLAUDE.md b/plugins/parallel-ai-agents/CLAUDE.md
deleted file mode 100644
index bd610bd..0000000
--- a/plugins/parallel-ai-agents/CLAUDE.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# parallel-ai-agents — CLAUDE.md
-
-## Purpose
-
-平行派發任務給多個 AI agent,獨立執行後交叉比對結果。使用 Claude orchestrated teams + Codex 實現跨模型、跨角色的盲驗。
-
-## Skills
-
-| Skill | 用途 | 架構 |
-|-------|------|------|
-| `/parallel-ai-agents:ensemble-review` | 審閱文件/程式碼,交叉比對產出共識/盲點報告 | 4 Claude teammates (team) + 1 Codex |
-
-## 審閱架構
-
-```
-ensemble-review
-├── Claude Team(4 teammates,orchestrated)
-│ ├── architecture — 設計、API、依賴
-│ ├── correctness — 邏輯、bug、edge case
-│ ├── security — 攻擊者視角
-│ └── devils-advocate — 反駁前 3 人
-└── Codex(gpt-5.5,跨模型盲驗)
-```
-
-## 依賴
-
-- Claude Code orchestrated teams(TeamCreate、SendMessage)
-- **Codex OAuth token**(`~/.codex/auth.json`)— 由 codex CLI 在首次登入時建立。本 plugin 自帶 wrapper `bin/codex-call` 直接讀這個檔案、走 OAuth refresh + HTTP 直連 `chatgpt.com/backend-api`,不再 spawn `codex exec` subprocess(避免 stdin/stdout pipe 互鎖造成的 hang)
-- Swift toolchain(Xcode CLT 內建;用 `#!/usr/bin/env swift` shebang,第一次跑會 compile cache)
-
-## bin/codex-call
-
-Swift script wrapper,取代原本的 `codex exec --full-auto`。設計目的:
-
-| 問題 | `codex exec` | `codex-call` (Swift) |
-|------|-------------|---------------------|
-| Subprocess hang | 偶發 | ✗ 純 URLSession,無 subprocess |
-| Hard timeout | 不可靠 | ✓ URLSession + DispatchSemaphore wait timeout |
-| OAuth refresh | CLI 自動 | 自帶 refresh + flock 防 race |
-| 計費 | ChatGPT 訂閱 | ChatGPT 訂閱(同一條 OAuth)|
-| service_tier=fast | CLI 接受(內部翻譯成 priority)| **接受 `fast`/`priority`/`flex`**,內部翻譯與 codex CLI 一致 |
-| Cold start | ~50ms (subprocess) | ~1.5s(swift compile + cache)|
-| 依賴 | `codex` CLI 安裝 | macOS 內建 swift(Xcode CLT)|
-
-範例:
-
-```bash
-codex-call \
- --output result.md \
- --model gpt-5.5 \
- --effort xhigh \
- --max-time 600 \
- --instructions "你是嚴謹 reviewer。" \
- --prompt-file prompt.txt
-```
-
-或 stdin:
-
-```bash
-echo "..." | codex-call --output out.md --model gpt-5.5 --effort xhigh
-```
-
-Wrapper 在 plugin 安裝時自動加入 PATH(透過 `bin/`),所以直接呼叫名字即可,不需要絕對路徑。
-
-### 為什麼 Swift script 不是 Python
-
-Python 在 macOS 上版本飄移:`/usr/bin/python3` 是 stub(要 Xcode CLT 才有真 binary);版本可能是 3.9 / 3.10 / 3.11 / 3.13,新語法(如 `dict | None`)需 3.10+ 不一定可用。Swift script 用 Xcode CLT 內建的 swift 5+,shebang 直接跑,無版本兼容問題。
-
-不走 Swift binary(che-mcps notarize 模式)的理由:這 wrapper 不需 TCC 權限(只發 HTTPS),開新 repo + notarize 流程過度工程化。Swift script 的 1-2s cold start 對 ensemble 場景(5-15s LLM response 為主)是可接受的雜訊。
-
-## Development
-
-- 測試:`claude --plugin-dir ./plugins/parallel-ai-agents`
-- 更新:`/plugin-tools:plugin-update parallel-ai-agents`
diff --git a/plugins/parallel-ai-agents/bin/codex-call b/plugins/parallel-ai-agents/bin/codex-call
deleted file mode 100755
index 4a8231e..0000000
--- a/plugins/parallel-ai-agents/bin/codex-call
+++ /dev/null
@@ -1,386 +0,0 @@
-#!/usr/bin/env swift
-
-// codex-call — direct HTTP wrapper for chatgpt.com/backend-api
-//
-// Replaces `codex exec --full-auto -o output "prompt"` with a clean HTTP call
-// that bypasses the codex CLI subprocess (which can hang on stdin/stdout pipes).
-//
-// Usage:
-// codex-call --output FILE [--model gpt-5.5] [--effort xhigh]
-// [--service-tier ""] [--max-time 600]
-// [--instructions TEXT] [--prompt-file FILE | PROMPT]
-//
-// Reads OAuth token from ~/.codex/auth.json (codex CLI's token store).
-// Auto-refreshes access_token if within 5 min of expiry. Refresh uses a file
-// lock to prevent concurrent races during parallel ensemble runs.
-
-import Foundation
-#if canImport(Darwin)
-import Darwin
-#endif
-
-// MARK: - Configuration
-
-let HOME_DIR = FileManager.default.homeDirectoryForCurrentUser
-let AUTH_FILE = HOME_DIR.appendingPathComponent(".codex/auth.json").path
-let LOCK_FILE = HOME_DIR.appendingPathComponent(".codex/.token-refresh.lock").path
-let TOKEN_URL = URL(string: "https://auth.openai.com/oauth/token")!
-let CODEX_URL = URL(string: "https://chatgpt.com/backend-api/codex/responses")!
-let CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann"
-let REFRESH_THRESHOLD_SEC: Int = 300
-
-// MARK: - Helpers
-
-func die(_ msg: String, code: Int32 = 1) -> Never {
- FileHandle.standardError.write(Data("error: \(msg)\n".utf8))
- exit(code)
-}
-
-func log(_ msg: String) {
- FileHandle.standardError.write(Data("[codex-call] \(msg)\n".utf8))
-}
-
-// MARK: - JWT exp
-
-func jwtExp(_ token: String) -> Int {
- let parts = token.split(separator: ".")
- guard parts.count >= 2 else { return 0 }
- var payload = String(parts[1])
- .replacingOccurrences(of: "-", with: "+")
- .replacingOccurrences(of: "_", with: "/")
- while payload.count % 4 != 0 { payload += "=" }
- guard let data = Data(base64Encoded: payload),
- let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
- let exp = json["exp"] as? Int
- else { return 0 }
- return exp
-}
-
-// MARK: - Auth file
-
-func loadAuthRaw() throws -> [String: Any] {
- let data = try Data(contentsOf: URL(fileURLWithPath: AUTH_FILE))
- guard let obj = try JSONSerialization.jsonObject(with: data) as? [String: Any]
- else { throw NSError(domain: "codex-call", code: 1,
- userInfo: [NSLocalizedDescriptionKey: "auth.json is not an object"]) }
- return obj
-}
-
-func saveAuthRaw(_ auth: [String: Any]) throws {
- let data = try JSONSerialization.data(withJSONObject: auth, options: [.prettyPrinted, .sortedKeys])
- let tmp = AUTH_FILE + ".tmp"
- try data.write(to: URL(fileURLWithPath: tmp), options: .atomic)
- _ = chmod(tmp, 0o600)
- if rename(tmp, AUTH_FILE) != 0 {
- throw NSError(domain: "codex-call", code: 2,
- userInfo: [NSLocalizedDescriptionKey: "rename failed: \(String(cString: strerror(errno)))"])
- }
-}
-
-// MARK: - OAuth refresh
-
-func httpFormPost(url: URL, fields: [String: String], timeout: TimeInterval = 30) throws -> Data {
- var req = URLRequest(url: url, timeoutInterval: timeout)
- req.httpMethod = "POST"
- req.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
- let body = fields.map { (k, v) in
- let ek = k.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? k
- let ev = v.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? v
- return "\(ek)=\(ev)"
- }.joined(separator: "&")
- req.httpBody = body.data(using: .utf8)
-
- let sem = DispatchSemaphore(value: 0)
- var result: Data?
- var error: Error?
- var status: Int = 0
- URLSession.shared.dataTask(with: req) { data, resp, err in
- status = (resp as? HTTPURLResponse)?.statusCode ?? 0
- result = data
- error = err
- sem.signal()
- }.resume()
- sem.wait()
-
- if let err = error { throw err }
- guard status == 200, let data = result else {
- let body = result.flatMap { String(data: $0, encoding: .utf8) } ?? "(no body)"
- throw NSError(domain: "codex-call", code: status,
- userInfo: [NSLocalizedDescriptionKey: "HTTP \(status): \(body.prefix(500))"])
- }
- return data
-}
-
-func refreshIfNeeded(_ auth: inout [String: Any]) throws {
- guard var tokens = auth["tokens"] as? [String: Any],
- let access = tokens["access_token"] as? String,
- let refresh = tokens["refresh_token"] as? String
- else { throw NSError(domain: "codex-call", code: 3,
- userInfo: [NSLocalizedDescriptionKey: "auth.json missing tokens.access_token/refresh_token"]) }
-
- let now = Int(Date().timeIntervalSince1970)
- if jwtExp(access) - now > REFRESH_THRESHOLD_SEC { return }
-
- // file lock
- try FileManager.default.createDirectory(
- at: URL(fileURLWithPath: LOCK_FILE).deletingLastPathComponent(),
- withIntermediateDirectories: true)
- let fd = open(LOCK_FILE, O_CREAT | O_WRONLY, 0o600)
- if fd < 0 {
- throw NSError(domain: "codex-call", code: 4,
- userInfo: [NSLocalizedDescriptionKey: "open lock failed: \(String(cString: strerror(errno)))"])
- }
- defer { close(fd) }
- if flock(fd, LOCK_EX) != 0 {
- throw NSError(domain: "codex-call", code: 5,
- userInfo: [NSLocalizedDescriptionKey: "flock failed: \(String(cString: strerror(errno)))"])
- }
- defer { _ = flock(fd, LOCK_UN) }
-
- // Re-read after acquiring lock — another process may have refreshed
- auth = try loadAuthRaw()
- if let t = auth["tokens"] as? [String: Any],
- let a = t["access_token"] as? String,
- jwtExp(a) - now > REFRESH_THRESHOLD_SEC {
- return
- }
- tokens = auth["tokens"] as? [String: Any] ?? tokens
-
- let respData = try httpFormPost(url: TOKEN_URL, fields: [
- "grant_type": "refresh_token",
- "refresh_token": refresh,
- "client_id": CLIENT_ID,
- ])
- guard let json = try JSONSerialization.jsonObject(with: respData) as? [String: Any],
- let newAccess = json["access_token"] as? String
- else { throw NSError(domain: "codex-call", code: 6,
- userInfo: [NSLocalizedDescriptionKey: "refresh response missing access_token"]) }
-
- tokens["access_token"] = newAccess
- if let newRefresh = json["refresh_token"] as? String { tokens["refresh_token"] = newRefresh }
- if let newId = json["id_token"] as? String { tokens["id_token"] = newId }
- auth["tokens"] = tokens
-
- let fmt = ISO8601DateFormatter()
- fmt.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
- auth["last_refresh"] = fmt.string(from: Date())
-
- try saveAuthRaw(auth)
- log("token refreshed")
-}
-
-// MARK: - SSE streaming
-
-final class StreamCollector: NSObject, URLSessionDataDelegate {
- var accumulated = ""
- var buffer = ""
- var statusCode: Int = 0
- var streamError: Error?
- let done = DispatchSemaphore(value: 0)
- var firstBytes: Data?
-
- func urlSession(_ session: URLSession, dataTask: URLSessionDataTask,
- didReceive response: URLResponse,
- completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
- statusCode = (response as? HTTPURLResponse)?.statusCode ?? 0
- completionHandler(.allow)
- }
-
- func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
- if statusCode != 200 {
- // Buffer error body for reporting
- firstBytes = (firstBytes ?? Data()) + data
- return
- }
- guard let chunk = String(data: data, encoding: .utf8) else { return }
- buffer += chunk
- while let range = buffer.range(of: "\n\n") {
- let event = String(buffer[buffer.startIndex.. String? in
- guard line.hasPrefix("data:") else { return nil }
- return String(line.dropFirst(5)).trimmingCharacters(in: .whitespaces.subtracting(.newlines))
- }
- let payload = dataLines.joined()
- if payload.isEmpty || payload == "[DONE]" { return }
- guard let data = payload.data(using: .utf8),
- let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
- let type = json["type"] as? String
- else { return }
-
- switch type {
- case "response.output_text.delta":
- if let delta = json["delta"] as? String { accumulated += delta }
- case "error", "response.failed":
- let msg = (json["message"] as? String)
- ?? ((json["response"] as? [String: Any])?["error"] as? [String: Any])?["message"] as? String
- ?? "Codex error"
- streamError = NSError(domain: "codex-call", code: -1,
- userInfo: [NSLocalizedDescriptionKey: msg])
- default:
- break
- }
- }
-}
-
-func streamCodex(prompt: String, outputFile: String, model: String, effort: String,
- serviceTier: String, maxTime: Int, instructions: String) throws {
- var auth = try loadAuthRaw()
- try refreshIfNeeded(&auth)
- guard let tokens = auth["tokens"] as? [String: Any],
- let access = tokens["access_token"] as? String
- else { throw NSError(domain: "codex-call", code: 7,
- userInfo: [NSLocalizedDescriptionKey: "post-refresh: tokens missing"]) }
- let accountId = (tokens["account_id"] as? String) ?? ""
-
- var body: [String: Any] = [
- "model": model,
- "store": false,
- "stream": true,
- "instructions": instructions,
- "input": [["role": "user", "content": [["type": "input_text", "text": prompt]]]],
- "text": ["verbosity": "medium"],
- "include": ["reasoning.encrypted_content"],
- "tool_choice": "auto",
- "parallel_tool_calls": true,
- "reasoning": ["effort": effort, "summary": "auto"],
- ]
- // Translate legacy/friendly names to backend wire values.
- // Mirrors codex-rs ServiceTier::request_value(): Fast→priority, Flex→flex.
- // Backend rejects "fast" with HTTP 400; codex CLI does this translation internally.
- let wireTier: String = {
- switch serviceTier.lowercased() {
- case "fast", "priority": return "priority"
- case "flex": return "flex"
- case "": return ""
- default: return serviceTier // pass through unknown values
- }
- }()
- if !wireTier.isEmpty { body["service_tier"] = wireTier }
-
- var req = URLRequest(url: CODEX_URL, timeoutInterval: TimeInterval(maxTime))
- req.httpMethod = "POST"
- req.setValue("Bearer \(access)", forHTTPHeaderField: "Authorization")
- req.setValue("application/json", forHTTPHeaderField: "Content-Type")
- req.setValue("responses=experimental", forHTTPHeaderField: "OpenAI-Beta")
- req.setValue("codex_cli_rs", forHTTPHeaderField: "originator")
- req.setValue(accountId, forHTTPHeaderField: "chatgpt-account-id")
- req.setValue("text/event-stream", forHTTPHeaderField: "Accept")
- req.httpBody = try JSONSerialization.data(withJSONObject: body)
-
- let collector = StreamCollector()
- let config = URLSessionConfiguration.default
- config.timeoutIntervalForRequest = TimeInterval(maxTime)
- config.timeoutIntervalForResource = TimeInterval(maxTime)
- let session = URLSession(configuration: config, delegate: collector, delegateQueue: nil)
-
- session.dataTask(with: req).resume()
- let waitResult = collector.done.wait(timeout: .now() + .seconds(maxTime + 5))
- session.invalidateAndCancel()
-
- if waitResult == .timedOut {
- throw NSError(domain: "codex-call", code: 408,
- userInfo: [NSLocalizedDescriptionKey: "Hard timeout after \(maxTime)s"])
- }
- if let err = collector.streamError { throw err }
-
- try collector.accumulated.write(toFile: outputFile, atomically: true, encoding: .utf8)
- log("wrote \(collector.accumulated.count) chars to \(outputFile)")
-}
-
-// MARK: - Argument parsing
-
-struct Args {
- var output: String?
- var model: String = "gpt-5.5"
- var effort: String = "xhigh"
- var serviceTier: String = ""
- var maxTime: Int = 600
- var instructions: String = "You are a careful, rigorous reviewer. Respond in the user's language."
- var promptFile: String?
- var prompt: String?
-}
-
-func parseArgs() -> Args {
- var a = Args()
- var args = Array(CommandLine.arguments.dropFirst())
- while !args.isEmpty {
- let head = args.removeFirst()
- func next() -> String {
- guard !args.isEmpty else { die("missing value for \(head)") }
- return args.removeFirst()
- }
- switch head {
- case "--output", "-o": a.output = next()
- case "--model": a.model = next()
- case "--effort": a.effort = next()
- case "--service-tier": a.serviceTier = next()
- case "--max-time": a.maxTime = Int(next()) ?? a.maxTime
- case "--instructions": a.instructions = next()
- case "--prompt-file": a.promptFile = next()
- case "--help", "-h":
- print("""
- codex-call — direct HTTP wrapper for chatgpt.com/backend-api
-
- Usage:
- codex-call --output FILE [--model gpt-5.5] [--effort xhigh]
- [--service-tier ""] [--max-time 600]
- [--instructions TEXT]
- [--prompt-file FILE | PROMPT]
-
- If no PROMPT and no --prompt-file is given, reads prompt from stdin.
-
- Auth: reads ~/.codex/auth.json (auto-refreshes if expired).
- """)
- exit(0)
- default:
- if a.prompt == nil { a.prompt = head }
- else { die("unexpected positional argument: \(head)") }
- }
- }
- return a
-}
-
-// MARK: - Main
-
-let a = parseArgs()
-guard let output = a.output else { die("--output is required") }
-
-let prompt: String
-if let pf = a.promptFile {
- do { prompt = try String(contentsOfFile: pf, encoding: .utf8) }
- catch { die("cannot read prompt file: \(error.localizedDescription)") }
-} else if let p = a.prompt {
- prompt = p
-} else {
- let stdinData = FileHandle.standardInput.readDataToEndOfFile()
- prompt = String(data: stdinData, encoding: .utf8) ?? ""
-}
-if prompt.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
- die("empty prompt")
-}
-
-do {
- try streamCodex(prompt: prompt, outputFile: output, model: a.model, effort: a.effort,
- serviceTier: a.serviceTier, maxTime: a.maxTime, instructions: a.instructions)
-} catch {
- die(error.localizedDescription)
-}
diff --git a/plugins/parallel-ai-agents/skills/ensemble-academic-review/skill.md b/plugins/parallel-ai-agents/skills/ensemble-academic-review/skill.md
deleted file mode 100644
index c7fb66b..0000000
--- a/plugins/parallel-ai-agents/skills/ensemble-academic-review/skill.md
+++ /dev/null
@@ -1,714 +0,0 @@
----
-name: ensemble-academic-review
-description: |
- 學術論文 ensemble 審閱:methodology、writing、reference verification、number-verification、devils-advocate。
- 用 che-zotero-mcp 驗證文獻真實性(抓幻覺文獻)、用 R/Python 重跑 ground-truth 抓幻覺數字,用 perspective-writer 審查寫作風格。
- 三種模式:independent(獨立單輪)、hybrid(DA 看前輪的單輪)、mix N(交替 N 輪)。
- Use when: 碩博論文、期刊投稿、學術報告、計量/實證作業需要嚴格審閱。
-argument-hint: "FILE [--mode independent|hybrid|mix] [--rounds N] [--prior summary.md] [--focus 'topic'] [--no-numeric|--no-references]"
-allowed-tools:
- - Read
- - Write
- - Edit
- - Bash
- - Grep
- - Glob
- - Agent
- - TeamCreate
- - SendMessage
- - TaskCreate
- - TaskUpdate
- - TaskList
- - TaskGet
- - AskUserQuestion
- - Skill
- - mcp__plugin_che-zotero-mcp_zotero__zotero_search
- - mcp__plugin_che-zotero-mcp_zotero__zotero_search_by_doi
- - mcp__plugin_che-zotero-mcp_zotero__academic_search
- - mcp__plugin_che-zotero-mcp_zotero__academic_lookup_doi
- - mcp__plugin_che-zotero-mcp_zotero__academic_get_references
- - mcp__plugin_che-zotero-mcp_zotero__academic_get_citations
----
-
-# /ensemble-academic-review — 學術論文 Ensemble 審閱
-
-5 個 Claude teammates(學術審閱角色)+ 1 個 Codex(gpt-5.5)各自獨立審閱,合成比較表找共識和盲點。
-
-> **原理同 Ensemble OCR**:不同角色的錯誤模式不重疊。5 個 Claude 以不同學術審閱角度審閱且互相挑戰,Codex 提供跨模型盲驗。
-
-## 五個 reviewer 角色
-
-| 角色 | 任務 | 預設啟用 |
-|------|------|---------|
-| **methodology** | 研究設計、統計方法、推論邏輯 | ✅ 永遠 |
-| **writing** | 論述結構、學術語氣、APA、文法 | ✅ 永遠 |
-| **reference-verifier** | 用 zotero-mcp 逐一驗證引用文獻,抓幻覺文獻 | ✅ doc 內偵測到 References / Bibliography 區塊;可 `--no-references` 關閉 |
-| **number-verifier** | 用 R/Python 重跑原始計算 artifact,逐位驗證 doc 中每個數字 vs ground truth,抓幻覺數字 | ✅ 偵測到 `analysis/`、`data/`、`notebooks/`、`.ipynb`、`.Rmd` 或 doc 路徑旁有 `*.rds` / `*.csv`;可 `--no-numeric` 關閉 |
-| **devils-advocate** | 對抗性驗證;hybrid 輪看所有前輪結果,挑戰其他 reviewer 的 PASS/LOW 判決 | ✅ 永遠 |
-
-**何時可關掉 reference-verifier**:純技術筆記、計量作業、無學術引用之文件 → `--no-references`
-**何時可關掉 number-verifier**:純理論論文、無實證計算結果之文件 → `--no-numeric`
-
-兩者皆關 = 退化為 3 reviewer + Codex(保留核心 4 角色 + Codex)。
-
-## 四種模式
-
-| 模式 | 說明 | 適用情境 |
-|------|------|---------|
-| **independent**(預設) | 所有審閱者從零開始,不知道前輪結果 | 第一輪審閱、或想要完全獨立的第二意見 |
-| **hybrid** | 3 reviewer + Codex 獨立審閱,**只有 devil's advocate 看得到前輪結果** | 在前一輪基礎上挖更深,同時避免 anchoring bias |
-| **mix N** | 自動交替 independent → hybrid → independent → hybrid... 共 N 輪 | 最完整的審閱,每輪都是完整 ensemble,用 tasks 追蹤進度 |
-| **`--auto-iterate`**(v2.3.0+,#34) | round → fix → round 自治收斂迴圈,直到 Codex 標 `PERMANENT_CONVERGENCE` 或 `--max-rounds` 到上限 | 反覆審閱 + 修正直至 reviewer 全綠;適用稿件最終 polish |
-
-### mix N 的運作邏輯
-
-```
-mix 4 thesis.md
-│
-├── Round 1: independent — 全新獨立審閱
-│ → 產出 review-round-1.md
-│
-├── Round 2: hybrid — DA 看到 Round 1 結果,找盲點
-│ → 產出 review-round-2.md(標記 🆕 新發現)
-│
-├── Round 3: independent — 再一次全新獨立(不看 Round 1-2)
-│ → 產出 review-round-3.md
-│
-├── Round 4: hybrid — DA 看到 Round 1-3 所有結果,找盲點
-│ → 產出 review-round-4.md(標記 🆕 新發現)
-│
-└── Final: 合併所有輪次 → review-summary.md
- - 跨輪共識(多輪都指出)
- - 每輪獨有的新發現
- - 收斂趨勢(第 N 輪新發現數量遞減 = 審閱飽和)
-```
-
-**為什麼交替?**
-- independent 輪:不受前輪汙染,能從完全不同的角度發現新問題,也能驗證/修正前輪結論
-- hybrid 輪:devil's advocate 帶著所有前輪知識,專門挖前面所有輪次都沒發現的盲點
-- 交替進行:每一輪都有獨立發現的機會,也有針對性深挖的機會
-
-### hybrid 模式的資訊分配
-
-| 角色 | 看到什麼 | 為什麼 |
-|------|---------|--------|
-| methodology | 什麼都不看 | 避免 anchoring,獨立發現新問題 |
-| writing | 什麼都不看 | 同上 |
-| Codex | 什麼都不看 | 跨模型盲驗必須獨立 |
-| reference-verifier | 前輪的可疑文獻 watch list | 重點檢查 + 獨立全面查核 |
-| number-verifier | 什麼都不看(每輪都要從 ground-truth 重跑)| 防止前輪錯數抄來抄去 |
-| **devil's advocate** | **所有前輪的完整結果** | 專攻盲點、升/降級前輪判斷 |
-
-## 審閱架構
-
-```
-/ensemble-academic-review FILE [--mode independent|hybrid|mix] [--rounds N] [--no-numeric|--no-references] [--auto-iterate [--max-rounds N] [--converge-on VERDICT]]
-│
-├── Claude Team(最多 5 teammates)
-│ ├── methodology — 研究設計、統計方法(永遠獨立)
-│ ├── writing — 論述結構、學術語氣、APA(永遠獨立)
-│ ├── reference-verifier — 逐一查文獻(hybrid 時收到 watch list)— 可關
-│ ├── number-verifier — 逐一驗證數字 vs 原始計算 artifact(永遠獨立)— 可關
-│ └── devils-advocate — 反駁(hybrid 時看得到所有前輪結果)
-│
-└── Codex(gpt-5.5,永遠獨立)
-
-→ 每輪產出獨立的 review-round-{N}.md
-→ mix 模式最後合併所有輪次 → review-summary.md
-```
-
-## 執行流程
-
-### Phase 0: 解析輸入
-
-```
-Arguments:
- FILE — 要審閱的學術論文檔案(.md, .tex, .docx, .pdf, .ipynb, .Rmd)
- --mode — independent(預設)、hybrid、mix
- --rounds — mix 模式的輪數(預設 2)
- --prior — hybrid 模式的前輪摘要檔案(mix 模式自動管理)
- --focus — 審閱重點(可選)
- --no-numeric — 關閉 number-verifier(純理論論文、無實證計算)
- --no-references — 關閉 reference-verifier(純技術筆記、無學術引用)
- --auto-iterate — v2.3.0+,啟動自治 round → fix → round 收斂迴圈(見下方 § auto-iterate 模式)
- --max-rounds N — `--auto-iterate` 的上限,default 12,clamp [1, 30]
- --converge-on VERDICT — `--auto-iterate` 的停止條件,default `PERMANENT_CONVERGENCE`,
- 其他可選: `CONVERGED` (寬鬆 — 任一輪 Codex 給就停)
-
-如果沒有 FILE,問使用者。
-如果 --mode hybrid 但沒有 --prior,自動搜尋同目錄下的 review-round-*.md。
-如果是 .docx,用 che-word-mcp 的 get_document_text 讀取。
-如果是 .pdf,用 macdoc convert --to md 轉換後讀取。
-
-#### Auto-detect reviewer 啟用
-
-掃 FILE 同層及上層 1-2 級目錄:
-- 找到 `analysis/*.rds`、`data/*.csv`、`*.ipynb`、`output/*.npz`、`scripts/*.{R,py}` → number-verifier ON
-- doc 內含 `\bibliography{}`、`References` / `参考文献` 標題下 5+ 條引用 → reference-verifier ON
-- 兩者都沒:fallback 到 methodology+writing+devils-advocate(3 reviewer + Codex)
-
-使用者可用 `--no-numeric` / `--no-references` 強制關閉。
-```
-
-### Phase 0.5: Mix 模式的 Task 建立(僅 mix 模式)
-
-用 TaskCreate 建立所有輪次的 tasks,作為進度追蹤:
-
-```
-TaskCreate: "Round 1/N: independent review"
-TaskCreate: "Round 2/N: hybrid review"
-TaskCreate: "Round 3/N: independent review"
-...
-TaskCreate: "Final: merge all rounds"
-```
-
-每完成一輪就 TaskUpdate 為 completed,然後開始下一輪。
-**每一輪都是完整的 Phase 1-4 流程,不可偷工減料。**
-
-### Phase 1: 讀取文件 + 準備 context
-
-1. 讀取論文全文
-2. 提取所有引用文獻(References / Bibliography 區塊)
-3. 準備 context 字串,包含:檔案路徑、全文內容、文獻列表、ground-truth artifact 清單、focus 指示
-4. (hybrid 模式)讀取前輪結果,提取:
- - `prior_ref_issues` — 可疑/幻覺文獻清單(給 reference-verifier)
- - `prior_number_issues` — 可疑/幻覺數字清單(給 number-verifier)
- - `prior_full_report` — 所有前輪的完整結果(只給 devil's advocate)
-
-### Phase 2: 平行啟動 Claude Team + Codex
-
-**CRITICAL: 所有 tool calls(TeamCreate + Codex Bash)必須在同一個 message 送出。不可分步驟。**
-
-**啟用的 reviewer 數依設定變動**:預設 5(含 number+reference verifier),加 `--no-numeric` 變 4,再加 `--no-references` 變 3。Codex 永遠跑。一個 message 內 = (啟用 reviewer 數) Agent + 1 Bash。
-
-**CRITICAL: Teammates 必須用 `subagent_type: "general-purpose"`。不可用 `Explore`。**
-
-#### 2a. Claude Team(4 reviewers)
-
-用 TeamCreate 建立 team,然後在**同一個 message** 啟動 4 個 Agent + 1 個 Codex Bash(共 5 個 tool calls):
-
-```
-TeamCreate:
- name: "academic-review-{timestamp}-round{N}"
- description: "Academic review round {N} for {FILE}"
-```
-
-**Agent 1: methodology**
-```
-Agent:
- name: "methodology"
- subagent_type: "general-purpose"
- team_name: "academic-review-{timestamp}-round{N}"
- prompt: |
- 你是 Methodology Reviewer,專門審閱學術研究方法。
- 審閱論文:{FILE}
- {context}
-
- 你的任務:
- 1. 研究設計是否合理(實驗設計、對照組、隨機化)
- 2. 統計方法是否正確(假設檢定、效果量、信賴區間)
- 3. 樣本量是否足夠(power analysis)
- 4. 推論邏輯是否成立(因果 vs 相關、過度推論)
- 5. 研究限制是否充分討論
- 6. 分析流程是否可重現
-
- {focus_instruction}
-
- 用 Read 工具讀取論文相關段落確認。
- 用中文逐點列出問題和建議。每個問題標注嚴重性(HIGH/MEDIUM/LOW)。
- 最後給整體評價(一段話)。
-```
-
-**Agent 2: writing**
-```
-Agent:
- name: "writing"
- subagent_type: "general-purpose"
- team_name: "academic-review-{timestamp}-round{N}"
- prompt: |
- 你是 Writing Quality Reviewer,專門審閱學術寫作品質。
- 審閱論文:{FILE}
- {context}
-
- 你的任務:
- 1. 論述邏輯 — 各章節之間的銜接是否流暢
- 2. 段落結構 — 每段是否有明確的 topic sentence 和 supporting evidence
- 3. 學術語氣 — 是否適當使用 hedging language,避免過度武斷
- 4. APA 格式 — 引用格式、標題層級、圖表標註是否符合規範
- 5. 文法與用詞 — 英文文法錯誤、用詞精確度、一致性
- 6. Abstract 品質 — 是否完整涵蓋 background、method、results、conclusion
-
- 你可以使用 Skill tool 呼叫 perspective-writer 來分析特定段落的寫作風格。
-
- {focus_instruction}
-
- 用中文逐點列出問題和建議。每個問題標注嚴重性(HIGH/MEDIUM/LOW)。
- 引用具體段落或句子作為例證。
- 最後給整體評價(一段話)。
-```
-
-**Agent 3: reference-verifier**
-```
-Agent:
- name: "reference-verifier"
- subagent_type: "general-purpose"
- team_name: "academic-review-{timestamp}-round{N}"
- prompt: |
- 你是 Reference Verifier,專門驗證學術文獻的真實性。
- 審閱論文:{FILE}
- {context}
-
- 你的核心任務:**偵測幻覺文獻**(hallucinated references)。
-
- {hybrid_mode_ref_verifier_instruction}
-
- 步驟:
- 1. 從論文中提取所有引用文獻(作者、年份、標題、期刊)
- 2. 對每一筆文獻,使用 che-zotero-mcp 工具驗證:
- - 用 `academic_search` 搜尋標題或作者+年份
- - 如果有 DOI,用 `academic_lookup_doi` 驗證
- - 用 `zotero_search` 檢查是否已在 Zotero 資料庫中
- 3. 分類每筆文獻:
- - ✅ 已驗證(找到匹配的真實文獻)
- - ⚠️ 存疑(部分匹配,可能是資訊不完整)
- - ❌ 疑似幻覺(完全找不到,或作者/標題/年份不匹配)
- 4. 檢查 in-text citation 與 reference list 是否一致(有沒有引了但沒列、或列了但沒引)
-
- 輸出格式:
- ```
- ## 文獻驗證結果
-
- ### 已驗證 ✅
- 1. Author (Year). Title. — DOI: xxx ✅
-
- ### 存疑 ⚠️
- 1. Author (Year). Title. — 原因:找到類似文獻但年份不同
-
- ### 疑似幻覺 ❌
- 1. Author (Year). Title. — 原因:完全查無此文獻
-
- ### 引用一致性
- - 引了但沒列在 references:...
- - 列在 references 但文中未引用:...
- ```
-
- 每筆文獻都要查。不可跳過。
- 用中文輸出結果。
-```
-
-**Agent 4: number-verifier**(如未 `--no-numeric`)
-```
-Agent:
- name: "number-verifier"
- subagent_type: "general-purpose"
- team_name: "academic-review-{timestamp}-round{N}"
- prompt: |
- 你是 Number Verifier,專門驗證學術/實證文件中每一個數字 vs ground truth artifact。
- 審閱論文:{FILE}
- {context}
-
- 你的核心任務:**偵測幻覺數字**(hallucinated numbers)— tex/docx/md 中與原始計算不符的數值。
-
- {hybrid_mode_number_verifier_instruction}
-
- 步驟:
- 1. 識別 ground-truth 來源:
- - R 專案:`analysis/*.rds`、`*.RData`、`*.R` 腳本
- - Python 專案:`*.npz`、`*.csv`、`*.ipynb`、`*.py`
- - Excel/csv 原始資料:`*.xlsx`、`*.csv`
- 2. 從 doc 中提取每個數值(test stat、coef、p-value、AIC/BIC、forecast、平均、sd、t-stat、F、χ²、CI 等)
- 3. 對每個數字,找對應 ground-truth:
- - 直接讀 .rds:`Rscript -e 'x <- readRDS("..."); print(x$path$to$value)'`
- - 直接讀 .npz:`python -c 'import numpy as np; print(np.load("...")["k"])'`
- - 重跑腳本:`Rscript analysis/q1.R` 或 `python scripts/main.py`
- - 從原始資料重算:必要時自己跑 ADF / ARIMA / VAR / OLS
- 4. 分類每個數字:
- - ✅ 已驗證(與 ground truth 完全相符)
- - ⚠️ rounding(最後一位 ±1 可接受)
- - ❌ 幻覺數字(差量超過 rounding 容差)
- 5. 跨檔一致性:若有多版本(EN tex、ZH tex、DOCX),每個數字三檔一致嗎?
- 6. 內部一致性:tex 表格中的 forecast 是否真的等於 last_obs + cumulative diff?
-
- 輸出格式:
- ```
- ## 數字驗證結果
-
- ### ✅ 已驗證
- - ARIMA(1,1,0) coef 0.5564 — matches q1c.rds$fit$coef ✅
-
- ### ⚠️ rounding 偏差(last digit ±1)
- - log s_q[1] = -0.04723 vs rds -0.04724 (rounding) ⚠️
-
- ### ❌ 幻覺數字(必修)
- - tex line 52 寫 y_T=890569 — 實際 RGDPCAN.xlsx 末值 836072 ❌
- - tex line 200 寫 1-step σ̂=0.0207 — 實際 fc_se=0.0181(標籤錯)❌
-
- ### 三檔一致性(EN tex / ZH tex / DOCX)
- - 13 個 spot-check 全綠 ✅
- - 或:EN/ZH 一致但 DOCX 不同步 ❌
- ```
-
- 每個出現在 tex 中的數字都要查。不可只抽樣。
- HIGH count = 幻覺數字總數。MEDIUM = rounding-only。
- 用中文輸出結果,最後給一段 verdict。
-```
-
-**Agent 5: devils-advocate**
-```
-Agent:
- name: "devils-advocate"
- subagent_type: "general-purpose"
- team_name: "academic-review-{timestamp}-round{N}"
- prompt: |
- 你是 Devil's Advocate,學術審閱的對抗性驗證者。
- 審閱論文:{FILE}
- {context}
-
- 你的任務:等其他 3 個 reviewer(methodology、writing、reference-verifier)完成後,
- 用 SendMessage 詢問他們的結論,然後**試著反駁每一個「通過」或「LOW」的判斷**。
-
- {hybrid_mode_devils_advocate_instruction}
-
- 步驟:
- 1. 先用 Read 工具讀取論文,形成自己的理解
- 2. 用 SendMessage 分別問 methodology、writing、reference-verifier 他們的 findings
- 3. 對每個「通過」的判斷,找理由說它其實有問題
- 4. 對每個「LOW」的判斷,論證為什麼應該是 MEDIUM 或 HIGH
- 5. 特別挑戰:
- - methodology 說統計方法 OK → 找 alternative interpretation
- - writing 說邏輯清晰 → 找隱含的邏輯跳躍
- - reference-verifier 說文獻 OK → 質疑文獻的相關性和時效性
- 6. 如果你找不到反駁的理由,才承認確實通過
-
- 這是對抗性驗證 — 你的存在是為了防止群體盲點。
- 用中文輸出你的反駁結果。
-```
-
-#### Mode-specific prompt injections
-
-以下變數在 independent 輪為空字串,在 hybrid 輪注入內容:
-
-**`{hybrid_mode_ref_verifier_instruction}`** — 給 reference-verifier:
-```
-(hybrid 輪時注入)
-前幾輪審閱標記了以下可疑文獻,請特別留意:
-{prior_ref_issues}
-但你的核心任務仍然是逐一查核所有文獻,不要只看這份清單。
-前輪的判斷可能有誤,你需要獨立驗證。
-```
-
-**`{hybrid_mode_number_verifier_instruction}`** — 給 number-verifier:
-```
-(hybrid 輪時注入)
-注意:本作業已跑過至少一輪驗證;前輪 number-verifier 標記過的可疑數字:
-{prior_number_issues}
-但你的核心任務仍是逐一從 ground truth 重跑驗證所有數字,**不要只看這份清單**。
-前輪可能漏掉新出現或剛修進去的數字(修正常引入新錯)。
-```
-
-**`{hybrid_mode_devils_advocate_instruction}`** — 給 devil's advocate:
-```
-(hybrid 輪時注入)
-## 所有前輪審閱結果
-
-以下是前面所有輪次的 ensemble 審閱結果:
-{prior_full_report}
-
-你的額外任務(除了反駁本輪 reviewer 的判斷之外):
-1. **挑戰前輪「通過」的判斷** — 前輪認為 OK 或只給 LOW 的項目,是否有被低估的問題?
-2. **找出所有前輪的盲點** — 有什麼問題是前面所有輪次都沒想到的?
-3. **驗證前輪的結論** — 前輪的 HIGH 判斷是否真的那麼嚴重?有沒有過度反應的?
-4. **不要重複已知問題** — 前輪已經充分討論的問題不需要重新論述,除非你有新的反駁角度
-
-在輸出中,明確區分:
-- 「前輪已知 + 本輪確認」的問題
-- 「前輪已知但需要升級/降級」的問題
-- 「前輪完全未發現」的新問題 🆕
-```
-
-#### 2b. Codex(背景執行 — 直接 HTTP,繞過 codex CLI subprocess)
-
-```bash
-codex-call \
- --output "{output_file}" \
- --model gpt-5.5 \
- --effort xhigh \
- --service-tier fast \
- --max-time 900 \
- --instructions "你是嚴謹的學術論文審閱者,從 methodology、writing、reference 三個角度審閱。用中文輸出。" << 'EOF'
-{codex_prompt}
-EOF
-```
-
-> **為什麼不用 `codex exec`**:subprocess 偶爾會 hang(stdin/stdout pipe 互鎖、tty 問題),等 10 分鐘 timeout 才能繼續。`codex-call` 是 plugin 自帶 wrapper(`bin/codex-call`,Swift script,安裝時自動加入 PATH),直接 HTTP POST 到 `chatgpt.com/backend-api/codex/responses`,仍走你的 ChatGPT 訂閱 OAuth — 但 `--max-time` 是硬性保證,不會 hang。
->
-> **論文審閱用 max-time 900s**(15 分鐘),因為輸入長、reasoning 比 code review 重。Fast mode:傳 `--service-tier fast`,wrapper 內部翻譯成 `priority`(backend 拒絕字面 "fast",但接受 codex CLI 內部翻譯後的 `priority`)。
->
-> **OAuth token**:wrapper 自動讀 `~/.codex/auth.json`(codex CLI 的同一份),到期前 5 分鐘自動 refresh,用 file lock 避免 ensemble 平行 race。
-
-Codex prompt 應包含:
-- 論文全文(或摘要 + 關鍵段落,視長度而定)
-- 要求從 methodology、writing、reference 三個角度審閱
-- 用中文回答
-- **不提及 Claude team 的存在**(確保獨立性)
-
-### Phase 3: 收集結果
-
-1. 等待 4 個 Claude teammates 完成(透過自動訊息通知)
-2. 等待 Codex 完成(輪詢 status)
-3. 如果 Codex 失敗或超時(>10 分鐘),跳過,標注「Codex 不可用」
-
-### Phase 4: 合併去重 + 寫入本輪結果
-
-由主 session 的 Claude 讀取所有結果,產出本輪比較表:
-
-1. **去重**:相同問題 → 合併,標註來源
-2. **severity 以最高為準**
-3. **Devil's Advocate 的反駁如果成立** → 升級 severity
-4. **幻覺文獻特別標示** — reference-verifier 的 ❌ 結果優先級最高
-
-#### hybrid 輪額外步驟
-
-5. **與前輪交叉比對**:將本輪發現分為三類:
- - **前輪已知 + 本輪確認**:增加可信度
- - **前輪已知但本輪修正**:前輪判斷不夠精確
- - **本輪新發現 🆕**:前輪所有審閱者都未發現的問題
-
-#### 寫入本輪結果
-
-將本輪結果寫入 `review-round-{N}.md`(與論文同目錄),然後:
-- independent / hybrid 單輪模式:這就是最終輸出
-- mix 模式:TaskUpdate 標記本輪完成,繼續下一輪
-
-### Phase 5: Mix 模式的輪次循環
-
-```
-for round in 1..N:
- if round is odd:
- run Phase 1-4 as independent
- else:
- run Phase 1-4 as hybrid (prior = all previous rounds)
-
- TaskUpdate: "Round {round}/{N}" → completed
- Write review-round-{round}.md
-
-TaskUpdate: "Final: merge all rounds" → in_progress
-```
-
-### Phase 5b: `--auto-iterate` 模式的自治收斂迴圈(v2.3.0+, #34)
-
-`--auto-iterate` 是 `mix N` 的擴展,加上「每輪結束讀 Codex verdict + 自動 apply HIGH-severity fix + 自動 commit per round」的 round → fix → round 收斂迴圈。
-
-#### 啟動條件
-
-- User 傳 `--auto-iterate` flag
-- 不可與 `--mode independent` 或 `--mode hybrid` 同時使用 (auto-iterate 自含 mode 邏輯,內部沿用 mix 的 alternating independent/hybrid pattern)
-
-#### 主迴圈
-
-```
-N=1
-verdict=NEEDS_ITER_1
-focus_history=[]
-
-while N <= max_rounds:
- # 1. Run round (alternating: odd=independent, even=hybrid)
- mode = 'independent' if N is odd else 'hybrid'
- run Phase 1-4 with mode → review-round-{N}.md
-
- # 2. Parse Codex verdict
- verdict = extract_verdict(codex_output)
- # Look for PERMANENT_CONVERGENCE, CONVERGED, etc.
-
- # 3. Halt check
- if verdict == converge_on:
- break
-
- # 4. Apply HIGH-severity fixes
- high_findings = parse_findings(review-round-{N}.md, severity='HIGH')
- apply_fixes(high_findings) → working tree modified
-
- # 5. Auto-commit checkpoint
- git add -A
- git commit -m "iter-{N}: apply HIGH fixes from ensemble round {N}"
-
- # 6. Rotate focus heuristic (after K=3 same-focus CONVERGED)
- focus_history.append((current_focus, verdict))
- if last_3_verdicts_all_CONVERGED_with_same_focus(focus_history):
- current_focus = next_focus_in_pool()
- # focus pool: method-section, proofs, typography, cross-references, boundary-cases
-
- N += 1
-
-if N > max_rounds:
- log("Halted at max_rounds without reaching {converge_on}")
-```
-
-#### Verdict 解析 protocol
-
-Codex prompt 結尾必須含明確 instruction:
-
-```
-At the very end of your review, output exactly one structured verdict tag:
-
- NEEDS_ITER_{N} — issues remain, iterate again
- CONVERGED — review converged within current focus
- PERMANENT_CONVERGENCE — converged across all foci, paper-level done
-
-Choose conservatively. If unsure, NEEDS_ITER_{N}.
-```
-
-Skill 用 regex `([A-Z_0-9]+)` 從 Codex output 抓 tag。Robust 對 phrasing 變異;regex 容易 miss 「basically converged」近義詞,因此採結構化 tag。
-
-#### Apply-fixes protocol
-
-從 `review-round-{N}.md` 解出 HIGH-severity findings(MEDIUM/LOW 累積到最後一輪一次處理):
-
-```
-For each finding with severity=HIGH:
- parse 「file:line — issue description — suggested fix」
- Apply via Edit tool;若 fix 模糊或 suggestion 帶推測,skip + log to {SESSION}/skipped_fixes.log
-```
-
-跳過 ambiguous fix 而非硬套,避免 reviewer suggestion 自身錯誤被放大。
-
-#### Backup / rollback
-
-每輪結束 auto-commit `iter-{N}: apply HIGH fixes from ensemble round {N}`。User 可隨時:
-
-```bash
-git log --oneline | grep 'iter-' # 列所有迭代 checkpoint
-git revert iter-{N} # 回退某輪
-git reset --hard iter-{N-1} # hard reset 到前一輪
-```
-
-#### Rotate-focus heuristic
-
-如連續 K=3 輪同一 focus 都 CONVERGED 但未 PERMANENT_CONVERGENCE → 自動 switch focus 避免 local optimum。Focus pool:
-
-| Focus | 描述 |
-|-------|------|
-| `method-section` | 統計方法、研究設計 |
-| `proofs` | 數學證明、推導 |
-| `typography` | 排版、引用、bibliography |
-| `cross-references` | 交叉引用、ToC、bookmarks |
-| `boundary-cases` | edge case、退化情境 |
-
-Default 起始 focus = (none) — 不設,讓 reviewer 自主探;同一 focus 重複 CONVERGED 才強制 rotate。
-
-#### 與 ralph-loop 的差別
-
-`--auto-iterate` 是 **self-contained Bash while + state machine**,不依賴 ralph-loop 的 Stop-hook re-feed。Mode boundary 明確,可隨時中止 (`Ctrl+C` 在 round 之間生效);ralph-loop 把整個 session 鎖進迴圈,容易意外干擾其他 skill。
-
-若 user 同時跑 `ralph-loop` + `--auto-iterate`,skill 偵測 ralph-loop active 會印警告。
-
-#### Default 上限與 cost 警示
-
-- `--max-rounds` default 12,max 30
-- 每輪約 5 reviewer + Codex ≈ 6 LLM call;30 rounds × 6 ≈ 180 call
-- Skill prompt 會提示預估 token cost 並要求 confirm 才開跑
-
-### Phase 6: 最終合併(mix 模式)
-
-讀取所有 `review-round-*.md`,產出最終的 `review-summary.md`:
-
-```markdown
-## Ensemble Academic Review: {FILE}
-## Mode: mix {N} rounds
-
-### 審閱歷程
-| 輪次 | 模式 | 新發現數 | 累計問題數 |
-|------|------|---------|-----------|
-| Round 1 | independent | 15 | 15 |
-| Round 2 | hybrid | 8 🆕 | 23 |
-| Round 3 | independent | 4 | 27 |
-| Round 4 | hybrid | 1 🆕 | 28 |
-
-### 收斂判斷
-新發現數逐輪遞減(15 → 8 → 4 → 1),審閱已趨近飽和。
-
-### 跨輪共識(多輪都獨立指出)
-| # | 問題 | 出現輪次 | 嚴重性 |
-|---|------|---------|--------|
-| 1 | ... | R1, R2, R3 | HIGH |
-
-### 僅單輪發現
-| # | 問題 | 首次出現 | 嚴重性 | 後續輪次確認? |
-|---|------|---------|--------|--------------|
-| 1 | ... | R2 🆕 | HIGH | R3 確認 |
-| 2 | ... | R4 🆕 | MEDIUM | 未再驗證 |
-
-### 文獻驗證(取最完整的一輪)
-...
-
-### 建議修改優先順序
-...
-```
-
-### Phase 7: 詢問下一步
-
-```
-審閱完成({mode}, {N} 輪)。
-新發現趨勢:{round1_new} → {round2_new} → ... → {roundN_new}
-{收斂判斷}
-
-要怎麼做?
-1. 修正幻覺文獻和 HIGH 問題
-2. 只看不改(純審閱)
-3. 針對特定問題深入討論
-4. 用 /perspective-writer 改寫特定段落
-5. 再跑一輪(如果新發現數未收斂)
-```
-
-## 鐵律
-
-### 所有模式共用
-
-- **所有 tool calls 在同一個 message 送出**(N Agent + 1 Bash codex;N ∈ {3,4,5} 視啟用設定)。不可分步驟。
-- **Codex 看不到 Claude Team 的討論**。完全獨立的盲驗。
-- **Codex 的審稿結果原封不動呈現**,不要修改或摘要。
-- **reference-verifier 必須逐一查每筆文獻**。不可跳過或抽樣。
-- **number-verifier 必須對每個出現在 doc 中的數字查 ground truth**。不可只抽樣。
-- **幻覺文獻、幻覺數字皆最高優先級**。任何 ❌ 結果都是 HIGH severity。
-- **共識問題 > 單方問題**:多個來源都指出的問題最需要修。
-- **衝突不自動裁決**:呈現給使用者判斷。
-- **Devil's Advocate 是必要的**。防止群體盲點。
-
-### hybrid 輪專屬
-
-- **methodology、writing、Codex 絕對不看前輪結果**。防止 anchoring bias。
-- **只有 devil's advocate 拿到所有前輪完整結果**。
-- **reference-verifier 與 number-verifier 只拿到 watch list**,不是完整判斷。仍須獨立全面查核(從 ground truth 重跑)。
-- **合併時必須標記 🆕 新發現**。
-
-### mix 模式專屬
-
-- **每一輪都是完整的 Phase 1-4**。不可偷工減料、跳過 Codex、或減少 reviewer。
-- **用 TaskCreate/TaskUpdate 追蹤每輪進度**。讓使用者看到即時狀態。
-- **每輪結果獨立寫入 `review-round-{N}.md`**。不可覆蓋前輪。
-- **最終合併必須包含「收斂判斷」**:新發現數是否遞減。如果最後一輪仍有大量新發現,建議使用者再跑一輪。
-- **前輪結論可以被後輪推翻**。independent 輪的獨立審閱者如果得出不同結論,標記衝突供使用者判斷。
-
-### `--auto-iterate` 模式專屬(v2.3.0+)
-
-- **不可在 `--mode independent|hybrid` 上同時開**;mode 自含 alternating logic
-- **每輪 auto-commit `iter-{N}` checkpoint**,user 可隨時 git revert 回退
-- **HIGH-only fix application**;MEDIUM/LOW 累積到最後一輪一次處理(降低 round-to-round 雜訊)
-- **Ambiguous fix 一律 skip + log to `skipped_fixes.log`**,寧少做不錯做
-- **`...` tag 必填**;Codex prompt 結尾強制要求,parsing 用結構化 regex 不靠語意
-- **rotate-focus 在 K=3 同 focus CONVERGED 才觸發**;新 focus 從 pool 順序輪換
-- **`max_rounds` 上限 30**;達上限 halt 並報告未達 verdict 條件
-- **同時跑 ralph-loop + `--auto-iterate` 時 skill 警告**(雙 Stop-hook 衝突風險)
-
-## 8 個 cumulative methodological lessons (v2.3.0+, from real 23-round campaign)
-
-來源:`PsychQuantHsu/psychophysic_representations_manuscript/docs/rounds/INDEX.md`。可作 `--auto-iterate` 模式 review 中的「常踩坑」清單,Codex prompt 可選擇性 inject 部分 lessons 加強 detection。
-
-1. **Light-weight spot-check 容易 false-positive CONVERGED** — 至少跑滿 3 reviewer + Codex 才能 trust verdict
-2. **Theorem counter shared across `\newtheorem{lemma}[theorem]` = printing off-by-one** — 必查 LaTeX counter 結構
-3. **Hypothesis silently inherited across theorems** — 在某 theorem 加的 condition 可能影響後續 theorem,需明示「not inherited by Theorem N」
-4. **Stress-test on rare-audited sections (§Notation, §Discussion) 抓得到 11+ NEW HIGH** — 建議 rotate-focus 時主動進這些區
-5. **Codex `gpt-5.5 xhigh` 比 4-Claude consensus 嚴格** — 4-Claude 全 PASS 不等於 Codex 也 PASS
-6. **PDF Token warnings (hyperref) 是真 bug 不是 cosmetic** — silent 不 fix 會在 ToC/bookmarks 失敗
-7. **degenerate counter-example 必查** — 「u≡0」「g(z)=z²-1」這類 counter 應在 case-taxonomy 之內排除
-8. **CONVERGED ≠ PERMANENT_CONVERGENCE** — 前者是 scope-limited 的「目前 focus 沒抓到新東西」,後者是 cross-focus 全綠;只接受後者作 halt verdict 是 default 設計
diff --git a/plugins/parallel-ai-agents/skills/ensemble-code-review/SKILL.md b/plugins/parallel-ai-agents/skills/ensemble-code-review/SKILL.md
deleted file mode 100644
index 6708241..0000000
--- a/plugins/parallel-ai-agents/skills/ensemble-code-review/SKILL.md
+++ /dev/null
@@ -1,322 +0,0 @@
----
-name: ensemble-code-review
-description: |
- Claude + Codex 雙 AI 獨立審閱程式碼,交叉比對找共識和盲點。
- 4 Claude teammates(architecture, correctness, security, devils-advocate)+ Codex GPT-5.5 獨立審一遍,最後合成比較表。
- Use when: 程式碼、技術文件、設計文件發布前需要嚴格審閱。
-argument-hint: "FILE_OR_DIR [--focus 'review focus'] e.g. 'src/auth/', 'packages/ocr-swift/ --focus API正確性'"
-allowed-tools:
- - Read
- - Write
- - Edit
- - Bash
- - Grep
- - Glob
- - Agent
- - TeamCreate
- - SendMessage
- - TaskCreate
- - TaskUpdate
- - TaskList
- - TaskGet
- - AskUserQuestion
----
-
-# /ensemble-review — Orchestrated Team + Codex 交叉審閱
-
-4 個 Claude teammates(orchestrated team)+ 1 個 Codex(gpt-5.5)各自獨立審閱,合成比較表找出共識和盲點。
-
-> **原理同 Ensemble OCR**:不同模型、不同角色的錯誤模式不重疊。4 個 Claude 以不同專業角度審閱且互相挑戰,Codex 提供跨模型盲驗。
-
-## 審閱架構
-
-```
-/ensemble-review FILE_OR_DIR
-│
-├── Claude Team(4 teammates,互相挑戰)
-│ ├── architecture — 設計模式、API 用法、依賴關係、全局合理性
-│ ├── correctness — 邏輯正確性、bug、edge case、型別安全
-│ ├── security — injection、secrets、權限、輸入驗證(攻擊者視角)
-│ └── devils-advocate — 讀前 3 人結論,反駁「通過」判斷
-│
-└── Codex(gpt-5.5,完全獨立 process,跨模型盲驗)
-
-→ 5 份 findings 合併去重 → 比較表
-```
-
-**為什麼 5 個?**
-- 4 個 Claude teammates 在同一個 team 裡**互相挑戰**(不是各自獨立報告)
-- Devil's Advocate 的工作是**試著證明其他 3 個的通過判斷是錯的**
-- Codex 是完全不同的模型家族(gpt-5.5),提供**跨模型盲驗**
-
-## 執行流程
-
-### Phase 0: 解析輸入
-
-```
-Arguments:
- FILE_OR_DIR — 要審閱的檔案或目錄路徑
- --focus — 審閱重點(可選,如「API正確性」「技術準確性」「安全性」)
-
-如果沒有 FILE_OR_DIR,問使用者。
-如果 FILE_OR_DIR 是目錄,讀取所有原始碼檔案作為審閱範圍。
-```
-
-### Phase 1: 讀取文件 + 準備 context
-
-1. 讀取目標文件(如果是目錄,列出所有檔案路徑和內容摘要)
-2. 自動判斷審閱類型:
-
-| 檔案類型 | 審閱重點 |
-|---------|---------|
-| `.md` blog/文章 | 技術準確性、邏輯一致性、聲明可驗證性 |
-| `.md` 設計文件 | 架構合理性、邊界情況、可行性、遺漏 |
-| `.swift` / `.py` / `.ts` 程式碼 | bug、安全漏洞、效能、API 用法、edge case |
-| 目錄(整個 package) | 架構、死碼、API 一致性、依賴管理 |
-
-3. 準備 context 字串,包含:檔案路徑、內容、focus 指示
-
-### Phase 2: 平行啟動 Claude Team + Codex
-
-**CRITICAL: 所有 tool calls(TeamCreate + Codex Bash)必須在同一個 message 送出。不可分步驟。**
-
-**CRITICAL: Teammates 必須用 `subagent_type: "general-purpose"`。不可用 `Explore`(Explore 不會主動 SendMessage 回報結果,會直接 idle)。**
-
-#### 2a. Claude Team(4 reviewers)
-
-用 TeamCreate 建立 team,然後用 Agent 啟動 4 個 teammates:
-
-```
-TeamCreate:
- name: "ensemble-review-{timestamp}"
- description: "Ensemble review for {FILE_OR_DIR}"
-```
-
-然後在**同一個 message** 啟動 4 個 Agent + 1 個 Codex Bash(共 5 個 tool calls):
-
-**Agent 1: architecture**
-```
-Agent:
- name: "architecture"
- subagent_type: "general-purpose"
- team_name: "ensemble-review-{timestamp}"
- subagent_type: "general-purpose"
- prompt: |
- 你是 Architecture Reviewer。
- 審閱範圍:{FILE_OR_DIR}
- {context}
-
- 你的任務:
- 1. 設計模式是否正確(protocol 使用、抽象層級)
- 2. API 用法是否符合上游框架的推薦方式
- 3. 依賴關係是否合理(有沒有多餘或缺少的)
- 4. 檔案組織是否清晰
- 5. 有沒有死碼或重複實作
-
- {focus_instruction}
-
- 用 Read/Grep/Glob 工具實際去看相關檔案確認。
- 用中文逐點列出問題和建議。每個問題標注嚴重性(HIGH/MEDIUM/LOW)。
- 最後給整體評價(一段話)。
-```
-
-**Agent 2: correctness**
-```
-Agent:
- name: "correctness"
- subagent_type: "general-purpose"
- team_name: "ensemble-review-{timestamp}"
- subagent_type: "general-purpose"
- prompt: |
- 你是 Correctness Reviewer。
- 審閱範圍:{FILE_OR_DIR}
- {context}
-
- 你的任務:
- 1. 邏輯正確性 — 有沒有 bug
- 2. Edge cases — null、empty、boundary values
- 3. 型別安全 — 隱式轉換、optional handling
- 4. 控制流程 — if/else 覆蓋、switch fall-through
- 5. 錯誤處理 — 有沒有漏接的 error
-
- {focus_instruction}
-
- 用 Read 工具查看完整函數上下文。
- 用中文逐點列出問題和建議。每個問題標注嚴重性(HIGH/MEDIUM/LOW)。
- 最後給整體評價(一段話)。
-```
-
-**Agent 3: security**
-```
-Agent:
- name: "security"
- subagent_type: "general-purpose"
- team_name: "ensemble-review-{timestamp}"
- subagent_type: "general-purpose"
- prompt: |
- 你是 Security Reviewer,以攻擊者視角審閱。
- 審閱範圍:{FILE_OR_DIR}
- {context}
-
- 你的任務:
- 1. Injection 風險(SQL、command、path traversal)
- 2. Hardcoded secrets(API keys、passwords、tokens)
- 3. 權限檢查(有沒有繞過的可能)
- 4. 輸入驗證(external data 是否被信任)
- 5. 敏感資訊洩漏(error message、log)
-
- {focus_instruction}
-
- 用 Grep 搜尋可疑模式(hardcoded strings、eval、exec 等)。
- 用中文逐點列出問題和建議。每個問題標注嚴重性(HIGH/MEDIUM/LOW)。
- 最後給整體評價(一段話)。
-```
-
-**Agent 4: devils-advocate**
-```
-Agent:
- name: "devils-advocate"
- subagent_type: "general-purpose"
- team_name: "ensemble-review-{timestamp}"
- subagent_type: "general-purpose"
- prompt: |
- 你是 Devil's Advocate。
- 審閱範圍:{FILE_OR_DIR}
- {context}
-
- 你的任務:等其他 3 個 reviewer(architecture、correctness、security)完成後,
- 用 SendMessage 詢問他們的結論,然後**試著反駁每一個「通過」或「LOW」的判斷**。
-
- 步驟:
- 1. 用 SendMessage 分別問 architecture、correctness、security 他們的 findings
- 2. 對每個「通過」的判斷,找理由說它其實有問題
- 3. 對每個「LOW」的判斷,論證為什麼應該是 MEDIUM 或 HIGH
- 4. 如果你找不到反駁的理由,才承認確實通過
-
- 這是對抗性驗證 — 你的存在是為了防止群體盲點。
- 用中文輸出你的反駁結果。
-```
-
-#### 2b. Codex(背景執行 — 直接 HTTP,繞過 codex CLI subprocess)
-
-```bash
-codex-call \
- --output "{output_file}" \
- --model gpt-5.5 \
- --effort xhigh \
- --service-tier fast \
- --max-time 600 \
- --instructions "你是嚴謹的程式碼審閱者,用中文輸出。" << 'EOF'
-{codex_prompt}
-EOF
-```
-
-> **為什麼不用 `codex exec`**:subprocess 偶爾會 hang(stdin/stdout pipe 互鎖、tty 問題),等 10 分鐘 timeout 才能繼續。`codex-call` 是 plugin 自帶 wrapper(`bin/codex-call`,Swift script,安裝時自動加入 PATH),直接 HTTP POST 到 `chatgpt.com/backend-api/codex/responses`,仍走你的 ChatGPT 訂閱 OAuth — 但 `--max-time` 是硬性保證,不會 hang。
->
-> **Fast mode**:傳 `--service-tier fast`,wrapper 內部會翻譯成 backend 接受的 `priority`(codex CLI 內部也是這樣翻譯)。Fast = 1.5× 速度、2.5× credit(gpt-5.5);ensemble 場景值得,因為 user 在等。
->
-> **OAuth token**:wrapper 自動讀 `~/.codex/auth.json`(codex CLI 的同一份),到期前 5 分鐘自動 refresh,用 file lock 避免 ensemble 平行 race。
-
-Codex prompt 應包含:
-- 審閱範圍和 focus
-- 要求逐點分析,標注嚴重性
-- 用中文回答
-- **不提及 Claude team 的存在**(確保獨立性)
-
-### Phase 3: 收集結果
-
-1. 等待 4 個 Claude teammates 完成(透過自動訊息通知)
-2. 等待 Codex 完成(輪詢 status)
-3. 如果 Codex 失敗或超時(>10 分鐘),跳過,標注「Codex 不可用」
-
-`codex-call` 完成後輸出會寫入 `--output` 指定的檔案,直接用 Read 讀取即可。
-
-### Phase 4: 合併去重 + 交叉比對
-
-由主 session 的 Claude 讀取所有結果,產出比較表:
-
-1. **去重**:相同檔案 + 相似描述 → 合併,標註來源 `[team:architecture+codex]`
-2. **severity 以最高為準**:如果 correctness 說 MEDIUM 但 codex 說 HIGH → HIGH
-3. **Devil's Advocate 的反駁如果成立** → 升級 severity
-
-輸出格式:
-
-```markdown
-## Ensemble Review: {FILE_OR_DIR}
-
-### 審閱者
-- **Claude Team**: architecture, correctness, security, devils-advocate(orchestrated)
-- **Codex GPT-5.5**: 獨立盲驗
-
-### 共識(≥2 個來源都指出)
-| # | 問題 | 嚴重性 | 來源 | 說明 |
-|---|------|--------|------|------|
-| 1 | ... | HIGH | team:arch+correct+codex | ... |
-
-### 僅 Claude Team 指出
-| # | 問題 | 嚴重性 | 來源 | 說明 |
-|---|------|--------|------|------|
-| 1 | ... | ... | team:security | ... |
-
-### 僅 Codex 指出
-| # | 問題 | 嚴重性 | 說明 |
-|---|------|--------|------|
-| 1 | ... | ... | ... |
-
-### Devil's Advocate 反駁結果
-| # | 原始判斷 | 反駁 | 成立? |
-|---|---------|------|--------|
-| 1 | correctness: LOW | 「其實是 MEDIUM 因為...」 | ✅ 升級 |
-| 2 | security: 通過 | 「未能反駁」 | ❌ 維持 |
-
-### 衝突(來源間意見矛盾)
-| # | 議題 | Claude Team | Codex | 建議 |
-|---|------|------------|-------|------|
-| 1 | ... | ... | ... | 交由使用者判斷 |
-
-### Summary
-- 共識問題: N 個(最需要修)
-- 僅 Claude Team: M 個
-- 僅 Codex: K 個
-- Devil's Advocate 升級: L 個
-- 衝突: J 個
-
-### 建議修改優先順序
-1. {highest priority fix}
-2. ...
-```
-
-### Phase 5: 詢問下一步
-
-```
-審閱完成。要怎麼做?
-1. 根據共識問題修改文件
-2. 只看不改(純審閱)
-3. 針對特定問題深入討論
-```
-
-## Codex CLI 參考
-
-```bash
-# companion script 路徑(優先 marketplace,fallback cache)
-CODEX_SCRIPT="$HOME/.claude/plugins/marketplaces/openai-codex/plugins/codex/scripts/codex-companion.mjs"
-
-# 啟動 task
-node "$CODEX_SCRIPT" task --effort high "prompt"
-
-# 查狀態
-node "$CODEX_SCRIPT" status --all
-
-# 取結果
-node "$CODEX_SCRIPT" result $JOB_ID
-```
-
-## 鐵律
-
-- **5 個 tool calls 在同一個 message 送出**(4 Agent + 1 Bash codex)。不可分步驟。
-- **Codex 看不到 Claude Team 的討論**。它是完全獨立的盲驗。
-- **Codex 的審稿結果原封不動呈現**,不要修改或摘要。
-- **交叉比對由主 session 的 Claude 做**,因為主 session 有完整 context。
-- **共識問題 > 單方問題**:多個來源都指出的問題最需要修。
-- **衝突不自動裁決**:呈現給使用者判斷。
-- **Devil's Advocate 是必要的**。防止 3 個 reviewer 的群體盲點。
diff --git a/plugins/parallel-ai-agents/skills/ensemble-lecture-review/SKILL.md b/plugins/parallel-ai-agents/skills/ensemble-lecture-review/SKILL.md
deleted file mode 100644
index 31dbafb..0000000
--- a/plugins/parallel-ai-agents/skills/ensemble-lecture-review/SKILL.md
+++ /dev/null
@@ -1,209 +0,0 @@
----
-name: ensemble-lecture-review
-description: |
- 教學講義 Ensemble 審閱:4 個 Claude teammates(教學審閱角色)各自獨立審閱講義品質。
- 當用戶提到「review 講義」「審閱講義」「講義品質」「lecture review」時使用。
-argument-hint: "[講義 HTML 路徑] [--srt 對應逐字稿路徑]"
----
-
-# /ensemble-lecture-review — 教學講義 Ensemble 審閱
-
-4 個 Claude teammates 各自獨立審閱講義,合成比較表找共識和盲點。
-
-> **與 ensemble-academic-review 的差異**:角色從「學術論文審閱」改為「教學材料審閱」。不查文獻真偽,改查逐字稿覆蓋率。
-
-## 審閱架構
-
-```
-/ensemble-lecture-review lecture.html [--srt transcript.srt]
-│
-├── Claude Team(4 teammates)
-│ ├── content-accuracy — 內容正確性(統計、理論、公式)
-│ ├── student-readability — 學生可讀性(白話程度、邏輯銜接)
-│ ├── completeness — 完整性(對照逐字稿找遺漏)
-│ └── devils-advocate — 反駁前三個的判斷
-│
-└── 比較表 + 修改建議
-```
-
-## 執行流程
-
-### Phase 0: 解析輸入
-
-```
-Arguments:
- FILE — 講義 HTML 檔案路徑
- --srt — 對應的 SRT 逐字稿(可選,completeness reviewer 會用)
-
-如果沒有 FILE,掃描 handout 目錄列出所有講義讓用戶選。
-如果沒有 --srt,嘗試從 lectures/ 目錄自動匹配。
-```
-
-### Phase 1: 讀取文件 + 準備 context
-
-1. 讀取講義 HTML 全文
-2. 如果有 SRT,讀取逐字稿全文
-3. 讀取 teaching.json(了解學生背景)
-4. 準備 context 字串
-
-### Phase 2: 平行啟動 4 個 Claude Teammates
-
-**CRITICAL: 所有 4 個 Agent tool calls 必須在同一個 message 送出。**
-
-**CRITICAL: Teammates 必須用 `subagent_type: "general-purpose"`。**
-
-用 TeamCreate 建立 team,然後在同一個 message 啟動 4 個 Agent:
-
-#### Agent 1: content-accuracy
-
-```
-你是 Content Accuracy Reviewer,專門檢查教學講義的知識正確性。
-審閱講義:{FILE}
-{context}
-
-學生背景:{student_info}
-
-你的任務:
-1. **統計概念**:定義是否正確(p-value、power、effect size、confidence interval)
-2. **公式**:數學符號有沒有寫錯(KaTeX 語法是否正確)
-3. **理論解釋**:心理學理論的描述是否準確(Higgins, Regulatory Focus/Fit)
-4. **因果推論**:有沒有把相關說成因果、或過度推論
-5. **術語一致性**:同一個概念在不同地方是否用同一個名稱
-6. **範例正確性**:舉的例子是否恰當地支持概念
-
-用 Read 工具讀取講義確認。
-逐點列出問題,每個標注嚴重性(HIGH/MEDIUM/LOW)。
-引用具體的段落或句子。
-```
-
-#### Agent 2: student-readability
-
-```
-你是 Student Readability Reviewer,從學生的角度審閱講義的易懂程度。
-審閱講義:{FILE}
-{context}
-
-學生背景:{student_info}(注意:學生零程式基礎,概念理解可能表面化)
-
-你的任務:
-1. **白話程度**:有沒有用了專業術語但沒解釋的地方
-2. **邏輯銜接**:段落之間的跳躍是否太大(學生能不能跟上)
-3. **具體例子**:抽象概念有沒有搭配具體例子
-4. **視覺輔助**:表格、圖表是否幫助理解(還是增加混淆)
-5. **篇幅平衡**:重要概念是否得到足夠篇幅(vs 次要內容佔太多)
-6. **結構導航**:學生能不能快速找到想看的段落(標題是否清楚)
-7. **前後呼應**:「重點整理」是否真的涵蓋了最重要的內容
-
-用 Read 工具讀取講義。
-站在學生的角度思考:「如果我是零基礎的學生,讀到這裡我會卡住嗎?」
-逐點列出問題,每個標注嚴重性(HIGH/MEDIUM/LOW)。
-```
-
-#### Agent 3: completeness
-
-```
-你是 Completeness Reviewer,檢查講義是否完整覆蓋了上課教的內容。
-審閱講義:{FILE}
-{context}
-
-{srt_instruction}
-
-你的任務:
-1. **逐字稿覆蓋率**:逐字稿裡有教但講義沒寫到的重點(最重要)
-2. **結構完整性**:
- - 有沒有「重點整理」section
- - 有沒有「課後作業」section
- - h2/h3 層級是否正確(沒有孤立的 h3)
- - h2 之間有沒有 --- 分隔
-3. **KaTeX/Mermaid**:有數學符號的地方有沒有加 KaTeX CDN?有路徑圖的地方有沒有用 Mermaid 或 ASCII art?
-4. **連結有效性**:href 指向的檔案是否存在
-5. **缺少的教學元素**:
- - 有沒有該有 blockquote 提醒但沒有的地方
- - 有沒有該用表格對比但只用文字描述的地方
-
-如果有 SRT,分段讀(每次 200 行),逐段對照講義找遺漏。
-沒有 SRT 就只做結構完整性檢查。
-逐點列出問題,每個標注嚴重性(HIGH/MEDIUM/LOW)。
-```
-
-SRT instruction(有 SRT 時注入):
-```
-逐字稿路徑:{SRT_PATH}
-請用 Read 工具分段讀取逐字稿(每次 200 行),逐段對照講義。
-如果逐字稿裡有教學重點但講義沒寫到,標記為 HIGH。
-```
-
-#### Agent 4: devils-advocate
-
-```
-你是 Devil's Advocate,教學講義審閱的對抗性驗證者。
-審閱講義:{FILE}
-{context}
-
-你的任務:等其他 3 個 reviewer 完成後,用 SendMessage 詢問他們的結論,
-然後試著反駁每一個「通過」或「LOW」的判斷。
-
-步驟:
-1. 先用 Read 工具讀取講義,形成自己的理解
-2. 用 SendMessage 分別問 content-accuracy、student-readability、completeness 他們的 findings
-3. 對每個「通過」的判斷,找理由說它其實有問題:
- - content-accuracy 說概念正確 → 找邊界情況或過度簡化
- - student-readability 說易懂 → 找可能讓特定背景學生困惑的地方
- - completeness 說完整 → 找隱含的教學目標是否達成
-4. 特別挑戰:
- - 「重點整理」是否真的是重點,還是只是把小標題抄了一遍
- - 表格是否真的幫助理解,還是增加認知負擔
- - 課後作業是否可執行,學生知不知道具體要做什麼
-5. 如果找不到反駁的理由,才承認確實通過
-
-用中文輸出反駁結果。
-```
-
-### Phase 3: 收集結果
-
-等待 4 個 teammates 完成(透過自動訊息通知)。
-
-### Phase 4: 合併去重
-
-由主 session 的 Claude 讀取所有結果,產出比較表:
-
-```markdown
-## Ensemble Lecture Review: {FILE}
-
-### 比較表
-| # | 問題 | 嚴重性 | 來源 | 位置 |
-|---|------|--------|------|------|
-| 1 | Power 的定義缺少直覺解釋 | HIGH | content-accuracy, student-readability | 統計概念 section |
-| 2 | h3 「OpenClaw」沒有 h2 父層 | HIGH | completeness | AI 工具比較 section |
-| 3 | ... | ... | ... | ... |
-
-### 共識問題(多個 reviewer 都指出)
-...
-
-### Devil's Advocate 升級的問題
-...
-
-### 統計
-- content-accuracy: N 個問題(H: x, M: y, L: z)
-- student-readability: N 個問題
-- completeness: N 個問題
-- devils-advocate 升級: N 個
-```
-
-### Phase 5: 詢問下一步
-
-```
-審閱完成。要怎麼做?
-1. 修正 HIGH 問題
-2. 只看不改
-3. 針對特定問題深入討論
-4. 用 /teaching-toolkit:lecture-enrich 充實講義
-```
-
-## 鐵律
-
-- **4 個 tool calls 在同一個 message 送出**。不可分步驟。
-- **completeness reviewer 必須讀逐字稿**(如果有提供)。不可跳過。
-- **共識問題 > 單方問題**:多個 reviewer 都指出的問題最需要修。
-- **Devil's Advocate 是必要的**。防止群體盲點。
-- **考慮學生背景**:所有 reviewer 都要知道學生的程度和目標。