Cursor hook 完整指南,以及它們有時不觸發的原因

Cursor hook 讓指令碼可以監看或封鎖代理程式的動作:每個 shell 指令、MCP 呼叫、檔案讀取和編輯。它們功能強大,失敗時卻悄無聲息。這裡整理了我們實際串接 hook 時學到的一切。

作者:Aslan,Pet Island 團隊 · 更新於 2026年10月26日 · 閱讀時間 7 分鐘

簡答

在 ~/.cursor/(所有專案)或儲存庫的 .cursor/ 中放一個含有 "version": 1 的 hooks.json,把每個事件指向一個指令,並把 JSON 印到 stdout。使用 beforeShellExecution 和 beforeMCPExecution 來允許、拒絕或詢問;如果故障的 hook 必須封鎖而不是放行指令,請設定 failClosed: true。當 hook 似乎被忽略時,請先開啟 Hooks 輸出頻道:大多數問題出在路徑、未受信任的工作區、無效的 JSON,或 Cursor CLI 尚未傳送的事件。

Cursor hook 是什麼

hook 是 Cursor 在代理程式迴圈中固定時間點執行的指令。Cursor 會透過該指令的標準輸入傳送一個描述即將發生之事的 JSON 物件,等待,然後從標準輸出讀取 JSON 回應。有些 hook 只負責觀察(記錄編輯、格式化檔案)。有些則負責決定:beforeShellExecution hook 可以讓指令執行、停止它,或先詢問你。

因此 hook 適合三種工作:防護(沒有人確認就絕不執行 rm -rf 或 git push --force)、自動化(每次編輯後格式化或 lint),以及可見性(記錄或轉送代理程式的動作,讓你知道它何時需要你)。

hooks.json 放在哪裡

Cursor 會從四個位置讀取 hook 並全部執行。所有來源中符合的 hook 都會執行,Cursor 再合併它們的回應。

層級檔案備註
使用者~/.cursor/hooks.json套用到所有專案。相對路徑的指令以 ~/.cursor/ 為基準解析。
專案<project>/.cursor/hooks.json提交到儲存庫中。只在受信任的工作區中執行。相對路徑的指令以專案根目錄為基準解析。
團隊Cursor 網頁儀表板僅限 Enterprise,會同步給每位成員。
企業C:\ProgramData\Cursor\hooks.json(Windows)、/Library/Application Support/Cursor/hooks.json(macOS)、/etc/cursor/hooks.json(Linux、WSL)由 IT 管理。

當回應彼此衝突時,最嚴格的勝出:任何來源的 deny 都勝過 ask,ask 又勝過 allow。最精簡的可用檔案如下(取自 Cursor 文件的範例):

~/.cursor/hooks.json複製
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": "./hooks/format.sh" }]
}
}

version 必須是 1。Cursor 會監看這個檔案,儲存時重新載入。如果變更沒有生效,請重新啟動 Cursor。光是這一步就解決了論壇上數量驚人的回報。

可以掛上 hook 的事件

以下是 Cursor 文件中的最新清單,依用途分組:

群組事件可以封鎖嗎?
Shell 與 MCPbeforeShellExecution、afterShellExecution、beforeMCPExecution、afterMCPExecution兩個 before… hook:允許、拒絕或詢問
任何工具preToolUse、postToolUse、postToolUseFailurepreToolUse:允許或拒絕(目前不強制執行 ask)
檔案beforeReadFile、afterFileEditbeforeReadFile:允許或拒絕
提示beforeSubmitPrompt可以,使用 continue: false
代理程式迴圈stop、afterAgentResponse、afterAgentThought、preCompact不行(stop 可以傳送後續訊息)
子代理程式subagentStart、subagentStopsubagentStart:允許或拒絕(ask 視為拒絕)
工作階段與應用程式sessionStart、sessionEnd、workspaceOpen不行
Tab 自動完成beforeTabFileRead、afterTabFileEditbeforeTabFileRead:允許或拒絕

每個事件都會收到幾個共通欄位(conversation_id、generation_id、model、hook_event_name、cursor_version、workspace_roots),以及事件自己的欄位。beforeShellExecution 會收到完整的 command 及其 cwd;stop 會收到值為 completed、aborted 或 error 的 status。

允許、拒絕與詢問

負責決定的 hook 會印出一個 JSON 物件。shell hook 的輸出如下:

beforeShellExecution hook 的 stdout複製
{
"permission": "ask",
"user_message": "This pushes to main. Run it?",
"agent_message": "The user wants to confirm pushes."
}
  • permission 是 allow、deny 或 ask。
  • user_message 是你在 Cursor 中看到的內容。
  • agent_message 是告訴代理程式的內容,讓它能改變做法,而不是重試同一個指令。

