AI 寫程式 CLI 的 hooks 與 Claude Code Mod 說明

用官方文件說明 Grok CLI、agy(Antigravity CLI),以及 Claude Code 的 hooks、Mod 與 MCP。

資料查核日期:2026-10-26(台北時間)。內容只摘錄官方文件與註明的社群來源。

Grok CLI 的 hooks

Hook 是某個生命週期事件發生時,Grok 會呼叫的 shell 指令或 HTTP 端點。用途包含擋危險動作、記 log、發通知,以及接你自己的工具。

事件

事件分三種節奏:每次工作階段(SessionStart、SessionEnd)、每一輪(UserPromptSubmit、Stop、StopFailure),以及這一輪裡的每次工具呼叫。

事件 一句話
SessionStart 工作階段開始。子代理自己的工作階段不會觸發。
SessionEnd 工作階段結束。子工作階段會帶 subagentType,方便和自己的結束分開。
UserPromptSubmit 你送出提示時。可以擋下這則提示。
PreToolUse 工具即將執行。可以拒絕這次呼叫。
PostToolUse 工具已經跑完(含內建的邏輯錯誤,例如 run_terminal_command 非零結束)。不能擋呼叫,但可以把回饋交給模型,或換成模型讀到的輸出。
PostToolUseFailure 工具沒派送出去,或 MCP 工具回傳錯誤。不能擋,但可以給模型 additionalContext。
PermissionDenied 權限系統拒絕了一次工具呼叫。不能擋。
Stop 代理這一輪正常做完。中斷會改走 StopCancelled。可以不讓它停。
StopFailure 這一輪因為 API 錯誤結束。只供觀察。

同一份文件還有 StopCancelled、Notification、SubagentStart、SubagentStop、PreCompact、PostCompact。SubagentStop 可以擋住子代理結束。SubagentEnd 是 SubagentStop 的別名。

哪些事件可以擋

事件 怎麼擋
PreToolUse stdout 的 {"decision":"deny"}(或 hookSpecificOutput.permissionDecision 的 deny)。結束碼 2 也是明確拒絕。stdout 裡的 deny 不論結束碼都會生效。
UserPromptSubmit {"decision":"block","reason":"..."},任何結束碼都算。結束碼 2 也擋,stderr 變成訊息。只能擋你打的提示。
Stop、SubagentStop {"decision":"block","reason":"..."},或結束碼 2(stderr 當回饋)。

PreToolUse 還可以回 allow、ask、defer。舊拼法 approve、block 也認。有 permissionDecision 時以它為準。

逾時、當掉、輸出壞掉是 fail-open:會記在畫面上,但不會擋工具。要擋,腳本必須跑完並明確給出 deny。例外是 updatedInput 不符合工具 schema 時,這次呼叫會被擋住。

PostToolUse 的 {"decision":"block"} 不會取消已執行的工具。它是把 reason 和工具結果一起交給模型。

timeout 單位是秒。一般預設 5 秒。UserPromptSubmit 預設 30 秒。Stop、SubagentStop、PostToolUse 預設 600 秒。

設定放哪裡

