트렌딩 딥다이브 · 2026-07-22 · TrendShift Daily #5 · TIRTH8205

tirth8205/code-review-graph 딥다이브
— 코드베이스를 지식 그래프로 만들어 리뷰 토큰을 아끼는 도구

code-review-graph(별칭 crg)는 Tree-sitter로 내 코드베이스를 통째로 파싱해, 함수·클래스·호출·상속 같은 관계를 SQLite 지식 그래프로 만든다. 그러면 AI 코딩 도구(Claude Code·Codex·Cursor 등)가 리뷰할 때 코드 전체를 다시 읽는 대신, "이 변경이 실제로 건드리는 파일만" 골라 받는다. 저자가 6개 실제 저장소에서 잰 결과 질문당 토큰이 중앙값 82배(최대 528배) 줄었다. 핵심은 blast radius(변경 파장 반경)다. 파일 하나를 고치면 그 파일을 호출·상속·테스트하는 노드들만 그래프에서 골라내, AI가 "정말 봐야 할 최소 집합"만 컨텍스트로 삼게 한다. 여기에 파일 감시·증분 재인덱싱, 30개 MCP 툴, 커뮤니티 검출·시각화까지 하나의 로컬 도구에 들어 있다.

(저장소 tirth8205/code-review-graph · PyPI code-review-graph · v2.3.7 · Python 3.10+ · Tree-sitter + SQLite · 약 4.2만 줄·70여 모듈 · MCP 툴 30 + 프롬프트 5 · 로컬 전용·클라우드 불필요 · MIT · 클론 소스 직접 분석)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 주목받는가 — grep·RAG·전체읽기와 뭐가 다른가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 — 파싱·그래프·blast radius·MCP
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 여기서 훔쳐올 설계
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"Stop burning tokens. Start reviewing smarter." — 토큰 그만 태우고, 똑똑하게 리뷰하라
한 문장으로

code-review-graph = 코드베이스를 "구조 지도(SQLite 지식 그래프)"로 만들고, 변경이 건드리는 부분만 MCP로 AI에 건네주는 local-first 코드 인텔리전스

pip install code-review-graphcode-review-graph install(설치된 AI 코딩 툴 자동 감지·MCP 설정 주입) → code-review-graph build(코드베이스 파싱) 세 줄이면 끝이다. 이후 AI가 리뷰할 때, crg가 그래프에서 변경 파장 반경(blast radius)을 계산해 "이 diff가 영향 주는 함수·클래스·테스트"만 추려 넘긴다.

외부 DB도, 클라우드도, 임베딩 서버도 필요 없다. 모든 것이 .code-review-graph/ 폴더 안 SQLite 파일 하나에 들어간다. "코드는 내 컴퓨터를 떠나지 않는다(local-first)"는 게 이 도구의 큰 매력이다.

이 프로젝트가 푸는 문제는 요즘 누구나 겪는 것이다. Claude Code나 Codex 같은 AI 코딩 도구에게 "이 PR 리뷰해줘"라고 하면, 도구는 관련 파일을 반복해서 통째로 다시 읽는다. 큰 저장소일수록 매 질문마다 수십만 토큰이 날아가고, 비용도 시간도 늘어난다. crg의 발상은 "코드를 매번 다 읽지 말고, 한 번 구조를 지도로 만들어 두고, 필요한 조각만 꺼내 쓰자"는 것이다. README의 한 줄 정의를 그대로 옮기면 "MCP와 CLI를 통한 토큰 효율적 코드 리뷰를 위한 local-first 지식 그래프"다.

용어
지식 그래프(knowledge graph)
여기서 지식 그래프는 "코드의 구성 요소를 노드(node)로, 그들 사이 관계를 엣지(edge)로 표현한 데이터베이스"다. crg에서 노드는 파일·클래스·함수·타입·테스트이고, 엣지는 CALLS(호출)·IMPORTS_FROM(임포트)·INHERITS(상속)·TESTED_BY(테스트됨) 같은 관계다. 이렇게 만들어 두면 "이 함수를 호출하는 게 누구지?"를 파일 전체를 읽지 않고 그래프 질의 한 번으로 답할 수 있다 — 마치 위키백과의 하이퍼링크망처럼, 항목을 다 읽지 않아도 연결을 따라갈 수 있는 것이다.
용어
MCP(Model Context Protocol)
AI 에이전트(Claude Code·Codex 등)에게 "도구(tool)"를 표준 방식으로 노출하는 프로토콜이다. crg는 MCP 서버로 동작하면서 get_impact_radius_tool·query_graph_tool 같은 30개 도구를 AI에게 내민다. AI는 코드를 직접 뒤지는 대신 이 도구들을 호출해 "필요한 조각"만 받아온다. 즉 crg는 AI와 코드베이스 사이에 낀 똑똑한 중개인 역할을 한다.

도구는 순수 Python 프로젝트로 약 4.2만 줄, 70여 개 모듈에 테스트 파일만 64개다. 핵심 엔진은 세 개다 — 코드를 파싱하는 parser.py(가장 큰 모듈), 그래프를 저장·질의하는 graph.py, AI에게 도구를 노출하는 MCP 서버 main.py. 여기에 별도의 VSCode 확장GitHub Action(PR에 자동 리뷰 코멘트)까지 딸려 있어, "CLI → 에디터 → CI"로 이어지는 삼면 제품이다.