結束代碼和 JSON 一樣重要。結束代碼 0 表示「使用我的 JSON」。結束代碼 2 會封鎖動作,等同 deny。其他任何結束代碼都會被視為 hook 失敗,動作會繼續執行,除非你設定了 failClosed。對權限 hook 而言,無效的 JSON 或不符合結構描述的 JSON 會封鎖動作。

Cursor 文件列出 beforeShellExecution 和 beforeMCPExecution 支援 ask。2026 年 3 月,Cursor 員工在論壇上表示 hook 只會強制執行 deny,而 allow 和 ask「basically ignored」(基本上被忽略),在開啟指令允許清單或沙箱時尤其如此。我們沒有找到修正公告。如果某項防護必須守住,請回傳 deny 而不是 ask,並在你自己的版本中測試。

failClosed 與 timeout

每個 hook 項目都可以在 command 旁邊加上選項:

.cursor/hooks.json複製
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true 會把當機、逾時、非零結束代碼或空白輸出都變成封鎖。預設值是 false:故障的防護會悄悄放行一切。對安全性 hook 來說,你幾乎一定要設成 true。
  • timeout 的單位是秒。如果你的 hook 要等人回應,請留足時間:一個人閱讀差異內容需要的不只五秒。
  • matcher 用來篩選 hook 何時執行。對 shell hook,會比對完整的指令字串;對工具 hook,則比對工具類型,例如 Shell、Read、Write 或 MCP:<tool_name>。

這裡有個取捨。2026 年 7 月,一位 macOS 使用者遇到「MainThreadShellExec not initialized」:Cursor 自己的 shell 主機尚未就緒,而因為 hook 是 fail-closed,代理程式的 shell 就被封鎖了。Cursor 員工表示修正已經推出,並建議保留 failClosed: true。如果你在較舊的組建上看到這個錯誤,因應方式是執行「Developer: Reload Window」。

Windows 上的 hook

在 Windows 上,Cursor 桌面應用程式會透過 PowerShell 執行 hook 指令,並以管道送入 JSON。PowerShell 指令碼從 $input 讀取;其他程式則照常讀取標準輸入。有三件事常讓人踩雷:

  1. Bash 指令碼無法直接執行。 macOS 同事寫的 guard.sh 在 PowerShell 下會失敗。請使用 .ps1 指令碼、編譯好的程式,或明確呼叫你的直譯器(python .cursor/hooks/guard.py)。2026 年 1 月的一個論壇討論串中,Git Bash 設定以 syntax error near unexpected token '[Convert]::FromBase64String' 失敗,這就是 PowerShell 程式碼跑到了 bash。
  2. 執行原則。 如果 PowerShell 拒絕執行指令碼,請用 powershell -NoProfile -ExecutionPolicy Bypass -File … 啟動,印出 JSON,最後以 exit 0 結束。
  3. GUI 程式太早返回。 這個問題花了我們一整天。如果你的 hook 是為 GUI 子系統建置的 Windows 程式,PowerShell 啟動它之後就會繼續往下,不會等待。Cursor 讀到空白輸出,hook 看起來就像什麼都沒做(若設定了 failClosed,則會封鎖一切)。請把 hook 建置為主控台程式,或加上包裝讓 PowerShell 等它結束。

專案層級的 hook 也需要受信任的工作區。一位 Cursor 員工列出了它們毫無作用時要檢查的項目:Hooks 記錄中的「Hook N produced no output」這一行、Settings → Hooks 是否顯示工作區已受信任,以及主控台中的 spawn、ENOENT、EPERM 或 ExecutionPolicy 等錯誤。

Cursor CLI 中的 hook

Cursor CLI(cursor-agent)會讀取同樣的 ~/.cursor/hooks.json 和 .cursor/hooks.json,但它從未傳送編輯器傳送的所有事件。2026 年 1 月時只有兩個 shell hook 會觸發。到了 4 月,Cursor 員工確認 beforeShellExecution、afterShellExecution、afterFileEdit、postToolUse、stop 和 sessionStart 在 CLI 中可以運作,而 afterAgentResponse 和 afterAgentThought 仍然不行(5 月再次確認)。不在這份清單上的事件,請先測試再依賴。

雲端代理程式更嚴格:來自 ~/.cursor/hooks.json 的使用者層級 hook 在那裡完全不會執行。

