저장소가 열 개를 넘어가자 CLAUDE.md가 저장소마다 같은 규칙을 복사한 800줄짜리 문서가 됐다. 2026-07-13 아침, 이걸 두 번에 나눠서 정리했다. 그 뒤 석 달 동안 이 구조가 어떻게 자랐는지를 git 로그와 파일 생성 시각으로 되짚어 본다.

0. 시작: 복사해서 키운 CLAUDE.md

AI 접두어가 붙은 프로젝트(AICura, AILicet, AICopia, AIFid, AILign…)가 하나씩 늘어날 때마다 CLAUDE.md를 새로 만들었다. 새 저장소를 만들면 이전 저장소 문서를 복사해서 시작했다. 그러면 이런 내용이 저장소마다 똑같이 들어간다.

  • 응답은 한국어로, 커밋은 이모지 + Conventional Commits + 한국어
  • feature/* → dev → main 브랜치 전략, 머지 방식
  • SQL 바인딩, XSS 이스케이프, CSRF 같은 보안 금지 목록
  • PSR-12, 네이밍, 레이어 책임
  • PHPStan·PHPUnit 실행 방법

문제는 규칙이 바뀔 때 드러났다. "문서만 바뀐 경우는 dev에 직접 커밋해도 된다"는 예외 하나를 추가하려면 저장소 수만큼 같은 문장을 고쳐야 한다. 하나라도 빠지면 저장소마다 규칙이 조금씩 달라진다. 게다가 CLAUDE.md는 세션이 시작될 때마다, 그리고 대화가 이어지는 동안 매번 컨텍스트에 실리는 문서다. 800줄이 넘는 문서에서 저장소 고유 정보는 일부인데, 나머지 공통 규칙까지 매번 읽히고 있었다.

1. 7월 13일 08:13 — 주제별로 쪼갠다 (.claude/rules/)

첫 번째 시도는 파일을 나누는 것이었다. 하나의 긴 CLAUDE.md를 주제별 파일로 분리하고, 본문에서는 @import로 불러온다.

  CLAUDE.md ← 개요 + 저장소 고유 내용 .claude/rules/ git-workflow.md security.md code-style.md testing.md  

AICura 커밋 로그에는 📝 docs: CLAUDE.md 규칙 .claude/rules/ 로 분기가 08:13에 찍혀 있다. AILicet은 08:14, AICopia는 08:44다. 같은 요청을 저장소마다 던져서 처리한 흔적이다. 이 과정에서 08:49에 "문서만 바뀌면 dev에 직접 커밋" 예외도 함께 문서화했다.

주제별로 나누니 읽기는 편해졌다. 하지만 여전히 저장소마다 같은 네 개 파일이 복사돼 있었다. 분리했을 뿐 중복은 그대로였다.

2. 7월 13일 09:37 — 공통 규칙은 전역으로 올린다

한 시간 반 뒤, 방향을 바꿨다. 공통 규칙은 저장소 안에 둘 이유가 없다. Claude Code는 ~/.claude/CLAUDE.md를 모든 프로젝트에서 읽는다. 그러면 공통 규칙은 한 곳에만 있으면 된다.

커밋 메시지는 📝 docs: 공통 CLAUDE 규칙을 전역 ~/.claude로 통합. 결과는 이랬다.

저장소 7/13 오전 통합 후
AICura 870줄 116줄
AILicet 853줄 106줄
AICopia 517줄 355줄 (프로젝트 고유 규칙이 많아 덜 줄었다)

저장소 CLAUDE.md에는 이제 이 한 단락이 맨 위에 들어간다.

공통 규칙은 전역 ~/.claude/CLAUDE.md에서 자동으로 상속된다. 이 문서는 해당 저장소 고유 규칙만 정의한다.

문서 계층이 이렇게 정리됐다

~/.claude/CLAUDE.md 전역: 언어, 커밋, 아키텍처 원칙, 타임존 규약 

~/.claude/rules/*.md 전역 상세: git-workflow, security, code-style, testing, api-design, php-lsp (@import)

~/claude-works/CLAUDE.md 작업 폴더 공통: Spark 명령, CI 러너 주의사항

/CLAUDE.md 저장소 고유: 스택, 명령어, 도메인, 아키텍처

/.claude/rules/*.md 저장소 고유 상세 (필요한 곳에만)  

충돌 규칙도 한 줄로 정했다. 저장소 CLAUDE.md가 전역과 다르면 저장소가 이긴다. 전역은 기본값이고, 저장소는 그 위에 덮어쓰는 예외다. 전역 문서 첫머리에는 적용 범위도 못 박았다. PHP 백엔드 프로젝트용이므로 다른 스택에서는 이 규칙을 무시하고 그 프로젝트의 규칙을 따른다.

3. 무엇을 전역에 두고 무엇을 저장소에 둘지

기준은 하나다. "다른 저장소에서도 똑같이 참인가?"

  • 참이면 전역: 한국어 응답, 커밋 형식, 보안 금지 목록, PSR-12, 에러 코드 이름 규칙
  • 거짓이면 저장소: 포트 번호, PHP 버전 조합, 도메인 용어, 배포 대상, 현재 개발 단계

경계가 애매한 것도 있었다. 타임존이 그랬다. "DB는 UTC로 저장하고 앱과 화면은 KST"라는 원칙은 여러 저장소에 공통이라 전역에 올렸다. 다만 맨 아래에 "실제 설정은 저장소마다 다를 수 있고, 저장소 문서가 정의하면 그쪽이 우선"이라는 단서를 달았다. 규칙은 올리되 예외의 자리는 남겨 두는 방식이다.

4. 문서만으로 부족한 건 스킬로 뺐다

문서는 "무엇을 지켜라"를 말한다. 반복되는 절차는 문서로는 약하다. 그래서 같은 시기에 절차를 스킬로 만들었다. 파일 생성 시각을 보면 흐름이 보인다.

날짜 스킬 역할
6/15 end-issue 작업 내역 코멘트 + 이슈 닫기
7/13 prune-branch, start-issue, dev-issue 브랜치 정리, 이슈 착수, 한 사이클 오케스트레이션
8/5 api-error-contract API 에러 응답 규약
9/14 finish-issue PR → 머지 → 정리 → 이슈 종료

공교롭게 start-issue, dev-issue가 만들어진 날도 7월 13일이다. 문서를 정리하던 그날, 절차도 같이 스킬로 옮겼다. 규칙은 rules/에, 절차는 skills/에 둔다는 역할 분담이 이때 잡혔다. 스킬 사용 횟수는 이전 글에 정리했다.

5. 그 뒤로 자란 것들

5-1. 8월 20일: AGENTS.md — Codex용 지침

Codex도 같이 쓰기 시작하면서 저장소마다 AGENTS.md가 생겼다(📝 docs: Codex 작업 지침 추가). Codex는 CLAUDE.md의 @import도, .claude/ 설정도 읽지 않는다. 그래서 AGENTS.md는 그 파일 하나만 읽어도 작업 규칙이 완결되도록 필요한 내용을 풀어 썼다. 첫머리에 "Claude Code 전용 설정은 Codex에서 쓰지 않는다"고 적어 두었다.

도구가 늘면 지침 문서도 도구별로 늘어난다. 같은 내용을 두 군데에 적는 비용이 다시 생기는 지점이라, 요즘 가장 신경 쓰는 부분이다.

5-2. 9월 9일: 영문 번역과 언어 예외

전역 규칙 파일들의 생성 시각이 9월 9일 14:5915:00이다. 같은 날 오후 저장소들에 📝 docs: CLAUDE.md 영문 번역 커밋이 15:4215:44 사이에 줄지어 들어갔다. 이어서 응답 언어 예외 규칙 추가 (중간 메세지 영어, 최종 결과 한국어)가 붙었다.

  • 규칙 문서 본문은 영어로 둔다.
  • 사용자에게 보이는 응답은 한국어를 원칙으로 한다.
  • 단, 작업 도중의 진행 메시지는 영어, 최종 결과 요약만 한국어로 한다.

중간 진행 메시지는 길고 자주 나온다. 이 부분을 영어로 두는 대신 최종 보고는 한국어로 받는 타협이다.

5-3. 10월 5일: CI 러너 교훈을 테스트 규칙으로

조직 러너(runner-01~03)로 이전하면서 여러 저장소에서 같은 실패가 반복됐다. 호스트에 게시한 포트에 접속이 안 되는 문제, 러너마다 PHP 버전이 다른 문제, Docker 컨테이너 액션이 작업 디렉터리를 못 보는 문제 등이다. 이 교훈을 두 군데에 나눠 적었다.

  • 전역 rules/testing.md: 어느 PHP 저장소에서든 통하는 일반 교훈
  • claude-works/CLAUDE.md: 이 작업 폴더의 러너 환경 특성에 묶인 체크리스트

실패 과정은 CI 실패 기록과 러너 이전 기록에 따로 썼다. 이번에 중요한 건 실패한 날 바로 규칙 문서에 올려 둔 것이다. 다음 저장소에서 같은 함정을 밟지 않는다.

5-4. 10월 15일: 토큰 관리와 응답 스타일

가장 최근 수정은 전역 CLAUDE.md의 "세션·토큰 사용 관리" 절과 응답 스타일 규칙이다. 세션 로그를 분석했더니 누적 토큰이 불어난 주범은 수백~수천 턴짜리 마라톤 세션과 컨텍스트에 계속 남는 큰 스크린샷이었다. 그래서 작업 단위가 끝나면 새 세션을 열거나 /compact로 정리하고, 반복 탐색은 서브에이전트에 맡기도록 적었다. 응답은 군더더기를 뺀 짧은 문체로 받는다.

문서가 곧 비용이라는 점을 이 단계에서 다시 확인했다. 전역 문서는 모든 프로젝트의 모든 세션에 실리기 때문에, 여기에 한 줄을 추가하는 일은 모든 세션에 한 줄을 더 읽히는 일이다.

6. 같은 요청을 여러 저장소에 던지는 방식

이 구조의 부수 효과가 하나 있다. 정책이 바뀌면 전역을 한 번 고치고, 저장소별로 달라질 부분만 각 저장소에서 고친다. 7월 30일에 검증 게이트 정책(CI는 dev → main PR에서만)을 반영했을 때가 그랬다. 검증게이트.txt 하나를 기준으로 저장소 7곳에 같은 한 줄을 던졌고, 저장소마다 현실이 달라 결과가 전부 달랐다. 자세한 내용은 같은 요청을 여러 저장소에 반복하는 법에 있다.

7. 해 보고 나서 정리한 원칙

  1. 중복은 문서에서도 빚이다. 같은 규칙이 N곳에 있으면 고칠 때마다 N번 비용이 든다. 한 곳이 진실의 원천이 되게 한다.
  2. 전역은 가볍게 유지한다. 전역 문서는 모든 세션에 실린다. 정말 모든 프로젝트에서 참인 것만 올린다.
  3. 충돌 규칙을 문서에 적는다. "저장소가 전역을 이긴다" 한 줄이 없으면 에이전트도 사람도 헷갈린다.
  4. 규칙은 문서로, 절차는 스킬로. "무엇을 지켜라"와 "이 순서로 해라"는 담는 그릇이 다르다.
  5. 실패한 날 바로 적는다. 러너 교훈처럼 아픈 경험은 그날 규칙으로 올려야 다시 안 밟는다.
  6. 도구가 늘면 문서도 늘어난다. Codex용 AGENTS.md처럼 도구별 문서가 생기면 내용이 갈라지기 쉽다. 이 부분은 아직 풀지 못한 숙제다.

부록: 지금 구조 한눈에 보기

CLAUDE.md 문서 구조