← ClaudeAtlas

hook-standardslisted

Claude Code hook 的規格:什麼行為該用 hook 強制、什麼該留在 CLAUDE.md 判斷層、 deny 與 ask 怎麼選、匹配與失敗紀律、輸出格式、註解義務,以及安裝與更新步驟。 另附三支現行守衛(git-guard、destructive-guard、worktree-hookspath-fix)的逐支規格。 Use when 新增或修改 Claude Code hook、編輯 settings.json 的 hooks 區塊、 審查一支 hook 是否合格,或需要知道目前環境有哪些守衛、它們會擋下什麼。
jurislm/jurislm-tools · ★ 0 · AI & Automation · score 56
Install: claude install-skill jurislm/jurislm-tools
## 分層原則 Hook 是強制層,`CLAUDE.md` 的常駐文字是判斷層。**兩者並存,不互相取代。** Hook 只看得到 Bash 指令的字面。Claude 走 MCP 工具、走 `Edit`、或在還沒下指令的判斷 階段就決定要做某件事時,hook 完全看不到。把一條安全禁令只寫進 hook,等於只擋住了 Bash 那一條路徑。 因此:**安全禁令的文字不因為有了 hook 就從 `CLAUDE.md` 移出。** 新增 hook 是加上一層 強制,不是把規則搬家。 ## 入選判準 一句話:**漏做一次就會出事嗎?** | 情況 | 該進 hook 嗎 | |---|---| | 零例外必須被擋,且代價不可逆 | 是 | | 壞掉時無聲——不報錯、不警告 | 是。沒有 hook 就沒有人會發現 | | 需要看上下文才知道對不對 | 否,留在 `CLAUDE.md` | | 只是「最好這樣做」 | 否 | 第二列是 `worktree-hookspath-fix.sh` 的存在理由:git 找不到 `core.hooksPath` 指向的目錄 就直接不跑 hook,不報錯也不警告。除非有人主動去 `git config --get core.hooksPath`, 否則沒人會發現防護已經沒了。 ## deny 與 ask | 決定 | 什麼時候用 | 例子 | |---|---|---| | `deny` | 零例外,且有明確的替代路徑可以講給呼叫者聽 | 直推預設分支 → 走 feature 分支開 PR | | `ask` | 動作本身合法,對不對取決於只有呼叫者知道的上下文 | `rm -rf` 的目標路徑是不是真的那一個 | `deny` 的理由**必須包含替代路徑**。只說「不准」會讓呼叫者原地重試或繞路,兩種都比 放行更糟。 ## 匹配紀律 三條都有實戰來源,不是預防性的潔癖。 1. **錨定真實的指令位置,不比對裸字串。** `git-guard.sh` 早期用裸子字串比對跳過 hook 的旗標,結果 `echo "... <旗標> ..."` 被 擋,連 hook 檔本身都無法透過 Bash 編輯。現在錨定在行首,或 `;` `&` `|` `(` `&&` `||` 之後。殘留誤判:引號內看起來像 git 指令的字串仍可能命中——要根治需要真正的 shell parser,不值得那個複雜度,所以寫進 catalog 的「不攔什麼」欄位而不是假裝沒有。 2. **列舉選項,不用開放式 pattern。** `git[^;&|]*push` 會命中 `git log --grep push`,而它不 push 任何東西。`git-guard.sh` 改為列舉 git 的 global option(`-C`、`-c`、`--git-dir=`、`--work-tree=`、 `--no-pager`、`-P`)再接 `push`。 3. **解析失敗一律退回最保守的答案,絕不因此放行。** `git-guard.sh` 判斷「這個指令推去哪個 repo」的順序是 `git -C <path>` → push 之前 最後一個 `cd` → session cwd。路徑含變數、subshell、glob,或根本不是工作樹時,退回 session cwd 再判一次,不會因為解析不出來就放行。 這條的來源是一次誤擋:早期版本問的是「ses