Hooki w Cursor: kompletny przewodnik i dlaczego czasem się nie uruchamiają

Hooki w Cursor pozwalają skryptowi obserwować lub blokować to, co robi agent: każde polecenie powłoki, każde wywołanie MCP, każdy odczyt i edycję pliku. Mają duże możliwości i zawodzą po cichu. Oto wszystko, czego nauczyliśmy się, podłączając je w prawdziwym projekcie.

Autor: Aslan, zespół Pet Island · Zaktualizowano 26 paź 2026 · 7 min czytania

KRÓTKA ODPOWIEDŹ

Umieść plik hooks.json z "version": 1 w ~/.cursor/ (wszystkie projekty) lub w .cursor/ w repozytorium, przypisz każdemu zdarzeniu polecenie i wypisuj JSON na stdout. Używaj beforeShellExecution i beforeMCPExecution, żeby zezwalać, odmawiać lub pytać, i ustaw failClosed: true, jeśli uszkodzony hook ma blokować, zamiast przepuszczać polecenie. Gdy hook wydaje się ignorowany, najpierw otwórz kanał wyjściowy Hooks: większość problemów to ścieżka, niezaufany obszar roboczy, nieprawidłowy JSON albo zdarzenie, którego Cursor CLI jeszcze nie wysyła.

Czym są hooki w Cursor

Hook to polecenie, które Cursor uruchamia w określonym punkcie pętli agenta. Cursor wysyła na standardowe wejście polecenia obiekt JSON opisujący, co ma się wydarzyć, czeka i odczytuje odpowiedź JSON z jego standardowego wyjścia. Niektóre hooki tylko obserwują (logują edycję, formatują plik). Inne decydują: hook beforeShellExecution może pozwolić na uruchomienie polecenia, zatrzymać je albo najpierw zapytać ciebie.

Dzięki temu hooki są właściwym narzędziem do trzech zadań: zabezpieczeń (nigdy nie uruchamiaj rm -rf ani git push --force bez człowieka), automatyzacji (formatowanie lub lintowanie po każdej edycji) i widoczności (logowanie lub przekazywanie tego, co robi agent, żebyś wiedział, kiedy cię potrzebuje).

Gdzie znajduje się hooks.json

Cursor wczytuje hooki z czterech miejsc i uruchamia wszystkie. Każdy pasujący hook z każdego źródła zostaje uruchomiony, a Cursor łączy ich odpowiedzi.

PoziomPlikUwagi
Użytkownik~/.cursor/hooks.jsonDotyczy każdego projektu. Względne polecenia są rozwiązywane względem ~/.cursor/.
Projekt<project>/.cursor/hooks.jsonZapisany w repozytorium. Działa tylko w zaufanym obszarze roboczym. Względne polecenia są rozwiązywane względem katalogu głównego projektu.
ZespółPanel webowy CursorTylko Enterprise, synchronizowany ze wszystkimi członkami zespołu.
EnterpriseC:\ProgramData\Cursor\hooks.json (Windows), /Library/Application Support/Cursor/hooks.json (macOS), /etc/cursor/hooks.json (Linux, WSL)Zarządzany przez dział IT.

Gdy odpowiedzi są sprzeczne, wygrywa najsurowsza: deny z dowolnego źródła ma pierwszeństwo przed ask, a ask przed allow. Najmniejszy działający plik wygląda tak (to przykład z dokumentacji Cursor):

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

version musi mieć wartość 1. Cursor obserwuje plik i wczytuje go ponownie po zapisaniu. Jeśli zmiana nie zaczyna działać, uruchom Cursor ponownie. Już samo to rozwiązuje zaskakująco wiele zgłoszeń na forum.

Zdarzenia, do których możesz podpiąć hook

Aktualna lista z dokumentacji Cursor, pogrupowana według przeznaczenia:

