# AI 에이전트

CLAUDE.md가 1,500줄이면 Claude는 규칙을 놓칠까?

@Hong2026-10-14

이 글에 담긴 코드와 결과는 직접 실행해 측정한 값을 바탕으로 작성했습니다. 실측은 Hong과 팀원들이 진행했고, 그 결과를 바탕으로 AI가 글을 쓰고 Hong이 검토합니다.

실습 코드 내려받기

질문
CLAUDE.md가 1,500줄로 길어지면 Claude Code가 그 안의 규칙을 덜 지킬까?
답
규칙 없이 0%였던 네 규칙이 8줄부터 1,499줄까지 모든 호출에서 지켜졌지만 모든 조건이 거의 100%라 길이의 영향은 가를 수 없고, 1,499줄은 요청마다 63,739토큰을 더 실었다.
조건
2026-10-12, Claude Code 2.1.295 claude -p, Opus 5.5(claude-opus-5-5), effort medium, Python 과제 20개, 조건마다 1회 또는 3회

환경

측정일
2026-10-12
Claude Code
2.1.295, --model opus(결과 JSON modelUsage의 모델 ID는 claude-opus-5-5), --effort medium
반복
과제 20개를 조건마다 1회 또는 3회
실행
도구를 끈 한 턴 응답, 채점·집계 Python 스크립트는 python:3.12-slim 컨테이너
비용
구독 로그인으로 호출, 금액은 Claude Code가 API 목록 단가로 환산한 추정치(실제 청구액 아님)
목차
  1. 실습 준비
  2. 실습 1: 규칙이 없을 때
  3. 실습 2: 길이를 늘리면
  4. 정리

이번 시간에는 CLAUDE.md가 1,500줄 가까이 길어질 때 Claude Code가 그 안의 규칙을 덜 지키는지를 claude -p로 측정하며 배워가는 시간입니다. claude -p는 대화 화면 없이 질문 하나를 보내고 결과를 받는 실행 방식이에요. 무관한 팀 규칙 사이에 규칙 다섯 줄을 숨겨 두고, CLAUDE.md가 없을 때와 길이를 8줄부터 1,499줄까지 늘렸을 때의 준수율과 입력 토큰을 볼게요.

모델 출력은 비결정적이라 다시 돌리면 숫자가 달라질 수 있어요. --model opus가 가리키는 모델도 시간이 지나면 달라질 수 있습니다.

실습 준비

이 글의 명령은 모두 실습 코드의 claude-md-length-compliance/ 디렉터리에서 실행합니다.

  • run.sh: 조건 하나의 과제 20개를 내 설정이 섞이지 않게 격리한 claude -p로 돌려 out/<조건>/에 결과 JSON을 남기는 진입점
  • conditions/: build.py가 만든 조건별 CLAUDE.md 디렉터리
  • tasks/: 과제 20개의 질문 파일(tasks/prompts/t01.txt~t20.txt)과 과제 목록(파일 22개)
  • grade.py: 결과 JSON을 심어 둔 규칙별로 채점해 out/grades.jsonl에 쓰는 채점기
  • filler/: 무관한 지침 생성(gen.sh)·거르기(filter.py) 스크립트, 주제 목록, 생성 원본과 결과 filler.md
  • rules/: 심은 규칙 5개, 추가 규칙 10개, 비슷한 규칙 파일(파일 3개)
  • build.py: filler/filler.md와 rules/로 조건별 CLAUDE.md를 conditions/에 쓰고 build/manifest.txt에 줄 수·해시를 남기는 스크립트
  • build/: 조건 목록 manifest.txt와 --append-system-prompt용 sys_1500_dispersed.md(이 글에서는 쓰지 않아요)
  • aggregate.py: out/grades.jsonl을 조건·규칙별 준수율과 조건 비교로 집계하는 스크립트
  • exclude.txt: 규칙 없이도 지킨 비율이 높아 aggregate.py가 결론 집계에서 빼는 규칙 목록

그 밖의 파일은 데이터·보조 스크립트입니다.

claude -p를 그냥 실행하면 사용자 홈의 ~/.claude/CLAUDE.md, 사용자 설정(권한 허용 목록, effort 기본값, 훅), 계정에 연결된 MCP 서버가 함께 들어가요. 길이 실험에서 이것들이 섞이면 토큰도 준수율도 내 환경의 값이 되겠죠.

