Cursor hook 完整指南,以及它們有時不觸發的原因
Cursor hook 讓指令碼可以監看或封鎖代理程式的動作:每個 shell 指令、MCP 呼叫、檔案讀取和編輯。它們功能強大,失敗時卻悄無聲息。這裡整理了我們實際串接 hook 時學到的一切。
簡答
在 ~/.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 文件的範例):
version 必須是 1。Cursor 會監看這個檔案,儲存時重新載入。如果變更沒有生效,請重新啟動 Cursor。光是這一步就解決了論壇上數量驚人的回報。
可以掛上 hook 的事件
以下是 Cursor 文件中的最新清單,依用途分組:
| 群組 | 事件 | 可以封鎖嗎? |
|---|---|---|
| Shell 與 MCP | beforeShellExecution、afterShellExecution、beforeMCPExecution、afterMCPExecution | 兩個 before… hook:允許、拒絕或詢問 |
| 任何工具 | preToolUse、postToolUse、postToolUseFailure | preToolUse:允許或拒絕(目前不強制執行 ask) |
| 檔案 | beforeReadFile、afterFileEdit | beforeReadFile:允許或拒絕 |
| 提示 | beforeSubmitPrompt | 可以,使用 continue: false |
| 代理程式迴圈 | stop、afterAgentResponse、afterAgentThought、preCompact | 不行(stop 可以傳送後續訊息) |
| 子代理程式 | subagentStart、subagentStop | subagentStart:允許或拒絕(ask 視為拒絕) |
| 工作階段與應用程式 | sessionStart、sessionEnd、workspaceOpen | 不行 |
| Tab 自動完成 | beforeTabFileRead、afterTabFileEdit | beforeTabFileRead:允許或拒絕 |
每個事件都會收到幾個共通欄位(conversation_id、generation_id、model、hook_event_name、cursor_version、workspace_roots),以及事件自己的欄位。beforeShellExecution 會收到完整的 command 及其 cwd;stop 會收到值為 completed、aborted 或 error 的 status。
允許、拒絕與詢問
負責決定的 hook 會印出一個 JSON 物件。shell hook 的輸出如下:
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 旁邊加上選項:
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 讀取;其他程式則照常讀取標準輸入。有三件事常讓人踩雷:
- Bash 指令碼無法直接執行。 macOS 同事寫的
guard.sh在 PowerShell 下會失敗。請使用.ps1指令碼、編譯好的程式,或明確呼叫你的直譯器(python .cursor/hooks/guard.py)。2026 年 1 月的一個論壇討論串中,Git Bash 設定以syntax error near unexpected token '[Convert]::FromBase64String'失敗,這就是 PowerShell 程式碼跑到了 bash。 - 執行原則。 如果 PowerShell 拒絕執行指令碼,請用
powershell -NoProfile -ExecutionPolicy Bypass -File …啟動,印出 JSON,最後以exit 0結束。 - 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 不觸發時的檢查清單
- 開啟 Hooks 輸出頻道(View → Output → Hooks)或 Customize 中的 Hooks 分頁。它會顯示載入了哪些 hook、每次執行和錯誤。
- 檢查 JSON 檔案本身。 是否有
"version": 1、事件名稱拼寫是否完全正確(區分大小寫)、JSON 是否有效。 - 檢查路徑。 專案 hook 的相對路徑指令以專案根目錄為基準解析,使用者 hook 則以
~/.cursor/為基準。 - 信任工作區。 專案 hook 不會在未受信任的資料夾中執行。
- 手動執行 hook。 以管道送入範例 JSON,然後查看 stdout。除了一個 JSON 物件以外的任何內容(多出來的
echo、一則警告)都會導致解析失敗。 - 重新啟動 Cursor。 儲存會重新載入檔案,但好幾則論壇回報都是完整重新啟動後才解決。
- 了解已知缺口。 有回報指出在允許清單和沙箱旁,
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日 對照下列頁面確認。代理程式更新很快;若內容不再相符,請以官方頁面為準。
- Cursor 文件:Hooks
- Cursor 論壇:Cursor hook 未如預期執行(員工:只強制執行 deny)
- Cursor 論壇:beforeShellExecution 的 allow/ask 被忽略,允許清單優先
- Cursor 論壇:Fail-closed hook 與 MainThreadShellExec not initialized
- Cursor 論壇:hook 回傳格式錯誤的 JSON 時悄悄放行指令(已修正)
- Cursor 論壇:Cursor CLI 未傳送所有 hook 事件
- Cursor 論壇:專案層級 hook 無法在 Windows 上執行
- Cursor 論壇:專案 hook 在 Windows 上搭配 Git Bash 時失敗
- Cursor 論壇:subagentStart 和 subagentStop 從未觸發