Claude가 자꾸 내가 하지 말라고 한 실수들을 코드에 남겨서, 그걸 막는 훅을 만들었음
Claude keeps naming things after the mistakes I told it not to make. So I built a hook for it.
핵심 요약
Claude가 대화 맥락을 코드에 남기는 '잔여물' 문제를 해결하기 위해, 커밋 전 이를 감지하고 차단하는 도구 'ship-the-result'를 개발함.
- 대화 잔여물 문제 — Claude가 대화 맥락을 코드나 파일명에 남겨 미래의 개발자가 이해하기 어렵게 만드는 현상
- 해결 원칙 — 코드는 대화 상대가 아닌, 나중에 파일을 읽을 사람을 위해 작성해야 함
- ship-the-result 도구 — 규칙 정의, 스캐너, PreToolUse 훅으로 구성되어 커밋 시 잔여물을 자동으로 감지 및 차단
- 사용자 피드백 수용 — 도구의 완성도를 높이기 위해 사용자들의 테스트와 피드백을 적극적으로 반영할 예정
Claude한테 그릴드 치즈 만들어달라고 해봐.
케첩을 뿌리네?
케첩 넣지 말라고 하면,
파일 이름을 grilled_cheese_no_ketchup.md로 저장해버림.
실제 레포지토리 상황은 어떨까?
git commit -m "Add retry logic (without exponential backoff)"
아무도 백오프(backoff) 넣어달라고 한 적 없거든. Claude가 지 맘대로 넣길래 빼라고 했더니, 이제 "without backoff"라는 문구가 깃 히스토리에 영원히 박제됨. 주석(// iterative, as you asked)이나 테스트 이름(test_parser_without_regex), PR 본문에서도 똑같은 짓을 함.
원인을 찾으려고 이런 사례들을 좀 모아봤어. 단순히 부정문 때문은 아니더라고. 절반은 "no"라는 단어조차 없었음: "as discussed", "per your feedback", "fixed version", "sorry, previous commit" 같은 것들 말이야. 공통점은 Claude가 나중에 파일을 읽을 사람을 생각하는 게 아니라, 여전히 나랑 대화하고 있다는 거임. 그 사람은 채팅방에 없었으니까 이런 문구들은 아무 의미가 없지.
그래서 해결책은 이거야: 채팅 상대가 아니라, 파일을 읽을 사람을 위해 작성해라.
ship-the-result는 이걸 세 가지 단계로 해결함:
- 규칙과 간단한 테스트가 담긴 SKILL.md: "채팅 기록 없이 1년 뒤에 이 줄을 봐도 이해가 될까?"를 자문하게 함. "Allow login without password for SSO users"처럼 찌꺼기 같아 보이지만 실제 요구사항인 경우도 다룸.
- 6가지 유형의 찌꺼기를 잡아내는 스캐너 스크립트.
- git commit, gh pr create, 그리고 스테이징된 주석, 테스트 이름, 새 파일 이름에 대해 스캐너를 돌리는 PreToolUse 훅. 걸리면 차단하고 Claude한테 이유를 알려줌. 똑같은 명령어를 다시 실행하면 통과되는데, 이게 진짜 요구사항인지 확인하는 방식임. 프롬프트 규칙은 대화 40번 넘어가면 까먹지만 정규식은 안 까먹으니까 훅으로 만든 거임.
내 테스트 셋에서는 결과가 괜찮은데, 데이터가 좀 적어. 한번 써보고 놓치는 거나 잘못 잡아내는 거 있으면 알려줘. 바로 수정해서 반영할게.