그래서 run.sh는 모든 호출을 CLAUDE.md 하나만 둔 조건 디렉터리에서 다음 조합으로 돌려요. ./run.sh <조건> <반복 수>로 부르면 conditions/<조건>/을 작업 디렉터리로 tasks/prompts/의 과제 20개를 보내고, 결과 JSON을 out/<조건>/에 남깁니다.

  • --setting-sources project: 사용자 설정과 사용자 CLAUDE.md를 빼고, 작업 디렉터리의 프로젝트 CLAUDE.md만 읽게 합니다.
  • --strict-mcp-config: --mcp-config로 준 MCP 서버만 씁니다. 여기서는 아무것도 주지 않았으므로 MCP 서버가 하나도 붙지 않아요.
  • --tools "": 내장 도구를 모두 끕니다. 모델은 파일을 쓰지 못하고 답을 텍스트로만 내요.
  • --effort medium: 지정하지 않으면 부모 셸의 CLAUDE_EFFORT 환경 변수나 사용자 설정의 effortLevel이 끼어들 수 있어 명시했습니다.
  • --max-turns 1: claude --help에는 없지만 동작합니다. 도구가 없으니 한 번에 끝나야 하고, 이를 안전장치로 걸었어요.
  • --no-session-persistence: 대화 기록 파일을 남기지 않습니다.

--safe-mode는 쓰지 않았어요. claude --help의 설명대로 safe 모드는 CLAUDE.md까지 끄기 때문입니다. 한도 오류가 나오면 그 조건을 멈추고, 같은 명령으로 다시 돌리면 남은 과제만 이어서 돕니다.

Python 스크립트는 호스트에 아무것도 설치하지 않도록 python:3.12-slim 컨테이너에서 돌려요. 아래 블록의 py 함수가 그 일을 합니다.

아래 블록은 파일로 만들지 말고 실습 디렉터리에서 연 터미널에 그대로 붙여 넣어 주세요. 이후 명령은 모두 이 터미널에서 실행하고, 터미널을 새로 열면 다시 붙여 넣으시면 됩니다.

py() { docker run --rm --network none -v "$PWD":/w -w /w python:3.12-slim python "$@"; }

심은 규칙은 다음 다섯 줄이에요. 강조어 없이 평서문으로 썼습니다.

  • R1: 응답 첫 줄은 요약: 으로 시작하는 한 문장으로 쓴다.
  • R2: 새 파이썬 파일의 코드를 보여 줄 때는 코드 블록 첫 줄에 # file: <경로> 주석을 쓰고, 파일 이름은 hp_로 시작하는 snake_case로 짓는다(예: # file: src/hp_duration.py).
  • R3: 변수·인자·함수·속성 이름에 result, data, tmp라는 단어를 쓰지 않는다. parsed, payload처럼 뜻이 드러나는 이름을 쓴다.
  • R4: 예외를 일으킬 때는 내장 예외(ValueError, TypeError 등) 대신 from hp.errors import HpError로 가져온 HpError를 쓴다.
  • R5: 응답 마지막 줄은 검증: 으로 시작하고 그 뒤에 이 코드를 확인할 pytest 명령 한 줄을 적는다(예: 검증: pytest -q tests/test_hp_duration.py).

고른 기준은 세 가지예요. 모델이 규칙 없이도 원래 하는 행동이 아니어야 하고, 사람이 보지 않고 정규식이나 Python AST(코드를 구문 단위로 나눈 트리)로 판정할 수 있어야 하며, Claude Code가 스스로 넣는 커밋·PR 지침과 겹치지 않아야 합니다.

과제는 Python 함수 하나를 만드는 한국어 요청 20개예요. 기간 문자열 파싱, slugify, 휴대폰 번호 검증, semver 비교, 로마 숫자, Luhn 검사, 구간 병합, IPv4 검증처럼 짧은 함수이고, 문장 형식은 모두 같습니다.

"1h30m", "45s" 같은 기간 문자열을 초 단위 정수로 바꾸는 함수 `parse_duration`을 새 파이썬 파일 하나에 들어갈 코드로 작성해서 답변에 보여 주세요. 입력이 잘못되면 예외를 일으켜야 합니다.

