Community程式設計與開發github.com

adamstallard/bug-hunter

在程式碼提交前捕捉錯誤。在每次包含剛寫好的程式碼的 `git commit` 之前執行此技能,並確保每個被報告的錯誤都伴隨著一個可重現的失敗測試。

bug-hunter 是什麼?

Bug Hunter 是一個 AI 代理技能,旨在防止錯誤進入版本控制。它透過分析暫存區的差異來運作:找出潛在的錯誤候選、為每個錯誤撰寫一個最初會失敗的回歸測試、透過第二意見來反駁弱點、修復經得起考驗的錯誤,並最終透過「觀察測試從紅變綠」來驗證每個修復。此技能支援 Claude Code、Cursor 和 Codex 等平台,並強制執行嚴格的工作流程,避免在 git pre-commit 鉤子中執行(它會修改工作目錄並自行提交)。輸出內容包含一個 `Bug-hunter:` 追蹤行,供一個伴隨的 git 鉤子使用,以確保在每個包含程式碼的提交之前都執行過此檢查。文件的規格、文件或測試本身會跳過檢查(但仍會經過此技能,並帶有跳過追蹤行)。

相容平台✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/adamstallard/shared-skills/tree/HEAD/.agents/skills/bug-hunter

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Bug Hunter

一個沒有失敗測試的主張只是猜測。 此技能報告的一切內容,都透過一個在修復前觀察到為紅色、修復後為綠色的測試來證明;它無法證明的一切都會被丟棄。這就是核心概念,也是其產出值得閱讀的原因。

它會編輯工作目錄、新增測試檔案,並在預設情況下進行提交。

  • 如何執行每個步驟 — reference.md。在執行步驟 4–7、撰寫報告以及提交之前,請先閱讀它。
  • 突變測試,步驟 3 到步驟 9 — mutation.md。在開始任何突變體之前,請先閱讀它。

合約

  1. 每個已修復的錯誤都有一個回歸測試,該測試在未修復的程式碼上觀察到為紅色,並在修復後變為綠色。
  2. 每個無法驅動為紅色,或被第二意見反駁的候選錯誤都會被丟棄 — 其測試也會被刪除,絕不留下失敗狀態。
  3. 任何真實但超出範圍或無法測試的問題都會被報告,而非修復。
  4. 完整的測試套件最終狀態不會比開始時更差。

工作流程檢查清單

- [ ] 步驟 0:界定變更範圍 — 僅限暫存區差異
- [ ] 步驟 1:分類 — 這個提交是否值得審查?
- [ ] 步驟 2:基準線 — 在觸碰任何東西之前先執行測試套件
- [ ] 步驟 3:尋找候選錯誤(使用強模型,需要可達性);在變更的函式已有測試的情況下,旁邊執行突變子代理
- [ ] 步驟 4:證明 — 撰寫測試、執行它,並要求得到相符的紅色結果
- [ ] 步驟 5:反駁 — 第二意見嘗試消滅每個已證明的錯誤,並檢查每個存活下來的測試和死程式碼主張
- [ ] 步驟 6:修復(預防性提問,範圍限定)
- [ ] 步驟 7:驗證 — 新測試變為綠色;在步驟 9 之前,完整執行一次套件
- [ ] 步驟 8:迭代 — 連續進行,最多 3 次,不經詢問;絕不進行第 4 次
- [ ] 步驟 9:最後報告一次;向使用者詢問每個未決的決定(使用選擇器 — 寫下來不等於詢問);然後提交(當 prose 已安裝時,附上 prose 的追蹤行)或留待審查 — 或者,在「呼叫者提交」模式下,以 `scripts/caller-result.sh` 的區塊結束

絕對不要從 git pre-commit 鉤子內部執行此技能。 它會寫入檔案、新增測試並提交 — 這些操作都會與 git 的索引鎖定衝突。它在提交被建立之前執行,而提交發生在步驟 9。

