Хуки Cursor: полное руководство и почему они иногда не срабатывают

Хуки Cursor позволяют скрипту наблюдать за действиями агента или блокировать их: каждую shell-команду, вызов MCP, чтение и правку файла. Это мощный инструмент, и ломается он незаметно. Здесь собрано всё, что мы узнали, настраивая их в реальной работе.

Автор: Aslan, команда Pet Island · Обновлено 26 окт. 2026 г. · 7 мин чтения

КОРОТКО

Поместите hooks.json с "version": 1 в ~/.cursor/ (для всех проектов) или в .cursor/ в репозитории, назначьте каждому событию команду и выводите JSON в stdout. Используйте beforeShellExecution и beforeMCPExecution, чтобы разрешать, запрещать или спрашивать, и задайте failClosed: true, если сломанный хук должен блокировать команду, а не пропускать её. Если хук будто игнорируется, сначала откройте канал вывода Hooks: чаще всего проблема в пути, в недоверенной рабочей области, в некорректном JSON или в событии, которое Cursor CLI пока не отправляет.

Что такое хуки Cursor

Хук — это команда, которую Cursor запускает в определённой точке цикла агента. Cursor передаёт на стандартный ввод команды объект JSON с описанием того, что сейчас произойдёт, ждёт и читает ответ JSON из её стандартного вывода. Одни хуки только наблюдают (записывают правку в лог, форматируют файл). Другие принимают решения: хук beforeShellExecution может позволить команде выполниться, остановить её или сначала спросить вас.

Поэтому хуки подходят для трёх задач: защитные ограничения (никогда не запускать rm -rf или git push --force без человека), автоматизация (форматировать или проверять линтером после каждой правки) и наблюдаемость (записывать или пересылать действия агента, чтобы вы знали, когда нужны ему).

Где находится hooks.json

Cursor читает хуки из четырёх мест и запускает их все. Выполняется каждый подходящий хук из каждого источника, а Cursor объединяет их ответы.

УровеньФайлПримечания
Пользователь~/.cursor/hooks.jsonДействует во всех проектах. Относительные команды разрешаются от ~/.cursor/.
Проект<project>/.cursor/hooks.jsonХранится в репозитории. Работает только в доверенной рабочей области. Относительные команды разрешаются от корня проекта.
КомандаВеб-панель CursorТолько Enterprise, синхронизируется у всех участников.
EnterpriseC:\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. Одно это решает удивительно много проблем, о которых пишут на форуме.

События, на которые можно повесить хук

Актуальный список из документации Cursor, сгруппированный по назначению:

ГруппаСобытияМожет блокировать?
Shell и MCPbeforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecutionДва хука before…: разрешить, запретить или спросить
Любой инструментpreToolUse, postToolUse, postToolUseFailurepreToolUse: разрешить или запретить (ask сейчас не применяется)
ФайлыbeforeReadFile, afterFileEditbeforeReadFile: разрешить или запретить
ПромптbeforeSubmitPromptДа, с continue: false
Цикл агентаstop, afterAgentResponse, afterAgentThought, preCompactНет (stop может отправить дополнительное сообщение)
СубагентыsubagentStart, subagentStopsubagentStart: разрешить или запретить (ask считается запретом)
Сессия и приложениеsessionStart, sessionEnd, workspaceOpenНет
Автодополнения TabbeforeTabFileRead, afterTabFileEditbeforeTabFileRead: разрешить или запретить

Каждое событие получает несколько общих полей (conversation_id, generation_id, model, hook_event_name, cursor_version, workspace_roots) и свои собственные. beforeShellExecution получает полную command и её cwd; stop получает status со значением completed, aborted или error.

Разрешить, запретить или спросить

Хук, принимающий решение, выводит один объект JSON. Для shell-хука это выглядит так:

stdout хука beforeShellExecutionКопировать
{
"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. Любой другой код выхода считается сбоем хука, и действие выполняется, если не задан failClosed. Для хуков разрешений некорректный JSON или JSON, не соответствующий схеме, блокирует действие.

Документация Cursor указывает, что ask поддерживается для beforeShellExecution и beforeMCPExecution. В марте 2026 года сотрудники Cursor написали на форуме, что хуки применяли только deny, а allow и ask «basically ignored» (по сути игнорировались), особенно при включённом списке разрешённых команд или песочнице. Объявления об исправлении мы не нашли. Если защита должна срабатывать гарантированно, возвращайте deny, а не ask, и проверьте это в своей версии.

failClosed и timeout

У каждой записи хука рядом с command могут быть параметры:

.cursor/hooks.jsonКопировать
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true превращает сбой, тайм-аут, ненулевой код выхода или пустой вывод в блокировку. По умолчанию false: сломанный защитный хук молча пропускает всё. Для хука безопасности почти всегда нужно true.
  • timeout задаётся в секундах. Оставьте достаточный запас, если хук ждёт человека: тому, кто читает дифф, нужно больше пяти секунд.
  • matcher определяет, когда запускается хук. Для shell-хуков он сравнивается с полной строкой команды, для хуков инструментов с типом инструмента, например Shell, Read, Write или MCP:<tool_name>.

Здесь есть компромисс. В июле 2026 года пользователь macOS столкнулся с ошибкой «MainThreadShellExec not initialized»: собственный shell-хост Cursor ещё не был готов, и поскольку хук работал в режиме fail-closed, shell агента оказался заблокирован. Сотрудники Cursor сообщили, что исправление уже вышло, и рекомендовали оставить failClosed: true. Если вы видите эту ошибку в старой сборке, обходным решением была команда «Developer: Reload Window».

Хуки в Windows

В Windows настольное приложение Cursor запускает команды хуков через PowerShell и передаёт им JSON по конвейеру. Скрипт PowerShell читает его из $input; любая другая программа читает стандартный ввод как обычно. Спотыкаются на трёх вещах:

  1. Bash-скрипты не запускаются как есть. guard.sh от коллеги на macOS падает в PowerShell. Используйте скрипт .ps1, скомпилированную программу или явно вызывайте интерпретатор (python .cursor/hooks/guard.py). В обсуждении на форуме от января 2026 года конфигурация с Git Bash падает с ошибкой syntax error near unexpected token '[Convert]::FromBase64String', то есть код PowerShell попадает в bash.
  2. Политика выполнения. Если PowerShell отказывается запускать скрипты, запускайте их командой powershell -NoProfile -ExecutionPolicy Bypass -File …, выводите JSON и завершайте exit 0.
  3. Программы с GUI возвращаются слишком рано. Это стоило нам целого дня. Если хук — программа Windows, собранная для подсистемы GUI, PowerShell запускает её и идёт дальше, не дожидаясь завершения. Cursor читает пустой вывод, поэтому кажется, что хук ничего не сделал (или, с failClosed, блокирует всё). Соберите хук как консольную программу или оберните его так, чтобы PowerShell дожидался его завершения.

Хукам уровня проекта также нужна доверенная рабочая область. Сотрудник Cursor перечислил, что проверить, если они ничего не делают: строку в логе Hooks «Hook N produced no output», отметку о доверенной рабочей области в Settings → Hooks и ошибки вроде spawn, ENOENT, EPERM или ExecutionPolicy в консоли.

Хуки в Cursor CLI

Cursor CLI (cursor-agent) читает те же ~/.cursor/hooks.json и .cursor/hooks.json, но никогда не отправлял все события, которые отправляет редактор. В январе 2026 года срабатывали только два shell-хука. К апрелю сотрудники Cursor подтвердили, что в CLI работают beforeShellExecution, afterShellExecution, afterFileEdit, postToolUse, stop и sessionStart, а afterAgentResponse и afterAgentThought по-прежнему нет (повторно подтверждено в мае). Любое событие не из этого списка проверьте, прежде чем на него полагаться.

Облачные агенты ещё строже: пользовательские хуки из ~/.cursor/hooks.json там вообще не запускаются.

Когда хук не срабатывает: чек-лист

  1. Откройте канал вывода Hooks (View → Output → Hooks) или вкладку Hooks в Customize. Там видно, какие хуки загрузились, каждый запуск и ошибки.
  2. Проверьте сам файл JSON. Есть "version": 1, имена событий написаны точно (они чувствительны к регистру), JSON корректен.
  3. Проверьте путь. Относительные команды разрешаются от корня проекта для хуков проекта и от ~/.cursor/ для пользовательских хуков.
  4. Отметьте рабочую область как доверенную. Хуки проекта не запускаются в недоверенной папке.
  5. Запустите хук вручную. Передайте ему на вход пример JSON и посмотрите на stdout. Всё, кроме одного объекта JSON (случайный echo, предупреждение), ломает разбор.
  6. Перезапустите Cursor. При сохранении файл перезагружается, но в нескольких случаях с форума помог только полный перезапуск.
  7. Знайте о пробелах. Сообщалось, что ask и allow игнорируются при списке разрешённых команд и песочнице; что subagentStart/subagentStop в некоторых версиях не срабатывают; CLI пропускает часть событий. Коммиты из встроенной панели Source Control не перехватываются: события хука pre-commit нет.

Хуки, auto-run и Auto-review

Хуки работают отдельно от собственных настроек подтверждения Cursor (Settings → Agents → Approvals & Execution). Auto-run и Auto-review определяют, спросит ли вас Cursor в своей панели; ваш хук добавляет поверх своё решение. Поэтому жалоба «мой хук сказал ask, а команда просто выполнилась» встречается так часто: её уже разрешил другой механизм разрешений.

Ещё одно, что мы узнали на собственном опыте: с Auto-review Cursor может спросить о некоторых командах в своём окне. Хук этого вопроса никогда не видит. Он возникает внутри Cursor, а не в конвейере хуков.

Где здесь Pet Island

Если от хуков вам нужно «показывай каждую рискованную команду и дай решить, не переключая окна», именно это Pet Island и делает с Cursor. Он сам устанавливает хуки (beforeShellExecution и beforeMCPExecution, с включённым failClosed, чтобы упавший помощник никогда не пропустил команду) и выводит каждый запрос на маленький остров в верхней части экрана с полной командой. Вы разрешаете или запрещаете его там; собственный агент Cursor ждёт.

Команды и правки файлов из редактора Cursor работают с острова. Вопросы и планы показываются на острове, а отвечаете вы на них в Cursor. В Cursor CLI команды работают с острова; остальные события зависят от того, что отправляет CLI. При удалении убираются только записи, добавленные Pet Island; ваши собственные хуки остаются.

Частые вопросы

Работают ли хуки Cursor в Windows?

Да. Настольное приложение запускает их через PowerShell и передаёт JSON на стандартный ввод ($input в скрипте PowerShell). Bash-скриптам, написанным для macOS, нужна версия на PowerShell или Python, а программы подсистемы GUI нужно оборачивать, чтобы PowerShell дожидался их завершения.

Почему хук возвращает ask, а команда всё равно выполняется?

В марте 2026 года сотрудники Cursor сообщили, что хуки надёжно применяли только deny; allow и ask могли переопределяться списком разрешённых команд или песочницей. Используйте deny для всего, что не должно выполняться, и проверяйте в канале вывода Hooks, что на самом деле вернул хук.

Что делает failClosed?

Если failClosed равен true, сбой, тайм-аут, ненулевой код выхода или пустой вывод блокируют действие. Без него сломанный хук пропускает действие.

Где посмотреть ошибки хуков?

В канале вывода Hooks (View → Output → Hooks) и на вкладке Hooks в Customize.

Работают ли хуки в Cursor CLI?

Частично. CLI читает те же файлы hooks.json. По состоянию на май 2026 года сотрудники Cursor подтвердили shell-хуки, afterFileEdit, postToolUse, stop и sessionStart, но не afterAgentResponse и afterAgentThought.

Может ли хук остановить git-коммит из панели Source Control?

Нет. В Cursor нет события хука pre-commit, и коммиты через встроенный интерфейс Source Control не перехватываются. Для этого используйте обычный git-хук pre-commit.

Источники

Все настройки и описанное поведение на этой странице сверены с этими источниками 26 октября 2026 г.. Агенты быстро меняются; если что-то уже не совпадает, приоритет за официальной страницей.

ЧИТАЙТЕ ТАКЖЕ

Отвечайте любому агенту прямо с верхней части экрана.

Windows и Mac · 7 дней бесплатно, затем $8.99 один раз · $1 с каждой продажи идёт на корм бездомным животным

Попробовать Pet Island бесплатно