# Claw Code 깊이 읽기 #1 — 프로젝트 배경과 아키텍처 개요

조현상·2026년 4월 1일

ClaudeCode

목록 보기
1/17
post-thumbnail

Claude Code가 노출된 그 날, 누군가는 아카이브를 저장했고 누군가는 아키텍처를 읽었다.
이 시리즈는 후자의 결과물인 Claw Code 프로젝트를 코드 레벨에서 분석하는 스터디 기록입니다.
https://github.com/instructkr/claw-code?tab=readme-ov-file


들어가며: 왜 이 프로젝트를 분석하는가

2026년 3월 31일, Claude Code의 TypeScript 소스 코드가 예기치 않게 노출되었다. 이 사건은 AI 개발 도구 생태계에 큰 파장을 일으켰는데, 단순히 "유출"이라는 사건 자체보다 그 소스 코드가 담고 있는 에이전트 하네스(Agent Harness) 아키텍처의 설계 수준이 업계에 충격을 주었기 때문이다.

이 와중에 @instructkr(Sigrid Jin)은 독특한 접근을 택했다. 원본 코드를 그대로 복사하는 대신, 아키텍처 패턴만 학습하여 Python과 Rust로 Clean-room 재구현하는 것이었다. 그 결과물이 바로 Claw Code다.

공개 2시간 만에 GitHub 50,000 스타를 달성했다는 점에서, 이 프로젝트에 대한 커뮤니티의 관심이 어느 정도인지 짐작할 수 있다. 하지만 스타 수보다 중요한 것은 이 프로젝트가 보여주는 설계 결정들이다. 이 시리즈에서는 코드를 직접 들여다보며 그 결정들을 하나씩 해부해본다.


1. Clean-room 재구현이란 무엇인가

Clean-room 재구현(Clean-room reimplementation)은 소프트웨어 역공학에서 법적 리스크를 회피하기 위해 사용하는 고전적인 기법이다. 핵심 원칙은 단순하다:

"원본 코드를 보는 팀"과 "새 코드를 작성하는 팀"을 분리한다.

Claw Code의 경우, 한 사람이 두 역할을 모두 수행했지만 원칙은 동일하다. README.md에 명시된 것처럼:

"We decided NOT to copy the original TypeScript source. Instead, we study the architecture patterns and reimplement from scratch."

이것이 단순한 법적 방어막이 아닌 이유는, Clean-room 방식이 기술적 개선의 기회를 제공하기 때문이다. 원본의 TypeScript 구현을 그대로 옮기는 대신, Rust의 타입 시스템과 소유권 모델을 활용해 더 안전하고 빠른 구현을 추구할 수 있다. 이것이 바로 Claw Code가 택한 전략이다.


2. 저장소 구조: 이중 포팅의 해부학

Claw Code 저장소를 클론하면 가장 먼저 눈에 들어오는 것이 두 개의 병렬적인 코드베이스다.

claw-code/
├── src/              # Python 포팅 워크스페이스 (26개 모듈)
├── rust/             # Rust 프로덕션 런타임 (6개 크레이트, ~20,000 LOC)
├── tests/            # Python 통합 테스트 (26개)
├── assets/           # 스크린샷, 이미지
├── CLAUDE.md         # 개발 규칙
├── PARITY.md         # 기능 격차 추적
└── README.md         # 프로젝트 설명

왜 이중 포팅인가?

이 구조에서 핵심적인 설계 질문은 "왜 두 언어로 포팅하는가?"이다. 답은 각 언어가 서로 다른 역할을 맡기 때문이다.

계층언어역할설계 의도
참조 구현Python (src/)원본 TS 구조의 문서화 + 빠른 프로토타이핑"이해를 위한 코드"
프로덕션 런타임Rust (rust/)고성능 실행 환경"배포를 위한 코드"

Python 코드는 사실상 실행 가능한 문서에 가깝다. src/models.py의 frozen dataclass들이 이를 잘 보여준다:

@dataclass(frozen=True)
class Subsystem:
    """소프트웨어 서브시스템 메타데이터"""
    name: str
    path: str
    file_count: int
    notes: str

@dataclass(frozen=True)
class PortingModule:
    """모듈 포팅 추적"""
    name: str
    responsibility: str
    source_hint: str
    status: str

