Claude Code 모노레포 토큰 최적화 — LSP 컨텍스트 폭발 방지 실전 설정법

목차

claude code 모노레포 토큰 최적화의 핵심은 세 가지로 요약된다. CLAUDE.md 계층 분리로 불필요한 규칙 로딩을 차단하고, LSP를 통해 텍스트 기반 탐색을 대체하며, Extended Thinking 토큰 상한을 명시적으로 제어하는 것이다. 모노레포는 프론트엔드, 백엔드, 인프라 코드가 한 저장소에 공존한다. 패키지가 10개를 넘어가면 Claude Code가 세션마다 로딩하는 컨텍스트 양이 늘어나고, grep이 저장소 전체를 훑으면서 토큰 소비가 가파르게 증가한다. 이 글에서는 설정 파일 수준에서 토큰 소비를 통제하는 구체적 방법을 다룬다.

CLAUDE.md 계층 구조 설계 — claude code 모노레포 토큰 최적화의 시작

모노레포에서 CLAUDE.md는 디렉토리 트리를 따라 계층적으로 로드된다. packages/api/ 디렉토리에서 Claude Code를 실행하면 packages/api/CLAUDE.md뿐 아니라 상위 경로의 CLAUDE.md도 함께 로드된다. 하위 디렉토리의 CLAUDE.md는 해당 디렉토리 파일 접근 시 on-demand로 로드되는 구조다. 이 동작을 이해하지 못하면 작업과 무관한 팀의 규칙까지 매 세션마다 컨텍스트에 쌓인다.

Anthropic Claude Code 비용 관리 문서에서는 CLAUDE.md를 간결하게 유지하고, 전문 워크플로는 별도 파일로 분리할 것을 권장한다. 모노레포에서는 루트 CLAUDE.md를 50줄 이하로 줄이고, 각 패키지 디렉토리에 100줄 이하의 개별 CLAUDE.md를 두는 편이 현실적이다.

루트 CLAUDE.md — 공통 규칙만 남기기

루트에는 모노레포 전체에 적용되는 최소한의 규칙만 기재한다. 린트 설정, 커밋 컨벤션, CI 파이프라인 정보 정도다. 특정 패키지의 API 스타일 가이드나 테스트 전략은 해당 패키지 디렉토리로 이동시킨다.

# 프로젝트 공통 규칙
- 커밋 메시지: conventional commits (feat/fix/chore)
- 린터: ESLint + Prettier (루트 설정 상속)
- CI: GitHub Actions, PR마다 lint + test 필수

# Compact instructions
When you are using compact, focus on test output and code changes

compaction 지시를 루트에 두면, 자동 compaction이 컨텍스트 한도 접근 시 대화 이력을 요약할 때 핵심 정보를 보존한다. prompt caching이 시스템 프롬프트 등 반복 콘텐츠 비용을 절감하므로, 루트 CLAUDE.md가 짧을수록 캐싱 효율이 높아진다.

claudeMdExcludes로 다른 팀 규칙 차단

claudeMdExcludes 설정은 모노레포에서 컨텍스트 분리의 핵심이다. 프론트엔드 개발자가 백엔드 팀의 CLAUDE.md를 로딩할 이유가 없다. .claude/settings.json에 다음과 같이 설정한다.

{
  "claudeMdExcludes": [
    "**/api/CLAUDE.md",
    "**/infra/CLAUDE.md",
    "/home/user/monorepo/other-team/.claude/rules/**"
  ]
}
claudeMdExcludes 설정 시 주의점
루트 CLAUDE.md를 제외하면 공통 규칙도 함께 사라진다. 루트 제외 시 해당 규칙을 각 패키지 CLAUDE.md에 복사하거나, 루트 대신 특정 팀 디렉토리만 제외하는 방식을 택해야 한다.
모노레포 디렉토리 구조 예시는 다음과 같다.
monorepo/
├── CLAUDE.md              ← 공통 (50줄 이하)
├── packages/
│   ├── web/
│   │   └── CLAUDE.md      ← 프론트 전용 규칙
│   ├── api/
│   │   └── CLAUDE.md      ← 백엔드 전용 규칙
│   └── infra/
│       └── CLAUDE.md      ← 인프라 전용 규칙
└── .claude/
    └── settings.json      ← claudeMdExcludes 설정

on-demand 로딩 특성상 해당 디렉토리 파일을 건드리지 않으면 로딩 자체가 안 되지만, 크로스 패키지 의존성 추적 시 의도치 않게 로딩될 수 있다. 명시적 제외가 안전하다.

