본문으로 건너뛰기

© 2026 Molayo

Qiita헤드라인2026. 06. 16. 08:13

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, typescript 5.6, eslint 9.x, prettier 3.x

  • ~/.claude/settings.jsonhooks.PostToolUse를 한 블록 추가하는 것만으로, Write / Edit 시마다 prettier --writetsc --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가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0