Hooks Quality gate and Variables

Eleven·2026년 4월 17일

Hello Again, Claude Code

목록 보기
4/5

요약

파일 저장 시 자동 포맷팅, main 브랜치 직접 커밋 차단, 위험 명령어 차단을 Hooks로 구현했다. Windows 환경에서 cmd /c 래퍼 이슈가 다시 발생했고, 이를 통해 OS별 명령어 차이 문제와 크로스 플랫폼 배포 시 해결 전략을 정리했다.


개발 기록

생성된 파일 구조

~/.claude/hooks/               ← 전역 Hook 스크립트
├── security-gate.sh           ← 보안 게이트 (PreToolUse)
└── notify-complete.sh         ← 작업 완료 알림 (Stop)

onboarding-automation/
└── .claude/
    └── settings.json          ← Hook 이벤트 연결 설정

주의: ~/.claude/hooks/는 프로젝트 폴더가 아닌 홈 디렉토리에 있어서 파일 트리에 보이지 않는다. 전역 Hook은 모든 프로젝트에 공통 적용되므로 홈 디렉토리에 두는 게 표준 패턴이다.

팀 Plugin으로 공유하려면 프로젝트 전용 위치에 둬야 한다:

onboarding-automation/
└── .claude/
    └── hooks/
        └── security-gate.sh   ← 프로젝트 전용, git으로 팀 공유 가능

security-gate.sh

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# rm -rf 위험 명령어 차단
if echo "$CMD" | grep -qE 'rm\s+-rf\s+(/|~)'; then
  echo "위험한 명령어 감지됨: $CMD" >&2
  exit 2
fi

# main 브랜치 직접 커밋 차단
if echo "$CMD" | grep -q "git commit" && \
   [ "$(git branch --show-current 2>/dev/null)" = "main" ]; then
  echo "main 브랜치 직접 커밋은 금지되어 있습니다." >&2
  exit 2
fi

# .env 파일 git add 차단
if echo "$CMD" | grep -q "git add" && echo "$CMD" | grep -q "\.env"; then
  echo ".env 파일은 git에 추가할 수 없습니다." >&2
  exit 2
fi

exit 0

settings.json Hook 연결

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "cmd /c npx prettier --write \"$TOOL_INPUT_FILE_PATH\" 2>nul || exit 0"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/security-gate.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash ~/.claude/hooks/notify-complete.sh"
          }
        ]
      }
    ]
  }
}

트러블슈팅

문제 — Prettier Hook에서 cmd /c 필요

원인: MCP 트러블슈팅에서 동일하게 나타난 문제. Windows Git Bash 환경에서 npx를 직접 실행하면 Claude Code가 실행하지 못한다.

해결:

"command": "cmd /c npx prettier --write \"$TOOL_INPUT_FILE_PATH\""

핵심 개념: 크로스 플랫폼 배포 시 cmd vs npx 문제 해결 전략

문제 본질

개발자 A (Windows)  →  cmd /c npx -y 패키지명
개발자 B (macOS)    →  npx -y 패키지명

같은 settings.json을 git으로 공유하면 한쪽에서 반드시 에러가 난다.


해결 전략 4가지

전략 1 — OS 감지 설치 스크립트 (추천)

팀원 각자가 한 번만 실행하는 셸 스크립트를 제공한다.

# .claude/scripts/setup-mcp.sh
#!/bin/bash

OS=$(uname -s)

if [[ "$OS" == *"MINGW"* ]] || [[ "$OS" == *"CYGWIN"* ]]; then
  # Windows Git Bash
  claude mcp add slack -- cmd /c npx -y @modelcontextprotocol/server-slack
  echo "Windows 환경 설치 완료"
else
  # macOS / Linux
  claude mcp add slack -- npx -y @modelcontextprotocol/server-slack
  echo "macOS/Linux 환경 설치 완료"
fi
bash .claude/scripts/setup-mcp.sh

Plugin README에 이 스크립트 실행을 설치 가이드 첫 번째 단계로 안내한다.


전략 2 — settings.json에 OS별 분기 없이, settings.local.json에서 덮어쓰기