도구를 끈 상태에서 "새 파일로 작성해 주세요"라고 물으면 모델이 코드 블록 없이 "gcd.py에 작성했습니다"라고 답한 사례가 있어서, "답변에 보여 주세요"로 바꿨어요. 채점기 grade.py가 보는 것은 다음과 같아요.

  • R1: 비어 있지 않은 첫 줄이 요약: 으로 시작하면 지킴
  • R2: ast.parse가 성공하는 첫 코드 블록의 첫 줄이 # file: (경로/)hp_이름.py 형식이면 지킴
  • R3: 그 코드 블록에서 모델이 지은 이름을 _로 나눈 조각에 result, data, tmp가 있으면 어김
  • R4: raise 문의 예외 이름이 모두 HpError면 지킴. 인자 없는 raise는 세지 않고, 센 것이 없으면 판정하지 않습니다.
  • R5: 비어 있지 않은 마지막 줄이 검증: pytest로 시작하면 지킴

규칙을 숨길 무관한 지침은 실제 팀 CLAUDE.md처럼 ## 제목 아래 글머리표가 이어지는 문서여야 해요. 1,500줄을 사람이 쓸 수는 없어서 Claude로 생성했습니다. Kotlin·Spring 서비스, React, Terraform, Kubernetes 배포, SQL 마이그레이션, Kafka처럼 Python과 응답 형식이 아닌 주제마다, filler/gen.sh <번호>가 --safe-mode로 한 번씩 "팀 저장소의 개발 규칙을 150줄 안팎으로 써 달라"고 요청하고 결과 JSON을 filler/raw/에 남깁니다.

그다음 filler/filter.py가 python, pytest, 요약, 검증, 예외, result, data, IMPORTANT, 응답처럼 심은 규칙과 겹치거나 경쟁할 낱말이 든 줄을 지우고, 주제 순서대로 이어 붙여 1,550줄을 넘으면 멈추고 filler/filler.md로 씁니다.

py filler/filter.py | tail -1
topics used: 14  generated 1674  dropped 214 (13%)  filler.md 1651 lines, 191 sections

길이 조건은 이 파일의 앞부분을 섹션 단위로 잘라 써요. 기본 배치(흩어 둠)에서는 규칙 i를 파일 길이의 i/6 지점에 가장 가까운 섹션 끝에 한 줄로 끼우고, 따로 제목을 달지 않았어요. 출력은 이 글에서 쓰는 조건만 남긴 발췌예요.

py build.py | grep -v pre-
  998 lines   89281 bytes  200e7c2ef46ae06b  conditions/disp-1000/CLAUDE.md
 1499 lines  134496 bytes  861a48c94389c34c  conditions/disp-1500/CLAUDE.md
  199 lines   17467 bytes  bed7e65c95663888  conditions/disp-200/CLAUDE.md
  496 lines   44516 bytes  703392c89f99a7e3  conditions/disp-500/CLAUDE.md
    8 lines     821 bytes  b8f999a30b2ee297  conditions/rules-only/CLAUDE.md

섹션 경계에서 자르기 때문에 목표 줄 수(200, 500, 1,000, 1,500)와 몇 줄씩 달라요. 그래서 이후에는 실제 줄 수로 적습니다. rules-only는 규칙 다섯 줄만 둔 8줄 CLAUDE.md예요.

run.sh는 시작할 때 조건 디렉터리부터 /까지 올라가며 다른 CLAUDE.md, CLAUDE.local.md, AGENTS.md, .claude/가 없는지 확인해요. Claude Code는 작업 디렉터리 위의 모든 상위 디렉터리에서 이 파일들을 읽기 때문입니다.

집계는 aggregate.py가 out/grades.jsonl을 읽어 out/summary.txt로 내요. 인자로 조건 이름을 주면 그 조건만, --rules를 주면 그 규칙 줄만 보여 줍니다. 이후 블록의 출력에는 run.sh와 grade.py가 내는 진행 줄(<조건> r1: 20개 실행 (시간), graded <N> calls -> out/grades.jsonl 같은 줄)을 옮기지 않았어요.

실습 1: 규칙이 없을 때

