Codex를 활용한 사내 AI 코드 리뷰 시스템
개요
몇 달 전 GeekNews에 Claude Code 창시자 Boris Cherny가 Claude Code를 사용하는 방법이라는 글이 올라왔습니다. Threads나 X를 통해 많이 공유된 글이었고, 지금은 꽤 널리 알려진 내용이지만, 그중 코드 리뷰에 대한 부분에서 힌트를 얻어 사내에 비슷한 흐름을 직접 만들었습니다.
LAH 개발팀은 GitLab을 SaaS로 사용중이라, MR에 봇을 태그하여 리뷰를 요청할 수 있게 구성했습니다. 팀 규모가 크지 않고, 아직 AI 리뷰가 충분히 검증되지 않았기 때문에 AI 리뷰와 승인을 필수 룰로 두지는 않았고, 팀원의 피어 리뷰를 보조하는 도구로 사용중입니다. 다만 추후 파이프라인 확장이나 자동화를 고려하여, 치명적인 결함이 없으면 봇이 MR을 승인하는 구조까지 갖춰 두었습니다.
| 구성 요소 | 역할 |
|---|---|
| GitLab (SaaS) | MR, 댓글, 웹훅 이벤트 |
| 사내 웹훅 수신 서버 | 이벤트 수신, 댓글 파싱, Codex 호출, GitLab API 연동 |
| Codex CLI | lah-review 스킬과 함께 diff 리뷰 |
| 리뷰 대시보드 | 히스토리·로그 조회 |
전체 데이터 플로우
이벤트는 GitLab → 사내 서버 → Codex → 다시 GitLab 순으로 흐른다. MR에 달린 댓글은 리뷰 요청 시 프롬프트의 일부로 함께 넘긴다.

요약하면 다음과 같다.
- 개발자가 MR에 회사 봇을 멘션하고
리뷰라는 키워드를 포함해 요청한다. - GitLab이 웹훅으로 사내 서버에 이벤트를 보낸다.
- 웹서버가 댓글을 파싱하고, 조건에 맞으면 Codex CLI를 실행한다.
- Codex는 미리 정의한
lah-review스킬과 프로젝트 컨텍스트를 바탕으로 diff를 검토하고 JSON 형태로 결과를 돌려준다. - 웹서버가 결과를 GitLab 댓글을 달고, 조건에 따라 MR을 승인한다.
- 실행 이력은 대시보드에서 확인할 수 있다.
GitLab에서의 사용법
리뷰는 MR 댓글 한 줄로 시작한다. 봇 계정을 태그하고, 자연어로 무엇을 봐 주면 좋을지 적어 두면 그 내용이 그대로 프롬프트에 실린다.

