오픈소스 기여 후기: AI와 페어로 첫 PR을 올려 하루 만에 머지된 과정
오픈소스 기여 후기입니다. 매일 쓰던 터미널 앱의 작은 불편을 AI와 페어로 고쳐 첫 PR을 하루 만에 머지했고, 머지 후 한 시간 만에 후속 수정도 올렸습니다.
목차
평소 쓰던 터미널 앱에 작은 불편이 있었다. AI한테 "이거 한번 고쳐서 PR 올려볼까?" 하고 시작했더니, 점심 먹기 전에 머지가 됐고 한 시간 만에 후속 fix까지 올라왔다.
어, 이거 내가 고쳐볼 수 있는 거 아닌가#
매일 쓰는 터미널 앱(muxy) 얘기다. 두 탭을 띄워두고 비활성 탭에 이미지를 끌어다 놓으면, 어딘가에 들어가긴 하는데 어느 탭에 들어가는지 시각적으로 안 보인다. 그리고 들어간 후 그 탭으로 자동 전환도 안 된다.
별 거 아닌 것 같지만 매일 쓰면 매일 거슬린다.

오픈소스 앱이라 GitHub repo는 열려 있다. 평소 같으면 "음, 언젠가 issue로 올려야겠다" 정도로 끝났을 거다. 근데 옆에 AI(Claude)가 켜져 있었다.
"이거 같이 고쳐서 PR 한번 올려보면 어떨까?"
AI는 코드를 짜고, 나는 테스트한다#
페어 프로그래밍 흐름이 자연스럽게 만들어졌다.
- AI가 관련 파일 찾고 변경 작성
- 나는 빌드해서 실제로 띄워서 동작 확인
- 안 되거나 이상하면 증상을 그대로 말로 설명
- AI가 다음 가설 세우고 다시 시도
처음엔 잘 됐다. 비활성 탭 영역 위로 드래그하면 파란 오버레이가 뜨고, 잠깐 머무르면 자동 전환되고. 머지 직전 같았다.
근데 진짜 작업은 이제 시작이었다.
"마우스 살짝 움직이면 들어가요"#
테스트하다 보니 이상한 패턴이 보였다. 이미지를 드롭하고 나면 가끔 텍스트가 잠깐 안 들어갔다. 마우스를 살짝 움직이거나 키 한 번 누르면 그제서야 화면에 나타났다.
AI한테 그대로 말했더니 답이 왔다. "이건 macOS의 runloop mode 문제일 가능성이 높아요. 드래그 중엔 운영체제가 다른 모드에 잠깐 들어가서, 그동안 처리될 일들이 큐에 쌓이거든요."
runloop mode = 운영체제가 "지금 드래그 중", "지금 메뉴 선택 중" 같이 잠깐씩 모드를 바꾸며 일하는 방식. 모드마다 그 안에서 처리되는 일이 따로 있다.
여러 시도가 실패했고 일부는 더 악화시켰다. 결국은 우회 방법으로 일단 잡았는데, 가끔 잔존했다. 우리 PR 범위 밖의 muxy 자체 이슈로 보였다. 그래서 별도 issue로 따로 보고했다.
이런 타이밍 버그는 글보다 화면 녹화가 빨리 전달된다. macOS라면 클릭한 곳을 자동으로 확대해 MP4나 GIF로 내보내는 오픈소스 Loupecast로 재현 영상을 이슈에 붙일 수 있다.
"AI가 작성한 PR은 review 없이 닫힙니다"#
PR 올리려고 template 펼쳤더니 첫 줄에 이렇게 적혀 있었다.
Humans only: this PR's title, description, and comments must be written by you, not an AI. AI-generated text will be closed without review.
"음, 이건 AI한테 통째로 맡기면 안 되겠다."
방법은 간단했다. 내가 한국어로 적고, AI한테 영어로 옮겨달라고만 했다. 의도는 내 의도, 표현은 내 표현, 영어로 바꾸는 손만 빌렸다. 코드 작성은 OK라는 룰이라 그건 그대로.
PR 제목도 한국어로 먼저 적었다. "파일을 드래그 앤 드랍으로 첨부할 때 시각적 인지성을 높입니다". 그걸 영어로 옮겨 "Improve visual feedback for file drag-and-drop attachment".
머지 후 한 시간 만에 후속 fix#
PR을 올렸다. 첫 외부 OSS contribute라 maintainer가 워크플로우를 수동 승인해줘야 CI가 돌았다 (외부 fork 보안 정책). 그 후엔 빨랐다.
머지 시간을 다시 봤다. PR 올리고 머지까지, 머지 후 maintainer가 별도로 후속 PR을 올려서 release까지, 이 모든 게 같은 날 안에 끝났다. 해 뜨고 나서 시작해서 점심 먹기 전에 다 끝났다.
흥미로운 건 maintainer가 내가 보고한 issue를 root cause까지 정확히 진단해서, 우리가 5겹 우회로 만든 코드보다 더 깔끔한 한 줄로 고쳤다는 거다.
RunLoop.main.perform(inModes: [.default]) { ... }이 한 줄이 우리가 시도해본 NSApp.activate + makeKeyAndOrderFront + makeFirstResponder + notifySurfaceFocused + DispatchQueue.main.async 다섯 줄짜리 우회보다 결정적이었다. 진짜 원인은 macOS의 화면 갱신이 어느 모드에서 처리되느냐였는데, 그걸 정확히 짚은 거다.

내 PR이 production에서 돌고, 내가 보고한 버그가 같은 release에서 더 깔끔하게 고쳐진 걸 같이 받아본 게 좀 묘했다. 첫 외부 PR이 이렇게 깨끗하게 닫히는 경우가 흔치 않다고 들었다.
지금은 이렇게 동작한다#
드래그를 시작하면 드롭 받을 area만 파랗게 강조된다. split 두 영역 중 어디로 들어가는지 한눈에 보인다.

비활성 탭 헤더 위에 잠깐 머무르면 그 탭으로 자동 전환된다. macOS Finder의 spring-loaded 폴더 같은 패턴이다.
드롭하면 즉시 그 탭으로 들어간다. 키 바로 누를 수 있다 (이게 처음엔 안 됐던 부분). macOS의 "바탕화면 클릭으로 데스크탑 보기" 직후 같은 까다로운 상황에서도 똑같이 즉시 동작한다.
작은 변화지만, 매일 쓰는 동작이라 매일 체감된다.
새로운 협업 같다#
옛날엔 외부 OSS PR 한 번 올리는 게 꽤 큰 일이었다. 코드베이스 익히고, 컨벤션 맞추고, 빌드 환경 세팅하고, 영어로 본문 쓰고, review 받으면 또 영어로 답하고.
지금은 옆에 AI 켜놓고 페어 코딩하면 흐름이 다르다. AI는 코드를 짜고 내가 테스트하고, 막히면 같이 단서 찾고, PR 본문은 내 한국어를 영어로 옮긴다.
물론 AI가 지름길은 아니다. 핵심 단서("마우스 살짝 움직이면 들어가요")는 결국 내가 사용자로서 발견한 거다. 첫 가설이 빗나갔을 때 새 가설을 세우는 것도 협업의 흐름 안에서 일어났지, AI 혼자 한 일이 아니었다.
내 의도, AI의 손. 그게 새로운 협업처럼 느껴졌다.