GrupaZdarzeniaCzy może blokować?
Powłoka i MCPbeforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecutionDwa hooki before…: zezwól, odmów lub zapytaj
Dowolne narzędziepreToolUse, postToolUse, postToolUseFailurepreToolUse: zezwól lub odmów (ask nie jest obecnie egzekwowane)
PlikibeforeReadFile, afterFileEditbeforeReadFile: zezwól lub odmów
PromptbeforeSubmitPromptTak, przez continue: false
Pętla agentastop, afterAgentResponse, afterAgentThought, preCompactNie (stop może wysłać wiadomość uzupełniającą)
SubagentysubagentStart, subagentStopsubagentStart: zezwól lub odmów (ask liczy się jako odmowa)
Sesja i aplikacjasessionStart, sessionEnd, workspaceOpenNie
Uzupełnianie TabbeforeTabFileRead, afterTabFileEditbeforeTabFileRead: zezwól lub odmów

Każde zdarzenie otrzymuje kilka wspólnych pól (conversation_id, generation_id, model, hook_event_name, cursor_version, workspace_roots) oraz własne. beforeShellExecution dostaje pełne command i jego cwd; stop dostaje status o wartości completed, aborted lub error.

Zezwalanie, odmawianie i pytanie

Hook decyzyjny wypisuje jeden obiekt JSON. Dla hooka powłoki wygląda to tak:

stdout hooka beforeShellExecutionKopiuj
{
"permission": "ask",
"user_message": "This pushes to main. Run it?",
"agent_message": "The user wants to confirm pushes."
}
  • permission to allow, deny lub ask.
  • user_message to komunikat, który widzisz w Cursor.
  • agent_message to informacja dla agenta, dzięki której może zmienić kurs, zamiast ponawiać to samo polecenie.

Kody wyjścia są tak samo ważne jak JSON. Kod wyjścia 0 oznacza „użyj mojego JSON”. Kod wyjścia 2 blokuje akcję, tak samo jak deny. Każdy inny kod wyjścia jest traktowany jako nieudany hook i akcja zostaje wykonana, chyba że ustawisz failClosed. W przypadku hooków uprawnień nieprawidłowy JSON lub JSON niezgodny ze schematem blokuje akcję.

Dokumentacja Cursor podaje, że ask jest obsługiwane dla beforeShellExecution i beforeMCPExecution. W marcu 2026 pracownicy Cursor napisali na forum, że hooki egzekwowały tylko deny, a allow i ask były „basically ignored”, zwłaszcza przy włączonej liście dozwolonych poleceń lub piaskownicy. Nie znaleźliśmy ogłoszenia o poprawce. Jeśli zabezpieczenie musi działać, zwracaj deny, a nie ask, i przetestuj to w swojej wersji.

failClosed i timeout

Każdy wpis hooka może zawierać opcje obok command:

.cursor/hooks.jsonKopiuj
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true zamienia awarię, przekroczenie limitu czasu, niezerowy kod wyjścia lub puste dane wyjściowe w blokadę. Domyślnie jest false: uszkodzony strażnik po cichu przepuszcza wszystko. Dla hooka bezpieczeństwa prawie zawsze chcesz true.
  • timeout podaje się w sekundach. Zostaw wystarczający zapas, jeśli hook czeka na człowieka: osoba czytająca diff potrzebuje więcej niż pięciu sekund.
  • matcher filtruje, kiedy hook się uruchamia. Dla hooków powłoki jest porównywany z pełnym ciągiem polecenia; dla hooków narzędzi z typem narzędzia, takim jak Shell, Read, Write lub MCP:<tool_name>.

Jest tu pewien kompromis. W lipcu 2026 użytkownik macOS natrafił na „MainThreadShellExec not initialized”: własny host powłoki Cursor nie był gotowy, a ponieważ hook działał w trybie fail-closed, powłoka agenta została zablokowana. Pracownicy Cursor poinformowali, że poprawka została wydana, i zalecili pozostawienie failClosed: true. Jeśli widzisz ten błąd w starszej wersji, obejściem było „Developer: Reload Window”.

Hooki w systemie Windows