먼저 CLAUDE.md 없는 빈 디렉터리에서 같은 과제 20개를 3회 돌려 볼게요. 규칙이 없으니, 여기서 지킨 비율은 모델이 원래 그렇게 하는 비율이에요.

./run.sh none 3
py grade.py
py aggregate.py none --rules R1,R2,R3,R4,R5 \
  | grep -vE "^models|^excluded|^$|^   all|cost|duration|cache|r2_header"
== none  lines 0  bytes 0  calls 60  complete 60  reps [1, 2, 3]
   not_success 0  pseudo_tool 0  no_code 3  parse_error 3  func_defined 57/60  num_turns!=1 0
   R1   strict   0/60    0.0%  [r1 0/20, r2 0/20, r3 0/20]  lenient 0/60   0.0%  clean 0/57
   R2   strict   0/60    0.0%  [r1 0/20, r2 0/20, r3 0/20]  lenient 0/60   0.0%  clean 0/57
   R3   strict  51/60   85.0%  [r1 17/20, r2 17/20, r3 17/20]  lenient 51/60  85.0%  clean 48/57 (excluded)
   R4   strict   0/60    0.0%  [r1 0/20, r2 0/20, r3 0/20]  lenient 0/60   0.0%  clean 0/57
   R5   strict   0/60    0.0%  [r1 0/20, r2 0/20, r3 0/20]  lenient 0/60   0.0%  clean 0/57
   input_tokens median 2812  min 2799  max 2828
   R3 banned names {'result': 9, 'data': 3}

출력을 보면 R1, R2, R4, R5는 60번 모두 0이었어요. 그러니 이 네 규칙을 지켰다면 그건 CLAUDE.md 덕분이라고 봐도 됩니다.

R3는 규칙 없이도 85%를 지켰어요. 모델이 원래 result, data, tmp 같은 이름을 잘 쓰지 않는다는 뜻이라, R3는 준수율이 높아도 규칙 덕이라고 말할 수 없어서 결론에서 뺐어요(exclude.txt). 이후 출력의 all-concl은 결론에 쓰는 규칙 넷(R1, R2, R4, R5)을 한 호출에서 모두 지킨 비율이에요. CLAUDE.md가 없을 때 호출 하나의 입력은 2,812토큰(중앙값)이었어요.

실습 2: 길이를 늘리면

규칙 다섯 줄을 흩어 둔 1,499줄 조건(disp-1500)을 가장 먼저 1회 돌렸어요.

실험 전에 정해 둔 규칙이 있었습니다. 여기서 결론 규칙이 모두 20번 중 19번 이상 지켜지면 더 오를 여지가 없는 천장 상태예요. 그때는 나머지 길이를 1회만 돌려 토큰 측정과 참고용 준수율로 쓰기로 했어요. 1,499줄은 20번 모두 지켰습니다. 그래서 1,499줄만 3회, 나머지는 1회 돌렸어요.

./run.sh disp-1500 3
./run.sh rules-only 1
./run.sh disp-200 1
./run.sh disp-500 1
./run.sh disp-1000 1
py grade.py
py aggregate.py rules-only disp-200 disp-500 disp-1000 disp-1500 \
  | grep -E "^==|all-concl|input_tokens|instructions|cost"
== rules-only  lines 8  bytes 821  calls 20  complete 20  reps [1]
   all-concl  20/20  100.0%  [r1 20/20]  (R1+R2+R4+R5)
   input_tokens median 3360  min 3346  max 3375
   instructions tokens (median of cond - none per task) 547  per line 68.4  per KB 666.3
   cost estimate (API list price) r1 $0.67  r2+ $0.00  total $0.67
== disp-200  lines 199  bytes 17467  calls 20  complete 20  reps [1]
   all-concl  20/20  100.0%  [r1 20/20]  (R1+R2+R4+R5)
   input_tokens median 11242  min 11229  max 11258
   instructions tokens (median of cond - none per task) 8430  per line 42.4  per KB 482.6
   cost estimate (API list price) r1 $1.97  r2+ $0.00  total $1.97
