Хуки Cursor: полное руководство и почему они иногда не срабатывают
Хуки Cursor позволяют скрипту наблюдать за действиями агента или блокировать их: каждую shell-команду, вызов MCP, чтение и правку файла. Это мощный инструмент, и ломается он незаметно. Здесь собрано всё, что мы узнали, настраивая их в реальной работе.
КОРОТКО
Поместите 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, синхронизируется у всех участников. |
| 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. Одно это решает удивительно много проблем, о которых пишут на форуме.
События, на которые можно повесить хук
Актуальный список из документации Cursor, сгруппированный по назначению:
| Группа | События | Может блокировать? |
|---|---|---|
| Shell и MCP | beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution | Два хука before…: разрешить, запретить или спросить |
| Любой инструмент | 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 получает status со значением completed, aborted или error.
Разрешить, запретить или спросить
Хук, принимающий решение, выводит один объект JSON. Для shell-хука это выглядит так:
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 могут быть параметры:
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; любая другая программа читает стандартный ввод как обычно. Спотыкаются на трёх вещах:
- Bash-скрипты не запускаются как есть.
guard.shот коллеги на macOS падает в PowerShell. Используйте скрипт.ps1, скомпилированную программу или явно вызывайте интерпретатор (python .cursor/hooks/guard.py). В обсуждении на форуме от января 2026 года конфигурация с Git Bash падает с ошибкойsyntax error near unexpected token '[Convert]::FromBase64String', то есть код PowerShell попадает в bash. - Политика выполнения. Если PowerShell отказывается запускать скрипты, запускайте их командой
powershell -NoProfile -ExecutionPolicy Bypass -File …, выводите JSON и завершайтеexit 0. - Программы с 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 там вообще не запускаются.
Когда хук не срабатывает: чек-лист
- Откройте канал вывода Hooks (View → Output → Hooks) или вкладку Hooks в Customize. Там видно, какие хуки загрузились, каждый запуск и ошибки.
- Проверьте сам файл JSON. Есть
"version": 1, имена событий написаны точно (они чувствительны к регистру), JSON корректен. - Проверьте путь. Относительные команды разрешаются от корня проекта для хуков проекта и от
~/.cursor/для пользовательских хуков. - Отметьте рабочую область как доверенную. Хуки проекта не запускаются в недоверенной папке.
- Запустите хук вручную. Передайте ему на вход пример JSON и посмотрите на stdout. Всё, кроме одного объекта JSON (случайный
echo, предупреждение), ломает разбор. - Перезапустите Cursor. При сохранении файл перезагружается, но в нескольких случаях с форума помог только полный перезапуск.
- Знайте о пробелах. Сообщалось, что
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 г.. Агенты быстро меняются; если что-то уже не совпадает, приоритет за официальной страницей.
- Документация Cursor: Hooks
- Форум Cursor: The cursor hooks did not execute as expected (сотрудники: применяется только deny)
- Форум Cursor: beforeShellExecution allow/ask ignored, allow-list takes precedence
- Форум Cursor: Fail-closed hook and MainThreadShellExec not initialized
- Форум Cursor: Malformed JSON from a hook silently allowed the command (исправлено)
- Форум Cursor: Cursor CLI doesn’t send all hook events
- Форум Cursor: Project-level hooks fail to execute on Windows
- Форум Cursor: Project hooks fail on Windows with Git Bash
- Форум Cursor: subagentStart and subagentStop never fire