W systemie Windows aplikacja desktopowa Cursor uruchamia polecenia hooków przez PowerShell i przekazuje JSON przez potok. Skrypt PowerShell odczytuje go z $input; każdy inny program jak zwykle czyta standardowe wejście. Trzy rzeczy często zaskakują:

  1. Skrypty bash nie działają bez zmian. guard.sh od kolegi z zespołu pracującego na macOS zawodzi pod PowerShell. Użyj skryptu .ps1, skompilowanego programu albo jawnie wywołaj interpreter (python .cursor/hooks/guard.py). Wątek na forum ze stycznia 2026 pokazuje konfigurację z Git Bash, która kończy się błędem syntax error near unexpected token '[Convert]::FromBase64String', czyli kod PowerShell trafia do bash.
  2. Zasady wykonywania. Jeśli PowerShell odmawia uruchamiania skryptów, uruchamiaj je przez powershell -NoProfile -ExecutionPolicy Bypass -File …, wypisz JSON i zakończ exit 0.
  3. Programy GUI wracają za wcześnie. To kosztowało nas cały dzień. Jeśli twój hook to program Windows zbudowany dla podsystemu GUI, PowerShell go uruchamia i idzie dalej bez czekania. Cursor odczytuje puste dane wyjściowe, więc hook wygląda, jakby nic nie zrobił (albo przy failClosed blokuje wszystko). Zbuduj hook jako program konsolowy albo opakuj go tak, żeby PowerShell czekał na jego zakończenie.

Hooki na poziomie projektu wymagają też zaufanego obszaru roboczego. Pracownik Cursor wymienił, co sprawdzić, gdy nic nie robią: wiersz logu Hooks „Hook N produced no output”, czy Settings → Hooks pokazuje obszar roboczy jako zaufany oraz błędy takie jak spawn, ENOENT, EPERM lub ExecutionPolicy w konsoli.

Hooki w Cursor CLI

Cursor CLI (cursor-agent) wczytuje te same pliki ~/.cursor/hooks.json i .cursor/hooks.json, ale nigdy nie wysyłał wszystkich zdarzeń, które wysyła edytor. W styczniu 2026 uruchamiały się tylko dwa hooki powłoki. W kwietniu pracownicy Cursor potwierdzili, że beforeShellExecution, afterShellExecution, afterFileEdit, postToolUse, stop i sessionStart działają w CLI, a afterAgentResponse i afterAgentThought nadal nie (potwierdzone ponownie w maju). Każde zdarzenie spoza tej listy przetestuj, zanim zaczniesz na nim polegać.

Agenci w chmurze są jeszcze bardziej restrykcyjni: hooki na poziomie użytkownika z ~/.cursor/hooks.json w ogóle się tam nie uruchamiają.

Gdy hook się nie uruchamia: lista kontrolna

  1. Otwórz kanał wyjściowy Hooks (View → Output → Hooks) lub kartę Hooks w Customize. Pokazuje, które hooki zostały wczytane, każde uruchomienie i błędy.
  2. Sprawdź sam plik JSON. Obecne "version": 1, nazwy zdarzeń zapisane dokładnie (wielkość liter ma znaczenie), prawidłowy JSON.
  3. Sprawdź ścieżkę. Względne polecenia są rozwiązywane względem katalogu głównego projektu dla hooków projektu i względem ~/.cursor/ dla hooków użytkownika.
  4. Zaufaj obszarowi roboczemu. Hooki projektu nie działają w niezaufanym folderze.
  5. Uruchom hook ręcznie. Przekaż do niego przez potok przykładowy JSON i sprawdź stdout. Cokolwiek innego niż jeden obiekt JSON (zabłąkane echo, ostrzeżenie) psuje parsowanie.
  6. Uruchom Cursor ponownie. Zapisanie wczytuje plik ponownie, ale kilka zgłoszeń na forum rozwiązał dopiero pełny restart.
  7. Poznaj ograniczenia. Zgłaszano, że ask i allow są ignorowane przy włączonej liście dozwolonych poleceń i piaskownicy; zgłaszano, że subagentStart/subagentStop w niektórych wersjach się nie uruchamiają; CLI pomija niektóre zdarzenia. Commity z wbudowanego panelu Source Control nie są przechwytywane: nie ma zdarzenia hooka pre-commit.

Hooki, auto-run i Auto-review