2왜 주목받는가 — grep·RAG·전체읽기와 뭐가 다른가

"코드를 AI에 넣는 법"은 많다 — crg의 승부수는 구조 그래프 + 정직한 벤치마크

AI에게 코드베이스를 이해시키는 방법은 이미 여럿 있다. ① 파일을 통째로 읽어 컨텍스트에 밀어넣기, ② grep·ripgrep으로 텍스트 검색, ③ 코드를 잘게 쪼개 벡터로 임베딩해 RAG(의미 검색). crg가 이 무리에서 눈에 띄는 지점은 "더 똑똑한 검색"이 아니라 "코드의 구조적 관계를 미리 그래프로 만들어, 변경의 파급 범위를 정확히 계산한다"는 접근이다.

기존 방법과의 결정적 차이

전체읽기 / grep / RAGcode-review-graph
코드 이해 단위텍스트 줄·청크(의미 단위 아님)구조 단위(함수·클래스·호출·상속) — Tree-sitter AST 기반
"이 변경의 영향"사람이 직접 grep 반복 / RAG는 유사 텍스트만blast radius로 호출·상속·테스트 관계를 따라 자동 전파
토큰 비용매 질문마다 관련 파일 재적재(수십만 토큰)그래프 질의로 필요 조각만 — 중앙값 82배 절감
인프라RAG는 보통 벡터 DB·임베딩 서버 필요로컬 SQLite 파일 하나, 클라우드 불필요(local-first)
갱신바뀌면 다시 인덱싱(느림)SHA-256 해시로 바뀐 파일만 증분 재파싱(2,900파일 2초 이내)
AI 연동도구마다 수동 설정install 한 번에 14종 AI 툴 자동 감지·MCP 주입
비유

전체읽기/grep이 "책 전체를 매번 처음부터 훑어 답을 찾는 것"이라면, crg는 "먼저 색인 카드와 상호참조 지도를 만들어 둔 도서관 사서"다. 누가 "3층 A책이 바뀌면 영향받는 책이 뭐냐"고 물으면, 사서는 서가를 다시 안 뒤지고 카드 목록에서 상호참조를 따라 "이 책을 인용한 5권"을 즉시 짚어준다. crg의 blast radius가 정확히 그 상호참조 추적이다 — 코드에서 "이 함수를 고치면 무엇이 깨질 수 있나"를 그래프로 즉답한다.

실제 벤치마크 — 그리고 그 "정직함"

README가 내세우는 헤드라인은 6개 실제 오픈소스 저장소에서 잰 질문당 토큰 절감 중앙값 ~82배다. 아래는 "코드베이스를 통째로(naive) 넣을 때" 대비 "그래프 질의로 필요한 만큼만" 쓸 때의 토큰 비교다.

저장소통째로 넣기(토큰)그래프 질의(평균)절감
fastapi951,0712,169528.4배
code-review-graph(자기 자신)208,8212,49593.0배
gin166,8681,99091.8배
flask125,0221,98671.4배
express135,9553,46540.6배
httpx89,4922,43838.0배
주목할 점
"528배"를 대표값이라 우기지 않는다

많은 프로젝트가 최고 수치(fastapi 528배)를 헤드라인으로 뽑지만, crg의 README는 "528배는 단일 최선 사례이고 대표값이 아니다. 대표값은 중앙값 82배"라고 스스로 못박는다. 나아가 impact 정확도(F1 0.714)에 대해서도 "이건 그래프 유래 ground truth를 쓴 구조적 상한선이지 진짜 100% 리콜이 아니다"라고 한계를 자백한다. 이런 정직한 벤치마크 공개가 개발자 커뮤니티의 신뢰를 얻어 트렌딩에 올랐다.

주목 포인트 4가지

① 구조를 이해한다(텍스트가 아니라). Tree-sitter로 언어별 AST를 뽑아 함수·클래스·호출 관계를 실제로 파악한다. Python·JS·Go·Java뿐 아니라 Laravel(Blade·Eloquent 관계)·Spring(엔드포인트·이벤트)·Vue/Svelte(SFC)·Jupyter 노트북·Terraform까지 프레임워크를 인지하는 파서를 갖췄다.

② blast radius가 핵심 무기. "변경 파일 → 영향받는 함수/클래스/테스트"를 가중 그래프 전파로 계산한다. 단순 "어디서 호출하나"를 넘어, 엣지 종류마다 가중치를 다르게 주고(CALLS 1.0, TESTED_BY 0.7…) 깊이가 멀어질수록 점수를 감쇠시켜 정말 중요한 영향만 추린다.

③ 토큰 절감을 "1급 시민"으로 다룬다. 응답마다 절감 토큰 추정치를 메타데이터로 자동 첨부하고(context_savings), 노출하는 MCP 툴 개수 자체도 필터링해(serve --tools) "툴 설명이 잡아먹는 토큰"까지 70~85% 줄인다. 절감이 부산물이 아니라 설계 목표다.

④ CLI + VSCode + GitHub Action + 에이전트 스킬. 터미널 도구 하나로 끝이 아니라, 별도 VSCode 확장(blast radius 시각화), PR에 스티키 리뷰 코멘트를 다는 GitHub Action(composite), 7종 에이전트 스킬까지 갖춘 완성형 생태계다. 5개월간 30개 릴리스로 개발 속도도 빠르다.