一個伴隨的鉤子會監視那些未曾經過此處的提交:在每次指令後,它會詢問 git HEAD 是否移動,以及新提交是否帶有 Bug-hunter: 追蹤行。因此追蹤行是唯一重要的標記 — 不需要環境變數,不需要記憶,且記錄存在於提交本身中,git log 可以稽核它。

該鉤子也會對任何非跳過說明的追蹤行提出第二個問題(包括 0 bugs found 和 aborted ...,而不僅是報告修復的內容):Bug-hunter-Tree 追蹤行是否與實際落地的工作目錄樹匹配?這個綁定正是 scripts/mint-trailer.sh 在針對實際暫存區樹執行時所產生的,就在提交之前 — 請參閱步驟 9 了解如何運作。一個 Bug-hunter: 追蹤行可以是一個完全正確措辭的真實 git 追蹤行,但仍然只是從閱讀此檔案記住的句子,而不是執行其任何部分產生的 — 這是字串存在性檢查無法捕捉的一種形式,而這個綁定就是為此而設。

一個落地時沒有 Bug-hunter: 追蹤行的提交,或者其 Bug-hunter-Tree 綁定不匹配的提交,會在報告中被點名,並指出其所在的儲存庫。該報告會將你引導至下方章節,但不提供修復提交的指令:該鉤子無法得知你目前所在的位置,且它點名的提交通常不是你的 HEAD。


如果你是即將提交的代理

如果另一個技能會為你進行提交,並在每次提交前執行此技能,讓該技能從「提交此內容」開始;對於「錯誤檢查此內容」,仍然要執行。如果本次執行已經說明了提交主題,請保持該主題不變。只需新增追蹤行。

你建立的每個提交都會經過此技能,並帶有 Bug-hunter: 追蹤行。 並非僅在被明確要求時才這樣做 — 而是每次。包含程式碼的提交會進行狩獵。僅包含文件、規格、測試或格式化的提交會跳過狩獵,但不會跳過此技能。 「提交此內容」、「提交我的變更」、「打包並提交」,或你自己在完成任務後決定提交,都意味著:暫存變更、執行此技能、然後提交。分類(步驟 1)決定一個給定的提交是否值得審查,因此當它不適用時,總是執行它是代價低廉的。

在你自己的工作階段中自行執行它。 撰寫變更的代理應執行此技能。不要將整個執行過程交給一個子代理,然後該子代理再啟動自己的尋找器、反駁器和突變代理:執行需要一個保持存活以收集存活者和恢復代理的協調者,而巢狀委派會在其子代理執行時不斷結束自身的回合。將單次傳遞委派出去(如同步驟所述)才是它預期的運作方式。

不要規避此技能

一個標題,而不是五條規則,因為一個尋找逃避檢查方法的代理,總能可靠地找到分開陳述的規則之間的縫隙。這裡的每一行都是在某個代理繞過它所關閉的規則之後才新增的。

1. 每次都要說出你正在做的是哪一項。 在使用者可看見的回覆中寫一行:「正在對 N 個檔案執行 bug-hunter」,或「跳過 bug-hunter — <原因>」。不要寫在你的推理中 — 要在回覆中。在什麼都不說的情況下跳過,看起來就像執行了但什麼也沒找到。一個說出來的跳過可以被四個字推翻;一個沒說出來的跳過是你為他們做的決定。如果你跳過,提交仍然會帶有追蹤行 — 使用 commit-with-trailer.sh -F msg.txt "skipped — <原因>",如同步驟 9 所述。兩者都要做,而不是二選一。在呼叫者提交模式下,跳過則轉為使用結果腳本(當呼叫者提交時)。

2. 永遠不要請求執行它的權限。 觸發條件是程式碼的屬性,而不是某個時間點:如果自上次通過且結果乾淨的執行以來有撰寫過程式碼,那麼就應該執行一次通過。 在提交之前、在疊代之間、在使用者要求的修復之後、在重構之後、在已經落地的提交之後 — 這些不是獨立的情況,全部都是「程式碼被寫了」。列出時間點清單,就是在誘惑代理去尋找不在清單上的那個時間點。

