Cursor 훅 완벽 가이드, 그리고 가끔 실행되지 않는 이유

Cursor 훅을 사용하면 스크립트가 에이전트의 모든 셸 명령, MCP 호출, 파일 읽기와 편집을 지켜보거나 차단할 수 있습니다. 강력하지만 조용히 실패합니다. 실제로 훅을 연결하면서 배운 모든 것을 정리했습니다.

작성: Aslan, Pet Island 팀 · 업데이트: 2026년 10월 26일 · 읽는 데 7분

핵심 요약

"version": 1이 들어 있는 hooks.json을 ~/.cursor/(모든 프로젝트) 또는 저장소의 .cursor/에 두고, 각 이벤트를 명령에 연결한 다음, stdout에 JSON을 출력하세요. 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 전용이며 모든 구성원에게 동기화됩니다.
엔터프라이즈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를 다시 시작하세요. 이것만으로도 포럼에 올라온 놀라울 만큼 많은 문제가 해결됩니다.

훅을 걸 수 있는 이벤트

Cursor 문서의 현재 목록을 용도별로 묶었습니다.

그룹이벤트차단 가능 여부
셸 및 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불가
Tab 자동 완성beforeTabFileRead, afterTabFileEditbeforeTabFileRead: 허용 또는 거부

모든 이벤트는 몇 가지 공통 필드(conversation_id, generation_id, model, hook_event_name, cursor_version, workspace_roots)와 이벤트별 필드를 받습니다. beforeShellExecution은 전체 command와 그 cwd를 받고, stop은 completed, aborted, error 중 하나인 status를 받습니다.

허용, 거부, 확인 요청

결정을 내리는 훅은 JSON 객체 하나를 출력합니다. 셸 훅의 경우 다음과 같습니다.

beforeShellExecution 훅의 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와 마찬가지로 작업을 차단합니다. 그 밖의 종료 코드는 훅 실패로 처리되며, 작업은 계속 진행됩니다. 단, failClosed를 설정한 경우는 예외입니다. 권한 훅의 경우 잘못된 JSON이나 스키마와 맞지 않는 JSON은 작업을 차단합니다.

Cursor 문서는 beforeShellExecution과 beforeMCPExecution에서 ask를 지원한다고 명시합니다. 2026년 3월 Cursor 직원은 포럼에서 훅이 deny만 적용하며 allow와 ask는 특히 명령 허용 목록이나 샌드박스가 켜져 있을 때 "basically ignored"(사실상 무시됨)라고 밝혔습니다. 수정 공지는 찾지 못했습니다. 반드시 지켜져야 하는 가드레일이라면 ask가 아니라 deny를 반환하고, 사용 중인 버전에서 직접 테스트하세요.

failClosed와 timeout

각 훅 항목에는 command 옆에 옵션을 붙일 수 있습니다.

.cursor/hooks.json복사
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": "./.cursor/hooks/guard.sh",
"timeout": 30,
"failClosed": true
}
]
}
}
  • failClosed: true는 충돌, 타임아웃, 0이 아닌 종료 코드, 빈 출력을 차단으로 바꿉니다. 기본값은 false이며, 이 경우 고장 난 가드는 모든 것을 조용히 통과시킵니다. 안전용 훅이라면 거의 항상 true로 두어야 합니다.
  • timeout의 단위는 초입니다. 훅이 사람의 응답을 기다린다면 충분한 여유를 두세요. diff를 읽는 데는 5초보다 오래 걸립니다.
  • matcher는 훅이 실행될 조건을 거릅니다. 셸 훅에서는 전체 명령 문자열과 비교하고, 도구 훅에서는 Shell, Read, Write, MCP:<tool_name> 같은 도구 유형과 비교합니다.

여기에는 트레이드오프가 있습니다. 2026년 7월 macOS 사용자가 "MainThreadShellExec not initialized" 오류를 겪었습니다. Cursor 자체 셸 호스트가 준비되지 않았는데, 훅이 fail-closed였기 때문에 에이전트의 셸이 차단된 것입니다. Cursor 직원은 수정이 배포되었다고 밝히며 failClosed: true를 유지하도록 권장했습니다. 이전 빌드에서 이 오류가 보인다면 "Developer: Reload Window"가 임시 해결책이었습니다.

Windows의 훅

Windows에서 Cursor 데스크톱 앱은 PowerShell을 통해 훅 명령을 실행하고 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 프로그램은 너무 일찍 반환됩니다. 이 문제로 하루를 날렸습니다. 훅이 GUI 서브시스템용으로 빌드된 Windows 프로그램이라면 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년 1월에는 두 셸 훅만 실행되었습니다. 4월에 Cursor 직원은 beforeShellExecution, afterShellExecution, afterFileEdit, postToolUse, stop, sessionStart가 CLI에서 작동한다고 확인했지만, afterAgentResponse와 afterAgentThought는 여전히 작동하지 않았습니다(5월에 다시 확인됨). 이 목록에 없는 이벤트는 의존하기 전에 테스트하세요.