.claude/rules/ 경로 범위 규칙으로 조건부 로딩 구현

CLAUDE.md가 파일 단위 컨텍스트라면, .claude/rules/는 더 정밀한 제어를 제공한다. Anthropic Claude Code 메모리 관리 문서에 따르면 paths frontmatter로 특정 파일 패턴에만 규칙을 적용할 수 있다. 경로 범위 규칙은 해당 파일 작업 시에만 컨텍스트에 로드되어 토큰을 절약한다.

---
paths:
  - "src/api/**/*.ts"
---
# API Development Rules
- All API endpoints must include input validation
- Response format: { data, error, metadata }
- Error codes follow RFC 7807 Problem Details

paths 없는 규칙은 세션 시작 시 무조건 로드된다. 이 차이가 claude code 모노레포 토큰 최적화에서 중요한 지점이다. 패키지별로 코딩 컨벤션이 다른 경우 — Python 백엔드는 snake_case, TypeScript 프론트엔드는 camelCase — 각각의 규칙을 paths로 분리하면 충돌 없이 동작한다.

규칙 분리 전략

규칙을 나누는 기준은 단순하다. 세션에서 항상 필요한 규칙은 paths 없이, 특정 작업에서만 필요한 규칙은 paths를 지정한다.

규칙 유형 paths 지정 여부 로딩 시점 토큰 영향
커밋 컨벤션 없음 세션 시작 항상 소비
API 유효성 검사 src/api/** API 파일 접근 시 조건부
테스트 작성 규칙 **/*.test.* 테스트 파일 접근 시 조건부
인프라 IaC 규칙 infra/**/*.tf Terraform 파일 접근 시 조건부

항상 로딩되는 규칙은 5개 이하로 유지하고, 나머지는 전부 paths로 범위를 한정하는 것이 원칙이다. 팀별 규칙이 늘어날수록 paths 없는 규칙 하나가 추가될 때마다 모든 세션의 기본 토큰 소비가 증가한다.

규칙 파일 네이밍 컨벤션
`.claude/rules/` 내 파일명에 패키지명을 접두어로 붙이면 관리가 편하다. `api-validation.md`, `web-styling.md`, `infra-terraform.md` 식으로 네이밍하면 어떤 팀의 규칙인지 파일 목록만으로 파악된다.
## LSP 기반 코드 탐색으로 claude code 모노레포 토큰 최적화

코드 인텔리전스 플러그인(LSP)은 텍스트 기반 검색 대신 심볼 단위 네비게이션을 제공한다. ‘go to definition’ 한 번이 grep + 여러 후보 파일 읽기를 대체한다. 설치된 언어 서버는 편집 후 타입 에러도 자동 보고하여 컴파일러를 직접 실행하지 않아도 실수를 잡는다.

모노레포에서 이 차이가 뚜렷하게 드러난다. 패키지가 15개인 저장소에서 특정 함수 정의를 grep으로 찾으면 여러 패키지에 걸쳐 후보 파일이 반환되고, Claude가 각각을 읽으며 맞는 것을 찾는다. LSP는 정확한 위치를 한 번에 반환하므로 읽기 횟수 자체가 줄어든다.

LSP 우선 사용을 유도하는 CLAUDE.md 규칙

Claude Code에 LSP 사용을 유도하려면 CLAUDE.md에 명시적 지시를 추가한다.

# Code Navigation Rules
- 함수/클래스 정의를 찾을 때 grep 대신 LSP go-to-definition을 우선 사용
- 타입 에러 확인 시 LSP diagnostics를 먼저 조회
- LSP가 결과를 반환하지 못하는 경우에만 grep fallback 허용

이 규칙만으로도 Claude Code가 grep을 남발하는 패턴이 줄어든다. 핵심은 LSP가 실패할 때만 grep을 허용한다는 조건을 명시하는 것이다.

Hook을 통한 LSP 강제 적용

더 강한 제어가 필요하면 PreToolUse hook으로 Grep 호출 시 LSP 사용 여부를 검증하는 방식이 있다. 커뮤니티에서는 hook 스크립트로 Claude Code가 Grep 대신 LSP를 사용하도록 강제하는 접근이 시도되고 있다. 다만 이러한 hook의 정확한 토큰 절감 수치는 프로젝트 규모, 언어, LSP 구현체에 따라 다르며, 일반화된 벤치마크는 공식 문서에도 명시되어 있지 않다.

