CodeRabbitCodeRabbitKorea User Group
코드레빗코드래빗Kotlin MultiplatformKMPCompose MultiplatformCMP멀티플랫폼 코드 리뷰AI 코드 리뷰AI 코드 리뷰 설정coderabbit.yamlexpect actual베스트 프랙티스

CodeRabbit Kotlin Multiplatform & Compose Multiplatform AI 코드 리뷰 설정 가이드

CodeRabbit Korea User Group·

CodeRabbit을 그대로 켜 두기만 해도 코드 리뷰 자체는 잘 굴러갑니다. 다만 Kotlin Multiplatform(KMP) 프로젝트는 하나의 코드베이스가 여러 플랫폼(Android, iOS, Desktop/JVM, Web/Wasm)으로 동시에 컴파일되고, expect/actual로 플랫폼 차이를 메우며, Compose Multiplatform(CMP)으로 UI까지 공유합니다. 그래서 일반 Kotlin이나 단일 플랫폼 설정만으로는 "commonMain에 플랫폼 전용 코드가 새어 들어왔다" 같은 KMP 특유의 문제를 잡지 못합니다. 멀티플랫폼 컨텍스트.coderabbit.yaml에 알려주면 리뷰의 깊이가 눈에 띄게 달라집니다.

이 글에서는 KMP & Compose Multiplatform 프로젝트에 적용 가능한 .coderabbit.yaml을 단계별로 작성해 봅니다. 단일 플랫폼 버전을 함께 보고 싶다면 CodeRabbit Android & Jetpack Compose 설정 가이드CodeRabbit iOS & SwiftUI 설정 가이드를, 일반 Kotlin 설정은 코드래빗 Kotlin 활용 베스트 프랙티스를, .coderabbit.yaml 옵션 자체가 처음이시라면 코드래빗 설정 완벽 가이드를 함께 보시면 좋습니다.

왜 KMP/CMP 전용 설정이 필요한가요?

기본 설정은 "단일 타깃 Kotlin 코드" 만을 가정합니다. 그래서 다음 같은 멀티플랫폼 특유의 안티 패턴이 잘 잡히지 않습니다.

  • commonMain에 플랫폼 전용 API(android.*, java.*, platform.UIKit.*, kotlinx.browser.*)가 직접 들어와 특정 타깃에서만 컴파일되는 경우
  • expect 선언에 대응하는 actual이 일부 타깃에서 누락되거나, 시그니처가 달라 컴파일이 깨지는 경우
  • Dispatchers.IO처럼 JS/Wasm 타깃에 존재하지 않는 디스패처를 commonMain에서 직접 참조하는 경우
  • Compose Multiplatform 화면에서 Android 전용 R.string/androidx.compose.ui.res를 써서, 공유 UI가 Android에서만 동작하는 경우
  • iOS로 노출하는 public API에 suspend 함수나 Flow를 그대로 내보내, Swift 쪽에서 취소·구독이 어려워지는 경우(SKIE/NativeCoroutines 부재)
  • Android 전용 DI인 Hilt를 commonMain에서 쓰려다 멀티플랫폼 빌드가 깨지는 경우(Koin 등으로 분리 필요)
  • build.gradle.kts에서 의존성을 잘못된 소스셋(예: commonMain이어야 할 것을 androidMain)에 선언하는 경우

이런 항목들을 path_instructions로 명시하면, AI 코드 리뷰가 사람 시니어 KMP 개발자가 PR을 본 듯한 코멘트를 달아 줍니다.

기본 골격 만들기

루트 디렉터리에 .coderabbit.yaml을 만들고, 다음과 같은 헤더로 시작합니다.

# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: ko-KR
early_access: false
 
reviews:
  profile: chill            # 처음에는 chill, 익숙해지면 assertive
  high_level_summary: true
  collapse_walkthrough: true
  poem: false
  • language: ko-KR: 리뷰 코멘트를 한국어로 받습니다. CodeRabbit이 PR description, walkthrough, 인라인 코멘트 모두를 한국어로 생성합니다.
  • profile: chill: 처음 도입하는 팀에 권장합니다. 사소한 스타일 nitpick까지 받고 싶다면 assertive로.