這些來源會合併。

  • 全域:~/.grok/hooks/*.json。一律信任。
  • 專案:<project>/.grok/hooks/*.json。要先信任。第一次開有 hooks 的專案時,未信任的專案 hooks 會被悄悄跳過。用 /hooks-trust 或啟動參數 --trust。紀錄在 ~/.grok/trusted_folders.toml。
  • 設定檔:~/.grok/config.toml。hooks 與其他設定放在一起。組織還可以用 managed_config.toml 與 requirements.toml。

相容檔預設也會掃。全域的 ~/.claude/settings.json(含 settings.local.json)與 ~/.cursor/hooks.json 一律信任。專案裡的 .claude/settings.json、settings.local.json、.cursor/hooks.json 要先信任。要關掉某一家,在 ~/.grok/config.toml 設 [compat.<vendor>] hooks = false。

Grok 接受 Cursor 的 camelCase 事件名稱,所以 ~/.cursor/hooks.json 可以原樣載入。認不得的事件名稱會跳過,共用的 Claude 或 Cursor 設定檔仍可載入。

已安裝的外掛裡也可以包 hooks。在 Hooks 分頁用 /hooks 查看。非 VS Code 家族的終端機也可以按 Ctrl+L。

JSON 例子

摘自文件的 Safe Shell Guard。比對的是工具名稱 Bash。Grok 會把 Bash 對到自己的 run_terminal_command,原來的名字也仍然對得到。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "bin/safe-shell.sh", "timeout": 5 }
        ]
      }
    ]
  }
}

type 可以是 command 或 http。command 相對 JSON 檔的路徑,或一行 shell。

來源

agy(Antigravity CLI)的 hooks

Hooks 在代理動作執行前或剛執行完插入。文件說可以用來做起飛前檢查,或在寫完檔案後跑格式化(例如 prettier)。這份說明涵蓋 Antigravity App、CLI 與 IDE。下面以 CLI 為主。

事件

事件 一句話 matcher
SessionStart 新對話工作階段開始、第一次呼叫模型之前,跑一次。 忽略
PreToolUse 工具執行前。 工具名稱,例如 run_command
PostToolUse 工具完成後。 工具名稱
PreInvocation 呼叫模型之前。 忽略
PostInvocation 每一次模型呼叫結束後立刻跑。 忽略
Stop 執行迴圈結束時。 忽略

檔案放哪裡、長什麼樣子

CLI 可以放在這些地方:

  • 工作區:專案根目錄的 .agents/hooks.json。
  • 全域:~/.gemini/config/hooks.json。~/.gemini/antigravity-cli/settings.json 裡的 hooks 不會被載入。
  • 外掛:已安裝外掛裡的 hooks.json。

同一份文件裡,Antigravity App 與 IDE 也用工作區 .agents/hooks.json 與全域 ~/.gemini/config/hooks.json。

最外層的鍵是 hook 的名稱,不是事件名稱。可選的 enabled 設成 false 就停用,不必刪掉。預設 true。

matcher 只有 PreToolUse 與 PostToolUse 會用,內容是正規表示式。空字串或 * 比對所有工具。run_command 是完全符合。run_command|view_file 是兩者之一。browser_.* 是名稱開頭為 browser_。另外四個事件的 matcher 會被忽略,處理器直接列在事件鍵下面。

每個 handler 的欄位:

欄位 說明
type 選填。目前只支援 command。預設就是 command。
command 必填。要執行的 shell 指令。
timeout 選填。秒。預設 30。

Hook 從 stdin 收 JSON,從 stdout 回 JSON。欄位名稱是 camelCase。

PreToolUse 的 decision

decision 必填。reason 選填,會顯示給代理或給你。文件列出的值如下。

decision 意思
allow 讓這次呼叫繼續,交給下一個 hook 或預設政策。
auto_approve 預設政策原本會詢問時,自動核准。仍遵守你明確設定的規則。
deny 立刻硬性擋下,不再執行。
ask 請你核准,但會尊重「Always Allow」設定。
force_ask 一定詢問,忽略已快取的權限。
deny_unless_prior_grant 除非這項資源先前已經核准過,否則拒絕。

還可以選填 overwrite(淺層合併進 toolCall.args)與 permissionOverrides。

JSON 例子

摘自文件範例的其中一段。最外層是 hook 名稱。

{
  "my-linter-hook": {
    "PostToolUse": [
      {
        "matcher": "run_command",
        "hooks": [
          {
            "type": "command",
            "command": "./scripts/lint.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

在 TUI 輸入 /hooks,可以查看已載入且作用中的 hooks。

來源

Claude Code 的 Mod、MCP 與 hooks 怎麼分

使用者說的「MOD」就是 Claude Code 的 Mod(mods)功能。

Mod 是一種外掛。它用 JavaScript 或 TypeScript 事件處理函式組成。Claude Code 在事件發生時呼叫它,例如工具呼叫、送出的提示,或介面正在繪製的一部分。處理函式可以觀看、改寫,或接手這個事件。

官方概述寫,mod 可以加上你自己的功能,例如窗格、指令,以及工具呼叫規則。它也能在介面上畫出可操作的窗格或提示上方的橫條,改 Claude Code 自己畫的列,或在工具呼叫與請求中間插入步驟。

Claude Code 把 mod 的處理函式也叫 hook。設定檔裡那種 shell、HTTP 或 prompt,文件稱 settings hook。下面表格的「hooks」指 settings hook。

如果 settings hook、skill 或 MCP server 已經做得到你要的事,寫 mod 之前先對照它們。這是官方概述的原意。

內建的 /diff、版本與安裝

/diff 是內建 mod。/plugin 的 Installed 分頁、Built-in 底下,名稱是 cc-plugin-diff。它在互動終端機工作階段接管 /diff 並畫出窗格。內建 mod 不能更新或解除安裝。在 /plugin 停用它之後,/diff 還在,改由 Claude Code 內建的那個指令回答。

Mods 預設開啟。終端機要 Claude Code v2.1.287 或更新。Desktop app 自帶一份 Claude Code,從 v2.1.286 起可以使用 mods。終端機用 claude --version。Desktop 在 Code 分頁的本地工作階段輸入 /status,看 Claude Code 那一列。

安裝方式和外掛一樣,名稱、一個 @、市集名稱。在 shell:

claude plugin install <mod>@<marketplace>

文件範例是 claude plugin install token-chart@your-org。工作階段裡則是 /plugin install token-chart@your-org。shell 安裝時若工作階段已開著,要在裡面跑 /reload-plugins。

Mod 沒有沙箱。它用你的權限在機器上跑:能讀寫你的帳號可及的檔案、啟動程式、送網路請求,也能讀環境變數與設定(含 API 金鑰)、看見每個提示與工具呼叫。官方警告只安裝你信任的作者與市集。若你開了 sandbox,沙箱隔離的是 Claude 跑的 Bash 指令;mod 啟動的行程在沙箱外面。

安裝前可以先看它做什麼,不必執行。先拿到外掛檔(例如 clone),再對該目錄跑 claude plugin validate。輸出的 hooks: 與 calls: 列出它處理的事件,以及它要求 Claude Code 做的事。

官方文件寫,mod 的 hooks 在有載入該外掛的各類工作階段都會跑。畫出來的東西出現在終端機、Desktop app,以及 VS Code 擴充功能的聊天面板(擴充功能 2.1.299 起;不抓 feature flags 的工作階段要 2.1.304 起)。Desktop app 裡的 WSL 工作階段沒有外掛,hooks 與畫面都不會出現。

claude-mods.com 的安裝頁是社群/第三方站,不是 Anthropic 官網。安裝指令和官方大致重疊。該頁寫 VS Code 擴充功能的聊天面板不會畫出 mod。這點與上面的官方版本不同,本頁採用官方文件。

MCP 是什麼

MCP(Model Context Protocol)是 AI 工具整合的開放原始碼標準。MCP server 讓 Claude Code 使用你的工具、資料庫與 API。連上之後,Claude 可以直接讀取並操作那個系統。

三者對照

用語對齊官方「Compare mods, settings hooks, skills, and MCP servers」。官方表格還有一欄 Skill。這裡只留題目要的三欄。

項目 hooks(settings hook) Mod MCP
是什麼 Claude Code 在生命週期事件上執行的 shell 指令、HTTP 請求或 prompt。 外掛裡的函式,由 Claude Code 在自己的行程中呼叫。 外部行程或服務,提供工具給 Claude。
用什麼寫 一支腳本,加上 settings.json 的一筆設定。 JavaScript 或 TypeScript。 任何語言的 server。
典型用途 用你已有的腳本阻擋、允許或記錄一個事件。 要窗格、提示上方的橫條、自訂指令,或改寫一個事件。 Claude 需要碰到外部系統。

一個外掛可以同時帶著這幾種東西。Mod 可以和 skill、MCP server 放在同一個外掛裡。

來源

Claude Code hooks 的常見用途與前景

官方入門寫道:hooks 是你定義的 shell 指令。Claude Code 在生命週期的特定點執行它們,所以控制是確定的。某些動作一定發生,不靠模型自己決定要不要做。用來執行專案規則、自動化重複工作,以及接上既有工具。

官方指南裡的例子

例子 文件怎麼做
等人時的桌面通知 Notification。空的 matcher 對所有通知類型。macOS 用 osascript,Linux 用 notify-send,Windows 用 PowerShell 的 MessageBox。要縮小範圍可改用 idle_prompt(Claude 回完大約 60 秒、你還沒打字)或 permission_prompt 等。
編輯後跑 Prettier PostToolUse,matcher 為 Edit|Write。用 jq 取出 .tool_input.file_path,再交給 npx prettier --write。
擋住敏感路徑的編輯 PreToolUse,matcher 為 Edit|Write。範例腳本比對路徑,含 .env、package-lock.json、.git/ 就對 stderr 印原因並以結束碼 2 離開。
壓縮後把上下文塞回去 SessionStart,matcher 為 compact。指令寫到 stdout 的純文字會加進 Claude 的上下文。
稽核設定變更 ConfigChange。範例把時間、source、file_path 追加到紀錄檔。matcher 可依 user_settings、project_settings、local_settings、policy_settings、skills 過濾。要讓變更不生效,結束碼 2,或回 {"decision":"block"}。
把指令寫進紀錄 指南在「多個 hook 一起跑」的例子裡,用 PreToolUse、matcher 為 Bash,把 .tool_input.command 追加到 ~/.claude/bash.log。這不是獨立的一節。
自動核准特定權限提示 PermissionRequest,matcher 為 ExitPlanMode。stdout 的 JSON 裡 decision.behavior 為 allow。文件提醒 matcher 不要放太寬,空 matcher 或 .* 會自動核准每一個權限提示。

Prettier 那段設定摘錄如下。指南說加在專案根目錄的 .claude/settings.json。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

官方推薦參考的幾類

這份在 Anthropic 官方外掛市集 claude-plugins-official 裡 claude-code-setup 外掛的 claude-automation-recommender 技能(依來源連結的路徑)。檔案說這些是常見模式。

  • 格式與 lint:Prettier、ESLint、Black/isort、Ruff、gofmt、rustfmt。建議用 PostToolUse,多半接在 Edit/Write 之後。
  • 型別檢查:看到 tsconfig.json 就建議 tsc --noEmit。Python 則是 mypy/pyright。
  • 保護敏感檔與 lock 檔:PreToolUse 擋 Edit/Write。敏感檔例子有 .env、.env.local、.env.production、credentials.json、secrets.yaml、.git/。lock 檔例子有 package-lock.json、yarn.lock、pnpm-lock.yaml、Cargo.lock、poetry.lock、Pipfile.lock。
  • 跑相關測試:Jest 或 pytest,在編輯後的 PostToolUse。

同一份也有通知類,matcher 含 permission_prompt、idle_prompt、auth_success、elicitation_dialog。

社群清單的分類

awesome-claude-code-hooks 是社群策展清單。README 的分類是:Security and Prompt Injection、Safety and Protection、Monitoring and Observability、Code Quality Gates、Context and Memory、Model Routing and Cost、Session Management、File Organization、Notification and Alerts、Voice and Sound、Git Integration、Hook SDKs and Frameworks、Hook Collections、Creative and Utility、Learning Resources。清單裡有的項目標了星星數。那不是使用比例。

時限與文件怎麼擺 hooks

Hooks reference 的預設 timeout(秒)是:command、http、mcp_tool 為 600。指南把這三類寫成 10 分鐘,與 600 秒相同。prompt 為 30。agent 為 60。UserPromptSubmit、PreModelSwitch、PostModelSwitch 的 command/http/mcp_tool 降到 30 秒。MessageDisplay 降到 10 秒。SessionEnd 不論類型共用 1.5 秒預算;設定裡若寫了更長的 timeout,預算會跟著提高,上限 60 秒。

指南說時限依類型而異,要用每個 hook 的 timeout 覆寫,單位是秒。UserPromptSubmit 會擋住模型處理,所以這類事件的預設已經比較短。參考也寫,PreToolUse 的 command/http/mcp_tool 逾時後,預設不會擋住工具呼叫。要在逾時時擋住,command 或 http hook 要設 onFailure: "block"。Agent SDK 的 callback hook 逾時則會擋住工具呼叫。

需要判斷、而不是確定規則時,指南說改用 type 為 prompt 或 agent 的 hook,由 Claude 模型評估。agent hook 標成實驗性。正式流程指南建議優先用 command hooks。只要輸入資料就夠判斷時用 prompt hook。要對照程式庫實際狀態時用 agent hook。

參考在說明 hook 的 if 欄位時寫:這個過濾是盡力而為。要做硬性允許或拒絕,用權限系統,不要靠 if。指南另寫,設定檔或外掛 hooks/hooks.json 裡的 hook,不能把限制放得比 permission rules 更鬆。Hook 本身要執行政策時,用結束碼 2。結束碼 1 而且沒有合格的 JSON,預設是不阻擋的錯誤,除非這個 hook 屬於失敗就阻擋的那一種。

官方沒有「必裝 hooks」清單,也沒有找到社群的使用比例調查。

來源

Claude Code Auto Mode 與 hooks 怎麼搭配

提供的來源裡沒有社群對照。這節只摘錄官方文件。

Auto mode 讓 Claude 少問例行的權限。另一個分類器模型在動作執行前審查,擋下超出要求、指向未辨識基礎建設,或看來受敵意內容驅動的動作。明確的 ask 規則仍然會跳出提示。文件警告:auto mode 減少權限提示,但不保證安全。

Hook 與權限模式的先後

  • PreToolUse hooks 在每一種權限模式裡,都比任何權限模式檢查更早執行,包含 dontAsk。
  • Hook 回 permissionDecision: "deny" 會擋住工具,在 bypassPermissions 與 --dangerously-skip-permissions 下也一樣。因此在 auto mode 也擋。
  • Hook 回 allow 不會繞過設定裡的 deny 規則。Deny 與 ask 規則仍會評估,不論 hook 回什麼。它也不能核准 Claude Code 認得的 critical-path rm/rmdir(例如檔案系統根目錄、家目錄)。Allow 規則同樣不能核准這種刪除。
  • Hook 回 ask 會強制權限提示。在 auto mode,分類器仍可以拒絕這次呼叫,但不能安靜地核准。

指南還寫,allow 也不能壓掉這些提示:網路路徑的讀取、標成 requiresUserInteraction 的 MCP 工具,以及組織設成 ask 的 connector 工具。Plan mode 裡,hook 對檔案編輯回 allow,得到的提示、阻擋或核准,與沒有 hook 時相同。

建議的搭配順序

  1. 絕對不要做:用 permissions.deny。它在分類器之前擋住。分類器與使用者意圖都不能覆寫。文件說,不論使用者意圖或分類器設定都絕不能跑的動作,把 permissions.deny 放在 managed settings。
  2. 先問再做:用 permissions.ask。內容範圍的 ask 規則在分類器之前評估,auto mode 裡也一定提示。分類器不能自動核准對上的動作。文件範例是 Bash(git push *) 與 Bash(gh pr create *)。
  3. 規則的寫法對不到完整指令時,改用 PreToolUse hook 檢查整段指令。文件舉的例子是 git -C <dir> push 與 git -c <key>=<value> push。它們不會對上「以 git push 開頭」的規則。
  4. 要記錄 auto mode 的拒絕,加 PermissionDenied hook。它收到的是 tool_input。這個事件只在 auto mode 拒絕時出現,包含分類器沒有給出判決的拒絕。手動拒絕權限對話、被 PreToolUse hook 擋住、或對上 deny 規則時,都不會跑。

已安裝的 mod 可以翻案的例外

機器上沒有 managed settings,而且這個工作階段不是用 Team 或 Enterprise 的 /login 當憑證時,已安裝的 mod 可以核准一個被 PreToolUse hook 擋住的呼叫。用 API key 或長期的 CLAUDE_CODE_OAUTH_TOKEN 跑的工作階段,不算用了那個登入,就算登入資料還留著也一樣。

在 plan mode,mod 只能核准這種被擋住的呼叫裡的唯讀呼叫,不能核准檔案編輯。

反過來說:有 managed settings,或工作階段的憑證是 Team/Enterprise 的 /login 時,預設情況下 mod 的核准過不了你的 ask 規則,也過不了 PreToolUse hooks。

PostToolUse 的 classifierContext

PostToolUse hook 的 classifierContext 把這次結果的短註解交給 auto mode 分類器,而不是交給 Claude。分類器讀它時當成應用程式提供的上下文。分類器本身收不到工具結果,所以這是告訴它「這次呼叫回了什麼」的支援方式。需要 Claude Code v2.1.236 或更新。

參考裡的例子:

{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "classifierContext": "This query ran against the staging database, not production."
  }
}

來自設定檔、外掛、skills、agent frontmatter 的註解,分類器當成未經查證的應用程式上下文。它不會因此變成使用者意圖。若註解宣稱你已核准某事,分類器會對照你在對話裡自己說的話。不要把不受信任的工具輸出或第三方文字抄進這個欄位。

簡化順序

下面是文件裡的先後,收成三步。Critical-path 的 rm、受保護路徑,以及必須人工確認的 MCP 工具,文件另有分支。

  1. 1. PreToolUse hook 所有權限模式之前。deny 擋下這次呼叫。ask 強制詢問。allow 只表示這個 hook 沒擋。上面的 mod 例外仍可能核准被 hook 擋住的呼叫。
  2. 2. deny/ask/allow 規則 permissions.deny 在分類器之前擋下。permissions.ask 在 auto mode 仍會問。Deny 與 ask 規則不論 hook 回什麼都會再看一次。
  3. 3. 權限模式與分類器 依目前的權限模式處理。在 auto mode,規則沒有處理完的動作,有的直接核准,有的交給分類器。Hook 回 ask 時仍會提示:分類器可以拒絕,但不能安靜核准。

來源