LSP 지원 언어별 차이
TypeScript는 tsserver가 풍부한 심볼 정보를 제공하므로 LSP 효과가 크다. Python은 Pylance나 pyright 수준에 따라 차이가 있고, Go는 gopls가 안정적이다. 언어별 LSP 성숙도에 따라 효과가 달라지므로 팀의 주력 언어에서 먼저 테스트하는 것이 합리적이다.
“`json { “hooks”: { “PreToolUse”: [ { “matcher”: “Grep”, “hooks”: [ { “type”: “command”, “command”: “echo ‘LSP를 먼저 시도했는지 확인'” } ] } ] } } “`

hook 설정은 .claude/settings.jsonhooks 필드에 배치한다. matcherGrep이면 Claude Code가 Grep 도구를 호출할 때마다 hook이 실행된다. 실제 프로덕션에서는 단순 echo 대신 LSP 호출 이력을 확인하는 스크립트로 교체한다.

PreToolUse Hook으로 불필요한 파일 읽기 차단

PreToolUse hook은 Claude Code가 도구를 호출하기 직전에 실행되는 검증 레이어다. 모노레포에서는 Read 도구가 작업 범위 밖의 파일을 읽으려 할 때 이를 차단하는 용도로 활용된다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/read-scope-guard.js"
          }
        ]
      }
    ]
  }
}

모노레포에서의 hook 활용 패턴

scope guard 스크립트의 기본 구조는 다음과 같다. hook은 표준 입력으로 도구 호출 정보를 JSON으로 받고, 표준 출력으로 승인/거부를 반환한다.

// .claude/hooks/read-scope-guard.js
const fs = require('fs');
const path = require('path');

const ALLOWED_PATHS = [
  'packages/web/',
  'packages/shared/',
  'configs/'
];

async function main() {
  const input = JSON.parse(
    fs.readFileSync('/dev/stdin', 'utf-8')
  );
  const filePath = input.tool_input?.file_path || '';
  const isAllowed = ALLOWED_PATHS.some(
    (p) => filePath.includes(p)
  );

  if (!isAllowed) {
    console.log(JSON.stringify({
      decision: "block",
      reason: `${filePath}는 허용 범위 밖`
    }));
  }
}

main();
hook 스크립트 오류 처리
hook 스크립트가 예외를 던지면 Claude Code 세션 자체가 중단될 수 있다. try-catch로 감싸고, 예외 시에는 허용(passthrough)하는 방향이 안전하다. hook이 차단만 하고 허용 분기가 없으면 모든 Read가 막히는 사고가 발생한다.
이 패턴을 확장하면 Grep, Write 등 다른 도구에도 동일한 범위 제한을 적용할 수 있다. 패키지가 많은 모노레포에서 `ALLOWED_PATHS`를 팀별로 다르게 설정하면, 각 개발자가 자기 패키지 범위 안에서만 Claude Code를 사용하게 된다.

Extended Thinking 토큰 상한 제어

Claude Code의 Extended Thinking은 복잡한 추론에 유용하지만, 토큰 소비가 크다. 모노레포에서 패키지 간 의존성을 분석하는 작업처럼 넓은 범위를 다루면 thinking 토큰이 빠르게 소진된다.

비용 구조 이해

Extended Thinking 토큰은 일반 출력 토큰과 별도로 과금된다. 정확한 비율은 모델과 플랜에 따라 다르므로 Anthropic 공식 가격 페이지에서 확인해야 한다. 핵심은 thinking 토큰에 상한을 설정하지 않으면, 복잡한 질문 하나에 세션 토큰 대부분이 thinking에 소비될 수 있다는 점이다.

CLAUDE.md에 thinking 제어 지시를 추가하는 방법이 있다.

# Thinking Budget Rules
- 단순 코드 수정: thinking 최소화, 바로 결과 출력
- 아키텍처 분석: thinking 허용하되 단계별로 끊어서 진행
- 패키지 간 의존성 추적: 한 번에 3개 패키지 이상 분석하지 않기
작업 유형 Thinking 필요도 권장 접근
단일 파일 버그 수정 낮음 thinking 최소화
API 엔드포인트 추가 중간 해당 패키지 범위 내 thinking
크로스 패키지 리팩토링 높음 작업 분할 후 패키지별 진행
전체 아키텍처 리뷰 매우 높음 단계별 질문으로 분리
작업 분할이 토큰 절감의 핵심
“packages/api와 packages/web의 공통 타입을 리팩토링해줘”처럼 넓은 범위의 요청은 thinking 토큰을 대량 소비한다. “packages/shared에 공통 타입 파일을 만들고, packages/api에서 import를 변경해줘”처럼 단계를 나누면 각 단계의 thinking 범위가 좁아진다.
## 실전 적용 체크리스트 — claude code 모노레포 토큰 최적화 점검표

