파일 동기화에 665,000 토큰이 들지 않도록 Claude의 비공개 Design API를 역공학했습니다
요약
Claude Design의 비공개 API를 역공학하여 대규모 파일 동기화 시 발생하는 막대한 토큰 비용 문제를 해결한 과정을 다룹니다. 모델의 컨텍스트를 거치지 않고 파일 바이트를 직접 동기화하는 CLI 도구 개발 경험과 API 분석 시 주의점을 공유합니다.
핵심 포인트
- Claude Design 파일 동기화 시 발생하는 665k 토큰 비용 문제 해결
- 비공개 API 역공학을 통한 효율적인 파일 동기화 CLI 구현
- 모크(Mock) 테스트 시 실제 API 동작과 가정 간의 불일치 위험 경고
- API 분석 시 반환 타입, HTTP 상태 코드, 이진 파일 감지 방식의 중요성
프로토콜 고고학(protocol archaeology), 세 번의 잘못된 추측, 그리고 자신의 모크(mock)를 신뢰하기를 거부한 것에 관한 빌드 로그.
시작점이 된 토큰 비용
Claude Design (claude.ai/design)은 디자인 시스템을 보관하기에 좋은 곳이지만, 파일들은 서버의 _그곳_에 존재합니다. 이 파일들을 디스크로 가져오는 명백한 방법은 에이전트에게 "이 프로젝트의 모든 파일을 읽어서 로컬에 작성해줘"라고 요청하는 것입니다. 이 방법은 작동합니다. 제가 측정한 한 대규모 프로젝트의 경우, 이 작업에는 약 665,000 토큰이 소요되었습니다. 모든 파일의 모든 바이트가 출력되는 과정에서 모델의 컨텍스트(context)를 통과해야 하기 때문입니다.
그 수치는 터무니없습니다. A에서 B로 바이트를 이동하는 것은 추론(reasoning) 작업이 아닙니다. 모델이 매우 비싼 cp 명령어로 사용되고 있는 것입니다.
그래서 저는 git이 저장소(repo)를 동기화하는 방식처럼 — clone, pull, push, status, diff — 파일 바이트가 모델의 컨텍스트에 전혀 닿지 않으면서 Claude Design 프로젝트를 로컬 디렉토리와 동기화하는 단순한 CLI를 원했습니다. 665k 토큰이 들었던 동일한 pull 작업이 다음과 같이 한 줄의 요약으로 끝나야 합니다:
pulled 103, unchanged 0, binary 6 (660.1 KB)
한 가지 문제가 있었습니다. Claude Design이 통신하는 엔드포인트(endpoint)가 문서화되어 있지 않다는 점입니다.
프로토콜 고고학 (Protocol archaeology)
공개된 명세(spec)가 없습니다. 엔드포인트는 MCP 서버이므로 전송의 _형태(shape)_는 알려져 있지만(JSON-RPC, 도구 호출(tool calls)), 어떤 도구가 존재하는지, 어떤 인자(arguments)를 받는지, 무엇을 반환하는지는 모두 기록되어 있지 않습니다. 이를 알아내는 유일한 방법은 호출해 보고 돌아오는 값을 기록하는 것입니다.
괜찮습니다. 고고학은 API를 배우는 정당한 방법입니다. 함정은 배운 것을 가지고 무엇을 하느냐에 있습니다. 엔드포인트를 몇 번 호출하여 동작 방식에 대한 믿음을 형성하고, 그 믿음을 모크(mock)로 인코딩한 다음, 자신의 코드를 그 모크로 테스트하는 것은 매우 쉽습니다. 모든 테스트가 통과(green)됩니다. 제품을 출시합니다. 그리고 당신은 자신의 코드가 스스로의 가정과 일치하는지 외에는 아무것도 테스트하지 않은 셈이 됩니다.
제가 이를 아는 이유는 측정하기 전에 프로토콜에 관한 세 가지 사실을 틀렸고, 통과된 모크(green mock)였다면 그 모든 것을 숨겼을 것이기 때문입니다.
-
write_files는 리스트가 아닌 맵(map)을 반환합니다. 저는 파일당 하나의 결과가 담긴 리스트를 반환할 것이라고 가정했습니다. 하지만 이 결과는 경로(path)를 키(key)로 사용합니다. 리스트를 반환하는 모크(mock)였다면 제 테스트를 통과했겠지만, 실제 서버의 데이터를 잘못 파싱했을 것입니다. -
"이 프로젝트에 대한 액세스 권한이 없습니다" 케이스는 툴 레벨의 에러가 아니라 HTTP 403 에러입니다. 저는 이를 일반적인
200응답 내부의 에러 객체로 모델링했습니다. 하지만 이는 상태 코드(status code)이며, 완전히 다른 코드 경로(code path)를 따릅니다. -
이진 파일(Binary) 감지는 파일 확장명이 아닌 콘텐츠를 기준으로 합니다. 저는 서버가 파일명을 기준으로 판단할 것이라고 가정했습니다. 하지만 서버는 바이트(bytes)를 읽습니다. NUL 문자로 가득 찬
.txt파일은 서버 입장에서 이진 파일이며, 확장자가 없는 스크립트는 텍스트입니다.
이 중 어느 것도 생소한 것은 아닙니다. 80% 정도 확신하지만 틀리기 쉬운 종류의 것들입니다. 그래서 규칙이 생겼습니다: 모크(mock)는 저의 처리 로직을 테스트하고, 프로토콜에 관한 사실은 실제 서버를 통해 검증한다.
구체적으로, 이 저장소(repo)에는 PROTOCOL.md 파일이 있으며, 여기에 문서화된 모든 주장에는 실제 엔드포인트에 접속하는 상응하는 라이브 테스트(go test -tags=live)가 존재합니다. 만약 Anthropic이 서버를 변경하여 어떤 주장이 더 이상 사실이 아니게 되면, 해당 테스트는 실패(red)로 표시됩니다. 툴이 사용자 파일에 대해 조용히 잘못된 동작을 수행하는 대신 말입니다. 모크는 여전히 존재하지만, 오직 저의 로직만을 테스트할 뿐 세상에 대한 사실을 테스트하지는 않습니다.
토큰보다 더 두려웠던 부분
모델을 통해 바이트(bytes)의 흐름이 멈추면, 툴은 그저 서버와 통신하는 동기화 엔진(sync engine)일 뿐이며, 동기화 엔진은 데이터를 유실할 수 있습니다. 이것이 토큰 비용 다음으로 제가 집착하게 된 두 번째 요소가 되었습니다. 몇 가지 결정 사항은 다음과 같습니다:
-
모든 파일은 임시 파일로 작성된 후 이름이 변경됩니다 (temp-then-rename). 프로세스가 강제 종료되어도 절반만 작성된 파일이 남지 않습니다. 이는 생각보다 훨씬 중요합니다. 내용이 잘린 파일이 도구의 장부(ledger)에 기록되지 않은 채 남아있다면, 다음 실행 시 마치 사용자가 직접 편집한 것처럼 보여 도구가 "친절하게도" 작업물을 덮어쓰겠다고 제안할 수 있기 때문입니다. 원자적 쓰기 (Atomic writes) 방식은 이러한 부류의 버그를 완전히 차단합니다.
-
충돌 (Conflicts)은 타임스탬프(timestamps)나 etag가 아닌 바이트(bytes) 단위로 결정됩니다. 양쪽 모두 변경되었다면, 그것은 충돌입니다. etag 비교 방식으로는 양쪽 모두가 변경된 케이스를 물리적으로 감지할 수 없습니다.
-
--prune은 우리가 소유하고 있으며 수정되지 않았음을 증명할 수 있는 것만 삭제합니다. 추적되지 않는 파일(Untracked file) → 우리 것이 아니므로 그대로 둡니다. 로컬에서 편집된 파일(Locally edited) → 충돌이므로 건드리지 않습니다. 증거는 디스크 상의 장부(on-disk ledger)이며, 이 프로젝트 도중 해당 증명을 더 "스마트하게" 만들려던 시도가 두 번 있었으나, 그 결과 prune 루프가 삭제해서는 안 될 것을 삭제하는 법을 배웠습니다. 두 경우 모두 테스트를 통해 발견되었으며, 타인의 파일을 삭제하는 버그는 다음 사람이 똑같은 실수를 반복하지 않도록 한 단락 정도의 설명 가치가 있기에 리포지토리(repo)에 기록해 두었습니다. -
자격 증명(Credential)은 읽기만 하며, 절대 쓰거나 출력하지 않습니다. 이 도구는 Claude Code의 기존 OAuth 토큰을 읽어오므로 별도의 로그인이 필요 없습니다. 심지어 해당 토큰을 에러 문자열에 포함시키지도 않습니다. (토큰을 갱신하면 Claude Code의 리프레시 토큰(refresh token)이 무효화되므로 갱신하지 않습니다. 토큰이 만료되면 보고되며, 해결 방법은 아무
claude명령어나 실행하는 것입니다.)
stdlib 전용
전체 시스템은 서드파티 의존성(third-party dependencies)이 전혀 없는 단일 Go 바이너리이며, go.mod에는 아무것도 명시되어 있지 않습니다. 그 이유는 감사 가능성 (auditability) 때문입니다. 문서화되지 않은 서버로부터 신뢰할 수 없는 바이트를 파싱하고 사용자의 자격 증명을 다루는 모든 것은 Go 표준 라이브러리 (Go standard library)와 이 프로그램 하나뿐입니다. staticcheck, govulncheck 및 릴리스 도구는 의존성 그래프에 진입하지 않고 CI에서 실행됩니다. 사용자의 OAuth 토큰을 가지고 비공식 엔드포인트(unofficial endpoint)를 향해 도구를 실행하려 한다면, "모든 것을 읽을 수 있다"는 점은 매우 큰 가치를 지닙니다.
솔직한 주의 사항
해당 엔드포인트는 문서화되지 않았으며 비공식적입니다. 서버 배포로 인해 작동이 중단될 수 있습니다. 이 위험을 완전히 없앨 수는 없지만, 위험을 숨기기보다는 가시화(visible) 하려고 노력했습니다. 실시간 테스트가 일종의 탐지선(tripwire) 역할을 하며, 서버가 인식할 수 없는 형태의 응답을 보낼 경우 도구는 추측하는 대신 실행을 거부하고 이를 보고합니다.
이 도구의 이름은 dsx이며, macOS 및 Linux를 지원하는 단일 바이너리 형태의 MIT 라이선스 소프트웨어입니다. 만약 Claude Design을 사용하면서 토큰 비용을 체감했거나, 혹은 단순히 프로토콜 고고학 (protocol-archaeology) 기록물을 좋아하신다면, 코드와 PROTOCOL.md 파일은 이곳에서 확인하실 수 있습니다:
https://github.com/somework/dsx
프로토콜이나 데이터 손실(data-loss) 논리에 관한 질문이 있다면 기꺼이 답변해 드리겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기