path_filters: 어떤 파일을 보고 어떤 파일을 무시할까

KMP 프로젝트는 Android 빌드 산출물(build/)과 iOS 빌드 산출물(DerivedData/, Pods/), Kotlin/Native 캐시(.kotlin/), JS 의존성 스토어(kotlin-js-store/), .klib 등이 PR에 섞여 들어오곤 합니다. 정작 봐야 할 변경에 코멘트가 묻히지 않도록 처음부터 제외해 두는 편이 깔끔합니다.

reviews:
  path_filters:
    # Kotlin 소스(모든 소스셋: commonMain, androidMain, iosMain, jvmMain, wasmJsMain ...)
    - "**/*.kt"
    - "**/*.kts"
    # iOS 앱 래퍼(Swift)와 권한·보안 표면
    - "**/iosApp/**/*.swift"
    - "**/AndroidManifest.xml"
    - "**/Info.plist"
    - "**/*.entitlements"
    # Gradle / 버전 카탈로그
    - "**/*.gradle.kts"
    - "**/libs.versions.toml"
    - "**/gradle.properties"
    # Compose Multiplatform 리소스(문자열 등 텍스트만)
    - "**/composeResources/**/*.xml"
 
    # Android/Gradle 빌드 산출물
    - "!**/build/**"
    - "!**/.gradle/**"
    - "!**/generated/**"
    # Kotlin/Native·KSP·KAPT 캐시 및 생성물
    - "!**/.kotlin/**"
    - "!**/ksp/**"
    - "!**/kapt/**"
    - "!**/*.klib"
    # iOS 빌드 산출물·의존성
    - "!**/DerivedData/**"
    - "!**/Pods/**"
    - "!**/*.xcodeproj/**"
    - "!**/*.xcworkspace/**"
    # Web(JS/Wasm) 의존성 스토어
    - "!**/kotlin-js-store/**"
    # 잠금/래퍼
    - "!**/gradle-wrapper.properties"

!**/.kotlin/**, !**/*.klib 같은 패턴 덕분에 Kotlin/Native 중간 산출물에 잡음 코멘트가 달리지 않습니다.

auto_review: 자동 리뷰 동작

reviews:
  auto_review:
    enabled: true
    auto_incremental_review: true
    drafts: false
    base_branches:
      - main
      - develop
    ignore_usernames:
      - dependabot
      - "dependabot[bot]"
      - renovate
      - "renovate[bot]"
  • auto_incremental_review: true: 새 커밋이 푸시될 때마다 변경분에 대해 추가 리뷰를 받을 수 있습니다.
  • drafts: false: 작성 중인 Draft PR에는 리뷰를 달지 않아 알림 피로를 줄입니다.
  • ignore_usernames: dependabot/renovate가 만든 PR은 리뷰를 건너뜁니다. CI가 이미 libs.versions.toml 의존성 PR을 검증하므로 중복 리뷰가 불필요합니다.

path_instructions: KMP & CMP 전용 컨텍스트 주입

여기가 이 가이드의 핵심입니다. 같은 .kt 확장자라도 어느 소스셋(commonMain vs androidMain vs iosMain)에 있느냐에 따라 리뷰 기준이 완전히 달라야 합니다.

Kotlin 공통 베이스라인

모든 .kt 파일에 공통으로 적용되는 베이스라인입니다. 소스셋별 규칙이 뒤에 붙어도, 이 베이스라인은 모든 코틀린 파일에 동시에 적용됩니다.

reviews:
  path_instructions:
    - path: "**/*.kt"
      instructions: |
        Kotlin best practices to check:
 
        Language correctness:
        - Null safety: nullable 타입을 적절히 다루고, 불필요한 !! 단언 사용 금지
        - Immutability: var보다 val 우선, immutable collection 우선
        - Data/sealed: DTO·값 객체는 data class, 제한된 상태는 sealed interface/class
 
        Coroutines:
        - Structured concurrency 준수, GlobalScope 금지
        - CoroutineDispatcher는 주입받아 테스트 결정성 확보
        - 멀티플랫폼에서 디스패처 가용성은 타깃마다 다름(아래 commonMain 규칙 참고)
 
        Error handling:
        - 예외 삼키기 금지, 실패는 Result/sealed로 표현
 
        Security:
        - 하드코딩된 secret/credential 금지
        - 멀티플랫폼 시크릿은 BuildKonfig 등으로 빌드 타임 주입, 평문 커밋 금지
 
        Multiplatform 일관성:
        - expect 선언에는 모든 타깃의 actual이 짝으로 존재해야 함
        - 공용 로직은 commonMain으로 끌어올리고, 플랫폼 차이는 최소 표면의 expect/actual로

