這份記錄「怎麼跑掃描、花多少、踩過什麼坑」,讓後續批次不必重新摸索。
Claude Code 官方 plugin claude-security@claude-plugins-official v0.10.2.3。
啟動方式是 /claude-security 開選單,選 Scan codebase。 它實際跑的是 claude-security:scan workflow,會派出一群 subagent 分工。
第一批用的參數:
| 項目 | 值 |
|---|---|
| 掃描根目錄 | ~/Projects/Jedicogy/module/jedi-python-package |
| scope | jedi-common,jedi-iam(453 個 tracked 檔) |
| effort | medium |
| focus | attack-surface(tests/dist/docs 只當背景參考,不當稽核目標) |
這是踩坑重點。四個等級的差別全在研究階段派多少 agent,驗證面板固定三人。
| 等級 | 研究規模 | 實際 agent 數(約) |
|---|---|---|
| low | 單一 researcher 掃完整個 scope | 5 到 6 |
| medium | 每個「元件 × 弱點類別」各一位,再加一輪 breadth sweep | 40 以上 |
| high | 每格兩位、兩輪 sweep、更細的元件切分 | 80 以上 |
| max | high 再加紅隊逐條反駁 | 更多 |
medium 為什麼這麼貴:它先把套件切成 N 個元件,然後展開成矩陣派工。 每個 agent 都從零開始讀檔、沒有共用 context,所以同一支 ldap_adapter.py 被至少 8 個 researcher 各讀了一遍——這也是為什麼 32 筆原始發現去重後只剩 19 條。 重複的發現就是重複的 token。
再加上 researcher 與 verifier 的設定是 effort: xhigh、model: inherit, 等於一百多次前沿模型的高強度推理。
第一輪 medium:跑約 40 分鐘,派出 40 個 agent,研究階段收到 32 筆候選發現。 因為成本明顯失控,在面板驗證開始前手動停掉。 這 32 筆就是 batch1 清單的來源,屬未驗證的原始宣稱。
第二輪 low(只掃 jedi-iam):想驗證 low 是否真的便宜。 確實只派了 2 個 researcher(一個主掃、一個 secrets pass), 但跑了 2 小時 15 分後全部 agent 因 session 額度用盡而失敗,零產出。 工具重試了 4 次都撞同一道牆。
resumeFromRunId 續跑, 續不回去也還能從磁碟撈回已完成的部分。做法見下段。掃描中止時,正式報告與 stamp 不會產生,但已經做完的工作都還在。處理順序是「先續跑、續不回去才撈檔」。
resumeFromRunIdWorkflow 工具吃 resumeFromRunId 參數。傳入前一輪的 run ID, 已完成且 (prompt, opts) 未變的 agent 呼叫會回傳快取結果、不重跑, 只有失敗的與沒跑到的才重新派。這正對症我們的死法——被砍的通常是最後階段的 verifier, 前面數小時的研究階段是完整的。
三個限制:
TaskStop 停掉原本那輪。/clear 之後就再也接不回去。所以 runner 的鐵律是:撞到額度上限時停下回報,但那個視窗不要關、不要 /clear, 等額度窗口重置回同一視窗續跑。這條要寫進掃描卡,否則 runner 的直覺就是收工關窗。
看即時進度用 Claude Code 內建的 /workflows(在跑掃描的那個 session 輸入), 啟動後就該跑一次把 run ID 記下來。 順帶澄清一個常見誤會:我們講的「面板」是 panel(三人驗證投票機制),不是儀表板, 找不到「控制面板」是正常的。
run 目錄下不只有 journal,每個 agent 各有一份自己的逐字工作紀錄,即時寫入,被砍的 agent 也有:
~/.claude/projects/<專案 slug>/<session-id>/subagents/workflows/<run-id>/
├── journal.jsonl # 已完成 agent 的結構化回傳
├── agent-<id>.jsonl # 每個 agent 的逐字流水帳(含被砍的)
└── agent-<id>.meta.json
兩者用途不同:
journal.jsonl —— 乾淨結果,直接可讀。每行一個 JSON, {"type":"result", "result":{"findings":[...]}} 就是該 agent 的發現。 用 Python 逐行解析、按 file + title 去重即可還原清單。中斷後預設撈這個。agent-*.jsonl —— 流水帳,要派人讀完萃取,成本高。 只在「研究員明顯讀了關鍵檔卻被砍、journal 裡沒有它」時才值得撈。 規模參考:2026-09-06 S6 那輪的目錄有 59 個檔,單一 agent 的 jsonl 最大 1.1MB。 本專案至今沒做過,成本未實測。撈出來的一律標「未經面板驗證」。但人工開檔核對過的照樣能拿去開修正卡—— FR-077 R1(42 檔)面板全滅、正式 findings 是空陣列,runner 從 journal 撈回 8 條候選、 去重成 7 條、逐條核對全屬實,四張修正卡就是照那批開的。 不能宣稱的只有「這個範圍掃過了」。
第一輪的 run id 是 wf_442f835c-ddf。
四棒(43/49/47/74 檔)用 Sonnet 5 跑 low,結果:S4 派 7 研究員全砍、S5 派 7 唯一交卷是 343K 硬撐的零發現、 S6 派 6 全砍、S7 第 4 次跑完但 8 條越界重複 S1。
死法一致:plugin 把研究員定義成 model: inherit、effort: xhigh,prompt 要求「讀完每個檔、追每個 caller、 不信任何註解」。Sonnet 5 上限 200K,讀到 20 幾萬 token 時每一步思考變慢,超過 workflow 的 180 秒無 tool call 即判 stalled 門檻(scan.js 的 18e4 毫秒)就被砍掉,從零重派,永遠讀不完。 一顆被砍的 S4 研究員:411 回合、產出 91 萬 token、讀 30 個不同檔加 200 多次 grep,然後死。
effort 等級管不到這層。low/medium/high 控制的是 workflow 派幾個研究員;研究員自己的推理深度 寫死在 agents/scan-researcher.md,改了會被 plugin 更新蓋掉。
解法:runner 主 session 切 Opus 5 (1M context),其他全不動。1M 在 20 幾萬 token 時思考速度正常, 不會觸發 stall。代價是每棒成本約 Sonnet 的三到五倍,但至少有產出。
不要切小範圍:S7 的研究員為了追脈絡讀了 S1 整個 adapter 目錄、主專案的 route、還有 repo 裡既有的 四份掃描報告,然後把 S1 已開卡的 8 條原樣回報成「新發現」。切小不會減少它讀的量。
範圍相鄰時要在卡片明寫「不要讀這些已掃過的路徑」——面板只驗「發現是否成立」, 不驗「發現是否在指派範圍內」,越界要靠人工比對才抓得到。