예를 들어 아래와 같이 요청할 수 있다.
@company-bot 리뷰— 기본 리뷰@company-bot 리뷰. 인증 관련 변경만 집중해서 봐줘— 범위를 좁힌 리뷰
웹서버는 댓글 본문에 리뷰 단어가 포함된 경우에만 Codex 호출을 트리거한다. 그 외 댓글은 일반 대화·알림으로만 처리해, 불필요한 CLI 실행과 비용을 줄인다.
웹훅 수신 서버가 하는 일
GitLab 웹훅은 사내 서버로만 전달한다. 사내 서버에서 MR의 diff, 코드 Context, 댓글 텍스트를 묶어 CLI에 넘긴다.
- 웹훅 검증 — 시그니처·토큰으로 GitLab 출처 확인
- 이벤트 필터링 — note(댓글) 이벤트 처리
- 프롬프트 조립 — diff , 사용자 댓글, 프로젝트 fetch 및 worktree
- Codex CLI 실행 — 스킬 경로·작업 디렉터리·타임아웃 관리
- 결과 파싱 — JSON 리뷰 결과 → GitLab API로 코멘트·스레드·승인
- 자동 승인 —
critical/high수준의 이슈가 없으면 승인
치명적인 버그나 보안 이슈가 없다고 판단되면 승인까지 이어지지만, 사람이 먼저 보고 머지하는 흐름도 그대로 유지한다. 자동 승인은 “막히지 않게 해 주는 옵션”에 가깝고, 팀 전원이 AI 승인에 의존하도록 강제하지는 않는다.
Codex CLI와 lah-review 스킬
리뷰 품질의 핵심은 범용 챗봇 프롬프트가 아니라, 저장소에 맞춘 스킬(skill) 이다. Codex를 CLI로 호출할 때 lah-review를 함께 로드한다.
lah-review 스킬은 다음을 규정한다.
docs/ai-review/아래 프로젝트 컨텍스트를 먼저 읽을 것- MR diff와 변경 파일 주변 코드를 충분히 볼 것
- 리스크 높은 순서(빌드·런타임 → 아키텍처 → 인증·캐시 → 폼·UI)로 검토할 것
- GitLab에 직접 댓글 달지 말고 JSON만 반환할 것 — 게시는 웹서버가 담당
출력 스키마 일부는 아래와 같다. 파이프라인이 이 JSON을 파싱해 심각도별로 댓글을 나누거나, 이슈가 없으면 승인 분기로 넘긴다.
{
"summary": "Short review summary.",
"issues": [
{
"severity": "high",
"category": "bug",
"file": "src/user/service.ts",
"line": 128,
"title": "Missing null check",
"comment": "user can be null before accessing profile",
"suggestion": "Add guard clause before dereferencing user.profile"
}
]
}
리뷰 히스토리 대시보드
CLI는 일회성 실행에 가깝기 때문에, 운영할 때는 누가·어떤 MR·몇 분 걸렸는지·성공/실패를 남기는 쪽이 중요하다. 사내 대시보드에서 요청별 로그와 Codex 출력 요약을 볼 수 있게 해 두었다.


MCP·에이전트 프레임워크를 쓰지 않은 이유
요즘은 OpenClaw, Hermes 등 MCP와 스킬셋이 붙은 에이전트 도구도 많다. 익숙한 환경이라면 GitLab MCP만으로 MR 조회·댓글·파이프라인까지 한 번에 묶을 수도 있다.
개인적으로 이러한 스택은 프레임워크처럼 느껴졌다. 빠르게 시작할 수 있지만, 장기적으로는 걱정됐다.
- 웹훅 → 사내 정책 → Codex → 승인 조건 같은 우리만의 분기를 넣기 어렵다
- 버전·플러그인·MCP 서버 구성에 종속된다
- “MR 댓글 한 줄이 프롬프트가 된다” 같은 얇은 인터페이스를 그대로 유지하기 어렵다
그래서 대부분은 직접 개발하고, AI가 필요한 리뷰 영역만 Codex CLI로 호출하는 형태를 택했다. GitLab 연동·키워드 트리거·JSON 파싱·승인·대시보드는 전부 직접 개발했다. 물론 AI와 함께 개발했지만.
우리는 인원이 적고 규칙이 자주 바뀌지 않고 많지도 않아서, 현재 구조의 운영 부담이 더 적다고 생각했다.
운영 관점에서의 선택
정리하면 설계 원칙은 다음과 같다.
- 진입점은 GitLab 댓글 — 개발자가 이미 쓰는 UI에서
@봇 리뷰만 하면 된다. - 트리거는 명시적 —
리뷰키워드로 의도 없는 호출을 막는다. - 리뷰 품질은 스킬·docs로 고정 — lah-review +
docs/ai-review/ - 결과는 JSON — 댓글·승인은 웹서버가 일관되게 처리
- 필수가 아닌 보조 — 자동 승인은 있지만, 사람 리뷰·머지 습관은 그대로
시스템이 안정화되기 까지 한동안 개선은 없을 것 같다. 최소한 몇주는 사용해봐야 건설적인(?) 피드백이 나올 것 같다.
마무리
이제는 잘 알려진 리뷰 구조를 우리 환경에 맞게 웹훅 + Codex CLI로 구축해봤다.
비슷한 고민을 하고 있다면, 전체를 한 번에 프레임워크로 가져오기보다 간단히 웹훅 + Agent CLI만 먼저 붙여 보는 것도 방법이다. 안정되면, 그때 스킬과 승인 정책을 조금씩 두껍게 만들어도 늦지 않다.
즉, 사내 시스템도 MVP가 필요하다.