frozen=True로 불변 객체를 만든 것은 단순한 스타일 선택이 아니다. 이 데이터들은 원본 TypeScript 아키텍처의 스냅샷이므로, 런타임에 변경되어서는 안 된다. Python 코드가 "참조 구현"이라는 역할에 충실한 대목이다.

반면 Rust 쪽은 완전히 다른 관심사를 갖는다. rust/Cargo.toml의 workspace 설정을 보면:

[workspace]
members = ["crates/*"]
resolver = "2"

[workspace.package]
version = "0.1.0"
edition = "2021"
license = "MIT"

[workspace.lints.rust]
unsafe_code = "forbid"        # unsafe 코드 전면 금지

unsafe_code = "forbid" 정책이 눈에 띈다. AI 에이전트 하네스는 사용자의 시스템에서 bash 명령을 실행하고 파일을 수정하는 도구이므로, 메모리 안전성은 선택이 아닌 필수다. 이 한 줄의 설정이 프로젝트의 보안 철학을 압축적으로 보여준다.


3. Rust 크레이트 아키텍처: 6개의 레이어

Rust 워크스페이스는 6개의 크레이트로 구성되어 있으며, 각각이 명확한 책임 경계를 갖는다.

rust/crates/
├── api/              → Anthropic API 클라이언트, SSE 스트리밍, OAuth
├── runtime/          → 대화 루프, 세션 관리, 설정, 권한, MCP
├── tools/            → 18개 내장 도구 (bash, file, search, web 등)
├── commands/         → 22개 슬래시 명령어
├── rusty-claude-cli/ → CLI 진입점, REPL, 터미널 렌더링
└── compat-harness/   → TypeScript 호환성 레이어

이 구조의 의존성 방향을 그려보면 설계 의도가 더 명확해진다:

rusty-claude-cli (최상위 바이너리)
    ├── api ──────────┐
    │   └── runtime ──┤
    ├── tools ────────┤
    │   ├── api       │
    │   └── runtime   │
    ├── commands ─────┤
    │   └── runtime   │
    └── compat-harness│
        ├── commands  │
        ├── tools     │
        └── runtime ──┘

여기서 주목할 점은 runtime 크레이트가 중심축 역할을 한다는 것이다. api, tools, commands 모두가 runtime에 의존한다. 이는 대화 상태(conversation state)가 시스템의 핵심이라는 설계 판단을 반영한다. API 호출도, 도구 실행도, 명령어 처리도 결국 "현재 대화 세션"이라는 컨텍스트 안에서 이루어지기 때문이다.

기본 설정도 의미심장하다:

[workspace.metadata.defaults]
model = "claude-opus-4-6"
permission_level = "danger-full-access"
binary_name = "claw"

permission_level = "danger-full-access"가 기본값이라는 것은, 이 도구가 개발자용 파워 도구로 설계되었음을 의미한다. 일반 사용자 대상이었다면 가장 제한적인 권한이 기본값이었을 것이다.


4. Python 워크스페이스: 실행 가능한 아키텍처 문서

Python 쪽의 src/ 디렉토리는 총 26개의 모듈을 포함하며, 원본 TypeScript의 구조를 거의 1:1로 미러링한다.

main.py: 14개 서브커맨드 CLI

main.py는 argparse 기반의 CLI로, 서브커맨드를 기능별로 분류하고 있다:

# 워크스페이스 분석 계열
subparsers.add_parser('summary')        # 전체 요약
subparsers.add_parser('manifest')       # 워크스페이스 구조
subparsers.add_parser('parity-audit')   # TS 대비 격차 분석

# 그래프 시각화 계열
subparsers.add_parser('command-graph')   # 명령 세분화
subparsers.add_parser('tool-pool')       # 도구 인벤토리
subparsers.add_parser('bootstrap-graph') # 초기화 단계

# 런타임 계열
subparsers.add_parser('route')           # 프롬프트 라우팅
subparsers.add_parser('bootstrap')       # 런타임 부트스트랩
subparsers.add_parser('turn-loop')       # 대화 턴 루프

이 CLI 구조 자체가 원본 Claude Code의 내부 아키텍처를 역으로 드러내는 지도다. command-graph, tool-pool, bootstrap-graph 같은 서브커맨드는 원본에는 없는 것들로, Claw Code가 단순 포팅이 아닌 아키텍처 분석 도구로서의 성격도 갖고 있음을 보여준다.

