
Claude Code의 Hooks (PostToolUse)를 사용하여 파일 저장 시 자동으로 lint 및 타입 체크를 실행하는 최소
요약
Claude Code의 PostToolUse 훅을 활용하여 파일 수정 시 자동으로 lint와 타입 체크를 실행하는 방법을 설명합니다. 에러 발생 시 종료 코드 2를 반환하여 Claude가 스스로 코드를 재수정하도록 유도하는 워크플로우를 구축할 수 있습니다.
핵심 포인트
- PostToolUse 훅을 통해 Write/Edit 작업 후 자동 lint 및 타입 체크 가능
- 종료 코드 2를 반환하면 Claude에게 에러 피드백이 전달되어 자동 재시도 수행
- matcher는 정규표현식이 아닌 툴 이름의 완전 일치 리스트로 작성해야 함
- 프로젝트 전체 체크 대신 incremental 모드를 사용하여 실행 속도 최적화 권장
Claude Code가 Write / Edit를 수행한 후, 매번 수동으로 npm run lint를 입력하고 있지는 않은가?
Hooks를 사용하면 「파일이 수정된 순간」에 lint와 타입 체크 (Type Check)를 자동으로 실행하여, 에러가 있으면 그 자리에서 Claude에게 재수정을 요청할 수 있다.
-
대상: Claude Code를 업무 코드에 사용하기 시작하여, 로컬 환경에서 타입 에러 및 lint 에러를 매번 수동으로 해결하고 있는 사람
-
전제: Claude Code v2.x 계열 / Node.js 22.x / macOS 또는 Linux / TypeScript 프로젝트 (
prettier,eslint,tsc가 설치되어 있을 것) - 동작 확인: Claude Code v2.0.27, Node.js v22.11,typescript5.6,eslint9.x,prettier3.x -
~/.claude/settings.json에hooks.PostToolUse를 한 블록 추가하는 것만으로, Write / Edit 시마다prettier --write→tsc --noEmit를 실행할 수 있다. -
종료 코드 (Exit Code)
2를 반환하면 Claude 측에 stderr 내용이 피드백되어 자동으로 재시도(Retry) 된다 (이것이 핵심). -
matcher는 정규 표현식이 아니라 툴 이름의 완전 일치 리스트이다.Edit|Write와 같은 OR 표기는 작동하지 않는다.
~/.claude/settings.json (프로젝트 단위라면 .claude/settings.json)을 열고 아래 내용을 추가한다.
{
"hooks": {
"PostToolUse": [
...
matcher에는 Write와 Edit를 별도의 블록으로 작성한다. 후술하겠지만, 이곳을 "Write|Edit"로 작성해도 매칭되지 않는다.
~/.claude/hooks/format-and-check.sh를 만든다.
#!/usr/bin/env bash
set -uo pipefail
# Claude가 stdin으로 JSON을 흘려보낸다. file_path를 추출한다.
...
실행 권한을 잊지 말 것.
chmod +x ~/.claude/hooks/format-and-check.sh
Claude Code를 재시작하고, 적당한 .ts 파일을 Edit하게 한다. 의도적으로 타입 에러가 발생하는 코드를 작성하게 하면, stderr가 Claude 측으로 돌아가 스스로 재수정에 들어가는 것을 확인할 수 있다.
> // 타입을 의도적으로 틀리게 작성
> const n: number = "hello";
[hook] type check failed:
...
공식 문서에는 「matcher pattern」이라고 적혀 있어 Write|Edit로 작동할 것처럼 보이지만, 내부 구현은 완전 일치이다. 블록을 나누어 작성해야 한다.
일반적인 쉘 스크립트(Shell Script) 감각으로는 「비정상 종료 = 1」을 반환하고 싶겠지만, Claude Code의 Hook 사양에서는 exit 2만이 「Claude에게 피드백하는」 모드로 되어 있다. 1을 반환하면 Claude 측에서는 「Hook이 실패했다」라고만 인식될 뿐, 내용은 무시된다.
| 종료 코드 | 동작 |
|---|---|
| 0 | 성공 처리, 아무 일도 일어나지 않음 |
| ... |
tsc --noEmit를 루트에서 실행하면, 파일 1개의 Edit만으로 프로젝트 전체의 타입 체크가 실행되어 수 초에서 수십 초 동안 대기해야 한다. 변경 파일 + 그 의존성만 확인하는 tsc --noEmit --incremental이나, tsgo와 같은 대안을 검토하는 것이 좋다. 실측 결과 8초에서 0.4초까지 단축되었다.
launchd나 IDE를 통해 실행한 Claude Code는 PATH가 부족하여 npx가 없는 경우가 있다. 스크립트 서두에 export PATH="$HOME/.nvm/versions/node/v22.11.0/bin:$PATH"와 같은 행을 추가하거나, 절대 경로로 호출한다.
Hook의 본질은 「Claude의 툴 호출에 대한 pre/post 삽입」이며, PreToolUse...
로 실행을 중단할 수도 있다. 이번 Post의 사용법이 가장 리스크가 낮고 도입하기 쉽다.
exit 2
의 피드백 루프는 「Claude가 스스로 수정을 향하게」 하므로, 내가 자리를 비워두더라도 알아서 lint가 통과된 상태까지 가져다준다. 이는 상상 이상으로 효과적이다.
~/.claude/settings.json
의 hooks.PostToolUse
에 matcher: "Write"
와 "Edit"
를 각각 별도로 추가한다 - 스크립트는 종료 코드 2
로 stderr를 반환하면 Claude가 자동으로 재시도(retry)한다 - 무거운 타입 체크는 --incremental
또는 tsgo
로 회피한다 - PATH와 실행 권한 설정 시 주의한다.
「저장하면 자동으로 포맷팅 및 타입 체크가 통과된 상태로 만들어 주는」 상태는 Claude Code의 경험을 한 단계 끌어올린다. 익숙해지면 PreToolUse
를 통해 위험한 명령어를 차단하는 방향으로도 확장할 수 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기