# Claude Code 소스코드를 뜯어봤다


더 많은 글은 [radarlog.kr](https://radarlog.kr)에서.

---

Claude Code의 소스코드가 유출됐다. TypeScript 파일 1,884개, 총 31MB.

누군가 이미 Mintlify로 깔끔한 문서 사이트를 만들어서 공개했는데, 거기에 정리된 환경변수는 30개다. 소스코드에는 **195개** 있다. 문서화된 슬래시 커맨드는 20개 남짓이다. 소스코드에는 **80개 이상** 있다.

문서에 없는 나머지는 뭘까. 직접 뜯어봤다.


## 소스코드의 전체 구조

압축을 풀면 `src/` 하나에 모든 게 들어 있다. 게임 프로젝트처럼 폴더 구조가 역할별로 깔끔하게 나뉘어 있다.

```
src/
├── tools/          (2.8MB) — 40개의 도구 정의
├── components/     (9.5MB) — Ink 기반 터미널 UI
├── commands/       (2.8MB) — 80+ 슬래시 커맨드
├── services/       (1.9MB) — API, MCP, 분석, 컴팩트
├── hooks/          (1.3MB) — React 훅 (터미널 UI용)
├── utils/          (6.7MB) — 유틸리티 모음
├── constants/      (122KB) — 시스템 프롬프트, 상수
├── coordinator/    (23KB)  — 코디네이터 모드
├── buddy/          (79KB)  — 가상 펫 시스템 (!?)
└── voice/          (6.5KB) — 음성 모드
```

UE5 프로젝트의 `Source/` 폴더를 보는 것 같다. 모듈 간 의존성이 깔끔하고, 각 도구가 독립적으로 분리되어 있다. `tools/` 안에 40개 디렉토리가 각각 하나의 도구를 담당한다. 언리얼의 모듈 시스템이랑 느낌이 비슷하다.

런타임은 **Bun**이다. Node가 아니다. `feature()` 함수로 빌드 타임에 기능을 켜고 끄는 구조가 있는데, 이게 UE5의 `WITH_EDITOR` 같은 컴파일 플래그랑 정확히 같은 패턴이다.

```typescript
const buddy = feature('BUDDY')
  ? require('./commands/buddy/index.js').default
  : null
```

`feature('BUDDY')`가 빌드 타임에 `false`로 평가되면 해당 코드가 번들에서 통째로 빠진다. Dead code elimination. UE5에서 `#if WITH_EDITOR`로 에디터 전용 코드를 빼는 것과 같다.


## 문서에 없는 슬래시 커맨드들

공식 문서에 나오는 커맨드는 `/help`, `/compact`, `/config`, `/mcp` 정도다. 소스코드에서 발견한 커맨드는 훨씬 많다. 그중 실제로 쓸 수 있는 것들을 추려봤다.

**`/btw` — 사이드 질문**. 메인 대화를 끊지 않고 빠른 질문을 던진다. `immediate: true`로 설정되어 있어서 대화 맥락을 오염시키지 않는다. 작업 중에 "btw 이 함수 뭐하는 거야?" 같은 질문을 던지기에 딱이다.

```typescript
const btw = {
  type: 'local-jsx',
  name: 'btw',
  description: 'Ask a quick side question without interrupting the main conversation',
  immediate: true,
  argumentHint: '<question>',
}
```

**`/rewind` — 코드 되돌리기**. 대화와 코드를 이전 시점으로 되돌린다. alias가 `/checkpoint`다. Git의 특정 시점으로 돌아가는 게 아니라, Claude Code가 자체적으로 관리하는 체크포인트 시스템이다. 잘못된 방향으로 갈 때 "처음부터 다시"가 아니라 "여기서부터 다시"가 가능하다.

**`/compact` — 컨텍스트 요약**. 이건 문서에 나오지만, 인자를 받는다는 건 안 나온다. `/compact 코드 변경사항 위주로 요약해줘`처럼 요약 방향을 지정할 수 있다. 소스코드를 보면 `customInstructions`로 사용자 인자를 그대로 요약 프롬프트에 넘긴다.

**`/review` — PR 코드 리뷰**. `gh` CLI를 써서 PR diff를 가져온 다음 코드 리뷰를 해준다. PR 번호 없이 치면 열린 PR 목록을 보여준다.

```typescript
const LOCAL_REVIEW_PROMPT = (args: string) => `
  You are an expert code reviewer. Follow these steps:
  1. If no PR number is provided, run \`gh pr list\`
  2. If provided, run \`gh pr view <number>\`
  3. Run \`gh pr diff <number>\` to get the diff
  4. Analyze the changes...
`
```

**`/advisor` — 보조 모델 설정**. 메인 모델 외에 "어드바이저" 모델을 따로 붙일 수 있다. `/advisor opus`로 설정하면 메인 모델이 작업할 때 Opus가 조언을 한다. 해제는 `/advisor unset`.

**`/stickers` — 스티커 주문**. 진짜로 Claude Code 스티커를 주문하는 페이지(`stickermule.com/claudecode`)를 브라우저에서 연다. 이스터에그인데, 소스코드에 떡하니 있다.

**`/sandbox` — 샌드박스 토글**. Bash 명령을 격리된 환경에서 실행하는 샌드박스 모드를 제어한다. macOS에서 사용 가능하고, 자동 허용 모드와 결합하면 안전하게 "다 허용"을 할 수 있다.

**`/fast` — 빠른 모드**. 더 빠른 모델로 전환한다. Claude AI 구독자와 API 사용자만 쓸 수 있고, `isFastModeEnabled()`로 게이트된다.

**`/effort` — 노력 수준 조절**. `low`, `medium`, `high`, `max`, `auto` 5단계. 간단한 질문에는 low, 복잡한 리팩토링에는 max. API 비용을 직접 제어할 수 있다.

**`/stats` — 사용 통계**. Claude Code 사용 패턴과 활동 통계를 보여준다.

**`/passes` — 친구 초대**. 무료 1주일 이용권을 친구에게 공유하고, 자신은 추가 사용량을 받는 레퍼럴 시스템이다. `checkCachedPassesEligibility()`로 자격을 확인한다.

**`/mobile` — 모바일 앱 QR**. alias가 `/ios`, `/android`다. QR 코드를 터미널에 표시해서 모바일 앱 다운로드를 안내한다.

**`/chrome` — 크롬 확장 설정**. Claude in Chrome 베타 기능을 설정한다. Claude AI 구독자만 사용 가능.


## 195개 환경변수 — 숨겨진 설정 표면

Mintlify 분석에서 문서화한 환경변수는 약 30개다. 소스코드에서 `grep`으로 찾은 `CLAUDE_CODE_` 접두어 환경변수는 **195개**다.

전부 나열하진 않겠지만, 실전에서 유용한 것들이 있다.

**`CLAUDE_CODE_AUTO_COMPACT_WINDOW`** — 자동 컴팩트가 트리거되는 컨텍스트 윈도우 비율을 조절한다. 기본값보다 일찍 또는 늦게 컴팩트가 돌도록 할 수 있다.

**`CLAUDE_CODE_DISABLE_MOUSE`** — 마우스 입력을 완전히 끈다. tmux 안에서 Claude Code를 쓸 때 마우스 이벤트가 충돌하는 경우에 유용하다.

**`CLAUDE_CODE_SCROLL_SPEED`** — 스크롤 속도 조절. 터미널 환경에 따라 스크롤이 너무 빠르거나 느릴 때.

**`CLAUDE_CODE_TMUX_PREFIX`** — tmux 프리픽스 키 충돌을 해결한다. tmux 안에서 Claude Code의 키바인딩이 먹히지 않을 때 이걸로 조정한다.

**`CLAUDE_CODE_DISABLE_FILE_CHECKPOINTING`** — 파일 체크포인팅을 끈다. `/rewind`에 쓰이는 체크포인트 시스템인데, 디스크 I/O가 부담될 때 끌 수 있다.

**`CLAUDE_CODE_COORDINATOR_MODE`** — 코디네이터 모드를 활성화한다. Claude가 직접 코드를 안 쓰고, 워커 에이전트를 지휘하는 오케스트레이터 역할만 한다. 이건 2편에서 자세히 다룬다.

**`CLAUDE_CODE_STREAMLINED_OUTPUT`** — 출력을 간소화한다. 도구 호출 과정 같은 중간 과정을 숨기고 결과만 보여준다.

**`CLAUDE_CODE_SYNTAX_HIGHLIGHT`** — 구문 강조를 제어한다. 터미널에서 색상이 깨질 때 끄면 된다.

**`CLAUDE_CODE_DISABLE_CRON`** — 크론 스케줄링을 끈다. Claude Code에 크론이 있다는 것 자체가 놀라운데, 이건 3편에서 다룬다.

```bash
# 실전 조합 예시 — tmux 안에서 가볍게 쓰기
export CLAUDE_CODE_DISABLE_MOUSE=1
export CLAUDE_CODE_STREAMLINED_OUTPUT=1
export DISABLE_AUTO_COMPACT=1
```

환경변수 중에는 `CLAUDE_CODE_UNDERCOVER`처럼 Anthropic 내부용으로 보이는 것도 있다. 이건 3편에서 다룬다.


## 키바인딩 — 커스터마이징이 된다

Claude Code의 키바인딩이 전부 커스터마이징 가능하다는 건 거의 알려지지 않았다. 소스코드에 `defaultBindings.ts`가 있고, 사용자 오버라이드를 `keybindings.json`에서 읽는다.

기본 키바인딩 중 쓸만한 것들이 많다.

```typescript
// 글로벌
'ctrl+t': 'app:toggleTodos',     // 투두 리스트 토글
'ctrl+o': 'app:toggleTranscript', // 대화 전문 보기
'ctrl+r': 'history:search',       // 히스토리 검색

// 채팅
'shift+tab': 'chat:cycleMode',    // 모드 전환 (plan/code)
'meta+p': 'chat:modelPicker',     // 모델 선택
'meta+o': 'chat:fastMode',        // 빠른 모드 토글
'meta+t': 'chat:thinkingToggle',  // 사고 과정 표시 토글
'ctrl+s': 'chat:stash',           // 입력 스태시
'ctrl+g': 'chat:externalEditor',  // 외부 에디터로 열기

// 작업 중
'ctrl+b': 'task:background',      // 작업을 백그라운드로
```

`ctrl+b`로 현재 실행 중인 작업을 백그라운드로 보낼 수 있다. 에이전트가 긴 작업을 하고 있을 때, 끝날 때까지 기다리지 않고 다른 입력을 할 수 있다는 뜻이다. tmux에서는 `ctrl+b`를 두 번 눌러야 한다(tmux prefix와 겹치므로).

`ctrl+s`는 스태시다. git stash처럼, 지금 입력 중인 내용을 임시 저장하고 나중에 꺼낼 수 있다.

`shift+up`을 치면 메시지 액션 모드로 들어간다. 이전 메시지를 선택해서 복사하거나 다시 보낼 수 있다.

Windows에서는 VT 모드 지원 여부에 따라 `shift+tab` 대신 `meta+m`이 기본으로 바뀐다. 소스코드에서 Bun과 Node의 버전별 VT 모드 지원을 직접 체크하고 있다.

```typescript
const SUPPORTS_TERMINAL_VT_MODE =
  getPlatform() !== 'windows' ||
  (isRunningWithBun()
    ? satisfies(process.versions.bun, '>=1.2.23')
    : satisfies(process.versions.node, '>=22.17.0 <23.0.0 || >=24.2.0'))
```

이런 수준의 플랫폼별 호환성 처리는 UE5에서 iOS/Android 크로스플랫폼 입력 처리할 때 보던 패턴과 똑같다.


## macOS에서 잠들지 않는 이유

Claude Code가 작업 중일 때 맥이 잠들지 않는다. 운이 좋아서가 아니다. 소스코드에 **`caffeinate`**를 직접 호출하는 코드가 있다.

```typescript
const CAFFEINATE_TIMEOUT_SECONDS = 300 // 5분
const RESTART_INTERVAL_MS = 4 * 60 * 1000 // 4분마다 재시작

// refCount 기반 — 작업이 0개가 되면 caffeinate를 끈다
export function startPreventSleep(): void {
  refCount++
  if (refCount === 1) {
    spawnCaffeinate()
  }
}
```

레퍼런스 카운팅 방식이다. 작업이 시작되면 카운트가 올라가고, 끝나면 내려간다. 카운트가 0이 되면 caffeinate 프로세스를 죽인다. 5분 타임아웃을 걸고 4분마다 재시작하는 이유는, Node 프로세스가 SIGKILL로 죽으면 cleanup 핸들러가 안 돌기 때문이다. orphan caffeinate가 5분 뒤 자동으로 죽는다.

게임 서버에서 keepalive 체크하는 것과 같은 패턴이다. 부모가 죽어도 자식이 무한히 살아남지 않도록, 자체 타임아웃을 건다.


## 다음 편 — 시스템 프롬프트와 코디네이터 모드

1편에서는 표면에 드러나는 숨겨진 기능들을 다뤘다. 2편에서는 더 깊이 들어간다. Claude Code의 시스템 프롬프트가 어떻게 조립되는지, 프롬프트 캐시를 깨지 않기 위해 어떤 구조를 쓰는지, 코디네이터 모드에서 워커 에이전트를 어떻게 지휘하는지. "AI가 AI를 관리하는" 아키텍처의 내부 구조다.

> "Mintlify 문서에는 환경변수가 30개다. 소스코드에는 195개 있다."