스냅샷 기반 아키텍처

Claw Code의 Python 코드에서 가장 흥미로운 패턴은 스냅샷 기반 설계다. 명령어와 도구 정보를 동적으로 발견하는 대신, JSON 스냅샷으로 저장해두고 LRU 캐시로 로딩한다:

# commands.py에서의 스냅샷 로딩
@lru_cache(maxsize=1)
def _load_commands():
    with open('commands_snapshot.json') as f:
        return json.load(f)

왜 동적 발견 대신 스냅샷을 택했을까? 두 가지 이유가 있다:

  1. 오프라인 동작: 원본 TypeScript 런타임 없이도 명령/도구 메타데이터에 접근 가능
  2. 버전 일관성: 특정 시점의 원본 상태를 고정함으로써, 포팅 진행도를 정확히 측정

이는 parity_audit.py와 직접 연결된다. 스냅샷에 기록된 "원본 207개 명령, 184개 도구"라는 숫자가 바로 포팅 완성도의 분모가 되기 때문이다.


5. PARITY.md: 기능 격차의 솔직한 기록

PARITY.md는 이 프로젝트에서 가장 중요한 문서 중 하나다. 원본 TypeScript 대비 Rust 구현의 격차를 숨기지 않고 추적한다.

현재 구현 상태 요약

구현 완료된 핵심 영역:

  • Anthropic API 통신 및 OAuth 인증
  • 로컬 대화 및 세션 상태 관리
  • 핵심 에이전틱 도구 호출 루프 (tool-calling loop)
  • MCP(Model Context Protocol) stdio 연결
  • CLAUDE.md 파일 탐색
  • MVP 내장 도구: shell, 파일 연산, 웹 검색, todo, 설정

명시적으로 누락된 영역:

계층원본(TS)Rust 현황격차
HooksPreToolUse/PostToolUse 완전 지원설정 파싱만 가능, 런타임 실행 없음심각
Plugins내장 플러그인, 마켓플레이스, 로더완전 누락심각
Skills동적 레지스트리, 번들 스킬로컬 SKILL.md만 로드중간
Commands/agents, /hooks, /mcp 등 20+/help, /status 등 15개중간
Tools30+ 내장 도구18개 MVP 도구중간

이 표가 보여주는 것은 단순한 미완성이 아니다. 의도적인 우선순위 결정이다. Hook 실행 파이프라인과 플러그인 시스템은 아키텍처적으로 가장 복잡한 부분이며, 기초(API, 세션, 핵심 루프)가 안정된 후에 구현하는 것이 합리적이다.

특히 주목할 점은 MCP 통합이 이미 구현되어 있다는 것이다. MCP(Model Context Protocol)는 AI 에이전트가 외부 도구와 통신하는 표준 프로토콜로, 이것이 동작한다는 것은 Claw Code가 이미 외부 도구 생태계와 연결 가능하다는 의미다.


6. CLAUDE.md: 프로젝트의 개발 헌법

CLAUDE.md는 이름이 암시하듯 Claude(AI)가 이 프로젝트에서 코드를 작성할 때 따라야 할 규칙을 정의한다. 이 파일의 존재 자체가 흥미로운데, AI 보조 개발에서 코드 품질을 유지하기 위한 장치이기 때문이다.

핵심 규칙들:

# 모든 변경 전 반드시 실행
cargo fmt                                    # 포맷팅 통일
cargo clippy --workspace --all-targets -- -D warnings  # 경고를 에러로 승격
cargo test --workspace                      # 전체 테스트

-D warnings 플래그는 Clippy 경고를 에러로 취급한다는 뜻이다. 즉, 경고 하나라도 있으면 빌드가 실패한다. AI가 생성하는 코드에 대해 무관용 품질 기준을 적용하는 셈이다.

추가로 명시된 규칙들:

  1. 작은 변경 선호: 큰 리팩토링보다 리뷰 가능한 단위의 변경을 선호
  2. CLAUDE.md 자동 수정 금지: 이 파일은 의도적으로만 업데이트
  3. src/와 tests/ 동기화: 행위 변경 시 테스트도 함께 업데이트
  4. oh-my-codex(OmX) 워크플로우 활용: $team mode(아키텍처 리뷰)와 $ralph mode(실행 검증) 구분