commonMain: 플랫폼 중립성 검증 (KMP 핵심)

commonMain모든 타깃에서 컴파일되어야 하므로, 특정 플랫폼에만 존재하는 API가 들어오면 안 됩니다. KMP에서 가장 흔하고 치명적인 실수가 바로 여기서 나옵니다.

    - path: "**/commonMain/**/*.kt"
      instructions: |
        commonMain 플랫폼 중립성 best practices:
 
        플랫폼 API 누수 금지:
        - android.*, androidx.*(멀티플랫폼 아닌 것), java.*/javax.*,
          platform.UIKit/Foundation, kotlinx.browser.* 등 플랫폼 전용 import 금지
        - 위 기능이 필요하면 expect 선언으로 추상화하고 각 actual에서 구현
        - 멀티플랫폼 라이브러리(kotlinx-coroutines, kotlinx-serialization,
          kotlinx-datetime, Ktor, SQLDelight, multiplatform-settings)만 사용
 
        디스패처/동시성:
        - Dispatchers.IO는 JS/Wasm 타깃에 없음. 웹 타깃을 포함하면 commonMain에서 직접 참조 금지
        - Dispatchers.Main도 일부 타깃에서 의존성 필요. 디스패처는 주입하거나 expect로 추상화
        - Kotlin/Native에서도 안전하도록 가변 전역 상태·스레드 가정 회피
 
        expect 선언:
        - expect는 플랫폼 차이의 "최소 표면"만 노출(가능한 한 인터페이스/함수 단위로 작게)
        - expect 클래스보다 expect fun + 공용 인터페이스 조합이 유지보수에 유리한지 검토
 
        플랫폼 자원 의존:
        - 시간(Clock), 난수, 파일 경로, 로케일 등은 직접 호출하지 말고 주입/expect로

Compose Multiplatform 화면·UI

CMP는 Composable을 commonMain에 두고 모든 플랫폼에서 공유합니다. 따라서 Android 전용 Compose API가 아니라 멀티플랫폼 API를 써야 합니다. 화면 파일명(*Screen.kt)을 1차 신호로 삼고, 공용 UI 디렉터리를 보조로 겁니다.

    # 1) 화면 단위 Composable - 파일명 컨벤션
    - path: "**/*Screen.kt"
      instructions: |
        Compose Multiplatform 화면 best practices:
        - 리소스는 멀티플랫폼 리소스 사용: stringResource(Res.string.x),
          painterResource(Res.drawable.x) (org.jetbrains.compose.resources)
          → Android 전용 R.string / androidx.compose.ui.res.* 사용 금지
        - @Preview는 멀티플랫폼용(org.jetbrains.compose.ui.tooling.preview.Preview) 사용
        - 플랫폼 종속 UI(뒤로가기 처리, 시스템 바, 햅틱, 파일 피커 등)는 expect/actual로 분리
        - state hoisting: 비즈니스 상태를 ViewModel/StateHolder로, Composable은 stateless 지향
        - LaunchedEffect/DisposableEffect의 key 검증, rememberSaveable로 상태 보존
        - 하드코딩 색상/문자열 회피(MaterialTheme + 멀티플랫폼 리소스), 접근성 contentDescription
 
    # 2) 공용 UI / 디자인 시스템 디렉터리(commonMain)
    - path: "**/commonMain/**/{ui,designsystem,components}/**/*.kt"
      instructions: |
        공유 디자인 시스템 best practices:
        - @Composable 함수명은 PascalCase, Modifier 매개변수는 default와 첫 옵셔널 위치
        - 매개변수 데이터 클래스에 @Stable/@Immutable 검토(재구성 최적화)
        - 플랫폼 분기는 expect/actual 또는 LocalPlatform 같은 주입으로, 직접 분기 회피
        - 멀티플랫폼 리소스(Res.*)만 사용, Android 리소스 API 금지
        - @Preview(멀티플랫폼)에 라이트/다크 변형 제공