용어
Tree-sitter
소스 코드를 구문 트리(AST, 추상 구문 트리)로 빠르게 파싱하는 라이브러리다. 정규식과 달리 "이건 함수 정의, 이건 함수 호출, 이건 클래스"처럼 문법 구조를 정확히 안다. 수십 개 언어 문법을 플러그인으로 제공해, crg는 tree-sitter-language-pack으로 한 번에 여러 언어를 지원한다. 편집기(예: Neovim)의 문법 하이라이팅·코드 접기에도 널리 쓰이는, 요즘 코드 분석 도구의 사실상 표준 엔진이다.

3기술 스택 전체 지도

Python 하나 + Tree-sitter 파싱 + SQLite 저장 + FastMCP 서버

crg의 기술 선택은 "무거운 외부 인프라 없이, 로컬에서 완결되게"로 요약된다. 벡터 DB도, 클라우드도, 별도 서버도 필요 없고 — SQLite 파일 하나가 그래프이자 검색 인덱스다. 런타임 의존성도 소수만 엄격하게 골랐다.

① 코어 — Python 위의 Tree-sitter · SQLite · FastMCP

레이어선택비고
언어/런타임Python 3.10+ (3.10~3.13)빌드 백엔드는 hatchling. 현재 버전 2.3.7(Beta)
파싱tree-sitter >=0.23 + tree-sitter-language-pack다국어 문법을 번들로. 확장자→언어 매핑으로 디스패치
저장/검색표준 라이브러리 SQLite + FTS5그래프·전문검색(full-text)을 한 파일에. 외부 DB 없음
MCP 서버mcp >=1.0 + fastmcp >=3.2.4AI에 도구 노출. 특정 CVE 픽스 버전 명시적으로 핀 고정
그래프 알고리즘networkx >=3.2대체 BFS 엔진(CRG_BFS_ENGINE=networkx). 기본은 SQL 내 전파
파일 감시watchdog >=4.0watch/데몬 모드에서 변경 감지 → 증분 재인덱싱
설정 파싱pyyaml, (py<3.11엔) tomliAnsible/설정 파일·languages.toml 로딩
용어
FTS5 (SQLite Full-Text Search)
SQLite에 내장된 전문(全文) 검색 엔진이다. 별도 검색 서버(Elasticsearch 등) 없이도 "이름·시그니처에 이 단어가 든 노드"를 빠르게 찾을 수 있다. crg는 nodes_fts라는 가상 테이블을 만들어 porter unicode61 토크나이저로 키워드 검색을 처리하고, 임베딩이 없을 때의 폴백 검색기로도 쓴다. "검색 인프라까지 SQLite 하나로 끝낸다"는 local-first 철학의 핵심 축이다.

② 실행 진입점(entry points) — 3개

명령실체용도
code-review-graph...cli:main메인 CLI(30여 개 서브커맨드: build·query·install·serve…). 별칭 crg
crg-daemon...daemon_cli:main여러 저장소를 동시에 감시하는 멀티레포 데몬
uvx code-review-graph serve.mcp.jsonAI 툴이 MCP 서버로 실행하는 진입점(stdio)

③ 선택 기능(extras) — 필요할 때만 켜는 확장

코어는 가볍게 두고, 무거운 기능은 선택 의존성(optional extras)으로 분리했다. 필요 없으면 안 깔아도 되게 한 배려다.

④ 코어 밖 — VSCode 확장 · GitHub Action · 에이전트 스킬

구성요소스택/형식역할
code-review-graph-vscodeTypeScript(v0.2.2)blast radius·트리뷰·D3 웹뷰 시각화 확장
action.ymlGitHub Action(composite)PR에 스티키 리뷰 코멘트 자동 게시(자기 dogfooding)
skills/7종 에이전트 스킬build-graph·review-pr·debug-issue 등 워크플로 번들
시각화visualization.py → D3.jsforce-directed 그래프를 단일 HTML로 내보내기

4아키텍처 심화 — 파싱·그래프·blast radius·MCP

"저장소가 들어와 최소 리뷰 집합이 나가기까지"의 5단계

crg를 이해하는 핵심 파이프라인은 저장소 → Tree-sitter 파서 → SQLite 그래프 → blast radius → 최소 리뷰 집합이다. 각 단계가 무엇을 하고 어떤 실제 코드가 맡는지 뜯어보자.

저장소(소스 코드) │ ▼ ┌───────────────────────────────────────────────────────────────┐ │ ① Parser (parser.py · CodeParser) │ │ Tree-sitter로 AST 추출 → NodeInfo / EdgeInfo │ │ 확장자→언어 매핑, 프레임워크 인지(Laravel·Spring·Vue…) │ └───────────────────────────────────────────────────────────────┘ │ nodes[], edges[] ▼ ┌───────────────────────────────────────────────────────────────┐ │ ② GraphStore (graph.py) → SQLite .code-review-graph/ │ │ nodes / edges / metadata / communities / nodes_fts(FTS5) │ │ 엣지마다 confidence_tier(EXTRACTED/INFERRED/AMBIGUOUS) │ └───────────────────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────┐ ┌─────────────────────────┐ │ ④ 증분 (incremental.py) │ │ ③ Blast radius │◀──│ git diff + SHA-256 해시 │ │ get_impact_radius_sql │ │ 바뀐 파일 + 의존자만 재파싱 │ │ 엣지 가중치 × 깊이 감쇠 │ └──────────────────────────────┘ └─────────────────────────┘ │ 영향 함수/클래스/테스트 + 점수 ▼ ┌───────────────────────────────────────────────────────────────┐ │ ⑤ MCP 서버 (main.py · FastMCP) 30 tools + 5 prompts │ │ get_minimal_context → get_impact_radius → get_review_context│ │ context_savings 메타데이터 자동 첨부 │ └───────────────────────────────────────────────────────────────┘ │ ▼ AI 코딩 도구(Claude Code·Codex…)에 "최소 리뷰 집합"만 전달

