6. 규칙을 강제로
시작 상태
섹션 제목: “시작 상태”git log -1 --oneline && grep -n "push" CLAUDE.md첫 줄에 5단계 커밋(style: 접근성 지적 반영)이, 둘째 줄에 3단계에서 넣은 “push는 사람이
한다. 커밋까지만 한다” 줄이 나와야 합니다. 커밋이 다르면
5. 디자인 다듬기로, 줄이 없으면
3. 게이트 먼저로 돌아가 그 줄부터 넣습니다.
이 단계에서 하는 것
섹션 제목: “이 단계에서 하는 것”문장만 있을 때 무슨 일이 일어나는지 먼저 관찰합니다. 그다음 같은 규칙을 훅 스크립트로 옮기고, 등록 전에 파이프로 입력을 넣어 세 분기를 확인합니다. 등록한 뒤 같은 요청을 다시 관찰합니다. CLAUDE.md가 권고이고 훅이 강제인 이유는 CLAUDE.md 실전 가이드와 Hooks가 다룹니다.
따라하기
섹션 제목: “따라하기”- 관찰합니다. 원격이 없으니 실제로 push되지는 않습니다. 시켜 봅니다.
git push origin main 을 실행해 주세요.거부할 수도 있고 시도할 수도 있습니다. 문장으로만 적은 규칙은 어느 쪽 결과도 보장하지 않습니다. 어느 쪽이 나왔는지만 적어 두고, 어느 쪽이 나올지 미리 예측하지 않습니다.
- 훅 스크립트를 만듭니다.
hooks/block-push.sh:
#!/bin/sh# PreToolUse(Bash): git push를 차단한다. push는 사람이 한다.input=$(cat)cmd=$(printf '%s' "$input" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{process.stdout.write(JSON.parse(s).tool_input?.command??"")}catch{process.stdout.write("")}})')case "$cmd" in *"git push"*) echo "push는 사람이 직접 한다. 커밋까지만 하고 멈춘다." >&2 exit 2 ;;esacexit 0훅이 하는 일은 훅 입력 JSON에서 tool_input.command 하나를 꺼내는 것뿐이므로 Node의
-e 한 줄로 끝납니다. Node는 준비물에 이미 있으므로 인터프리터를 따로 깔지 않습니다.
- 등록하기 전에 파이프로 입력을 넣어 먼저 확인합니다. 왜 등록 전에 확인하는지는 Hooks 레시피가 다룹니다.
echo '{"tool_name":"Bash","tool_input":{"command":"git push origin main"}}' | sh hooks/block-push.sh; echo "exit=$?"echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | sh hooks/block-push.sh; echo "exit=$?"echo 'not json' | sh hooks/block-push.sh; echo "exit=$?"종료 코드는 순서대로 exit=2, exit=0, exit=0이어야 합니다. 세 번째 줄이 0이어야 JSON이
아닌 입력에서 훅이 통과합니다. 이 훅과 무관한 다른 도구 호출을 막지 않는다는 뜻입니다.
.claude/settings.json에 등록합니다.
{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "f=\"$CLAUDE_PROJECT_DIR/hooks/block-push.sh\"; if [ -f \"$f\" ]; then sh \"$f\"; fi", "timeout": 5 } ] } ] }}가드 형태가 Hooks 레시피의 UserPromptSubmit
예와 다릅니다. 그 예의 가드는 || true로 끝납니다. 스크립트가 실패해도 exit 0으로
덮어써서 프롬프트를 막지 않기 위한 것입니다. 여기서는 차단이 목적이므로 || true를
붙이면 안 됩니다. 붙이는 순간 exit 2가 exit 0으로 덮여 훅이 아무것도 막지
못합니다. 3번의 첫 줄 끝에 || true를 붙여 다시 실행하면 메시지는 그대로 출력되고
종료 코드만 exit=0으로 바뀝니다.
-
/hooks를 열어PreToolUse아래에 이 훅이 보이는지 확인합니다./hooks는 읽기 전용 뷰어이고, 설정 파일 편집은 파일 워처가 자동으로 반영합니다. 보이지 않으면 세션을 재시작합니다. -
1번을 다시 시킵니다.
git push origin main 을 실행해 주세요.이번에는 훅 메시지가 표시되고 실행이 막힙니다.
-
끝 비용과 컨텍스트 사용률을 읽어
docs/tutorial-log.md의 “6. 규칙 강제” 행에 적습니다. 메모 열에는 1번에서 거부했는지 시도했는지를 적습니다. -
훅과 기록표를 함께 커밋합니다.
git add hooks .claude/settings.json docs/tutorial-log.mdgit commit -m "chore: push 차단 훅"완료 확인
섹션 제목: “완료 확인”echo '{"tool_name":"Bash","tool_input":{"command":"git push origin main"}}' | sh hooks/block-push.sh; echo "exit=$?"echo '{"tool_name":"Bash","tool_input":{"command":"git status"}}' | sh hooks/block-push.sh; echo "exit=$?"echo 'not json' | sh hooks/block-push.sh; echo "exit=$?"세 줄의 종료 코드가 순서대로 exit=2, exit=0, exit=0이어야 합니다. 등록 후
6번에서 push 시도가 훅 메시지와 함께 막혀야 합니다.
계측 기록
섹션 제목: “계측 기록”값은 7번에서 이미 적었습니다. 시작 상태를 확인한 직후 시작 비용을, 커밋 직전에 끝 비용과 컨텍스트 사용률을 각각 적고 차액으로 읽습니다. 세션 수는 이 단계에서 연 세션 개수입니다. 5번에서 세션을 재시작했다면 그 개수를 그대로 적습니다.
어긋났을 때
섹션 제목: “어긋났을 때”- 등록했는데 6번에서 안 걸리면
/hooks에 훅이 보이는지 확인하고, 보이지 않으면 세션을 재시작합니다. 설정 파일 위치가 틀렸을 수 있습니다. 설정한 대로 동작하지 않을 때를 확인합니다. - 훅을 걸었더니 push와 무관한 다른 명령까지 막히면 3번 세 번째 분기(JSON이 아닌
입력)가
exit=0을 내는지 다시 확인합니다. 파싱 실패에서exit 2를 내고 있다면 스크립트를 고칩니다. - 3번 세 분기가 모두
exit=0이면 명령 추출이 빈 문자열이라case가 걸리지 않는 것입니다.node --version이 나오는지 먼저 확인합니다. 첫 분기가exit=2를 낼 때까지는 훅이 아무것도 막지 못하는 상태입니다. - 훅이 느리게 느껴지면 프로세스 기동 시간까지 포함해서 잽니다. 기준은 Rules에 있습니다.