플랫폼 소스셋(actual 구현)

androidMain, iosMain, jvmMain, wasmJsMain 등 플랫폼 소스셋은 expect에 대한 actual 구현과 플랫폼 전용 코드가 사는 곳입니다. 여기서는 플랫폼 API를 자유롭게 쓰되, 누수와 라이프사이클 버그를 막아야 합니다.

    - path: "**/{androidMain,iosMain,jvmMain,desktopMain,jsMain,wasmJsMain,nativeMain,appleMain}/**/*.kt"
      instructions: |
        플랫폼 소스셋(actual) best practices:
 
        actual 정합성:
        - actual 선언이 commonMain의 expect 시그니처와 정확히 일치하는지(가시성 포함)
        - 플랫폼 구현 세부는 internal로 캡슐화하고 공용 표면을 늘리지 않기
 
        Android(androidMain):
        - Activity/Context를 long-lived 객체에 보관 금지(메모리 누수)
        - androidx ViewModel/lifecycle은 androidMain에서만, commonMain으로 끌어올리지 않기
 
        iOS(iosMain, appleMain):
        - Kotlin/Native interop 시 메인 스레드 가정 주의(Dispatchers.Main 사용 가능 여부)
        - UIKit/Foundation 호출은 iosMain에 가두고, 공용 인터페이스로만 노출
        - 무거운 작업의 스레드 컨텍스트 전환이 명확한지
 
        JVM/Desktop, JS/Wasm:
        - 데스크톱 전용 파일 시스템/스레딩, 웹 전용 DOM/브라우저 API가 해당 소스셋에만 있는지

iOS 프레임워크 노출 / Swift interop

KMP의 공유 모듈은 iOS에 프레임워크(XCFramework) 로 노출되고, iosApp의 Swift 코드가 이를 소비합니다. Swift에서 쓰기 어려운 형태로 API를 내보내면 iOS 팀의 생산성이 크게 떨어지므로, 이 경계를 별도로 점검합니다.

    # 공유 모듈이 iOS로 노출하는 Swift 측 소비 코드
    - path: "**/iosApp/**/*.swift"
      instructions: |
        KMP ↔ Swift interop best practices:
        - 공유 모듈의 suspend 함수/Flow를 Swift에서 직접 다루기 어렵다면
          SKIE 또는 KMP-NativeCoroutines로 async/AsyncSequence 브리징 사용
        - 공유 코드가 던지는 에러를 Swift do/catch로 적절히 처리(KotlinException 누수 방지)
        - 공유 타입을 Swift에서 강제 캐스팅(as!)하지 말고 안전하게 처리
        - 메인 스레드 가정: UI 갱신은 메인에서, 공유 모듈 콜백의 스레드 확인
        - Swift 측 코드 스타일·메모리(클로저 [weak self])는 iOS 가이드 규칙과 동일하게 적용

참고: iOS 프레임워크의 baseName/isStatic/export 설정은 공유 모듈의 build.gradle.kts에서 관리합니다. 아래 Gradle 규칙에서 함께 검사합니다. 공유 모듈이 Swift에 노출하는 public API는 Swift-friendly하게(완료 핸들러 또는 SKIE 브리징) 설계됐는지 확인하세요.

의존성 주입(Koin)