(A) 그래프 빌드 — CodeParser (parser.py)

가장 큰 모듈(약 1.4만 줄)인 parser.py가 코드를 뜯는다. Tree-sitter로 AST를 만든 뒤, 두 종류의 데이터 구조로 낮춘다 — NodeInfo(파일·클래스·함수·타입·테스트)와 EdgeInfo(호출·임포트·상속·테스트 관계). 확장자로 언어를 판별하고, shebang(#!)으로도 감지한다.

# code_review_graph/parser.py — 그래프의 원자 단위 @dataclass class NodeInfo: kind: str # File, Class, Function, Type, Test name: str file_path: str line_start: int line_end: int language: str = "" parent_name: Optional[str] = None # 감싸는 클래스/모듈 params: Optional[str] = None return_type: Optional[str] = None is_test: bool = False @dataclass class EdgeInfo: kind: str # CALLS, IMPORTS_FROM, INHERITS, TESTED_BY … source: str # qualified name(정규화된 전체 이름) target: str file_path: str line: int = 0

단순 파싱을 넘어 프레임워크를 인지하는 게 특징이다. PHP/Laravel의 hasMany·belongsTo 같은 Eloquent 관계, Java/Spring의 REST 엔드포인트·스케줄러·이벤트, Vue/Svelte 단일 파일 컴포넌트(SFC), Jupyter 노트북, Terraform(HCL)까지 전용 파서가 있다. 파싱 후에는 별도 리졸버(spring_resolver·hcl_resolver 등)가 돌며 관계를 더 정확히 잇는다.

(B) 영속화 — GraphStore → SQLite

graph.pyGraphStore가 노드·엣지를 SQLite에 담는다. 스키마의 핵심은 nodes 테이블(정규화 이름이 UNIQUE, 파일 해시 포함)과 edges 테이블이다. 엣지에는 흥미로운 필드가 있다 — confidence_tier(신뢰도 3단계)다.

용어
confidence_tier (엣지 신뢰도 3단계)
코드 관계를 항상 100% 확신할 수는 없다. 예컨대 동적 언어에서 "이 호출이 정확히 어느 함수로 가는지"는 애매할 수 있다. crg는 각 엣지에 EXTRACTED(소스에서 직접 확인), INFERRED(추론), AMBIGUOUS(모호) 3단계 신뢰도를 매긴다. 덕분에 blast radius를 계산할 때 "확실한 관계"와 "추측성 관계"를 구분해 가중치를 다르게 줄 수 있다. 불확실성을 숨기지 않고 데이터에 명시하는 설계다.

테이블은 nodes·edges 외에 metadata·communities·flows(실행 흐름)·community_summaries, 그리고 전문검색용 가상 테이블 nodes_fts가 있다. 스키마 버전은 migrations.py가 관리한다(v5에서 FTS5 추가, v6에서 요약 테이블 추가처럼 점진적 진화).

(C) 핵심 알고리즘 — blast radius (get_impact_radius_sql)

crg의 심장이다. "변경 파일 → 영향받는 노드"를 계산하는데, 놀랍게도 그래프 전체를 Python 메모리에 올리지 않고 SQLite 안에서 전파를 돌린다(대규모 저장소에서 빠른 이유). 변경 파일을 씨앗(seed)으로 삼아, 임시 테이블로 프론티어(경계면)를 넓혀간다.

# graph.py — 엔드포인트마다 "최고 점수 1개"만 유지해 경로 폭발 방지 INSERT INTO _impact_next (node_qn, score) SELECT node_qn, MAX(score) FROM ( SELECT e.target_qualified AS node_qn, f.score * COALESCE(w.weight, ?) * ? AS score # 엣지가중치 × 깊이감쇠 FROM _impact_frontier f JOIN edges e ON e.source_qualified = f.node_qn LEFT JOIN _impact_weights w ON w.kind = e.kind UNION ALL SELECT e.source_qualified AS node_qn, ... # 역방향(피호출자→호출자)도 전파 ) GROUP BY node_qn;

가중치가 핵심이다. 엣지 종류마다 영향력이 다르다고 보고 IMPACT_EDGE_WEIGHTS로 차등한다: CALLS 1.0(호출은 영향 큼) > INHERITS/OVERRIDES 0.9 > TESTED_BY 0.7 > REFERENCES/DEPENDS_ON 0.6 > IMPORTS_FROM 0.5 > CONTAINS 0.3. 여기에 깊이 감쇠 0.6(멀어질수록 점수↓), 점수 하한 0.05(너무 약하면 잘라냄), 기본 최대 깊이 2·최대 노드 500을 건다 — 전부 CRG_* 환경변수로 조정 가능하다.

비유

blast radius는 "연못에 돌을 던졌을 때 퍼지는 물결"과 같다. 돌이 떨어진 자리(변경 파일)에서 물결이 사방으로 퍼지되, 멀어질수록 약해진다(깊이 감쇠). 그리고 물결이 잘 전달되는 방향(CALLS)과 덜 전달되는 방향(CONTAINS)이 다르다(엣지 가중치). 너무 약해진 물결은 무시한다(점수 하한). 이렇게 해서 "이 변경이 실제로 출렁이게 만드는 범위"만 남긴다 — 그게 AI에게 넘길 최소 리뷰 집합이다.

(D) 증분 업데이트 — 바뀐 것만 다시 (incremental.py)

코드가 바뀔 때마다 전체를 다시 파싱하면 느리다. crg는 git diff --name-only로 변경 파일을 찾고(스테이지/언스테이지 모두, SVN도 지원), 각 파일의 SHA-256 해시를 저장된 값과 비교해 진짜 바뀐 파일만 재파싱한다. 그 파일에 의존하는 노드(dependents)도 엣지를 따라 함께 갱신한다. 파싱은 ProcessPoolExecutor로 병렬화하되, MCP(stdio) 환경에서는 파이프 핸들 상속 데드락을 피하려 스레드 방식으로 전환하는 세심함도 있다. README 주장으로는 2,900파일 프로젝트를 2초 이내 재인덱싱한다.

(E) MCP 통합 — 30개 도구, 그중 "먼저 부를 것" 하나

main.py가 FastMCP 서버로, 30개 @mcp.tool() + 5개 @mcp.prompt()를 등록한다. AI에게 가장 먼저 부르라고 안내하는 진입 도구가 get_minimal_context_tool이다 — 약 100토큰짜리 초압축 요약(그래프 통계·리스크 점수·다음에 부를 도구 추천)을 돌려준다.

# code_review_graph/main.py — "항상 먼저 부르세요" 진입 도구 @mcp.tool() def get_minimal_context_tool(task="", changed_files=None, repo_root=None, base="HEAD~1") -> dict: """Get ultra-compact context for any task (~100 tokens). Always call this first. Returns graph stats, risk score, top communities/flows, and suggested next tools.""" root = _resolve_repo_root(repo_root) return with_provenance(get_minimal_context( task=task, changed_files=changed_files, repo_root=root, base=base, ), root)

주요 도구를 갈래로 보면: 컨텍스트(get_minimal_context·get_impact_radius·get_review_context), 질의(query_graphcallers_of·tests_for·endpoints_for 등 15개 패턴), 검색(semantic_search_nodes — 임베딩 있으면 의미검색, 없으면 FTS5), 변경 분석(detect_changes), 구조 파악(get_architecture_overview·get_hub_nodes·커뮤니티/플로우 도구들)이다.

영리한 디테일
토큰을 두 겹으로 아낀다 — 데이터도, 도구 설명도

보통 "토큰 절감"은 데이터(코드 조각)만 줄인다. crg는 한 겹 더 간다. MCP 툴이 28개+면 그 설명 텍스트만으로도 AI 턴당 ~8k 토큰이 나간다. crg는 serve --tools ...CRG_TOOLS로 노출 툴을 5~10개로 줄여 이 설명 토큰을 70~85% 깎는다. 또 응답마다 context_savings 메타데이터로 "이번에 몇 토큰 아꼈는지"를 자동 첨부해, AI가 사람에게 절감량을 바로 보고할 수 있다. 절감이 곳곳에 배어 있다.

5디렉토리 구조 해부

약 4.2만 줄 Python — code_review_graph/ 패키지 어디부터 열까
code-review-graph/ (PyPI: code-review-graph, CLI: crg) │ pyproject.toml ★ name/version(2.3.7)/deps/entry-points(3개) │ .mcp.json uvx code-review-graph serve │ action.yml ★ GitHub Action(PR 스티키 리뷰 코멘트) │ README.md (+ko/zh/ja/hi) 다국어 5종 — 한국어 README 이미 존재 │ ├─ code_review_graph/ ★★★ 메인 패키지 (~70 모듈, 4.2만 줄) │ ├─ parser.py ★★ Tree-sitter 파서(CodeParser). 최대 모듈(~1.4만 줄) │ ├─ graph.py ★★ SQLite 그래프 저장/질의(GraphStore) + blast radius │ ├─ main.py ★★ FastMCP 서버(30 tools + 5 prompts) │ ├─ cli.py ★ argparse CLI(30여 서브커맨드) │ ├─ incremental.py ★ full_build / incremental_update / git diff │ ├─ search.py 하이브리드 검색(FTS5 + 벡터, RRF 병합) │ ├─ embeddings.py 벡터 임베딩(local/openai/google) │ ├─ communities.py Leiden 커뮤니티 검출(igraph) │ ├─ flows.py 실행 흐름(진입점→호출 사슬) 추적 │ ├─ refactor.py 리네임 프리뷰·데드코드·리팩터 제안 │ ├─ visualization.py D3.js force-directed HTML 생성(~2.2천 줄) │ ├─ migrations.py SQLite 스키마 마이그레이션(v5=FTS5, v6=요약) │ ├─ context_savings.py 토큰 절감 추정(cl100k_base 근사) │ ├─ custom_languages.py languages.toml 커스텀 언어 로더 │ ├─ daemon.py / daemon_cli.py 멀티레포 감시 데몬 │ ├─ *_resolver.py jedi/spring/hcl/temporal/event 리졸버 │ └─ tools/ MCP 툴 구현체(build·query·context·review·flows…) │ ├─ code_review_graph/eval/ ★ 벤치마크 러너 + 6개 repo config │ └─ benchmarks/ token_efficiency·impact_accuracy·search_quality… ├─ code-review-graph-vscode/ ★ 별도 VSCode 확장(TypeScript, v0.2.2) ├─ skills/ 7종 에이전트 스킬(build-graph·review-pr·debug-issue…) ├─ docs/ USAGE·COMMANDS·architecture·schema·REPRODUCING ├─ hooks/ session-start.sh, hooks.json └─ tests/ 64개 테스트 파일
읽는 순서 추천

pyproject.toml(의존성·진입점으로 전체 구조 파악) → parser.pyNodeInfo/EdgeInfo(그래프의 원자 단위가 무엇인지) → graph.py의 스키마 + get_impact_radius_sql(저장 방식과 핵심 알고리즘) → main.py(어떤 MCP 도구를 AI에 노출하는지 = 이 프로젝트의 표면) → incremental.py(어떻게 빠르게 갱신하는지) → search.py(FTS5+벡터 하이브리드). 이 순서면 "코드가 그래프가 되어 AI에 전달되기까지"를 완주할 수 있다. docs/architecture.mddocs/REPRODUCING.md는 저자가 직접 쓴 고신뢰 배경 자료다.

용어
flows(실행 흐름) & communities(커뮤니티)
그래프 위에서 뽑아내는 두 종류의 "상위 구조"다. flows는 진입점(예: API 핸들러)에서 시작해 호출 사슬을 따라간 "하나의 실행 경로"다 — "이 요청이 들어오면 어떤 함수들을 거치나"를 보여준다. communities는 Leiden 알고리즘으로 "서로 촘촘히 연결된 코드 뭉치"를 자동으로 묶은 것이다(예: 인증 모듈, 결제 모듈). 개별 함수를 넘어 "이 코드베이스가 어떤 덩어리들로 이뤄졌나"를 AI가 한눈에 파악하게 돕는다.

6학습 포인트 — 여기서 훔쳐올 설계

코드 분석 도구에 관심 없어도 배울 값어치가 있는 것들
패턴 1 · 텍스트가 아니라 구조를 다룬다

Tree-sitter로 언어 중립 AST를 뽑는다

정규식·grep은 "함수 정의"와 "함수 이름이 든 주석"을 구분 못 한다. crg는 Tree-sitter AST로 구문 구조 자체를 다뤄, 노드(함수·클래스)와 엣지(호출·상속)를 정확히 추출한다. tree-sitter-language-pack 하나로 수십 언어를 커버하는 것도 핵심 교훈 — "코드를 분석하려면 먼저 파싱하라, 문자열로 때우지 말라". 린터·코드 검색·리팩터 도구 어디에나 옮겨 쓸 발상이다.

패턴 2 · 그래프를 SQL 안에서 순회한다

전부 메모리에 올리지 않고 임시 테이블로 전파

보통 그래프 알고리즘은 전체 그래프를 메모리에 로드한다. 큰 코드베이스에선 이게 부담이다. crg는 SQLite 임시 테이블로 프론티어를 넓히는 bounded relaxation으로 blast radius를 계산해, 그래프를 통째로 안 올리고도 빠르다. "엔드포인트당 최고 점수 1개만 유지"로 순환 그래프의 경로 폭발도 막는다. 재귀 CTE의 함정을 아는 실전 SQL 설계다.

패턴 3 · 관계에 가중치와 신뢰도를 매긴다

모든 엣지가 평등하지 않다

"영향 분석"을 이진(있다/없다)이 아니라 연속 점수로 다룬 게 crg의 정교함이다. 엣지 종류별 가중치(CALLS 1.0…CONTAINS 0.3), 깊이 감쇠(0.6), 점수 하한(0.05), 게다가 엣지마다 confidence_tier로 신뢰도까지. "불확실성을 데이터에 명시하고, 중요도를 수치로 랭킹한다"는 접근은 추천·검색·리스크 스코어링 어디에나 통한다.

패턴 4 · 증분 계산 — 바뀐 것만 다시

SHA-256 해시로 dirty tracking

전체 재계산은 느리다. crg는 파일 해시를 저장해 두고 바뀐 파일만 재파싱하며, 그 의존자까지 엣지로 추적해 갱신한다. git diff로 변경 후보를 좁히고 ProcessPoolExecutor로 병렬화한다. "결과를 캐시하고 입력 변화만큼만 다시 계산한다"는 증분 계산(incremental computation)은 빌드 시스템·정적분석·재렌더링의 공통 원리다.

패턴 5 · 하이브리드 검색 — 키워드 + 의미

FTS5와 벡터를 RRF로 합친다

키워드 검색(FTS5)은 정확한 이름에 강하고, 벡터 검색(임베딩)은 의미에 강하다. crg는 둘을 RRF(Reciprocal Rank Fusion)로 병합해 각자의 약점을 메운다. 임베딩이 없으면 FTS5로 우아하게 폴백(graceful degradation)하는 것도 배울 점 — 무거운 의존성을 선택으로 두고, 없어도 동작하게 만드는 설계다.

패턴 6 · 토큰(비용)을 1급 시민으로

절감을 측정하고, 응답에 붙여 보고한다

crg는 "얼마나 아꼈나"를 추정해(context_savings.py, cl100k_base 근사) 응답 메타데이터로 자동 첨부하고, 툴 개수까지 필터링해 설명 토큰을 줄인다. LLM 시대엔 토큰이 곧 돈이자 지연시간이다. "핵심 자원(여기선 토큰)을 계측하고, 최적화를 눈에 보이게 만든다"는 태도는 어떤 비용 민감 시스템에서도 값진 습관이다.

7하드웨어 / 시스템 요구사항

로컬 도구라 가볍다 — SQLite 파일 하나면 끝

crg는 요청을 받아 그래프를 만들고 질의하는 가벼운 로컬 도구다. 무거운 벡터 DB나 클라우드가 필요 없고, 평범한 개발용 노트북이면 충분하다. 유일하게 무거워질 수 있는 부분은 선택 기능인 임베딩(시맨틱 검색)인데, 그마저도 로컬 모델로 CPU에서 돌릴 수 있다.

항목요구/권장
Python3.10 이상(3.10~3.13). 그 외 런타임 불필요
설치pip install code-review-graph (또는 pipx/uvx)
초기 설정code-review-graph install(AI 툴 자동 감지·MCP 주입) → build
저장소(DB)프로젝트 안 .code-review-graph/SQLite 파일. 외부 DB 없음
OS크로스플랫폼(Windows는 SelectorEventLoop 전환 등 전용 처리 있음)
GPU불필요. 임베딩도 CPU 결정론 모드로 동작(재현성 확보)
선택 의존성시맨틱 검색(embeddings)·커뮤니티(igraph)·위키(ollama)는 필요할 때만
AI 툴 연동Claude Code·Codex·Cursor·Windsurf·Zed 등 14종 자동 지원
보안·프라이버시 관점
코드가 내 컴퓨터를 떠나지 않는다(local-first)

많은 코드 인텔리전스 도구가 코드를 클라우드로 보내 인덱싱한다. crg는 파싱·그래프·검색이 전부 로컬 SQLite에서 일어나 코드가 외부로 나가지 않는다(임베딩도 로컬 모델 선택 가능). 사내 코드·비공개 저장소를 다루는 팀에게 큰 장점이다. MIT 오픈소스라 무엇을 하는지 직접 감사할 수도 있다.

8직접 해볼 수 있는 실습 과제

난이도별로, 손을 움직이며 배우는 순서

과제 1. 설치하고 첫 그래프 만들기 난이도 ★☆☆

아무 프로젝트 폴더에서 pip install code-review-graphcode-review-graph build를 실행한다. 생성된 .code-review-graph/ 안의 SQLite 파일을 sqlite3로 열어 nodes·edges 테이블을 직접 들여다보라. "내 코드가 몇 개 노드와 엣지로 표현됐는지" 확인하는 것만으로 지식 그래프의 실체가 손에 잡힌다.

과제 2. AI 코딩 툴에 붙여 리뷰시키기 난이도 ★★☆

code-review-graph install로 Claude Code(또는 Cursor)에 MCP를 자동 주입한 뒤, 실제 변경을 만들고 AI에게 리뷰를 시켜본다. AI가 get_minimal_contextget_impact_radiusget_review_context 순으로 도구를 부르는지, 응답의 context_savings에 절감 토큰이 얼마로 찍히는지 관찰하라 — "필요한 것만 읽는" 흐름을 눈으로 확인하는 과제다.

과제 3. 그래프에 직접 질문 던지기 난이도 ★★☆

CLI로 query_graph의 15개 패턴을 하나씩 시험한다: callers_of(누가 이 함수를 부르나)·tests_for(이 함수의 테스트는)·endpoints_for(관련 API 엔드포인트)·importers_of 등. 그리고 파일 하나를 골라 get_impact_radius로 blast radius를 뽑아, "왜 이 노드들이 걸렸는지"를 엣지 가중치와 대조해본다.

과제 4. 벤치마크 재현하기 난이도 ★★★

docs/REPRODUCING.md를 따라 fastapi·flask 같은 샘플 저장소에서 토큰 절감 벤치마크를 직접 돌려본다. 저자가 주장하는 "중앙값 82배"가 내 환경에서도 나오는지, config가 upstream SHA를 고정하고 Leiden seed를 박아 재현 가능하게 만든 장치들을 확인하라. 벤치마크를 의심하고 검증하는 습관을 기르는 과제다.

과제 5. 새 언어/프레임워크 파서 확장 난이도 ★★★★

custom_languages.pylanguages.toml로 아직 없는 언어를 추가하거나, parser.py의 프레임워크 인지 로직(예: Spring 리졸버)을 참고해 새 프레임워크 관계 추출을 구현해본다. Tree-sitter 문법을 붙이고, 추출한 관계가 edges 테이블에 올바른 kindconfidence_tier로 들어가는지 검증하라 — 파서 확장성을 몸으로 익히는 과제다.

9관련 기술 심화 학습 로드맵

이 저장소를 발판 삼아 넓혀갈 4주 코스

1주차 — Tree-sitter와 AST 파싱

Tree-sitter 공식 문서로 "쿼리(query)"와 "구문 트리"를 익히고, Python·JS 같은 언어 문법 하나를 붙여 직접 함수·클래스를 추출해본다. crg의 parser.py에서 NodeInfo/EdgeInfo가 만들어지는 지점과 대조하면, "소스 코드 → 구조 데이터" 변환의 실체가 보인다. 정규식으로 코드를 분석하려다 실패한 경험이 있다면 이 주차가 특히 값지다.

2주차 — 그래프 이론과 SQLite에 그래프 담기

노드·엣지·인접 리스트·BFS/DFS·중심성(centrality) 같은 기본 그래프 개념을 정리하고, "그래프를 관계형 DB(SQLite)에 어떻게 저장·순회하는가"를 실습한다. crg의 graph.py 스키마와 get_impact_radius_sql를 교재 삼아, 재귀 CTE의 경로 폭발 문제와 crg가 그것을 "엔드포인트당 최고 점수 1개"로 푸는 방식을 따라가 본다.

3주차 — 검색과 토큰 회계(token accounting)

FTS5 전문검색, 임베딩 기반 시맨틱 검색, 그리고 둘을 합치는 RRF(Reciprocal Rank Fusion)search.py로 익힌다. 이어 context_savings.py를 읽으며 "LLM 토큰을 어떻게 세고 절감을 추정하는가"(cl100k_base 근사)를 배운다. LLM 애플리케이션에서 비용·지연을 관리하는 실전 감각을 기르는 주차다.

4주차 — MCP와 에이전트 컨텍스트 엔지니어링

main.py의 FastMCP 서버로 "AI에게 도구를 노출하는 법"을 익히고, Model Context Protocol 스펙과 대조한다. 특히 get_minimal_context를 "먼저 부를 진입점"으로 두는 설계, 툴 개수 필터링으로 설명 토큰을 줄이는 기법은 컨텍스트 엔지니어링(에이전트에게 무엇을, 얼마나 주는가)의 좋은 사례다. 직접 간단한 MCP 서버를 만들어 Claude Code에 붙여보며 마무리한다.

10핵심 키워드 사전

이 문서에 나온 용어를 한 줄로
code-review-graph / crg
코드베이스를 SQLite 지식 그래프로 만들어, 변경이 건드리는 부분만 MCP로 AI에 넘겨 리뷰 토큰을 아끼는 local-first 도구. 저장소는 tirth8205/code-review-graph, PyPI 패키지명도 동일.
지식 그래프(knowledge graph)
코드 요소(파일·클래스·함수·테스트)를 노드로, 관계(호출·임포트·상속·테스트)를 엣지로 표현한 DB. crg에선 SQLite에 저장된다.
blast radius(변경 파장 반경)
변경 파일이 그래프상 영향을 주는 노드 집합. crg의 핵심 알고리즘(get_impact_radius_sql)이 엣지 가중치×깊이 감쇠로 점수를 매겨 "정말 봐야 할 최소 집합"을 추린다.
Tree-sitter
소스 코드를 구문 트리(AST)로 빠르게 파싱하는 라이브러리. 정규식과 달리 문법 구조를 정확히 안다. crg는 tree-sitter-language-pack으로 다국어를 지원.
NodeInfo / EdgeInfo
파서가 뽑아내는 그래프의 원자 단위. NodeInfo=파일/클래스/함수/타입/테스트, EdgeInfo=CALLS/IMPORTS_FROM/INHERITS/TESTED_BY 등 관계.
confidence_tier
엣지(관계)의 신뢰도 3단계 — EXTRACTED(직접 확인)·INFERRED(추론)·AMBIGUOUS(모호). 불확실성을 데이터에 명시해 blast radius 가중에 활용.
MCP(Model Context Protocol)
AI 에이전트에 도구를 노출하는 표준 프로토콜. crg는 MCP 서버로 30개 도구를 AI에 내밀어, AI가 코드를 직접 뒤지는 대신 도구를 호출해 조각만 받게 한다.
get_minimal_context
"항상 먼저 부르세요"라고 안내되는 MCP 진입 도구. 약 100토큰짜리 초압축 요약(그래프 통계·리스크 점수·다음 도구 추천)을 반환.
context_savings
응답에 자동 첨부되는 "이번에 아낀 토큰" 추정 메타데이터. cl100k_base 토크나이저로 근사. 절감을 눈에 보이게 만드는 장치.
FTS5
SQLite 내장 전문검색 엔진. crg는 nodes_fts 가상 테이블로 키워드 검색을 처리하고, 임베딩이 없을 때의 폴백 검색기로 쓴다.
RRF(Reciprocal Rank Fusion)
여러 검색 결과(FTS5 키워드 + 벡터 의미)를 순위 기반으로 병합하는 기법(k=60). 서로의 약점을 메워 하이브리드 검색을 완성.
flows / communities
그래프에서 뽑는 상위 구조. flows=진입점에서 시작한 실행 경로(호출 사슬), communities=Leiden 알고리즘으로 묶은 촘촘히 연결된 코드 뭉치.
증분 인덱싱(incremental)
SHA-256 파일 해시로 바뀐 파일만 재파싱하고 의존자를 함께 갱신하는 방식. git diff로 변경 후보를 좁히고 병렬 파싱. 2,900파일 2초 이내 재인덱싱.
local-first
파싱·그래프·검색이 전부 로컬 SQLite에서 일어나 코드가 외부로 나가지 않는 설계. 벡터 DB·클라우드 불필요. 프라이버시와 오프라인 동작에 유리.

11참고 링크

원본부터 배경 지식까지

프로젝트

핵심 소스(먼저 읽을 파일)

기반 기술