저장소마다 CLAUDE.md를 두고 AI 에이전트에게 작업을 맡깁니다. 처음에는 이 파일을 신입 개발자용 온보딩 문서처럼 썼습니다. 프로젝트 소개, 기술 스택, 폴더 설명, 코딩 컨벤션 — 친절하고 빠짐없이.

그런데 에이전트는 그중 절반쯤을 무시했습니다. 그래서 규칙을 더 적었고, 문서는 길어졌고, 준수율은 오히려 떨어졌습니다.

문제는 문서의 양이 아니라 종류였습니다. 우리가 쓴 건 안내문이었는데, 필요한 건 계약서였습니다.

지금 이 저장소의 CLAUDE.md는 164줄, 1만 자쯤입니다.

절(##)이 열두 개고, 그중 넷은 "이 저장소에서만 다르게 하는 것"이고 셋은 "빌드가 검사하는 것과 안 하는 것"입니다. 프로젝트 소개는 다섯 줄입니다. 처음 버전은 이보다 길었는데 대부분이 소개와 일반론이었습니다.

1. 규칙 한 줄을 어디로 보낼 것인가

규칙을 하나씩 놓고 물어본 게 결국 네 질문이었습니다. 답의 조합이 그 규칙이 갈 자리를 정합니다.

질문 예 / 아니오 가는 곳 ────────────────────────────────────────────────────────────────────── Q1 안 적으면 반대로 할 것 같은가? 아니오 지운다 Q2 기계가 위반을 판정할 수 있는가? 예 빌드·린트·훅 Q3 판정은 되는데 작업 중에 도는가? 아니오 CI 에도 건다 Q4 사람 취향이 갈리는 문제인가? 예 문서에 이유와 함께 ────────────────────────────────────────────────────────────────────── 전부 아니오로 내려오면 문서에 한 줄

순서가 중요합니다. Q1 을 먼저 통과시키지 않으면 문서가 계속 붑니다. Q2 를 먼저 물으면 "일단 적어두고 나중에 자동화하자"가 되는데, 그 나중은 오지 않습니다.

이 저장소에서 실제로 갈린 예를 그대로 옮기면 이렇습니다.

규칙 Q1 Q2 결론 ──────────────────────────────────────────────────────────────────── 변수명은 의미가 드러나게 N - 지움 글은 ko/en 한 쌍이어야 한다 Y Y 빌드 훅으로 이동 글끼리 링크는 과거 방향으로만 Y Y 빌드 훅으로 이동 랜딩 페이지는 인라인 style 을 유지한다 Y N 문서 (이유 포함) 번역이 기계 번역처럼 읽히지 않게 Y N 문서 (이유 포함) staticPages.js 를 페이지와 맞춘다 Y N 문서 + 보고 규칙

마지막 줄이 애매한 자리입니다. 검사할 수는 있는데 아직 안 만들었습니다. 그래서 문서에 남기되 "빌드가 대신 잡아주지 않는 유일한 부분"이라고 명시했습니다. 자동화되지 않았다는 사실 자체가 정보입니다.

2. 에이전트가 이미 아는 것은 적지 않는다

초기 문서에는 이런 문장이 있었습니다.

- 함수는 한 가지 일만 하도록 작게 유지한다 - 변수명은 의미가 드러나게 짓는다 - 매직 넘버 대신 상수를 쓴다 - 커밋 메시지는 무엇을 왜 바꿨는지 설명한다

전부 맞는 말이고, 전부 없어도 되는 말이었습니다. 이런 건 에이전트가 시키지 않아도 합니다. 일반적인 좋은 관행이라 모델 안에 이미 들어 있습니다.

그런데 이 문장들이 공짜가 아닙니다. 문서가 길어지면 정말 중요한 규칙이 그 사이에 묻힙니다. 30줄짜리 목록에서 27줄이 당연한 말이면, 나머지 3줄도 당연한 말처럼 읽힙니다.

기준: 이 규칙을 안 적으면 반대로 할 것 같은가?

"아니오"면 지웁니다. 남는 건 이 저장소에서만 다르게 하는 것들입니다. 그게 문서가 존재하는 이유입니다.

3. 판단이 갈리는 지점만 남긴다

정리 후 남은 규칙들은 대체로 이런 모양이었습니다.

11ty 는 .njk 만 템플릿으로 처리한다. 나머지 .html 은 바이트 그대로 통과 복사된다 — 그래서 인라인 스타일과 딥링크 스크립트는 빌드의 영향을 받지 않는다. 랜딩·lab 페이지는 페이지 안 인라인 <style> 로 자기완결적으로 유지한다. 기존 방식이므로 굳이 외부 CSS 로 빼지 않는다. 글(posts)은 공유 posts.css 를 쓴다. 글마다 스타일을 새로 만들지 않는다.

두 번째 규칙이 중요합니다. 일반적인 좋은 관행은 "인라인 스타일을 외부 CSS로 빼라"입니다. 이 저장소에서는 반대입니다. 적어두지 않으면 에이전트는 선의로 리팩터링을 시작합니다. 그리고 통과 복사되는 페이지의 인라인 스타일을 뜯어내면서 조용히 뭔가를 깨뜨립니다.

세 번째 규칙은 정반대 방향입니다. 같은 저장소 안에서 페이지 종류에 따라 정책이 갈립니다. 이런 건 코드만 봐서는 의도인지 사고인지 알 수 없습니다.

정리하면 적을 가치가 있는 건 세 종류입니다.

  • 일반적 관행과 반대되는 것 — 안 적으면 에이전트가 "고쳐줍니다"
  • 같은 저장소 안에서 갈리는 것 — 한 사례만 보고 전체에 적용해버립니다
  • 코드에 흔적이 안 남는 것 — 외부 시스템, 배포 절차, 다른 저장소와의 약속

4. 금지에는 반드시 이유를 붙인다

이유 없는 금지는 잘 지켜지지 않습니다. 이유가 붙으면 비슷한 상황까지 일반화됩니다.

이유 없음 — 이 파일만 피하고 끝난다 검색엔진 소유권 확인 파일은 건드리지 않는다. 이유 있음 — 왜 위험한지 알면 판단할 수 있다 검색엔진 소유권 확인 파일(google*.html, naver*.html)은 이름과 내용을 건드리지 않는다. 파일 이름 자체가 인증 토큰이라, 이름을 바꾸면 사이트 소유권 확인이 풀린다.

후자를 읽은 에이전트는 나중에 app-ads.txt나 도메인 확인용 .well-known 파일을 만나도 같은 판단을 합니다. 앞의 문장은 그 파일들에 대해서는 아무것도 알려주지 않습니다.

같은 이유로 "~하지 마라" 대신 "~해라" 쪽이 낫습니다. 금지는 대안이 없으면 회피할 방법을 찾게 만듭니다. "React를 쓰지 마라"보다 "바닐라 JS로 작성한다. 클라이언트 프레임워크를 새로 끌어들이지 않는다"가 실제로 더 잘 지켜졌습니다.

5. 검증 방법을 명시한다

이게 가장 효과가 컸습니다. 에이전트가 "다 됐습니다"라고 말하는 기준을 문서가 정합니다.

## 검증 npm run build # 실패하면 배포도 실패한다. 반드시 통과시킨다. npm run dev # 로컬 서버로 실제 렌더 확인 빌드가 잡아주는 것: 로케일 대칭, 날짜 일치, 글 사이 링크, 템플릿 문법 오류, 참조 실패. 빌드가 잡아주지 않는 것 — 직접 확인한다: - 브라우저에서 레이아웃과 링크가 깨지지 않는지 - 통과 복사되는 .html 의 상대 경로가 디렉터리 깊이에 맞는지 - 딥링크 폴백 동작 (실기기 필요) - 링크 확인 없이 "검증했다"고 말하지 않는다.

앞 절반보다 뒤 절반이 훨씬 중요합니다. 빌드가 통과하면 다 된 줄 아는 게 기본값인데, 여기서 빌드가 무엇을 못 잡는지 명시적으로 알려주기 때문입니다.

마지막 줄은 특히 자주 걸립니다. 확인하지 않은 것을 확인했다고 말하지 않게 만드는, 문장 하나짜리 규칙입니다.

6. 문서가 못 지키는 규칙은 코드로 옮긴다

여기가 진짜 결론입니다. 중요한 규칙일수록 문서에 두면 안 됩니다.

이 사이트는 모든 글이 한국어·영어 한 쌍이어야 합니다. 처음에는 그냥 문서에 굵은 글씨로 적어뒀습니다. 그럼에도 한쪽만 올라가는 일이 생겼습니다. 문서는 읽히지 않을 수 있고, 읽혀도 긴 작업 도중에 밀려납니다.

그래서 빌드 훅으로 옮겼습니다. 이제 한쪽 로케일만 추가하면 빌드가 실패합니다.

Error: ko/en 포스트가 대칭이 아닙니다. en 누락: neat-daily-activity-guide

차이는 결정적입니다. 문서 규칙은 지키면 좋은 것이고, 빌드 규칙은 지키지 않으면 진행이 안 되는 것입니다. 에이전트는 실패한 빌드를 그냥 지나치지 못합니다.

문서에 굵은 글씨로 세 번 강조하고 싶어지면, 그건 코드로 옮길 때가 됐다는 신호입니다.

강조가 필요하다는 건 그 규칙이 자주 깨진다는 뜻이고, 자주 깨지는 규칙은 강조를 더 해도 깨집니다.

같은 방식으로 옮긴 게 하나 더 있습니다. 예약 게시를 붙이면서 글끼리 거는 링크가 미래를 향할 수 있다는 문제를 만났는데, 이것도 문서 규칙으로는 못 지킵니다 — 링크를 걸 때는 대상 파일이 저장소에 멀쩡히 있어서 아무 문제가 없어 보이기 때문입니다. 빌드가 본문의 글 링크를 전부 긁어서 대상의 발행일을 비교하게 만든 뒤로 이 실수가 사라졌습니다.

옮기고 나서 알게 된 게 하나 있습니다. 빌드로 옮긴 규칙은 문서에서 지우면 안 됩니다. 지우면 에이전트가 규칙의 존재를 모른 채 작업하다가 마지막에 빌드 실패로 알게 됩니다. 그 시점에는 이미 반대 방향으로 반나절을 간 뒤입니다. 그래서 문서에는 "빌드가 이걸 막는다"만 한 줄로 남겨둡니다 — 규칙 전문이 아니라 가드가 있다는 사실만.

코드로 옮긴 뒤 문서에 남기는 형태 빌드가 잡아주는 것: ko/en 글 슬러그 대칭, date·category 일치, 글 사이 링크(대상 존재 + 게시 순서), 템플릿 문법 오류. 빌드가 잡아주지 않는 것 — 직접 확인한다: - staticPages.js 가 실제 페이지와 일치하는지 - 통과 복사되는 .html 의 상대 경로가 디렉터리 깊이에 맞는지 - 딥링크 폴백 동작 (실기기 필요)

물론 전부 자동화할 수는 없습니다. "번역이 기계 번역처럼 읽히지 않게" 같은 건 검사할 방법이 없습니다. 그런 것만 문서에 남기고, 검사 가능한 건 전부 옮기는 게 좋습니다.

7. 보고 규칙 — 무엇을 말해야 하는지 적는다

마지막으로 넣은 절인데, 넣길 잘했습니다.

## 보고 규칙 - 페이지를 추가·이동·삭제했으면 sitemap 과 리다이렉트를 함께 처리했는지 명시한다. - 한 로케일만 작업했다면 반드시 그 사실과 남은 로케일을 보고한다. - 딥링크 스킴을 바꿨다면 iOS/Android 대응 필요를 별도로 명시한다.

에이전트 작업의 위험은 잘못한 걸 잘했다고 말하는 것보다, 절반만 하고 다 했다고 말하는 것에 있습니다. 앞은 리뷰에서 걸리는데 뒤는 안 걸립니다. 무엇을 반드시 언급해야 하는지 미리 정해두면 이 구멍이 상당히 메워집니다.

8. 문서에 남기면 안 되는 문장 다섯 가지

지우는 기준은 "당연한 말인가"만이 아니었습니다. 틀리지도 않고 당연하지도 않은데 시간이 지나면 해로워지는 문장들이 따로 있었습니다.

유형 예 대신 쓰는 것 ────────────────────────────────────────────────────────────────────────────── 시점에 묶인 수 "현재 각 로케일 10개 페이지" "ko/en 은 1:1 로 대응한다" 다른 문서의 요약 README 내용을 옮겨 적기 그 문서를 가리키는 한 줄 절 번호 상호 참조 "3절에서 본 것처럼" 내용으로 지칭 예외 없는 절대 규칙 "항상 X 한다" "X 한다. 단 Y 일 때는 Z" 사례 없는 추상 규칙 "일관성을 유지한다" 어긋난 예와 맞는 예 한 쌍

첫 줄이 이 저장소에 실제로 남아 있는 문장입니다. 페이지가 열한 개가 되는 날 이 줄은 조용히 거짓이 되고, 거짓인 줄이 하나 있는 문서는 나머지 줄의 신뢰도까지 같이 떨어뜨립니다. 세는 수는 문서가 아니라 빌드가 세게 하거나, 아예 적지 않는 게 낫습니다.

세 번째 줄은 이 사이트의 글을 고쳐 쓰다가 배운 것입니다. 절 번호로 다른 문서를 가리키면 그 문서에 절이 하나만 늘어도 조용히 틀린 문장이 됩니다. 규칙 문서에서도 똑같습니다 — 문서가 자기 자신을 절 번호로 참조하는 순간, 규칙을 하나 추가하는 일이 문서 전체를 검수하는 일이 됩니다.

네 번째는 반대로 지나치게 강한 문장의 문제입니다. 예외가 실제로 존재하는데 "항상"이라고 적으면, 예외 상황을 만난 에이전트는 규칙을 어기거나 작업을 멈춥니다. 둘 다 나쁩니다. 예외를 아는 사람이 예외를 적는 게 맞습니다.

9. 규칙이 무시될 때 — 원인 감별

"에이전트가 규칙을 안 지킨다"는 한 가지 현상이 아니었습니다. 증상마다 원인이 다르고, 고칠 자리도 다릅니다.

증상 유력한 원인 고칠 위치 ───────────────────────────────────────────────────────────────────────── 매번 같은 규칙만 어긴다 일반 관행과 충돌 이유를 붙인다 긴 작업의 후반부에만 어긴다 문서가 길다 절 수를 줄인다 규칙을 반대로 해석한다 문장이 모호하다 예를 한 쌍 넣는다 지키긴 하는데 과하게 한다 범위가 안 적혀 있다 적용 대상을 좁힌다 했다고 말했는데 안 했다 완료 기준이 없다 검증 명령을 적는다 한쪽만 하고 끝낸다 보고 규칙이 없다 무엇을 말할지 적는다

두 번째 줄이 가장 반직관적입니다. 규칙을 안 지켜서 규칙을 더 적었는데 더 적은 것 자체가 원인인 경우입니다. 저희가 정확히 이 자리에 있었습니다.

네 번째 줄은 이 저장소에서 실제로 겪었습니다. "인라인 스타일을 유지한다"를 랜딩 페이지 규칙으로 적었는데, 적용 대상을 안 적었더니 글(posts)에도 인라인 스타일을 쓰기 시작했습니다. 규칙은 지켰는데 결과가 틀렸습니다. 그래서 지금 문서는 규칙마다 적용 대상을 앞에 붙여 씁니다 — "랜딩·lab 페이지는", "글(posts)은".

10. 자주 묻는 것

문서는 몇 줄이 적당한가요?
줄 수보다 절의 개수가 체감에 가깝습니다. 이 저장소는 열두 절이고, 한 절이 화면 한 장을 넘지 않습니다. 절이 스무 개를 넘어가기 시작하면 대개 두 종류가 섞여 있습니다 — 규칙과 설명. 설명은 다른 문서로 빼고 규칙만 남기면 절반으로 줄어듭니다.

모노레포에서는 저장소마다 따로 두나요, 루트에 하나만 두나요?
저희는 둘 다입니다. 워크스페이스 루트에 공통 규칙을 두고, 각 저장소에 그 저장소만의 규칙을 둡니다. 대신 충돌하면 어느 쪽이 이기는지를 반드시 적습니다. 이 저장소 문서의 첫 문단이 "공통 규칙을 전제로 하고, 충돌하면 이 문서가 우선한다" 한 줄인 이유입니다. 이걸 안 적으면 두 문서가 다른 말을 할 때 에이전트가 임의로 고릅니다.

도구마다 파일 이름이 다른데(CLAUDE.md, AGENTS.md) 어떻게 하나요?
내용이 같다면 한쪽을 정본으로 두고 다른 쪽에서 가리키는 게 낫습니다. 두 파일을 각각 관리하면 반드시 갈라지고, 갈라진 뒤에는 어느 쪽이 맞는지 아무도 모릅니다. 이건 문서의 문제가 아니라 같은 사실을 두 곳에 적었을 때 늘 생기는 문제입니다.

규칙에 예시 코드를 넣어야 하나요?
"맞는 예" 하나보다 "어긋난 예와 맞는 예 한 쌍"이 훨씬 효과적이었습니다. 맞는 예만 있으면 경계가 안 보입니다. 다만 예시가 길어지면 그 자체로 문서를 불립니다. 한 쌍에 다섯 줄을 넘기지 않는 선에서 씁니다.

문서를 고치면 준수율이 언제 달라지나요?
다음 작업부터입니다. 문서는 매 세션 처음에 읽히므로 학습 같은 지연이 없습니다. 그래서 규칙이 깨진 걸 발견한 날 바로 고치는 게 맞습니다. 반대로 말하면, 고쳤는데도 다음 작업에서 또 깨지면 그건 문서로 해결될 문제가 아니라는 신호입니다 — 위 감별표로 돌아갈 차례입니다.

이 문서를 에이전트에게 쓰게 해도 되나요?
초안은 괜찮고, 판정은 사람이 해야 합니다. 에이전트가 쓴 규칙 문서는 대체로 일반론이 다시 늘어납니다 — 자기가 이미 아는 것과 이 저장소만의 예외를 구분할 근거가 문서 바깥에 있기 때문입니다. 실제로 도움이 됐던 사용법은 "이 저장소에서 네가 헷갈렸던 지점을 나열해라"였습니다. 그 목록이 곧 적어야 할 규칙 목록이었습니다.

11. 정리

결과적으로 문서는 절반 이하로 줄었고, 준수율은 확실히 올라갔습니다. 정리하면 이렇습니다.

  • 안 적어도 할 일은 적지 않는다. 중요한 규칙이 묻힙니다.
  • 판단이 갈리는 지점만 남긴다. 일반 관행과 반대되는 것, 저장소 안에서 갈리는 것, 코드에 흔적이 없는 것.
  • 금지에는 이유를 붙인다. 이유가 있어야 비슷한 상황으로 일반화됩니다.
  • 검증 방법을, 특히 빌드가 못 잡는 것을 명시한다.
  • 검사 가능한 규칙은 코드로 옮긴다. 문서는 마지막 수단입니다.
  • 무엇을 보고해야 하는지 적는다. 절반만 한 작업을 드러냅니다.
  • 시점에 묶인 수와 절 번호 참조는 적지 않는다. 시간이 지나면 조용히 거짓이 됩니다.
  • 규칙마다 적용 대상을 앞에 붙인다. 범위가 없으면 규칙은 지켜지면서 결과가 틀립니다.

CLAUDE.md를 사람용 README처럼 쓰고 있다면 한번 다시 보세요. 읽는 쪽은 프로젝트를 처음 보는 사람이 아니라, 일반적인 관행은 이미 다 아는데 이 저장소의 예외는 하나도 모르는 협업자입니다. 문서는 그 차이만 담으면 됩니다.