settings.json (git 공유)
→ npx 명령어를 넣지 않음
→ MCP 서버 이름과 구조만 정의

settings.local.json (개인, git 제외)
→ 각자 본인 OS에 맞는 명령어 작성

Plugin README에 OS별 설치 방법을 섹션으로 나눠서 안내한다.


전략 3 — 내장 커넥터 우선 사용 (OS 무관)

npx가 필요한 서비스는 Claude 내장 커넥터로 대체 가능한지 먼저 확인한다.

Gmail, Google Calendar → 내장 커넥터 → OS 무관
GitHub                 → HTTP 엔드포인트 → OS 무관
Slack                  → npx 필요 → OS 분기 처리 필요

전략 4 — 추상화 레이어 (The Wrapper Strategy)
에이전트가 "Prettier를 실행해"라고 명령하면, 내부의 '실행 워커'가 알아서 OS를 감지해 처리하도록 만드는 것.

Harness 설계: find-lead.md나 설정 파일에 직접 명령어를 박지 않고, run-prettier.js 같은 중간 매개 스크립트를 만든다.

작동 흐름: 클로드 코드 → node run-prettier.js 호출 → 스크립트 내부에서 OS 감지 후 Prettier 실행.

이렇게 하면 클로드 코드(에이전트)는 OS가 무엇인지 신경 쓸 필요 없이 동일한 인터페이스(node run-prettier.js)만 사용하면 됨.


환경변수 파일 관리 시점 가이드

개발에서 배포까지 각 시점에 따라 관리 방식이 달라진다.

로컬 개발
├── .env                  실제 토큰값 저장 (git 제외)
├── .env.example          키 이름만 있는 템플릿 (git 커밋)
├── settings.local.json   Claude Code용 env 주입 (git 제외)
└── settings.json         ${VAR} 플레이스홀더 (git 커밋)

팀 공유 (Plugin 배포)
├── .env.example          팀원이 복사해서 .env 만들 때 참고
├── settings.json         ${VAR} 플레이스홀더 포함 (커밋)
└── README.md             OS별 설치 가이드 포함

CI/CD 환경
└── GitHub Secrets        토큰값을 환경변수로 주입
    GITHUB_TOKEN, SLACK_BOT_TOKEN 등
    → settings.json의 ${VAR}가 여기서 해석됨

.env.example 예시 (git 커밋 가능):

GITHUB_TOKEN=           # GitHub Personal Access Token
SLACK_BOT_TOKEN=        # Slack Bot Token (xoxb-로 시작)
SLACK_TEAM_ID=          # Slack 워크스페이스 ID (T로 시작)
MAIN_REPO_PATH=         # 프로젝트 루트 경로

팀원은 이 파일을 복사해서 .env로 만들고 값을 채운다:

cp .env.example .env

핵심 요약 (TL;DR)

  • Hook 스크립트는 ~/.claude/hooks/(전역) 또는 .claude/hooks/(프로젝트) 둘 다 가능
  • 팀 공유용이면 반드시 프로젝트 전용 위치에 두어야 Plugin에 포함됨
  • Windows에서 npx 관련 Hook은 cmd /c 래퍼 필요
  • 크로스 플랫폼 배포 시 OS 감지 스크립트 또는 settings.local.json 분리로 해결
  • 내장 커넥터가 있는 서비스는 npx 대신 커넥터 사용 → OS 문제 원천 차단
  • 환경변수는 .env.example(커밋) + .env(git 제외) 패턴으로 팀 배포 표준화

회고

Hooks를 통해 CLAUDE.md의 "main 커밋 금지" 규칙이 실제로 강제되는 걸 확인했다. 규칙을 쓰는 것(CLAUDE.md)과 규칙을 집행하는 것(Hooks)은 다른 레이어이며, 자동화 시스템에서 이 두 가지를 분리하는 설계가 중요하다. 크로스 플랫폼 문제는 처음 환경을 설계할 때 고려하지 않으면 배포 단계에서 반드시 다시 마주치게 된다.

0개의 댓글