== disp-500  lines 496  bytes 44516  calls 20  complete 20  reps [1]
   all-concl  20/20  100.0%  [r1 20/20]  (R1+R2+R4+R5)
   input_tokens median 24016  min 24003  max 24032
   instructions tokens (median of cond - none per task) 21204  per line 42.8  per KB 476.3
   cost estimate (API list price) r1 $4.05  r2+ $0.00  total $4.05
== disp-1000  lines 998  bytes 89281  calls 20  complete 20  reps [1]
   all-concl  20/20  100.0%  [r1 20/20]  (R1+R2+R4+R5)
   input_tokens median 45342  min 45328  max 45357
   instructions tokens (median of cond - none per task) 42529  per line 42.6  per KB 476.3
   cost estimate (API list price) r1 $7.47  r2+ $0.00  total $7.47
== disp-1500  lines 1499  bytes 134496  calls 60  complete 60  reps [1, 2, 3]
   all-concl  60/60  100.0%  [r1 20/20, r2 20/20, r3 20/20]  (R1+R2+R4+R5)
   input_tokens median 66552  min 66538  max 66567
   instructions tokens (median of cond - none per task) 63739  per line 42.5  per KB 473.9
   cost estimate (API list price) r1 $9.86  r2+ $1.65  total $11.51

instructions tokens는 같은 과제의 입력 토큰에서 CLAUDE.md 없는 조건의 값을 뺀 중앙값, 곧 지침 블록이 차지한 토큰이에요. 출력을 보면 토큰과 준수율은 다르게 움직였습니다.

  • 토큰: 지침 블록은 줄당 약 42.5토큰, 1KB당 약 474토큰으로 줄 수에 비례해 늘었어요. 199줄이 8,430토큰, 1,499줄이 63,739토큰입니다. 이 무관한 지침은 한 줄이 평균 90바이트쯤 되는 한국어 글머리표라서 줄당 토큰이 꽤 커요. 자기 파일의 값은 따로 재 보셔야 합니다.
  • 준수율: 결론 규칙 넷을 어긴 호출이 어느 길이에서도 없었어요. 8줄도 1,499줄도 모두 지켰고, Memory 문서가 기준으로 말한 200줄 부근에서 꺾이는 모습도 없었습니다.

1,499줄 약 134KB 파일은 잘리지 않고 통째로 들어갔어요. Memory 문서도 "Claude Code loads a CLAUDE.md file of up to 4 MiB in full and skips a larger file."이라고 적습니다.

비용 추정치에는 캐시가 크게 작용했어요. 1,499줄 조건의 1회차 20호출은 $9.86(호출당 약 $0.49)이었는데, 2·3회차 40호출은 합쳐서 $1.65였습니다. 이 글에 싣지 않은 사전 확인에서 캐시 필드를 보면, 질문이 다르면 새 세션마다 CLAUDE.md까지 다시 캐시에 썼고 질문까지 같으면 캐시에서 읽었어요.

다만 비교하는 두 조건이 모두 95% 이상이면 차이를 볼 여지가 없으니, 길이 비교는 모두 "판정 불가(천장)"입니다. 차이를 찾지 못한 것을 길어도 괜찮다는 확인으로 쓰지는 않아요.

정리

범위: Claude Code 2.1.295의 claude -p, Opus 5.5(claude-opus-5-5), effort medium, 도구를 끈 한 턴 응답, Python 과제 20개, 조건마다 1회 또는 3회.

  • 지침 블록은 줄당 약 42.5토큰으로 줄 수에 비례해 늘었고, 1,499줄이면 요청마다 63,739토큰이 더 실렸습니다. 자기 CLAUDE.md의 줄당 토큰은 따로 재 보세요.
  • 규칙 없이 0%였던 네 규칙(R1, R2, R4, R5)이 8줄부터 1,499줄까지 모든 호출에서 지켜졌고, 200줄 부근에서 꺾이지도 않았어요. 1,499줄 외 길이는 1회만 돌렸고 모든 비교가 천장이었으니, 이 결과를 길어도 괜찮다는 증거로 쓰지는 마세요.
  • 1,499줄 약 134KB 파일은 잘리지 않고 통째로 들어갔어요. 비용 추정치는 1회차 20호출이 $9.86이었고, 질문까지 같은 2·3회차 40호출은 합쳐서 $1.65로 캐시가 크게 작용했습니다.
내 링크 만들기