hook 不觸發時的檢查清單

  1. 開啟 Hooks 輸出頻道(View → Output → Hooks)或 Customize 中的 Hooks 分頁。它會顯示載入了哪些 hook、每次執行和錯誤。
  2. 檢查 JSON 檔案本身。 是否有 "version": 1、事件名稱拼寫是否完全正確(區分大小寫)、JSON 是否有效。
  3. 檢查路徑。 專案 hook 的相對路徑指令以專案根目錄為基準解析,使用者 hook 則以 ~/.cursor/ 為基準。
  4. 信任工作區。 專案 hook 不會在未受信任的資料夾中執行。
  5. 手動執行 hook。 以管道送入範例 JSON,然後查看 stdout。除了一個 JSON 物件以外的任何內容(多出來的 echo、一則警告)都會導致解析失敗。
  6. 重新啟動 Cursor。 儲存會重新載入檔案,但好幾則論壇回報都是完整重新啟動後才解決。
  7. 了解已知缺口。 有回報指出在允許清單和沙箱旁,ask 和 allow 會被忽略;有回報指出某些版本中 subagentStart/subagentStop 不會觸發;CLI 會略過部分事件。從內建原始檔控制面板進行的提交不會被攔截:沒有 pre-commit hook 事件。

Hook、自動執行與 Auto-review

Hook 與 Cursor 自己的核准設定(Settings → Agents → Approvals & Execution)是分開的。自動執行和 Auto-review 決定 Cursor 是否在其面板中詢問你;你的 hook 則在此之上加入自己的決定。這就是為什麼「我的 hook 回傳了 ask,但指令還是直接執行了」是這麼常見的回報:另一條權限路徑已經允許了它。

還有一件我們吃過苦頭才學到的事:啟用 Auto-review 時,Cursor 可能會在自己的視窗中詢問某些指令。hook 永遠看不到這個提問。它發生在 Cursor 內部,而不是 hook 管線中。

Pet Island 的定位

如果你想從 hook 得到的是「讓我看到每個有風險的指令,並讓我不用切換視窗就能決定」,這正是 Pet Island 搭配 Cursor 所做的事。它會替你安裝 hook(beforeShellExecution 和 beforeMCPExecution,並開啟 failClosed,讓停止運作的輔助程式永遠不會放行指令),並把每個請求連同完整指令放到螢幕頂端的一座小島上。你在那裡允許或拒絕;Cursor 自己的代理程式會等待。

來自 Cursor 編輯器的指令和檔案編輯都能在島上處理。提問和計畫會顯示在島上,你再到 Cursor 中回答。在 Cursor CLI 中,指令可以在島上處理;其他事件則取決於 CLI 傳送了什麼。解除安裝只會移除 Pet Island 新增的項目;你自己的 hook 會保留。

常見問題

Cursor hook 在 Windows 上能用嗎?

可以。桌面應用程式會透過 PowerShell 執行它們,並透過標準輸入傳遞 JSON(PowerShell 指令碼中為 $input)。為 macOS 撰寫的 Bash 指令碼需要 PowerShell 或 Python 版本,而 GUI 子系統程式必須加上包裝,讓 PowerShell 等待它們。

為什麼我的 hook 回傳 ask,指令卻還是執行了?

Cursor 員工在 2026 年 3 月表示,hook 只能可靠地強制執行 deny;allow 和 ask 可能被允許清單或沙箱覆寫。凡是絕不能執行的東西都請用 deny,並查看 Hooks 輸出頻道,確認你的 hook 實際回傳了什麼。

failClosed 有什麼作用?

將 failClosed 設為 true 時,當機、逾時、非零結束代碼或空白輸出都會封鎖動作。沒有設定時,故障的 hook 會讓動作繼續執行。

在哪裡可以看到 hook 錯誤?

在 Hooks 輸出頻道(View → Output → Hooks)和 Customize 中的 Hooks 分頁。

hook 在 Cursor CLI 中能用嗎?

部分可以。CLI 會讀取同樣的 hooks.json 檔案。截至 2026 年 5 月,Cursor 員工確認 shell hook、afterFileEdit、postToolUse、stop 和 sessionStart 可以運作,但 afterAgentResponse 和 afterAgentThought 不行。

hook 可以阻止從原始檔控制面板進行的 git 提交嗎?

不行。Cursor 沒有 pre-commit hook 事件,透過內建原始檔控制介面進行的提交不會被攔截。這種情況請使用一般的 git pre-commit hook。

資料來源

本頁所有設定與行為均已於 2026年10月26日 對照下列頁面確認。代理程式更新很快;若內容不再相符,請以官方頁面為準。

延伸閱讀

從螢幕頂端回應每一個代理程式。

Windows 與 Mac · 免費試用 7 天,之後一次付清 $8.99 · 每筆銷售提撥 $1 餵養街頭動物

免費試用 Pet Island