RepoPrompt + CLI repoprompt-mcp)
LLM에게 "이 버그 고쳐줘"라고 시킬 때, 우리는 보통 파일을 통째로 복사해 붙여넣는다. 그런데 레포가 수천 개 파일이면? 전부 넣을 수도 없고, 넣어도 토큰 낭비 + 엉뚱한 파일에 정신 팔린 답변이 돌아온다. RepoPrompt CE는 바로 이 문제를 정면으로 다룬다. 핵심은 딱 하나 — "에이전트가 행동하기 전에, 코드베이스를 제대로 이해하게 만든다(helps coding agents understand your codebase before they act)".
변호사(=AI 에이전트)에게 창고에 쌓인 서류 10만 장(=전체 레포)을 전부 던지면 사건을 못 본다. 유능한 보조는 이 사건에 관련된 문서 20장을 골라, 각 문서의 요지를 한 줄로 요약하고, 최근 수정 이력을 붙여 얇은 폴더로 만들어 준다.
RepoPrompt CE가 하는 일이 정확히 이것이다. 재료는 ① 파일 원문 ② CodeMap(함수·타입 시그니처만 뽑은 목차) ③ 프로젝트 구조도 ④ Git diff. 이걸 토큰 예산 안에서 골라 담아, 사람이 한 번 검토(reviewable)한 뒤 에이전트에게 넘긴다.
그런데 여기서 한 발 더 나간다. RepoPrompt CE는 단순히 "프롬프트 만드는 도구"가 아니라, 자기 안에 MCP 서버를 켜 두고 Claude Code · Codex · Gemini · Cursor · OpenCode 같은 외부 CLI 에이전트를 이 앱에 연결시켜, 앱이 제공하는 컨텍스트·검색·편집 도구를 쓰게 하고, 그 에이전트들의 작업을 한 화면에서 지휘(orchestrate)한다. 즉 "컨텍스트 큐레이션 도구"이자 동시에 "여러 코딩 에이전트를 감싸는 오케스트레이터"다.
이 레포가 TrendShift에 뜬 이유는 별(star) 수(≈100개)가 아니라 소셜 멘션 모멘텀 — 개발자 커뮤니티에서 "그 RepoPrompt가 오픈소스로 풀렸다"가 화제가 됐기 때문이다. 배경을 셋으로 나눠 보자.
RepoPrompt(repoprompt.com)은 "코딩 에이전트 시대에 컨텍스트를 손으로 정교하게 짠다"는 흐름을 만든 인기 앱이다. 그 커뮤니티 에디션(CE)을 Apache-2.0으로 공개하면서, 유료로만 보던 내부 설계 — MCP 서버 구조, CodeMap 생성기, 멀티 에이전트 오케스트레이션 — 를 누구나 소스로 뜯어볼 수 있게 됐다. 실전에서 팔리던 대형 Swift 앱의 아키텍처를 통째로 공부할 수 있다는 점이 크다.
수동 복붙: 빠르지만 파일이 많으면 불가능하고 토큰이 폭발한다.
Cursor · Windsurf(IDE 내장): 편집기 안에서 자동으로 컨텍스트를 넣어주지만, "무엇이 들어갔는지" 사람이 검토·조정하기 어렵다.
aider(CLI): 강력하지만 터미널 중심이라 컨텍스트를 눈으로 큐레이션하기 불편하다.
RepoPrompt CE: "무엇을 넣을지 사람이 시각적으로 고르고 → 검토하고 → 여러 에이전트에게 넘기는" 그 중간 계층에 특화. 편집기도, 에이전트도 대체하지 않고 그 사이를 채운다.
가장 기술적으로 흥미로운 지점. RepoPrompt CE는 특정 AI에 종속되지 않는다. Claude 계열(Claude Code · GLM/Zai · Kimi)은 전용 플러그인 패키지로, Codex · Gemini · Cursor · OpenCode는 ACP(Agent Client Protocol) 경유로 붙인다. 앱 코어는 "에이전트가 무엇이든 상관없는(provider-neutral)" 계약만 알고, 각 provider의 세부는 갈아 끼울 수 있는 구조다. 이는 "AI 도구 위에 얇게 얹혀 금방 죽는 래퍼"가 아니라 여러 에이전트를 오래 감쌀 수 있게 설계된 하니스(harness)라는 뜻 — 오픈소스 기여자 입장에서 배울 게 많은 이유다.
RepoPrompt CE는 순수 SwiftPM 프로젝트다. Xcode 프로젝트 파일이 없고(.xcodeproj 없음), Package.swift 하나가 전부를 정의한다. Xcode 워크스페이스는 필요할 때 스크립트로 일회용 생성했다 버린다. 산출물은 2개의 실행 파일이다.
// Package.swift — 두 개의 실행 파일(products) products: [ .executable(name: "RepoPrompt", targets: ["RepoPrompt"]), // ① GUI 앱 (SwiftUI/AppKit) .executable(name: "repoprompt-mcp", targets: ["RepoPromptMCP"]) // ② CLI = MCP 소켓 프록시 ] platforms: [.macOS(.v14)] // 코드상 최소 macOS 14, 배포는 macOS 26+ 권장 swift-tools-version: 6.2 · swiftLanguageModes: [.v5]
| 영역 | 라이브러리 | 역할 |
|---|---|---|
| MCP | provencher/swift-sdk (포크) | MCP 서버·도구 정의. 앱이 외부 에이전트에게 도구를 노출하는 핵심 SDK |
| AI 클라이언트 | SwiftAnthropic · SwiftOpenAI(포크) | Claude·OpenAI 호환 API 호출 |
| 스키마 | JSONSchema · ontology (loopwork-ai) | 도구 입출력 스키마 검증·구조화 |
| 코드 파싱 | SwiftTreeSitter + 문법 13종 | c·cpp·c-sharp·dart·go·java·js·ts·php·python·ruby·rust·swift 파싱 → CodeMap 생성 |
| 구문 하이라이팅 | Neon · Rearrange (ChimeHQ) | 에디터 뷰의 실시간 하이라이팅 |
| 네트워킹 | SwiftNIO 스택 · async-http-client · swift-crypto/certificates · eventsource | HTTP/2·TLS·SSE 스트리밍(에이전트 응답 실시간 수신) |
| 수명주기 | swift-service-lifecycle · swift-log · swift-system | 서버 프로세스 부팅·종료·로깅 |
SwiftUI + AppKit 혼합. 마크다운 렌더링은 swift-markdown-ui, 단축키는 KeyboardShortcuts, 자동 업데이트는 Sparkle(바이너리 프레임워크 Sparkle.xcframework를 .binaryTarget으로 포함). 웹뷰 기반 앱이 아니라 완전한 네이티브 데스크톱 앱이다.
C 코드가 무려 16%다. 대부분은 벤더링된 PCRE2 정규식 엔진(Sources/CSwiftPCRE2, 약 3.6MB, sljit JIT 포함) — RepoPrompt의 파일 검색·스캐닝을 떠받치는 정규식 엔진이다. 그 외에 자체 작성한 고성능 C(Sources/RepoPromptC: 경로 검색 인덱스 path_search.c, 검색 점수화 search_scoring.c, gitignore식 와일드카드 매칭 wildmatch.c)가 있고, Swift에서는 bridging header로 이 C 함수들을 호출한다. 문자셋 감지는 uchardet(C)을 Cuchardet 패키지로 감쌌다.
| 도구 | 정체 | 역할 |
|---|---|---|
| SwiftPM | Swift Package Manager | Xcode 없이 의존성·빌드 전부 관리(핵심 결정) |
| Makefile | 2계층 진입점 | make build/run/test(직접) vs make dev-*(데몬 경유) |
| conductor | Python 데몬 (3,844줄) | 레인 직렬화 잡 큐 — 여러 에이전트가 동시에 빌드/실행해도 충돌 방지 (§4에서 상술) |
| Scripts/ | 70+ 스크립트 | package_app.sh·doctor.sh·guardrails·release.sh·xcode 생성 등 |
| SwiftFormat·SwiftLint | 스타일 강제 | make lint = format 검사 + swiftlint --strict |
| RepoPromptAgentProviders | 로컬 SwiftPM 패키지 | provider별 코드를 앱 코어와 분리해 담는 "탈부착" 패키지 |
전체 그림을 먼저 보자. 핵심은 "GUI 앱이 MCP 서버를 품고 있고, 얇은 CLI가 그 앞의 소켓 프록시 역할"이라는 이중 프로세스 구조다.
외부 에이전트는 얇은 repoprompt-mcp 바이너리에 붙고, 실제 도구 로직은 GUI 앱 안에 있다. CLI의 main.swift에는 "TCP/Bonjour transport has been removed. CLI now uses bootstrap socket only"라고 적혀 있다. 즉 네트워크 포트를 열지 않고 로컬 소켓만 쓴다(보안·단순성). CLI와 앱은 bootstrapProtocolVersion이 서로 맞아야 통신한다.
식당으로 치면 CLI = 홀의 주문 단말기, GUI 앱 = 주방이다. 손님(외부 에이전트)은 단말기에 주문만 넣고, 요리(파일 읽기·코드 구조 분석·편집)는 전부 주방에서 일어난다. 단말기를 아무리 여러 개 놔도 주방은 하나 — 상태(열린 워크스페이스·권한)가 한 곳에 모여 일관성이 유지된다.
가장 배울 만한 부분. "새로운 에이전트를 어떻게 깔끔하게 추가하는가?"를 위한 구조다. 핵심 원칙은 동적 로딩이 아니라 정적 SwiftPM 컴포지션 + DTO 경계.
// 앱 코어는 "provider가 무엇이든 상관없는" 계약만 안다 protocol NativeAgentRuntimeControlling { ... } // provider-중립 런타임 계약 // Claude 계열 구현은 별도 패키지(Foundation-only)에 격리 Packages/RepoPromptAgentProviders └─ RepoPromptClaudeCompatibleProvider // Claude Code·GLM/Zai·Kimi ├ ClaudeSDKProtocolCodec.swift // 프로토콜 코덱 ├ ClaudeSDKNDJSONTranslator.swift // 스트림 변환 └ ClaudeProviderJSONValue.swift // Sendable JSON 값 타입 // 코어 ↔ 패키지 사이엔 딱 2개의 '브릿지' 파일만 존재 ClaudeCompatibleProviderRuntimeBridge // 유일하게 패키지를 import ClaudeCompatiblePluginBridge // Agent Mode 쪽 facade
이 패키지는 앱 코드를 절대 import하지 않고 UserDefaults·Keychain도 모른다. API 키 같은 시크릿은 코어에서 읽어 정제(sanitize)한 DTO로만 패키지에 건넨다. 덕분에 provider 로직을 나중에 별도 저장소로 떼어내기 쉽다. Codex·Gemini·Cursor·OpenCode는 아직 이 심을 안 거치고 ACP(Agent Client Protocol) 어댑터로 붙는다.
CodeMap을 매번 다시 계산하면 느리다. 그래서 (파일 내용 + 문법 버전)을 SHA-256으로 해싱한 키로 결과를 저장한다. 매직 바이트를 가진 컨테이너 포맷, 상주 캐시 한도(soft/hard 쿼터), GC 예산, 격리(quarantine), orphan 정리까지 갖춘 본격 캐시다(CodeMapArtifactFileStore.swift). 파일이 안 바뀌면 캐시 히트 → 즉시 반환.
여러 AI 에이전트가 동시에 "빌드해줘 / 앱 켜줘 / 테스트해줘"를 날리면 .build 폴더나 실행 중인 앱이 서로 꼬인다. conductor(Python 데몬)는 작업을 레인(lane)으로 나눠 같은 레인은 한 번에 하나씩, 다른 레인은 병렬로 돌린다.
# 레인 5종 — 같은 레인끼리만 순서 대기 lanes = { build, debugArtifact, liveApp, release, style } # 티켓 기반 비동기 잡: 긴 빌드를 떼어놓고 나중에 조회 ./conductor build --async --request-key K # idempotent(같은 키=중복 실행 안 함) ./conductor job status / wait / list / cancel
AgentMode(에이전트 실행/지휘, 하위에 Runtime/Providers) · Chat · CodeMap · ContextBuilder(토큰 예산 큐레이션) · Diagnostics · Prompt · Search · Settings · WorkspaceFiles · Workspaces(멀티 루트 워크스페이스).
AI(+ Prompts/Workflows 프롬프트 템플릿) · MCP(앱 쪽 MCP 인프라, 매우 큼) · FileSystem · Diffing · SyntaxParsing · Regex · VCS(Git) · Networking · Persistence · Process · Security · Concurrency · WorkspaceContext · UI · Utilities.
docs/architecture/source-layout.md에 "제품 흐름은 Features로, 횡단 관심사는 Infrastructure로, 합성 루트는 App으로" 같은 규칙이 적혀 있고, make guardrails가 이를 자동 검사한다. 삭제된 레거시 폴더(Models·Services·Utils 등)를 다시 만들면 빌드 게이트에서 걸린다. 대형 팀 코드베이스가 "구조 부패"를 막는 실전 기법.1000개가 넘는 Swift 파일을 Features / Infrastructure / App 3-버킷으로 나누고, 배치 규칙을 스크립트로 강제하는 방식은 그 자체로 교과서다. "이 파일은 어디 둬야 하지?"라는 팀의 영원한 고민을 문서 + 자동 검사로 못 박았다.
"Tests/ 폴더 밑에 *.swift 소스가 들어오면 실패" 같은 규칙 하나를 셸 스크립트로 만들어 CI에 걸어보라. 구조 규칙을 코드로 강제하는 감을 잡을 수 있다.
ServiceRegistry에 서비스가 스스로 도구를 등록하고, ToolAvailabilityStore가 광고/억제를 관리하는 패턴은 "MCP 서버를 실제로 어떻게 짜는가"의 살아있는 예제다. 노출되는 도구 이름도 명확하다.
| 그룹 | 대표 MCP 도구 |
|---|---|
| 탐색(explore) | get_file_tree · get_code_structure · read_file · file_search · git |
| 편집(edit) | apply_edits · file_actions |
| 컨텍스트 | manage_selection · prompt · workspace_context · bind_context |
| 대화/에이전트 | ask_oracle · context_builder · agent_run · agent_manage |
| Git/워크트리 | git · manage_worktree |
전체 파일 대신 함수·타입 시그니처만 뽑는 get_code_structure는 토큰을 극적으로 아낀다. 언어별 전략(SwiftCodeMapStrategy·TypeScriptCodeMapStrategy)과 골든 픽스처 테스트까지 갖췄다.
파이썬 tree_sitter 바인딩으로 특정 .py 파일에서 함수 정의(def ...)의 시그니처만 뽑아 출력해 보라. RepoPrompt가 13개 언어로 하는 일의 축소판이다.
PCRE2·자체 C(path_search.c 등)를 Swift에서 호출하려고 RepoPrompt-Bridging-Header.h를 unsafe flag로 주입한다. "성능이 필요한 부분만 C로 내려 쓰는" 현실적 최적화의 예. 정규식 엔진을 통째로 벤더링해 넣은 결정도 흥미롭다(시스템 정규식 대신 일관된 PCRE2 확보).
"특정 AI에 종속되지 않는 계약을 코어에 두고, 세부 구현은 갈아 끼운다"는 헥사고날/포트-어댑터 사고의 실전판. NativeAgentRuntimeControlling 프로토콜 + 2개 브릿지 파일 + DTO 경계는, AI 도구가 매주 바뀌는 시대에 "래퍼가 죽지 않게" 만드는 방법을 보여준다.
conductor의 레인 직렬화는 "여러 자율 에이전트가 같은 작업 공간을 공유할 때 생기는 경합"이라는, 앞으로 점점 중요해질 문제의 구체적 해법이다. 티켓·비동기 잡·idempotent 키 설계까지 실무적이다.
| 항목 | 요구/특징 |
|---|---|
| OS | macOS 26 이상(배지 기준). Package.swift 최소는 macOS 14이나 배포/기능은 26+ 전제 |
| 빌드 도구 | Xcode 26 또는 macOS 26 SDK를 가진 Command Line Tools. Xcode를 열 필요는 없음 |
| 아키텍처 | Apple Silicon(arm64) 중심 — 빌드 산출물 .build/arm64-apple-macosx/ |
| 추가 | 로컬 프로덕션 설치 시 Python 3 필요(coordinated 데몬) |
| 서명 | 디버그: Apple Development 신원 또는 ALLOW_ADHOC_SIGNING=1 애드혹. 프로덕션: 자체 서명 인증서(맥에서만 신뢰) |
로컬 프로덕션 빌드는 노터라이즈(notarize)되지 않으며 다른 Mac으로 복사·재배포하면 안 된다. 애드혹 디버그 빌드는 보안 저장소가 인메모리라 저장한 API 키·권한이 재실행 시 사라진다(영구 저장하려면 SIGN_IDENTITY로 안정된 Apple Development 신원 지정). 이 요구사항 자체가 "왜 앱 서명·노터라이즈가 필요한가"를 배우는 좋은 사례다.
Mac(26+)에서 저장소를 클론하고 Finder에서 Launch RepoPrompt CE.command를 더블클릭해 소스에서 빌드·실행한다. 앱이 뜨면 MCP 서버가 노출하는 도구(get_code_structure·read_file 등)를 UI에서 확인한다. 목표: "컨텍스트 큐레이션 → 핸드오프" 흐름을 눈으로 체험.
이미 쓰는 코딩 에이전트(Claude Code 등)를 repoprompt-mcp에 MCP 클라이언트로 연결한다. get_code_structure로 큰 파일의 시그니처만 받아보고, file_search → read_file로 필요한 조각만 골라 컨텍스트를 만든다. 목표: 전체 파일 붙여넣기 대비 토큰이 얼마나 주는지 체감.
Tests/RepoPromptTests/CodeMap/{Fixtures,Goldens}를 열어, 입력 소스 → 기대 CodeMap 출력의 대응을 분석한다. tree-sitter 문법이 붙지 않은 언어(예: Kotlin) 하나를 고르고 "추가하려면 어디를 손대야 하나"를 Package.swift + 언어 전략 파일 기준으로 정리한다. 목표: 파서 파이프라인의 확장점 이해.
Packages/RepoPromptAgentProviders에 Foundation-only 라이브러리 product를 하나 더 만들고(예: RepoPromptEchoProvider), 문서(provider-plugins.md)의 "새 provider 추가 5단계"를 따라 어댑터 trio와 브릿지의 자리만이라도 스케치한다. 목표: 플러그인 심의 경계(코어는 패키지를 어떻게 최소로 import하는가)를 손으로 이해.
conductor의 개념(레인별 직렬화 + 티켓 + async + idempotent request-key)을 참고해, 파이썬으로 "같은 레인은 순차, 다른 레인은 병렬"인 미니 잡 러너를 만든다. 목표: 멀티 에이전트/멀티 프로세스 경합 제어의 핵심 아이디어 체득.
| 주차 | 주제 | 구체적 학습 내용 |
|---|---|---|
| 1주차 | Swift + SwiftPM 기초 | Swift 문법, SwiftPM으로 실행 파일 2개 만들기, target/product/dependency 개념. Package.swift 정독 |
| 2주차 | tree-sitter & 코드 파싱 | tree-sitter 문법/쿼리, AST 순회로 시그니처 추출. Python 바인딩으로 미니 CodeMap 실습 |
| 3주차 | MCP 서버 구현 | MCP 스펙(JSON-RPC, tools/list, tool call), Swift MCP SDK로 도구 노출. ServiceRegistry 패턴 모사 |
| 4주차 | 에이전트 오케스트레이션 | ACP(Agent Client Protocol), provider 추상화(포트-어댑터), 시크릿 격리 DTO 경계. 레인 잡 큐 개념 |
| 5주차 | 컨텍스트 엔지니어링 원리 | 토큰 예산, 컨텍스트 선택/압축, "검토 가능한 핸드오프". 왜 CodeMap·Git diff가 좋은 재료인가 |
get_code_structure로 노출.repoprompt-mcp)와 GUI 앱이 통신하는 로컬 소켓. TCP/Bonjour(네트워크 포트)를 없애고 로컬 소켓만 써 보안·단순성을 확보..worktreeinclude(gitignore 문법)에 매칭되고 동시에 이미 ignore된 파일만 새 워크트리로 복사 — .env.local 같은 로컬 설정을 안전하게 넘기는 규칙..binaryTarget(xcframework)으로 포함. 앱이 새 버전을 스스로 확인·설치하게 해준다.RepoPrompt-Bridging-Header.h로 노출해 성능 핫패스를 C로 처리.conductor가 build·liveApp·release 등 레인별로 작업을 관리 — 같은 레인은 순차, 다른 레인은 병렬. 여러 에이전트가 동시에 빌드/실행해도 충돌하지 않게 한다.