Android 전용인 Hilt는 commonMain에서 동작하지 않습니다. KMP에서는 보통 Koin(또는 kotlin-inject, Metro)을 사용합니다. 잘못 짜면 모든 플랫폼에 잘못된 인스턴스가 흘러 들어가므로 별도로 점검합니다.

    # 1) DI 디렉터리
    - path: "**/{di,koin,inject}/**/*.kt"
      instructions: |
        Multiplatform DI(Koin) best practices:
        - 공용 모듈은 commonMain의 module { } 로 정의, 플랫폼 의존은 expect fun platformModule(): Module
        - single/factory/scoped 수명이 의도와 일치하는지(특히 single 남용 주의)
        - 의존성은 인터페이스 바인딩 우선, 구체 타입 직접 결합 회피(테스트 교체 가능성)
        - initKoin(...) 진입점에서 플랫폼 모듈이 빠짐없이 등록되는지
        - Android 전용 DI(Hilt) 어노테이션이 commonMain에 들어오지 않았는지
        - 순환 의존성 금지
 
    # 2) /di 디렉터리 밖 모듈 정의도 잡기 위한 파일명 패턴
    - path: "**/*Module.kt"
      instructions: |
        Koin @Module/module { } 검증:
        - 플랫폼별 actual module이 commonMain expect와 일관된 의존성을 제공하는지
        - 테스트용 모듈이 운영 모듈과 동일한 인터페이스를 노출하는지

Gradle (KMP build script)

build.gradle.kts타깃 선언, 소스셋 의존성, iOS 프레임워크 export, Compose 플러그인이 모두 모이는 곳입니다. 의존성을 잘못된 소스셋에 두거나 타깃 설정이 어긋나면 빌드가 통째로 깨집니다.

    - path: "**/build.gradle.kts"
      instructions: |
        Gradle Kotlin Multiplatform review:
        - kotlin { } 타깃 선언이 프로젝트 지원 플랫폼과 일치(androidTarget, iosX64/Arm64/SimulatorArm64, jvm, wasmJs 등)
        - sourceSets 의존성이 올바른 위치에 선언됐는지
          (멀티플랫폼 라이브러리는 commonMain.dependencies, 플랫폼 전용은 해당 소스셋)
        - 의존성은 버전 하드코딩보다 version catalog(libs.versions.toml) 사용
        - iOS framework 블록: baseName 일관성, isStatic/export 설정 의도 확인
        - cocoapods 또는 XCFramework 배포 설정이 일관적인지
        - Compose Multiplatform 플러그인/리소스 설정과 compiler optIn 적절성
        - deprecated된 Gradle/KMP DSL 사용 시 마이그레이션 코멘트
 
    - path: "**/libs.versions.toml"
      instructions: |
        Version catalog review:
        - versions/libraries/plugins/bundles 분리, 멀티플랫폼 라이브러리 버전 일관성
        - Compose Multiplatform/Kotlin/AGP 버전 호환 조합 확인
        - 동일 라이브러리 중복 정의/충돌 확인

AndroidManifest / Info.plist (앱 래퍼)

KMP 프로젝트에도 Android 앱 모듈과 iOS 앱(iosApp)이 있으므로, 권한·보안 표면은 각 플랫폼 가이드 기준으로 점검합니다.

    - path: "**/AndroidManifest.xml"
      instructions: |
        AndroidManifest review:
        - 새 위험 권한에 사유와 런타임 요청 코드 동반, exported 명시,
          intent-filter scope, debuggable/cleartextTraffic/allowBackup 의도 일치.
 
    - path: "**/Info.plist"
      instructions: |
        Info.plist review:
        - 개인정보 권한 키에 사유 문자열 + 런타임 요청 코드 동반,
          ATS 전역 허용(NSAllowsArbitraryLoads) 금지, URL scheme·백그라운드 모드 과도 여부 점검.

테스트 코드

commonTest모든 플랫폼에서 실행되므로 플랫폼 API를 쓰면 안 됩니다. 플랫폼별 테스트는 각 소스셋에 둡니다.

    - path: "**/commonTest/**/*.kt"
      instructions: |
        commonTest best practices:
        - kotlin.test(assertEquals 등) + kotlinx-coroutines-test(runTest) 사용
        - 플랫폼 전용 API 사용 금지(commonTest는 전 타깃에서 컴파일·실행)
        - StateFlow/Flow 검증은 Turbine(멀티플랫폼) 사용
        - 의존성은 fake/test double로 주입, 외부 통신·디스크 접근 금지
        - Compose UI 테스트는 runComposeUiTest 등 멀티플랫폼 API로
 
    - path: "**/{androidUnitTest,androidInstrumentedTest,iosTest,jvmTest,desktopTest}/**/*.kt"
      instructions: |
        플랫폼별 테스트 best practices:
        - 해당 플랫폼 특화 동작(actual 구현, 플랫폼 통합)만 검증
        - 시나리오/기대 결과가 드러나는 테스트 이름, AAA 패턴
        - 안드로이드 계측 테스트/iOS 테스트의 메인 스레드·디스패처 가정 확인