3. 只有當你已經開始時,宣布才算數。 「除非你想停在這裡,否則下一步就是執行那個」 · 「如果你滿意,我就會啟動它」 · 「這些修復需要它們自己的通過 — 想讓我執行它嗎?」 每一次都在檢查尚未執行時結束了回合,這就像直接詢問一樣,把決定權交還給使用者。如果你正在用未來式描述一個執行,那你還沒有開始它,這就是錯誤。

4. 疊代要連續進行,並需要提供報告。 最多三次,它們之間不進行檢查點,也不提供中期報告 — 疊代之間的報告會誘使提早停止,並讓未完成的執行看起來像已完成。請參閱步驟 8 和 9。

三次是預算,而不是開價。沒有第四次疊代。 「想讓我再多執行一次通過嗎?」 · 「疊代 3 自己的修復從未被審查過 — 我應該做第 4 次嗎?」 這兩種情況都在預算已經用盡時,於使用者最可能拒絕的時刻,把決定權交了回去。達到上限的執行會以根本原因報告(步驟 9)結束,每個原因附帶一個選項,其中第一個選項是範圍限定在該原因、從疊代 1 開始的新執行。這並非規則 2 被暫停:對疊代 3 的修復進行一次通過確實是應做的,而且仍然應做 — 用完的是將它納入本次執行的預算,這就是為什麼它會變成一個新的執行,以及為什麼由使用者決定哪個原因獲得它。這也不是規則 3 的逆轉:在預算內,一次通過是應做的,你會不經詢問就開始;達到上限時,執行結束,剩下的是需要做出的決定,以選項的形式提供,而不是作為一個開放式問題。

5. 這些都不是理由。 每一個都曾被一個有能力的模型用來跳過此技能,而該次提交隨後帶來了錯誤:

  • 變更很小 — 一行變更也經常是錯的
  • 我對這段程式碼有信心 — 此技能找到的每個錯誤的作者也曾這麼想
  • 使用者在等 / 我們要快速前進 — 這正是品質被交易掉的時刻,也正是此技能存在的理由
  • 工作階段很長,這很昂貴 — 什麼都沒找到的執行是便宜的,分類會在進入昂貴部分之前阻止大部分提交,而且長時間的通過無論如何都是在背景運行的(步驟 3)
  • 我已經在相關程式碼上執行過它了 — 但你沒有在「這段」程式碼上執行過
  • 這是技能自己的機制,不是真正的程式碼 — 它是真正的程式碼,而且此技能歷史上最嚴重的錯誤恰恰發生在那些機制中
  • 使用者顯然在看著,如果他們介意的話會反對的 — 他們在看的是輸出,而不是輸出的缺席

製造錯誤然後因為檢查不方便就繼續前進,正是此技能存在的目的就是要阻止的特定行為。對這個技能做這種事不是諷刺,這就是錯誤本身。

誰來決定成本。 一次完整的執行是幾分鐘;糟糕的一次是半小時。安裝此技能的人已經權衡過較慢的提交與錯誤進入主分支的風險。一個悄悄決定今天檢查太慢的代理,並沒有做出工程判斷 — 它是在為一個不在場的人推翻那個決定,並且是朝著剛好比較省力的方向。如果成本真的在當下很重要,用一句話說出來,讓他們選擇。

誰的決定

兩個簡短的清單,因為兩種失敗都發生在它們的邊界上:問第一個會訓練使用者草率閱讀,而為他們決定第二個就是默默地做了選項 3。

你的決定,永遠不要問。 是否要執行以及何時執行;一個候選錯誤是否被證明、反駁或丟棄;如何在變更範圍內修復一個已證明的錯誤;是否要疊代(直到上限);執行測試套件;提交一個乾淨結束且沒有未決事項的執行 — 除非在呼叫者提交模式下,此時提交是呼叫者的責任。

