TypeScript/JavaScript 프로젝트를 위한 AI 코드 리뷰어
NestJS, Next.js, React, Express 프레임워크에 특화된 Claude 기반 PR 리뷰 GitHub Action
- Hawk/Owl 합의 시스템: Hawk(비판적 리뷰어)가 이슈를 찾고, Owl(실용적 검증자)이 ROI 기반으로 필터링
- 38개 내장 FP 패턴: SQL injection, 에러 핸들링, DI 등 알려진 오탐을 자동 억제
- Convention over Configuration:
CLAUDE.md와.github/review-guardrails.json을 자동 감지하여 별도 설정 없이 동작 - Prompt Caching: 시스템 메시지 캐싱으로 반복 리뷰 비용 최대 90% 절감
- Framework-Aware: NestJS, Next.js, React, Express 자동 감지 및 프레임워크별 리뷰 규칙
- Smart Filtering: 파일 우선순위 기반으로 토큰 예산 내에서 중요 파일 먼저 리뷰
.github/workflows/dialectic-pr.yml:
name: Dialectic PR Review
on:
pull_request:
types: [opened, synchronize, labeled]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
if: |
github.event.pull_request.draft == false &&
!contains(github.event.pull_request.labels.*.name, 'skip-ai-review')
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: timenco/dialectic-pr@main
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}ANTHROPIC_API_KEY: your-claude-api-key
PR을 열면 자동으로 리뷰가 시작됩니다.
.github/dialectic-pr.json:
{
"$schema": "https://raw.githubusercontent.com/timenco/dialectic-pr/main/config/dialectic-pr-schema.json",
"model": "claude-opus-4-6",
"language": "ko",
"exclude_patterns": ["**/*.lock", "**/dist/**", "**/coverage/**"]
}별도 설정 없이 다음 파일이 존재하면 자동으로 로드됩니다:
| 파일 | 용도 |
|---|---|
CLAUDE.md |
프로젝트 컨텍스트 (아키텍처, 컨벤션 등) → User Message에 주입 |
.github/review-guardrails.json |
프로젝트 고유 FP 패턴 → System Message에 주입 |
| 옵션 | 타입 | 기본값 | 설명 |
|---|---|---|---|
model |
string | claude-opus-4-6 |
사용할 Claude 모델 |
language |
string | — | 리뷰 출력 언어 (ISO 639-1, 예: ko, en, ja) |
exclude_patterns |
string[] | [] |
리뷰에서 제외할 글로브 패턴 |
strategies |
object | — | PR 크기별 토큰 예산 오버라이드 |
| Input | 필수 | 기본값 | 설명 |
|---|---|---|---|
anthropic_api_key |
✅ | — | Anthropic API key |
github_token |
— | ${{ github.token }} |
GitHub token |
config_path |
— | .github/dialectic-pr.json |
설정 파일 경로 |
log_level |
— | info |
로그 레벨 (debug|info|warn|error) |
dry_run |
— | false |
리뷰 포스트 없이 실행 |
| Output | 설명 |
|---|---|
issues_count |
발견된 총 이슈 수 |
critical_count |
크리티컬 이슈 수 |
review_posted |
리뷰 포스트 여부 |
System Message (캐시됨, Owl의 FP 판별 기준):
├── Hawk/Owl 합의 지침 ← 자동 (불변)
├── FALSE_POSITIVE_PATTERNS: ← 아래 소스가 머지됨
│ 빌트인 38개 자동 (프레임워크별)
│ + .github/review-guardrails.json 자동 감지
├── Framework Best Practices ← 자동 (감지된 프레임워크)
└── Language 지시 ← language 설정
User Message (매 PR마다 변경, Owl의 맥락 판단 근거):
├── REVIEW_CONTEXT (framework, flags) ← 자동
├── STRATEGY + INSTRUCTIONS ← 자동 (PR 크기 기반)
├── PROJECT_CONVENTIONS: ← CLAUDE.md 내용 (자동 감지)
│ {CLAUDE.md 파일 전문}
└── DIFF ← PR diff
Owl은 Hawk가 제기한 이슈를 두 곳에서 검증합니다:
- FALSE_POSITIVE_PATTERNS — "이 표현이 리뷰에 있으면 FP" (정밀 매칭)
- PROJECT_CONVENTIONS — "이 프로젝트의 맥락상 정상인가" (자연어 판단)
이 차이가 핵심입니다. FP 패턴은 좁고 정확하게 작동하고, 컨텍스트 파일은 넓고 해석적으로 작동합니다.
용도: 빌트인 38개가 커버하지 못하는, 이 프로젝트만의 안전한 패턴.
넣어야 하는 것:
- 프로젝트가 사용하는 라이브러리/인프라의 안전한 패턴
- 반복적으로 FP가 발생하는 프로젝트 고유 코드 패턴
- 명확한 기술적 근거가 있는 예외
파일 형식 (배열 또는 { "patterns": [...] } 모두 지원):
[
{
"id": "aurora-connection-pool-settings",
"category": "performance",
"severity": "medium",
"explanation": "Aurora Serverless v2 커넥션 풀은 인프라 레벨에서 관리되며, connection_limit 값은 Aurora 인스턴스 크기에 맞게 튜닝됨",
"falsePositiveIndicators": [
"connection pool size too small",
"connection pool size too large",
"커넥션 풀 설정"
]
}
]필드 설명:
| 필드 | 필수 | 설명 |
|---|---|---|
id |
✅ | 고유 ID. {주제}-{세부} 형식 권장. 빌트인과 동일 ID면 오버라이드 |
category |
✅ | sql-injection | error-handling | dependency-injection | logging | authentication | validation | performance | custom |
explanation |
✅ | 왜 이것이 FP인지 기술적 근거. Owl이 이것을 읽고 판단함 |
falsePositiveIndicators |
✅ | Hawk의 리뷰에 이 문구가 포함되면 FP로 간주. 구체적일수록 정밀함 |
severity |
— | critical | high | medium | low. 프롬프트에 참고 정보로 포함 |
falsePositiveIndicators 작성 규칙:
좋은 예 (구체적 → 정밀 매칭):
"Prisma $executeRaw에서 SQL injection"
"$queryRawSafe is unsafe"
"BigInt should be Int"
나쁜 예 (모호 → 과도한 FP 억제):
"SQL 관련 이슈"
"데이터베이스 문제"
"타입 관련"
규칙: Hawk가 실제로 쓸 법한 문장을 넣으세요. 리뷰 출력에서 이 문자열이 부분 매칭됩니다.
용도: 기술적 제약과 아키텍처 결정을 자연어로 기술. Owl이 맥락 판단에 사용.
넣어야 하는 것 (기술적 제약):
## Architecture
- AllExceptionsFilter가 모든 에러를 HttpException으로 변환
- BigInt 필드: orderId, paymentId (schema.prisma 기준)
- Timezone: Asia/Seoul (dayjs utc + tz)
## Critical Modules
- auth, payments, memberships — 변경 시 높은 주의 필요넣지 말아야 하는 것 (리뷰 품질 저하):
## 코드 스타일 ← Owl과 무관, 토큰 낭비
- camelCase 사용
- import 순서: external → internal
## 허용 예외 ← 위험: Owl 과도 관대화
- 테스트에서 as any 허용 ← review-guardrails.json으로 이동
- console.log 허용 ← 빌트인 패턴이 이미 커버핵심 원칙: CLAUDE.md에는 "무엇이 안전한가"가 아니라 "이 프로젝트가 어떻게 구성되어 있는가"를 넣으세요. "안전한 패턴"은 .github/review-guardrails.json의 구조화된 패턴으로 표현해야 Owl이 정밀하게 동작합니다.
로드 순서 (후순위가 동일 ID를 오버라이드):
1. 빌트인 패턴 38개
2. 프레임워크별 패턴 (FrameworkRegistry)
3. .github/review-guardrails.json (자동 감지)
예: 빌트인의 prisma-tagged-template-safe를 프로젝트에서 재정의하고 싶으면, .github/review-guardrails.json에 동일 id로 새 explanation과 falsePositiveIndicators를 정의하면 됩니다.
.github/
dialectic-pr.json # 메인 설정
review-guardrails.json # 프로젝트 FP 패턴 (6개)
CLAUDE.md # 프로젝트 컨텍스트 (자동 감지)
.github/dialectic-pr.json:
{
"$schema": "https://raw.githubusercontent.com/timenco/dialectic-pr/main/config/dialectic-pr-schema.json",
"model": "claude-opus-4-6",
"language": "ko",
"exclude_patterns": ["**/*.lock", "**/dist/**", "**/coverage/**", "**/cdk.out/**"]
}.github/review-guardrails.json (빌트인이 커버하지 못하는 프로젝트 고유 패턴만):
[
{
"id": "prisma-tagged-template-constants",
"category": "sql-injection",
"severity": "critical",
"explanation": "Prisma tagged template ($executeRaw`...${val}`)은 상수/변수 무관하게 모든 ${} 값을 자동 파라미터화하므로 안전",
"falsePositiveIndicators": [
"상수가 템플릿에 직접 삽입",
"constant directly inserted into query"
]
},
{
"id": "error-rethrow-in-service",
"category": "error-handling",
"severity": "medium",
"explanation": "Service catch 블록에서 에러를 rethrow하는 패턴은 AllExceptionsFilter와 조합하여 스택 트레이스를 보존하면서 컨텍스트를 추가하는 의도적 설계",
"falsePositiveIndicators": [
"error rethrow without handling",
"catch block only rethrows",
"에러를 다시 throw"
]
},
{
"id": "aurora-connection-pool-settings",
"category": "performance",
"severity": "medium",
"explanation": "Aurora Serverless v2 커넥션 풀은 인스턴스 크기에 맞게 튜닝되며, connection_limit은 인프라 팀이 관리",
"falsePositiveIndicators": [
"connection pool size",
"커넥션 풀 설정"
]
}
]CLAUDE.md (프로젝트 컨텍스트, 자동 감지):
# Review Context
## Architecture
- NestJS 10 + Prisma 5 + AWS Aurora Serverless v2
- AllExceptionsFilter → 모든 에러를 HttpException으로 변환
- JwtGuard + RolesGuard → @Auth() 데코레이터 패턴
## Database
- BigInt 필드: orderId, paymentId, membershipId
- Timezone: Asia/Seoul (dayjs utc + tz plugin)
- null = DB에 값 없음, undefined = 필드 미설정
## Critical Modules
- auth, payments, memberships, ordersPR 리뷰는 3단계 변증법 구조로 출력됩니다:
📊 리뷰 메트릭
- 전략: SMALL PR
- 변경 파일: 6개
- 변경 라인: +100/-50
- 영향 영역: 💳 Payments, ⚙️ Business Logic
- Consensus: ✅ LGTM (FP Rate: 100%)
- 플래그: 🔴 크리티컬 모듈, 🧪 테스트 포함
=== STEP 1: REVIEW AGENT ANALYSIS ===
Issue 1 (bug): 설명...
Issue 2 (security): 설명...
=== STEP 2: DEV AGENT CHALLENGE ===
Issue 1 Challenge: 반박... → REJECT (이유)
Issue 2 Challenge: 반박... → AGREE (이유)
=== STEP 3: OUTPUT ===
📋 Executive Summary
🔴 Critical Issues
🟡 Important Issues
✅ 긍정적인 점
📊 Final Verdict
🪄 Generated by Claude Opus 4.6 · Dialectic PR Review
단일 Claude API 호출 내에서 두 역할을 프롬프트로 정의합니다:
- 버그, 보안 취약점, 에지 케이스 탐지
- 에러 핸들링, 타입 안전성 집중
- 번호 매긴 이슈 목록 생성 (
Issue N (type): 설명)
- Hawk의 이슈를 하나씩 반박 (
Issue N Challenge:) - ROI 3질문: 버그 방지? 장애 가능? ROI 높음? — 모두 Yes가 아니면 REJECT
- 보안 이슈는 ROI 무관하게 항상 유지 (SECURITY OVERRIDE)
- Executive Summary, Critical/Important 이슈, 긍정적인 점, Final Verdict
- JSON:
{ consensus_completed, agreed_issues, rejected_issues, verdict, false_positive_rate }
결과: Owl의 필터링을 통과한 이슈만 최종 보고
GitHub Actions
→ action.ts (Action Entry) / cli.ts (CLI Entry)
→ review-engine.ts (runReview)
→ Security Layer (privacy-guard, exclude-filter)
→ PR Analyzer → Framework Detector → Smart Filter
→ Strategy Selector
→ ProjectRulesLoader (빌트인 + 프레임워크 FP 패턴)
→ ConfigLoader.loadGuardrails (review-guardrails.json 자동 감지)
→ Consensus Engine (STEP 1→2→3)
→ Claude API (prompt caching)
→ formatReviewBody (메트릭 + narrative + 푸터)
→ GitHub API
PR 크기에 따라 자동으로 전략을 선택합니다:
| 전략 | 크기 | 토큰 예산 | 리뷰 초점 |
|---|---|---|---|
| small | < 50KB | 16,000 | 포괄적 리뷰 |
| medium | < 150KB | 12,000 | 핵심 이슈 + 버그 |
| large | < 200KB | 8,000 | 보안 + 버그만 |
| xlarge | < 800KB | 4,000 | 보안 이슈만 |
| skip | >= 800KB | — | PR 분할 권고 |
크리티컬 모듈(auth, payments 등) 변경 시 토큰 예산이 1.5배로 증가합니다.
Claude API 비용은 사용자 본인의 Anthropic API 키로 직접 지불합니다.
시스템 메시지(에이전트 지침, FP 패턴, 프레임워크 룰)에 cache_control을 설정하여 캐시 할인을 받습니다:
- 첫 PR 리뷰: 전체 토큰 비용 (캐시 생성)
- 이후 리뷰 (캐시 히트 시): 시스템 메시지 부분 캐시 읽기 요금 적용
# 테스트 (104개)
npm test
# 타입 체크 + 빌드
npm run build
# Action 번들 빌드 (tsc + ncc)
npm run build:all
# Lint
npm run lintdialectic-pr/
├── src/
│ ├── core/ # 리뷰 엔진, 분석기, 전략, 합의 엔진
│ ├── adapters/ # Claude API, GitHub API, 재시도 핸들러
│ ├── security/ # 프라이버시 가드, 파일 제외 필터
│ ├── frameworks/ # 프레임워크 감지 및 특화 룰
│ ├── false-positive/ # 빌트인 FP 패턴, 패턴 매처, 프로젝트 룰 로더
│ ├── utils/ # 설정 로더, 로거, 메트릭, 파일 분류기
│ ├── action.ts # GitHub Action 진입점
│ ├── cli.ts # CLI 진입점 (로컬 디버깅용)
│ └── index.ts # 모듈 exports
├── tests/
│ └── unit/ # 테스트 (104개)
├── config/ # JSON Schema, 기본 설정
├── dist/action/ # 번들된 Action (커밋됨)
├── action.yml # GitHub Action 메타데이터
└── specs/ # 아키텍처 참조 문서
| Framework | 감지 | 프롬프트 룰 | FP 패턴 |
|---|---|---|---|
| NestJS | ✅ | ✅ | ✅ |
| Next.js | ✅ | ✅ | ✅ |
| React | ✅ | ✅ | ✅ |
| Express | ✅ | ✅ | ✅ |
| Vanilla | ✅ | ✅ | ✅ |
총 38개 패턴이 다음 카테고리에 분포:
| 카테고리 | 패턴 수 | 예시 |
|---|---|---|
| sql-injection | 5 | Prisma tagged template, $queryRawSafe |
| error-handling | 5 | NestJS AllExceptionsFilter, async wrapper |
| dependency-injection | 3 | NestJS constructor DI, @Inject |
| logging | 3 | NestJS Logger 패턴, CLI console |
| authentication | 3 | JWT env secret, bcrypt rounds |
| validation | 9 | class-validator DTO, Zod, null/undefined 분리 |
| performance | 1 | React.memo |
| custom | 1 | Prisma BigInt 직렬화 |
| React/Next.js/Express | 8 | Server Components, hooks, middleware |
MIT