我把 PreToolUse hook 過去 14 天的 ask 盤點了一遍:159 次,其中約七成是誤判。
ask 就是 hook 跳出來問你要不要放行。問太多次,人就麻木了。
誤判從哪來
逐筆看下來,誤判的來源很集中:
- heredoc 裡的文字。 指令本身沒有危險,只是 heredoc 內文提到了危險指令的字面,整段字串比對就中了。
--help、--dry-run。gog加上這兩個旗標根本不會動任何東西,卻照樣被攔。- 背景任務。
run_in_background也會觸發 log 檢查。 env | grep。 這種查環境變數的寫法被擋。- 安裝閘門裡的
uvx。 這個也被當成要確認的安裝動作。
怎麼修
我改了 bash-pretooluse-main.sh 和 scratch-doc-guard.sh。核心只有一個動作:先把 heredoc 剝掉,再比對「指令位置」,而不是比對整段字串。
其餘幾條各自處理:安裝閘門移除 uvx、gog 排除 --help 和 --dry-run、run_in_background 不再觸發 log 檢查、env | grep 放行。
怎麼量
統計的時候不用重播指令。hook 的 ask 事件會留在 transcript 裡,是 PreToolUse 的 hook_success attachment,它的 stdout 就是 hook 當時的回報,可以直接統計。
修完之後,把紀錄到的指令丟進新版 hook 重跑,會跳 ask 的從 135 次降到 50 次;另外準備的對照組 27 個全部通過。
還沒修好的:deny 類規則
這次修的是 ask。deny 類規則仍然掃原始指令,所以 heredoc 裡只要提到 git reset --hard,照樣被直接擋掉。這是目前已知的限制。
連整理這週週報草稿的時候,heredoc 誤擋都又重現了一次。
兩個旁邊的副作用
Stop 閘門在別的目錄被觸發。 我把 benchmark 用的 claude -p 放在 knowledge-base 當工作目錄跑。結果 vault-lint 的 Stop 閘門被觸發,逼著它去跑歸檔腳本,還自動 push 上去了。內容保留著,沒有還原。防呆已經寫進派工用的 skill。
缺 cwd 排除而誤指專案。 stakeholder-context hook 缺 cwd 排除,GMAT-skills 底下有位同名的聯絡人,被誤指到另一個客戶專案去。我在 hook 加了第三欄 cwd 排除,這個就不再發生。
這幾件事的共通點,跟我週報草稿裡寫的一樣:攔截類 hook 比對指令位置,不比對整段字串;上線之後用 transcript 裡的 hook 事件統計,不重播指令,並且用對照組驗證修正前後。
其他攔截類的設計我之前寫在怎麼寫一個真的會擋下來的閘門。