설정을 단계적으로 적용하는 순서를 정리한다. 한꺼번에 모든 설정을 적용하면 문제 발생 시 원인 파악이 어렵다.

1단계: CLAUDE.md 분리 (소요 시간 30분 이내)

루트 CLAUDE.md에서 패키지별 규칙을 분리한다. 루트는 50줄 이하, 패키지별 CLAUDE.md는 100줄 이하가 기준이다.

# 현재 루트 CLAUDE.md 줄 수 확인
wc -l CLAUDE.md

# 패키지별 CLAUDE.md 생성
touch packages/web/CLAUDE.md
touch packages/api/CLAUDE.md

2단계: 경로 범위 규칙 설정 (소요 시간 1~2시간)

.claude/rules/ 디렉토리에 규칙 파일을 생성하고, paths frontmatter를 지정한다. 항상 로딩 규칙 5개 이하를 유지하는 것이 목표다.

.claude/rules/
├── commit-convention.md     ← paths 없음 (항상 로딩)
├── api-validation.md        ← paths: src/api/**
├── web-styling.md           ← paths: src/web/**
├── test-rules.md            ← paths: **/*.test.*
└── infra-terraform.md       ← paths: infra/**/*.tf

3단계: Hook 설정 (소요 시간 2~4시간)

PreToolUse hook을 .claude/settings.json에 추가한다. Read scope guard부터 시작하고, 안정화된 후 Grep guard를 추가한다.

4단계: 검증

설정 적용 후 Claude Code 세션을 시작해서 실제 토큰 소비를 확인한다. Claude Code는 세션 종료 시 토큰 사용량 요약을 표시한다. 설정 전후의 수치를 비교하면 효과를 정량적으로 확인할 수 있다.

# Claude Code 세션 시작 후 간단한 작업 수행
claude "packages/api/src/index.ts에서 함수 목록을 보여줘"

# 세션 종료 시 표시되는 토큰 사용량 확인
# 설정 전후 수치를 비교

모노레포 규모별 설정 차이와 claude code 모노레포 토큰 최적화 주의사항

모노레포의 패키지 수에 따라 적용할 설정의 우선순위가 달라진다.

패키지 5개 이하의 소규모 모노레포에서는 CLAUDE.md 분리와 경로 범위 규칙만으로 충분한 경우가 많다. hook까지 설정하면 오히려 유지보수 부담이 늘어난다. 패키지 10~20개 수준의 중규모에서는 claudeMdExcludes와 PreToolUse hook이 효과를 발휘한다. 팀 간 코드 영역이 명확히 분리되어 있을수록 scope guard의 효과가 크다. 패키지 20개 이상의 대규모 모노레포에서는 모든 설정을 적용하되, hook 스크립트의 ALLOWED_PATHS를 팀별 설정 파일로 외부화하는 구조가 필요하다.

모노레포 규모 핵심 설정 추가 권장 설정
소규모 (5개 이하) CLAUDE.md 분리 + paths 규칙 없음
중규모 (10~20개) + claudeMdExcludes + Read hook LSP 규칙
대규모 (20개 이상) + 전체 hook + 외부 설정 팀별 settings.json

주의할 점이 있다. claudeMdExcludes에 너무 많은 경로를 추가하면 크로스 패키지 작업 시 필요한 규칙까지 누락된다. 예를 들어 shared 패키지의 규칙을 제외했는데, api 패키지에서 shared의 유틸 함수를 수정해야 하는 상황이 생기면 관련 규칙 없이 작업하게 된다. 제외 목록은 "절대 건드리지 않는 패키지"에만 적용하는 것이 안전하다.

hook 스크립트가 복잡해질수록 hook 자체의 실행 시간도 고려해야 한다. 매 도구 호출마다 Node.js 프로세스를 띄우는 구조이므로, hook 스크립트는 가볍게 유지한다. 파일 시스템 접근이나 외부 API 호출을 hook에 넣으면 Claude Code의 응답 속도가 눈에 띄게 느려진다.

다음 단계로는 Claude Code의 커스텀 슬래시 커맨드 활용이 있다. 반복되는 모노레포 작업 — 패키지 생성, 의존성 추가, 테스트 실행 — 을 슬래시 커맨드로 정의하면 매번 컨텍스트를 새로 설명할 필요가 없어 토큰이 절약된다. MCP 서버를 통해 패키지 메타데이터를 Claude Code에 직접 제공하는 방식도 claude code 모노레포 토큰 최적화의 다음 단계로 고려할 만하다.

관련 글

이 글 공유하기