tools: 정적 분석 통합

CodeRabbit은 자체 AI 리뷰 외에도 외부 정적 분석기를 PR에서 같이 돌리는 기능을 제공합니다. KMP 프로젝트라면 다음 조합을 권장합니다.

reviews:
  tools:
    # Kotlin 정적 분석(공유·Android·JVM 코드 전반)
    detekt:
      enabled: true
      # config_file: "config/detekt/detekt.yml"
 
    # iosApp의 Swift 코드 정적 분석
    swiftlint:
      enabled: true
 
    # 시크릿 스캐닝
    gitleaks:
      enabled: true
  • detekt: Kotlin 전용 린터로 commonMain·androidMain·jvmMain 등 Kotlin 코드 전반을 검사합니다. detekt baseline을 운영 중이라면 config_file로 연결하세요.
  • SwiftLint: iosApp의 Swift 래퍼 코드를 검사합니다. 공유 모듈은 Kotlin, iOS 앱 셸은 Swift이므로 둘 다 켜 두면 양쪽을 모두 커버합니다.
  • gitleaks: API 키·자격 증명이 커밋에 섞였는지 확인합니다. KMP는 local.properties, gradle.properties, iOS *.xcconfig에 키를 두기 쉬워 머지 전 단계에서 잡는 것이 중요합니다. 보안 관점의 더 깊은 맥락은 Vercel 침해 사고가 엔터프라이즈 코드 보안에 던지는 세 가지 교훈에서 이어 보실 수 있습니다.

참고: 포매터, Spotless / ktlint

많은 KMP 프로젝트가 detekt와 별개로 Spotless(ktlint 통합)로 포매팅을 적용합니다. 팀이 이미 CI에서 ./gradlew spotlessCheck를 돌리고 있다면, CodeRabbit은 코드 스타일이 아닌 로직·아키텍처·플랫폼 정합성 차원에 집중하게 두고 포매팅은 CI에 맡기는 분담이 효과적입니다.

이외에 OSV-Scanner로 Gradle/SPM 의존성의 알려진 CVE를 함께 점검할 수도 있습니다.

모듈식 프로젝트 추가 팁

KMP/CMP는 보통 shared(또는 composeApp) 공유 모듈 + androidApp + iosApp 구조로 시작해, 기능이 커지면 feature/core 모듈로 분리합니다. Confetti, KaMPKit, PeopleInSpace 같은 공개 프로젝트가 좋은 실제 사례입니다.

    # 공유 기능 모듈의 공개 API 경계
    - path: "**/feature/**/commonMain/**/*.kt"
      instructions: |
        공유 기능 모듈 best practices:
        - public으로 노출하는 타입 최소화, 구현 세부는 internal로 은닉
        - 기능 모듈 간 직접 의존 금지(core/shared 모듈 경유), 단방향 의존성
        - 공용 표면은 안정적 값 타입(data class/sealed) 위주로
 
    # 컨벤션 플러그인(build-logic) - 모듈식 프로젝트
    - path: "build-logic/**/*.kt"
      instructions: |
        Convention plugin best practices:
        - KMP 타깃·소스셋 설정을 헬퍼로 일원화하고 한 책임만 갖도록 분리
        - 버전은 libs.versions.toml에서 끌어오고 하드코딩 금지
        - 새 컨벤션은 settings.gradle.kts/pluginManagement에 등록됐는지

전체 예시: KMP 팀이 그대로 가져다 쓸 수 있는 yaml

# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
language: ko-KR
early_access: false
 