Hooki są niezależne od własnych ustawień zatwierdzania Cursor (Settings → Agents → Approvals & Execution). Auto-run i Auto-review decydują, czy Cursor zapyta cię w swoim panelu; twój hook dodaje do tego własną decyzję. Dlatego zgłoszenie „mój hook zwrócił ask, ale polecenie po prostu się wykonało” jest tak częste: inna ścieżka uprawnień już na nie zezwoliła.

Jeszcze jedna rzecz, której nauczyliśmy się na własnej skórze: przy Auto-review Cursor może pytać o niektóre polecenia we własnym oknie. Hook nigdy nie widzi tego pytania. Dzieje się ono w Cursor, a nie w potoku hooków.

Gdzie przydaje się Pet Island

Jeśli od hooków chcesz przede wszystkim „pokaż mi każde ryzykowne polecenie i pozwól zdecydować bez przełączania okien”, to właśnie robi Pet Island z Cursor. Instaluje hooki za ciebie (beforeShellExecution i beforeMCPExecution, z włączonym failClosed, żeby niedziałający pomocnik nigdy nie przepuścił polecenia) i umieszcza każdą prośbę z pełnym poleceniem na małej wyspie u góry ekranu. Tam zezwalasz lub odmawiasz; agent Cursor czeka.

Polecenia i edycje plików z edytora Cursor działają z wyspy. Pytania i plany pojawiają się na wyspie, a odpowiadasz na nie w Cursor. W Cursor CLI polecenia działają z wyspy; pozostałe zdarzenia zależą od tego, co wysyła CLI. Odinstalowanie usuwa tylko wpisy dodane przez Pet Island; twoje własne hooki zostają.

CZĘSTE PYTANIA

Czy hooki Cursor działają w systemie Windows?

Tak. Aplikacja desktopowa uruchamia je przez PowerShell i przekazuje JSON na standardowe wejście ($input w skrypcie PowerShell). Skrypty bash napisane dla macOS wymagają wersji w PowerShell lub Pythonie, a programy z podsystemu GUI trzeba opakować tak, żeby PowerShell na nie czekał.

Dlaczego mój hook zwraca ask, a polecenie i tak się wykonuje?

Pracownicy Cursor napisali w marcu 2026, że hooki niezawodnie egzekwowały tylko deny; allow i ask mogły zostać nadpisane przez listę dozwolonych lub piaskownicę. Używaj deny dla wszystkiego, co nie może się uruchomić, i sprawdź w kanale wyjściowym Hooks, co faktycznie zwrócił twój hook.

Co robi failClosed?

Gdy failClosed ma wartość true, awaria, przekroczenie limitu czasu, niezerowy kod wyjścia lub puste dane wyjściowe blokują akcję. Bez tego uszkodzony hook pozwala na wykonanie akcji.

Gdzie zobaczę błędy hooków?

W kanale wyjściowym Hooks (View → Output → Hooks) i na karcie Hooks w Customize.

Czy hooki działają w Cursor CLI?

Częściowo. CLI wczytuje te same pliki hooks.json. Według stanu na maj 2026 pracownicy Cursor potwierdzili hooki powłoki, afterFileEdit, postToolUse, stop i sessionStart, ale nie afterAgentResponse ani afterAgentThought.

Czy hook może zatrzymać commit git z panelu Source Control?

Nie. Cursor nie ma zdarzenia hooka pre-commit, a commity wykonane przez wbudowany interfejs Source Control nie są przechwytywane. Użyj do tego zwykłego hooka git pre-commit.

Źródła

Każde ustawienie i zachowanie opisane na tej stronie zostało sprawdzone z tymi stronami 26 października 2026. Agenci szybko się zmieniają; jeśli coś przestało się zgadzać, obowiązuje strona oficjalna.

CZYTAJ DALEJ

Odpowiadaj każdemu agentowi z górnej części ekranu.

Windows i Mac · 7 dni za darmo, potem jednorazowo 8,99 USD · 1 USD z każdej sprzedaży idzie na karmę dla bezdomnych zwierząt

Wypróbuj Pet Island za darmo