클라우드 에이전트는 더 엄격합니다. ~/.cursor/hooks.json의 사용자 수준 훅은 그곳에서 전혀 실행되지 않습니다.

훅이 실행되지 않을 때: 체크리스트

  1. Hooks 출력 채널을 여세요(View → Output → Hooks). 또는 Customize의 Hooks 탭을 여세요. 어떤 훅이 로드되었는지, 모든 실행 내역과 오류를 보여 줍니다.
  2. JSON 파일 자체를 확인하세요. "version": 1이 있는지, 이벤트 이름의 철자가 정확한지(대소문자 구분), JSON이 유효한지 확인합니다.
  3. 경로를 확인하세요. 상대 경로 명령은 프로젝트 훅의 경우 프로젝트 루트, 사용자 훅의 경우 ~/.cursor/ 기준으로 해석됩니다.
  4. 워크스페이스를 신뢰하세요. 프로젝트 훅은 신뢰하지 않는 폴더에서 실행되지 않습니다.
  5. 훅을 직접 실행해 보세요. 샘플 JSON을 파이프로 넣고 stdout을 확인합니다. JSON 객체 하나 외의 출력(불필요한 echo, 경고)은 파싱을 망가뜨립니다.
  6. Cursor를 다시 시작하세요. 저장하면 파일이 다시 로드되지만, 포럼에 보고된 여러 문제는 완전히 다시 시작해야만 해결되었습니다.
  7. 알려진 한계를 파악하세요. ask와 allow는 허용 목록 및 샌드박스와 함께 쓸 때 무시된다는 보고가 있고, subagentStart/subagentStop은 일부 버전에서 실행되지 않는다는 보고가 있으며, CLI는 일부 이벤트를 건너뜁니다. 기본 제공 소스 제어 패널에서 하는 커밋은 가로채지 않습니다. pre-commit 훅 이벤트가 없기 때문입니다.

훅, 자동 실행, Auto-review

훅은 Cursor 자체의 승인 설정(Settings → Agents → Approvals & Execution)과 별개입니다. 자동 실행과 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을 전달합니다(PowerShell 스크립트에서는 $input). macOS용으로 작성된 Bash 스크립트는 PowerShell이나 Python 버전이 필요하며, GUI 서브시스템 프로그램은 PowerShell이 기다리도록 래핑해야 합니다.

훅이 ask를 반환하는데도 명령이 실행되는 이유는 무엇인가요?

Cursor 직원은 2026년 3월에 훅이 deny만 안정적으로 적용하며, allow와 ask는 허용 목록이나 샌드박스에 의해 덮어쓰일 수 있다고 밝혔습니다. 절대 실행되면 안 되는 것에는 deny를 사용하고, Hooks 출력 채널에서 훅이 실제로 무엇을 반환했는지 확인하세요.

failClosed는 무엇을 하나요?

failClosed를 true로 설정하면 충돌, 타임아웃, 0이 아닌 종료 코드, 빈 출력이 작업을 차단합니다. 설정하지 않으면 고장 난 훅이 작업을 그대로 진행시킵니다.

훅 오류는 어디에서 볼 수 있나요?

Hooks 출력 채널(View → Output → Hooks)과 Customize의 Hooks 탭에서 볼 수 있습니다.

Cursor CLI에서도 훅이 작동하나요?

일부만 작동합니다. CLI는 같은 hooks.json 파일을 읽습니다. 2026년 5월 기준 Cursor 직원은 셸 훅, afterFileEdit, postToolUse, stop, sessionStart가 작동한다고 확인했지만 afterAgentResponse와 afterAgentThought는 아닙니다.

훅으로 소스 제어 패널에서 하는 git 커밋을 막을 수 있나요?

아니요. Cursor에는 pre-commit 훅 이벤트가 없으며, 기본 제공 소스 제어 UI로 하는 커밋은 가로채지 않습니다. 이 용도에는 일반 git pre-commit 훅을 사용하세요.

출처

이 페이지의 모든 설정과 동작은 2026년 10월 26일에 아래 페이지와 대조해 확인했습니다. 에이전트는 빠르게 바뀌므로, 내용이 더 이상 맞지 않으면 공식 페이지를 따르세요.

더 읽어보기

화면 상단에서 모든 에이전트에 응답하세요.

Windows 및 Mac · 7일 무료, 이후 $8.99 1회 결제 · 판매 1건마다 $1이 길 위 동물들의 사료가 됩니다

Pet Island 무료로 사용해 보기