.claude.json의 설정도 간결하다:

{
  "permissions": {
    "defaultMode": "dontAsk"
  }
}

dontAsk는 AI에게 권한 확인 없이 작업을 진행하라는 의미다. 개발 생산성을 위한 선택이지만, 프로덕션 환경에서는 절대 이렇게 설정하지 않을 것이다. 이 대비가 PARITY.md의 3단계 권한 모델(ReadOnly → WorkspaceWrite → DangerFullAccess)과 연결된다.


7. 아키텍처 전체 조망

지금까지 살펴본 내용을 하나의 다이어그램으로 정리하면:

┌──────────────────────────────────────────────────────┐
│                  Claw Code Project                   │
├────────────────────┬─────────────────────────────────┤
│  Python 포팅 참조    │       Rust 프로덕션 런타임          │
│    (src/)          │         (rust/crates/)          │
├────────────────────┼─────────────────────────────────┤
│ main.py (CLI)      │ rusty-claude-cli (바이너리)       │
│ runtime.py         │ runtime (세션/설정/권한/MCP)       │
│ query_engine.py    │ api (HTTP/SSE/OAuth)            │
│ commands.py        │ tools (18개 내장 도구)             │
│ tools.py           │ commands (22개 슬래시 명령)        │
│ parity_audit.py    │ compat-harness (TS 호환)         │
└────────────────────┴─────────────────────────────────┘

이 구조에서 읽어낼 수 있는 핵심 설계 원칙은 세 가지다:

  1. 관심사의 분리: API 통신, 대화 런타임, 도구 실행, CLI가 각각 독립된 크레이트로 분리
  2. 중심축으로서의 런타임: 모든 것이 runtime을 중심으로 동작
  3. 참조와 실행의 분리: Python은 "무엇을"을, Rust는 "어떻게"를 담당

마치며: 이 프로젝트에서 배울 수 있는 것

Claw Code는 단순한 "Claude Code 클론"이 아니다. 이 프로젝트를 분석하면서 배울 수 있는 것들은 이렇다:

아키텍처 레벨에서는, 대규모 AI 에이전트 시스템이 어떻게 모듈화되는지를 볼 수 있다. API 통신, 세션 관리, 도구 실행, 권한 제어가 어떤 경계를 가지고 분리되어야 하는지에 대한 실전 사례다.

포팅 전략으로서는, "이해를 위한 코드"(Python)와 "배포를 위한 코드"(Rust)를 병행하는 이중 포팅이 큰 시스템을 다른 언어로 옮길 때 효과적인 접근이 될 수 있음을 보여준다.

품질 관리 측면에서는, AI 보조 개발 환경에서 unsafe_code = "forbid", -D warnings, CLAUDE.md 규칙 등을 통해 코드 품질을 체계적으로 관리하는 방법을 제시한다.

다음 편에서는 Rust 워크스페이스의 6개 크레이트를 하나씩 열어보며, 각 크레이트의 설계 결정을 더 깊이 분석해보겠다.


실습 가이드

이 글을 읽으며 직접 해볼 수 있는 것들:

# 1. 저장소 클론
git clone https://github.com/instructkr/claw-code.git
cd claw-code

# 2. 전체 구조 탐색
tree -L 2 -I '__pycache__|node_modules|target'

# 3. PARITY.md 직접 읽기
cat PARITY.md

# 4. Python CLI 실행
python3 -m src.main summary

# 5. Rust 빌드 (Rust 툴체인 필요)
cd rust && cargo build --release

이 글은 [Claw Code 깊이 읽기] 시리즈의 1편입니다. 전체 8편에 걸쳐 프로젝트의 아키텍처를 코드 레벨에서 분석합니다.

시리즈 목차:
1. 프로젝트 배경과 아키텍처 개요 ← 현재 글
2. Rust 워크스페이스 아키텍처 심층 분석
3. API 통신과 SSE 스트리밍 구현
4. 대화 런타임과 세션 관리
5. 도구 시스템과 권한 모델
6. Python 포팅 워크스페이스 분석
7. 테스팅 전략과 패리티 추적
8. TUI 개선 로드맵과 미래 방향

profile
꿈꾸는 개발자

0개의 댓글