시작은 규칙 파일 하나였다
Claude Code 는 CLAUDE.md 라는 파일에 적어둔 규칙을 매 대화에 실어 보낸다. “테이블 행은
| 로 시작하고 끝낸다” 같은 걸 적어두면 매번 말하지 않아도 지켜진다.
처음엔 이 파일 하나였다. 지금은 이렇게 나뉘어 있다.
| 계층 | 줄 수 | 적용 범위 |
|---|---|---|
전역 CLAUDE.md
|
182 | 맥 4대 전부 |
CLAUDE-omc.md |
73 | 전역 + 플러그인이 자동 갱신 |
프로파일 CLAUDE.md
|
9~48 | 이 머신만 |
| 회사 공통 | 108 | 회사 머신 2대만 |
| 프로젝트별 | 가변 | 그 레포 안에서만 |
나누게 된 계기는 취향이 아니라 사고였다. 회사 서버 SSH 설정이 개인 레포로 올라갈 뻔했다.
- 머신 4대: 회사 2 · 개인 2
- 같은 dotfiles 저장소를 심링크(원본을 가리키는 바로가기 파일)로 공유
- 그래서 한쪽에 적은 게 다른 쪽에도 그대로 간다
회사 규칙 파일 첫 문단에 그때 정한 원칙이 그대로 적혀 있다.
개인 머신에는 심링크되지 않으므로, 여기에는
회사 머신에서만 성립하는 규칙만 적는다.
프로파일은 호스트명으로 갈린다
머신 이름(scutil --get ComputerName)을 읽어 매핑 파일에서 프로파일을 찾는다. install.sh
609줄이 그 프로파일에 맞는 것만 심링크한다.
회사 머신이면 회사 규칙을 걸고, 개인 머신이면 걸지 않는 게 아니라 지운다.
# company-* 가 아니면 남아 있던 회사 규칙을 제거한다
rm -f ~/.claude/CLAUDE.company.md
- 이유: 프로파일을 바꿔 달았을 때 이전 설정이 남으면 조용히 틀린 상태가 된다
- 심링크는 pull 로 전파되지 않는다 — 파일 내용만 간다
이 구분이 계속 발목을 잡았던 부분인데, 별도 글에서 다뤘다:
pull 은 됐는데 설정이 반만 적용된다
빈 계층을 미리 파둔다
회사 머신 두 대는 규칙이 같다. 그런데 각자의 프로파일 파일은 따로 있다. 회사 노트북 쪽
내용은 9줄이고 본문이 이게 전부다.
## 이 머신 전용
(없음 — company-pro 와 다른 규칙이 생기면 여기에 적는다)
빈 파일을 왜 두냐면, 나중에 한쪽에만 필요한 규칙이 생겼을 때 어디에 적을지 고민하지
않기 위해서다. 자리가 없으면 공용 파일에 넣게 되고, 그러면 다른 머신에도 실린다.
플러그인 — 셋을 함께 쓰는 이유
플러그인 6개를 쓰는데, 그중 셋이 역할이 겹쳐 보인다. 실제로는 층이 다르다.
| 도구 | 층 | 하는 일 |
|---|---|---|
| superpowers | 프로세스 | 절차 규율 — 브레인스토밍 → 계획 → 구현 |
| oh-my-claudecode | 오케스트레이션 | 여러 에이전트에 일을 나눠 실행 |
| ECC rules | 지식 | 언어별 코딩 규칙 |
겹치는 상황이 생기면 전역 규칙에 적어둔 라우팅 표를 따른다. 예를 들어 완료 검증은
superpowers 것을 1회만 쓰고, OMC 검증기는 자율 실행 모드 안에서만 돈다. 둘 다 돌리면
같은 일을 두 번 한다.
ECC 는 플러그인으로 깔지 않았다
everything-claude-code 는 플러그인으로 설치할 수 있지만 rules 만 가져왔다.
- 이유: 훅(자동 포맷·커밋 차단)과 에이전트 67개가 앞의 두 도구와 겹치거나 충돌한다
- 필요한 건 “언어별 코딩 규칙”이라는 지식뿐이었다
그리고 가져온 rules 중에서도 common 팩은 뺐다. 이게 이 글에서 가장 중요한 결정이다.
상시 로드 비용이라는 개념
CLAUDE.md 에 적은 내용은 모든 대화에 실린다. 브라우저를 안 쓰는 대화에도 브라우저
규칙이 실린다.
common 팩을 뺀 이유가 그거다.
- 다른 4개 팩에는
paths설정이 있다 — 예를 들어**/*.java를 건드릴 때만 로드된다 -
common에는 그게 없어 모든 세션에 약 40K 가 상시로 실린다
즉 21개 파일 1,970줄을 들여놓고도 평소 비용은 0 이다. 자바 파일을 열 때만 자바 규칙이
온다.
같은 이유로 규칙을 두 번 덜어냈다
이 개념을 알고 나서 이미 부어놓은 규칙들을 다시 봤다.
한 번째 — 브라우저 규칙 (2026-07-31)
커밋 메시지에 이유를 적어뒀다.
전역 CLAUDE.md 30줄은 브라우저를 쓰지 않는 모든 대화에도 실려
토큰을 소모하고 다른 규칙의 주의를 분산시켰다.
- 전역 CLAUDE.md 는 한 줄 포인터만 유지 (183 -> 157줄)
내용을 지운 게 아니라 스킬로 옮겼다. 스킬은 필요할 때만 읽힌다. 전역에는 “브라우저를
쓰기 전에 이 스킬을 읽어라” 한 줄만 남겼다.
두 번째 — 동기화 트러블슈팅 (2026-08-20)
이번엔 dotfiles 레포 자체의 규칙 파일이었다.
상시 로드되는 CLAUDE.md 에서 두 종류를 덜어냈다.
- 심링크 표 2개: install.sh 의 link 호출이 원본이라 표는 중복이었고,
스크립트가 바뀌면 문서만 조용히 낡는다. 포인터로 대체.
- 동기화 트러블슈팅 68줄: 평소엔 안 쓰는 내용이라 스킬로 옮겨
필요할 때만 로드되게 했다.
11,237자 → 6,155자(45%)
심링크 표를 지운 근거가 따로 있다. 문서에 목록을 적어두면 스크립트가 바뀔 때 문서만
조용히 어긋난다. 그래서 “목록은 install.sh 의 link 호출을 읽어라”로 바꿨다.
이름은 나중에 배웠다
두 번 다 “이건 평소엔 안 쓰는데 왜 매번 실리지”라는 감각으로 옮긴 것이었다. 정작 그 행동에
이름이 붙은 건 8월 22일, 에이전트용 문서 작성법을 다룬 외부 스킬을 가져오면서였다.
- context load — 상시 로드되는 문서가 매 대화에 지불하는 비용
- progressive disclosure — 필요할 때만 펼치는 구조
몸으로 먼저 알고 이름은 나중에 배운 순서였다. 이름을 알고 나니 남은 규칙들을 다시 볼 기준이
생겼다는 게 더 컸다.
훅 — 지금 실제로 도는 다섯 개
규칙이 “부탁”이라면 훅은 “차단”이다. 특정 시점에 스크립트가 끼어든다.
| 시점 | 하는 일 |
|---|---|
| Bash 실행 전 | 모든 명령을 타임스탬프와 함께 기록 |
| 파일 저장 후 | 마이그레이션 파일이면 버전 중복 검사 |
| 세션 시작 | 7일 지난 세션 로그 삭제 |
| 세션 시작 | 플러그인 자동 업데이트 |
| 세션 종료 | macOS 알림 |
두 번째가 실용적이다. 데이터베이스 마이그레이션은 버전 번호가 겹치면 안 되는데, 보통
합치고 나서야 터진다. 파일을 저장하는 순간 검사하면 그 자리에서 안다.
부탁과 차단은 다르다
이 구분이 중요하다는 걸 실험으로 알았다. 자동 동기화가 실패했을 때 Claude 를 무인으로
불러 해결하게 하는데, 그러려면 못 하게 할 것을 정해야 했다.
--allowedTools "Bash(git status:*)" 처럼 좁혀도
허용목록 밖 명령(cat 등)이 그대로 실행됐다.
반면 --disallowedTools 는 실제로 막혔다.
즉 범위를 좁히는 옵션은 모델에 대한 요청이지 기술적 차단이 아니었다. 반면 훅은
실제로 막혔다(whoami 차단 / echo 통과 확인).
그래서 도구 제한을 설정이 아니라 훅으로 걸었다. 실제로 스킬 24개 중 allowed-tools 를
쓰는 것이 하나도 없다.
정리
지금 상태를 숫자로 적으면 이렇다.
- dotfiles 커밋 256개,
install.sh609줄 - 규칙 계층 5단, 합쳐서 400줄 남짓
- 플러그인 6개, 훅 5개, 스킬 24개
- ECC rules 21파일 1,970줄 — 상시 비용은 0
그런데 이 글에서 실제로 배운 건 개수가 아니라 하나다. 모든 규칙에는 상시 로드 비용이
있고, 좋은 규칙도 잘못된 자리에 있으면 다른 규칙의 주의를 분산시킨다.
스킬 이야기는 다음 글에 썼다:
스킬 16개를 만들었더니 명령어 모음이 판단 문서가 됐다.
처음 만든 것은 16줄짜리 셸 래퍼였고 최근 것은 198줄짜리 판단 문서다.