使用者的決定,永遠要問。 要對什麼採取行動:每個根本原因和每個建議(立即修復 / 記錄下來 / 跳過)、中止時的每個未解決條目、當某個報告但未修復的問題改變了提交的意義時是否仍要繼續(僅報告模式),以及步驟 0 的停止 — 當一個檔案有分歧的暫存和未暫存編輯時,要保留哪一份。

當你詢問時,請使用主機的互動式選擇器(在 Claude Code 中,使用 AskUserQuestion 工具):任何帶有離散選項的問題都應透過它來提出,每個決定一個問題,按嚴重性排序,絕不要埋在長篇報告結尾的散文中。純文字是給沒有選擇器的主機使用的備案,而非預設。選擇器也是這裡唯一結構性而非建議性的東西 — 一個開啟了選擇器的回合不能結束,直到使用者回答 — 這就是為什麼下一條規則很重要。

詢問意味著使用者看到了它。 一個問題在它出現於使用者閱讀的回覆或他們回答的選擇器中時,才算是被問了 — 而不是當一個代理把它寫下來時。如果此技能在一個向另一個代理報告的代理中執行,那麼它的步驟 9 報告和它的問題會到達那個代理,而什麼都還沒被問:這一步只是移動了選擇器,並沒有處理掉問題。所以:

  • 如果你生成的一個代理在其自己的變更上執行了此技能,它的報告是你步驟 9 的輸入,而不是你的步驟 9 輸出。該報告中的每個未決決定都必須在你下一個回覆中、在任何其他事情之前呈現在使用者面前 — 透過你的選擇器,每個決定一個問題,或者在沒有選擇器的情況下,逐字呈現報告的編號區塊。「執行中止了」 或 「它發現了三個根本原因」 且底下沒有選項,這是在轉述報告而不是交付它;如果你正在寫那樣的句子,那就是錯誤。在一個回合中持有決定而同時完成其他工作,就是替他們做了選項 3 — 要嘛其他工作等待,要嘛回覆同時承載兩者。
  • 如果你在一個向另一個代理報告的代理中執行此技能,你沒有可以觸及使用者的選擇器。以指定的格式列印整個報告 — 而非摘要 — 並附上交接頁尾(reference.md),告知持有該報告的人哪些仍然是他們需要詢問的。清楚說明哪些決定是開放的,以及你無法詢問它們。在呼叫者提交模式下,結果區塊的決定清單會取代頁尾(當呼叫者提交時)。

一次執行在其問題呈現在使用者面前之前,都尚未結束,無論是哪個代理將它們送到那裡。

步驟 0 — 界定範圍

正在審查的變更是暫存區的差異:

git diff --cached --stat
git diff --cached

閱讀每個變更檔案的整個檔案內容,而不僅僅是差異片段 — 錯誤通常發生在新程式碼與周圍程式碼的互動中。

如果任何檔案同時出現在暫存區差異和未暫存差異中,請停止。 你將在推理索引的同時測試工作目錄樹,而它們不一致。告知使用者哪些檔案分歧,並要求他們暫存或還原那些編輯。絕對不要使用 git stash 來繞過此問題 — 使用者有未提交的工作,而此技能即將在其之上寫入檔案。

其他檔案中的未暫存變更則沒問題。在報告中註明它們。

不要搜尋規格、文件或現有測試中的錯誤。變更這些檔案仍然值得作為上下文閱讀。

步驟 1 — 分類

分類是根據差異來決定,而不是根據提交訊息。 對於大約最多 300 行變更的差異,由你自己進行分類,在你已經進行的循環中:啟動一個子代理的成本比閱讀那麼大的差異還要高。對於較大的差異,則委派給一個使用小型、便宜模型的單次快速通過。無論哪種方式,該次通過都會獲得檔案清單、差異,以及使用者是否要求檢查點(如下)。請求回傳 REVIEW 或 SKIP 其中一個,並附上一行原因。不要先請求提交訊息,也不要將主題前綴解讀為訊號 — 此技能不強制執行任何提交慣例(reference.md)。

當差異顯示以下內容時,回傳 SKIP:

  • 僅包含 docs、specs、tests、lockfiles 之外的內容...

相關技能