reviews:
  profile: chill
  high_level_summary: true
  collapse_walkthrough: true
  poem: false
 
  path_filters:
    - "**/*.kt"
    - "**/*.kts"
    - "**/iosApp/**/*.swift"
    - "**/AndroidManifest.xml"
    - "**/Info.plist"
    - "**/*.entitlements"
    - "**/*.gradle.kts"
    - "**/libs.versions.toml"
    - "**/composeResources/**/*.xml"
    - "!**/build/**"
    - "!**/.gradle/**"
    - "!**/.kotlin/**"
    - "!**/generated/**"
    - "!**/ksp/**"
    - "!**/kapt/**"
    - "!**/*.klib"
    - "!**/DerivedData/**"
    - "!**/Pods/**"
    - "!**/*.xcodeproj/**"
    - "!**/*.xcworkspace/**"
    - "!**/kotlin-js-store/**"
 
  auto_review:
    enabled: true
    auto_incremental_review: true
    drafts: false
    base_branches:
      - main
      - develop
    ignore_usernames:
      - dependabot
      - "dependabot[bot]"
      - renovate
      - "renovate[bot]"
 
  path_instructions:
    - path: "**/*.kt"
      instructions: |
        Kotlin best practices: null safety(!! 금지), val 우선, structured concurrency,
        디스패처 주입, GlobalScope 금지, Result/sealed로 실패 표현, 하드코딩 시크릿 금지,
        expect에는 모든 타깃의 actual이 짝으로 존재.
 
    # commonMain 플랫폼 중립성 (KMP 핵심)
    - path: "**/commonMain/**/*.kt"
      instructions: |
        commonMain: 플랫폼 전용 API(android.*, java.*, platform.UIKit, kotlinx.browser) 금지,
        멀티플랫폼 라이브러리만 사용, Dispatchers.IO는 JS/Wasm 미지원이니 직접 참조 금지(주입/expect),
        플랫폼 자원(시간·난수·파일)은 expect/주입으로 추상화.
 
    # Compose Multiplatform 화면
    - path: "**/*Screen.kt"
      instructions: |
        CMP 화면: 멀티플랫폼 리소스(Res.string/Res.drawable, org.jetbrains.compose.resources) 사용,
        Android R.string/androidx.compose.ui.res 금지, @Preview는 멀티플랫폼용,
        플랫폼 종속 UI는 expect/actual, state hoisting, LaunchedEffect key 검증, 접근성.
 
    # 공유 디자인 시스템(commonMain)
    - path: "**/commonMain/**/{ui,designsystem,components}/**/*.kt"
      instructions: |
        공유 디자인 시스템: @Composable PascalCase, Modifier 디폴트·위치,
        @Stable/@Immutable 검토, 플랫폼 분기는 expect/actual, 멀티플랫폼 리소스만 사용.
 
    # 플랫폼 소스셋(actual 구현)
    - path: "**/{androidMain,iosMain,jvmMain,desktopMain,jsMain,wasmJsMain,nativeMain,appleMain}/**/*.kt"
      instructions: |
        플랫폼 소스셋: actual이 expect 시그니처(가시성 포함)와 일치, 플랫폼 세부는 internal 캡슐화,
        androidMain은 Context 누수 금지·lifecycle은 여기서만, iosMain은 메인 스레드 가정·UIKit 가두기.
 
    # KMP ↔ Swift interop (iOS 앱 래퍼)
    - path: "**/iosApp/**/*.swift"
      instructions: |
        Swift interop: 공유 모듈 suspend/Flow는 SKIE/NativeCoroutines로 브리징,
        KotlinException은 do/catch 처리, 강제 캐스팅(as!) 회피, UI는 메인 스레드,
        클로저 [weak self]로 순환 참조 방지.
 
    # DI(Koin)
    - path: "**/{di,koin,inject}/**/*.kt"
      instructions: |
        Koin: 공용 모듈은 commonMain module { }, 플랫폼은 expect fun platformModule(),
        single/factory 수명 점검, 인터페이스 바인딩 우선, initKoin에 플랫폼 모듈 누락 없는지,
        Hilt 어노테이션이 commonMain에 들어오지 않았는지.
 
    - path: "**/*Module.kt"
      instructions: |
        Koin module 파일: 플랫폼 actual module이 commonMain expect와 일관된 의존성 제공,
        테스트 모듈이 운영 모듈과 동일 인터페이스 노출.
 
    # build-logic 컨벤션 플러그인
    - path: "build-logic/**/*.kt"
      instructions: |
        Convention plugin: KMP 타깃/소스셋 설정 일원화, 한 책임 원칙,
        libs.versions.toml에서 버전 끌어오기.
 
    - path: "**/build.gradle.kts"
      instructions: |
        Gradle KMP: kotlin{} 타깃 일관성, 의존성을 올바른 소스셋에 선언
        (멀티플랫폼은 commonMain, 플랫폼 전용은 해당 소스셋), version catalog 사용,
        iOS framework baseName/isStatic/export 일관성, Compose/compiler optIn 적절성.
 
    - path: "**/libs.versions.toml"
      instructions: |
        Version catalog: 멀티플랫폼 라이브러리 버전 일관성,
        Compose Multiplatform/Kotlin/AGP 호환 조합, 중복 정의 금지.
 
    - path: "**/AndroidManifest.xml"
      instructions: |
        Manifest: 위험 권한에 사유/런타임 요청 동반, exported 명시, intent-filter scope,
        debuggable/cleartextTraffic/allowBackup 의도 일치.
 
    - path: "**/Info.plist"
      instructions: |
        Info.plist: 개인정보 권한에 사유 문자열+런타임 요청 동반,
        ATS 전역 허용 금지, URL scheme·백그라운드 모드 과도 여부 점검.
 
    - path: "**/commonTest/**/*.kt"
      instructions: |
        commonTest: kotlin.test + runTest, 플랫폼 API 금지(전 타깃 실행),
        Flow는 Turbine, 의존성은 fake 주입, Compose UI는 runComposeUiTest.
 
    - path: "**/{androidUnitTest,androidInstrumentedTest,iosTest,jvmTest,desktopTest}/**/*.kt"
      instructions: |
        플랫폼별 테스트: 플랫폼 특화 동작·actual만 검증, 시나리오/기대가 드러나는 이름,
        AAA 패턴, 메인 스레드·디스패처 가정 확인.
 
  tools:
    detekt:
      enabled: true
    swiftlint:
      enabled: true
    gitleaks:
      enabled: true
 
chat:
  auto_reply: true

도입 후 점검 포인트

설정이 적용된 PR을 한두 개 받아 본 뒤, 다음을 가볍게 점검해 보시는 것을 추천 드립니다.

  • 소스셋 디렉터리 이름이 팀 컨벤션과 맞는가? 예를 들어 데스크톱 타깃을 desktopMain이 아니라 jvmMain으로 쓴다면 glob을 그에 맞게 바꿔 주세요. CMP 화면을 *Screen.kt가 아닌 다른 컨벤션으로 둔다면 파일명 패턴도 조정이 필요합니다.
  • commonMain 플랫폼 누수 코멘트의 정확도가 낮다면, 팀이 쓰는 멀티플랫폼 라이브러리 화이트리스트를 instructions에 명시하면 효과가 큽니다.
  • detekt가 이미 잡는 항목과 중복이 심하면 instructions"detekt가 잡는 스타일 nitpick은 제외" 한 줄을 추가하세요.

조직 단위로 동일한 정책을 강제하고 싶다면, 조직에 coderabbit 레포지터리를 만들고 같은 yaml을 Central Configuration으로 올려두면 모든 KMP 레포가 같은 기준으로 리뷰됩니다. 더 큰 그림에서 AI 코드 리뷰 도구를 평가하고 비교하는 관점은 AI 코드 리뷰 도구 완벽 가이드 2026에서, CodeRabbit이 처음이시라면 CodeRabbit으로 깃헙 PR 코드 리뷰 자동화 하기를 함께 보시기를 추천 드립니다.

이 설정을 들고 PR을 한 번 올려 보시고, 실제로 받은 리뷰를 팀에 공유해 보세요. AI 코드 리뷰의 톤과 깊이가 "팀 시니어 KMP 개발자가 본 듯" 한 모습으로 바뀌는 게 가장 큰 변화일 겁니다.

CodeRabbit 시작하기